14ed92545SAttilio Rao /*-
24ed92545SAttilio Rao * Copyright (c) 2010 Giovanni Trematerra <giovanni.trematerra@gmail.com>
34ed92545SAttilio Rao * All rights reserved.
44ed92545SAttilio Rao *
54ed92545SAttilio Rao * Redistribution and use in source and binary forms, with or without
64ed92545SAttilio Rao * modification, are permitted provided that the following conditions
74ed92545SAttilio Rao * are met:
84ed92545SAttilio Rao * 1. Redistributions of source code must retain the above copyright
94ed92545SAttilio Rao * notice, this list of conditions and the following disclaimer.
104ed92545SAttilio Rao * 2. Redistributions in binary form must reproduce the above copyright
114ed92545SAttilio Rao * notice, this list of conditions and the following disclaimer in the
124ed92545SAttilio Rao * documentation and/or other materials provided with the distribution.
134ed92545SAttilio Rao *
144ed92545SAttilio Rao * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
154ed92545SAttilio Rao * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
164ed92545SAttilio Rao * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
174ed92545SAttilio Rao * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
184ed92545SAttilio Rao * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
194ed92545SAttilio Rao * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
204ed92545SAttilio Rao * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
214ed92545SAttilio Rao * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
224ed92545SAttilio Rao * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
234ed92545SAttilio Rao * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
244ed92545SAttilio Rao * SUCH DAMAGE.
254ed92545SAttilio Rao */
264ed92545SAttilio Rao
274ed92545SAttilio Rao /*
284ed92545SAttilio Rao * PURPOSE:
294ed92545SAttilio Rao *
304ed92545SAttilio Rao * This kernel module helped to identify a deadlock in kthread
314ed92545SAttilio Rao * interface, also pointed out a race in kthread_exit function.
324ed92545SAttilio Rao *
334ed92545SAttilio Rao */
344ed92545SAttilio Rao
354ed92545SAttilio Rao #include <sys/param.h>
364ed92545SAttilio Rao #include <sys/kernel.h>
374ed92545SAttilio Rao #include <sys/kthread.h>
384ed92545SAttilio Rao #include <sys/lock.h>
394ed92545SAttilio Rao #include <sys/module.h>
404ed92545SAttilio Rao #include <sys/mutex.h>
414ed92545SAttilio Rao #include <sys/systm.h>
424ed92545SAttilio Rao #include <sys/time.h>
434ed92545SAttilio Rao
444ed92545SAttilio Rao #ifdef TESTPAUSE_DEBUG
454ed92545SAttilio Rao #define DPRINTF(x) do { \
464ed92545SAttilio Rao printf (x); \
474ed92545SAttilio Rao } while (0)
484ed92545SAttilio Rao #else
494ed92545SAttilio Rao #define DPRINTF(x)
504ed92545SAttilio Rao #endif
514ed92545SAttilio Rao
524ed92545SAttilio Rao static struct mtx test_global_lock;
534ed92545SAttilio Rao static int global_condvar;
544ed92545SAttilio Rao static int test_thrcnt;
554ed92545SAttilio Rao volatile int QUIT;
564ed92545SAttilio Rao
574ed92545SAttilio Rao static void
thr_suspender(void * arg)584ed92545SAttilio Rao thr_suspender(void *arg)
594ed92545SAttilio Rao {
604ed92545SAttilio Rao struct thread *td = (struct thread *) arg;
614ed92545SAttilio Rao int error;
624ed92545SAttilio Rao
634ed92545SAttilio Rao for (;;) {
644ed92545SAttilio Rao if (QUIT == 1)
654ed92545SAttilio Rao break;
664ed92545SAttilio Rao error = kthread_suspend(td, 10*hz);
674ed92545SAttilio Rao if (error != 0 && QUIT == 0) {
684ed92545SAttilio Rao if (error == EWOULDBLOCK)
694ed92545SAttilio Rao panic("Ooops: kthread deadlock\n");
704ed92545SAttilio Rao else
714ed92545SAttilio Rao panic("kthread_suspend error: %d\n", error);
724ed92545SAttilio Rao break;
734ed92545SAttilio Rao }
744ed92545SAttilio Rao }
754ed92545SAttilio Rao
764ed92545SAttilio Rao mtx_lock(&test_global_lock);
774ed92545SAttilio Rao test_thrcnt--;
784ed92545SAttilio Rao wakeup(&global_condvar);
794ed92545SAttilio Rao mtx_unlock(&test_global_lock);
804ed92545SAttilio Rao
814ed92545SAttilio Rao kthread_exit();
824ed92545SAttilio Rao }
834ed92545SAttilio Rao
844ed92545SAttilio Rao static void
thr_resumer(void * arg)854ed92545SAttilio Rao thr_resumer(void *arg)
864ed92545SAttilio Rao {
874ed92545SAttilio Rao struct thread *td = (struct thread *) arg;
884ed92545SAttilio Rao int error;
894ed92545SAttilio Rao
904ed92545SAttilio Rao for (;;) {
914ed92545SAttilio Rao /* must be the last thread to exit */
924ed92545SAttilio Rao if (QUIT == 1 && test_thrcnt == 1)
934ed92545SAttilio Rao break;
944ed92545SAttilio Rao error = kthread_resume(td);
954ed92545SAttilio Rao if (error != 0)
964ed92545SAttilio Rao panic("%s: error on kthread_resume. error: %d\n",
974ed92545SAttilio Rao __func__, error);
984ed92545SAttilio Rao }
994ed92545SAttilio Rao
1004ed92545SAttilio Rao mtx_lock(&test_global_lock);
1014ed92545SAttilio Rao test_thrcnt--;
1024ed92545SAttilio Rao wakeup(&global_condvar);
1034ed92545SAttilio Rao mtx_unlock(&test_global_lock);
1044ed92545SAttilio Rao
1054ed92545SAttilio Rao kthread_exit();
1064ed92545SAttilio Rao }
1074ed92545SAttilio Rao
1084ed92545SAttilio Rao static void
thr_getsuspended(void * arg)1094ed92545SAttilio Rao thr_getsuspended(void *arg)
1104ed92545SAttilio Rao {
1114ed92545SAttilio Rao for (;;) {
1124ed92545SAttilio Rao if (QUIT == 1)
1134ed92545SAttilio Rao break;
1144ed92545SAttilio Rao kthread_suspend_check();
1154ed92545SAttilio Rao }
1164ed92545SAttilio Rao
1174ed92545SAttilio Rao mtx_lock(&test_global_lock);
1184ed92545SAttilio Rao test_thrcnt--;
1194ed92545SAttilio Rao wakeup(&global_condvar);
1204ed92545SAttilio Rao mtx_unlock(&test_global_lock);
1214ed92545SAttilio Rao
1224ed92545SAttilio Rao kthread_exit();
1234ed92545SAttilio Rao }
1244ed92545SAttilio Rao
1254ed92545SAttilio Rao static void
kthrdlk_init(void)1264ed92545SAttilio Rao kthrdlk_init(void)
1274ed92545SAttilio Rao {
1284ed92545SAttilio Rao struct proc *testproc;
1294ed92545SAttilio Rao struct thread *newthr;
1304ed92545SAttilio Rao int error;
1314ed92545SAttilio Rao
1324ed92545SAttilio Rao QUIT = 0;
1334ed92545SAttilio Rao test_thrcnt = 3;
1344ed92545SAttilio Rao mtx_init(&test_global_lock, "kthrdlk_lock", NULL, MTX_DEF);
1354ed92545SAttilio Rao testproc = NULL;
1364ed92545SAttilio Rao error = kproc_kthread_add(thr_getsuspended, NULL, &testproc, &newthr,
1374ed92545SAttilio Rao 0, 0, "kthrdlk", "thr_getsuspended");
1384ed92545SAttilio Rao if (error != 0)
1394ed92545SAttilio Rao panic("cannot start thr_getsuspended error: %d\n", error);
1404ed92545SAttilio Rao
1414ed92545SAttilio Rao error = kproc_kthread_add(thr_resumer, newthr, &testproc, NULL, 0, 0,
1424ed92545SAttilio Rao "kthrdlk", "thr_resumer");
1434ed92545SAttilio Rao if (error != 0)
1444ed92545SAttilio Rao panic("cannot start thr_resumer error: %d\n", error);
1454ed92545SAttilio Rao
1464ed92545SAttilio Rao error = kproc_kthread_add(thr_suspender, newthr, &testproc, NULL, 0, 0,
1474ed92545SAttilio Rao "kthrdlk", "thr_suspender");
1484ed92545SAttilio Rao if (error != 0)
1494ed92545SAttilio Rao panic("cannot start thr_suspender error: %d\n", error);
1504ed92545SAttilio Rao }
1514ed92545SAttilio Rao
1524ed92545SAttilio Rao static void
kthrdlk_done(void)1534ed92545SAttilio Rao kthrdlk_done(void)
1544ed92545SAttilio Rao {
1554ed92545SAttilio Rao int ret;
1564ed92545SAttilio Rao DPRINTF(("sending QUIT signal to the thrdlk threads\n"));
1574ed92545SAttilio Rao
1584ed92545SAttilio Rao /* wait kernel threads end */
1594ed92545SAttilio Rao mtx_lock(&test_global_lock);
1604ed92545SAttilio Rao QUIT = 1;
1614ed92545SAttilio Rao while (test_thrcnt != 0) {
1624ed92545SAttilio Rao ret = mtx_sleep(&global_condvar, &test_global_lock, 0, "waiting thrs end", 30 * hz);
1634ed92545SAttilio Rao if (ret == EWOULDBLOCK) {
1648ce070c1SUlrich Spörlein panic("some threads not die! remaining: %d", test_thrcnt);
1654ed92545SAttilio Rao break;
1664ed92545SAttilio Rao }
1674ed92545SAttilio Rao }
1684ed92545SAttilio Rao if (test_thrcnt == 0)
1694ed92545SAttilio Rao DPRINTF(("All test_pause threads die\n"));
1704ed92545SAttilio Rao
1714ed92545SAttilio Rao mtx_destroy(&test_global_lock);
1724ed92545SAttilio Rao }
1734ed92545SAttilio Rao
1744ed92545SAttilio Rao static int
kthrdlk_handler(module_t mod,int what,void * arg)1754ed92545SAttilio Rao kthrdlk_handler(module_t mod, int /*modeventtype_t*/ what,
1764ed92545SAttilio Rao void *arg)
1774ed92545SAttilio Rao {
1784ed92545SAttilio Rao switch (what) {
1794ed92545SAttilio Rao case MOD_LOAD:
1804ed92545SAttilio Rao kthrdlk_init();
1814ed92545SAttilio Rao uprintf("kthrdlk loaded!\n");
1824ed92545SAttilio Rao return (0);
1834ed92545SAttilio Rao case MOD_UNLOAD:
1844ed92545SAttilio Rao kthrdlk_done();
1854ed92545SAttilio Rao uprintf("Bye Bye! kthrdlk unloaded!\n");
1864ed92545SAttilio Rao return (0);
1874ed92545SAttilio Rao }
1884ed92545SAttilio Rao
1894ed92545SAttilio Rao return (EOPNOTSUPP);
1904ed92545SAttilio Rao }
1914ed92545SAttilio Rao
1924ed92545SAttilio Rao static moduledata_t mod_data= {
1934ed92545SAttilio Rao "kthrdlk",
1944ed92545SAttilio Rao kthrdlk_handler,
195*9823d527SKevin Lo 0
1964ed92545SAttilio Rao };
1974ed92545SAttilio Rao
1984ed92545SAttilio Rao MODULE_VERSION(kthrdlk, 1);
1994ed92545SAttilio Rao
2004ed92545SAttilio Rao DECLARE_MODULE(kthrdlk, mod_data, SI_SUB_EXEC, SI_ORDER_ANY);
201*9823d527SKevin Lo
202