xref: /freebsd/tools/regression/kthread/kld/kthrdlk.c (revision 6bfca4dcab07dad45a805879d954876b353c0810)
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