Path: blob/main/tools/regression/kthread/kld/kthrdlk.c
48254 views
/*-1* Copyright (c) 2010 Giovanni Trematerra <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526/*27* PURPOSE:28*29* This kernel module helped to identify a deadlock in kthread30* interface, also pointed out a race in kthread_exit function.31*32*/3334#include <sys/param.h>35#include <sys/kernel.h>36#include <sys/kthread.h>37#include <sys/lock.h>38#include <sys/module.h>39#include <sys/mutex.h>40#include <sys/systm.h>41#include <sys/time.h>4243#ifdef TESTPAUSE_DEBUG44#define DPRINTF(x) do { \45printf (x); \46} while (0)47#else48#define DPRINTF(x)49#endif5051static struct mtx test_global_lock;52static int global_condvar;53static int test_thrcnt;54volatile int QUIT;5556static void57thr_suspender(void *arg)58{59struct thread *td = (struct thread *) arg;60int error;6162for (;;) {63if (QUIT == 1)64break;65error = kthread_suspend(td, 10*hz);66if (error != 0 && QUIT == 0) {67if (error == EWOULDBLOCK)68panic("Ooops: kthread deadlock\n");69else70panic("kthread_suspend error: %d\n", error);71break;72}73}7475mtx_lock(&test_global_lock);76test_thrcnt--;77wakeup(&global_condvar);78mtx_unlock(&test_global_lock);7980kthread_exit();81}8283static void84thr_resumer(void *arg)85{86struct thread *td = (struct thread *) arg;87int error;8889for (;;) {90/* must be the last thread to exit */91if (QUIT == 1 && test_thrcnt == 1)92break;93error = kthread_resume(td);94if (error != 0)95panic("%s: error on kthread_resume. error: %d\n",96__func__, error);97}9899mtx_lock(&test_global_lock);100test_thrcnt--;101wakeup(&global_condvar);102mtx_unlock(&test_global_lock);103104kthread_exit();105}106107static void108thr_getsuspended(void *arg)109{110for (;;) {111if (QUIT == 1)112break;113kthread_suspend_check();114}115116mtx_lock(&test_global_lock);117test_thrcnt--;118wakeup(&global_condvar);119mtx_unlock(&test_global_lock);120121kthread_exit();122}123124static void125kthrdlk_init(void)126{127struct proc *testproc;128struct thread *newthr;129int error;130131QUIT = 0;132test_thrcnt = 3;133mtx_init(&test_global_lock, "kthrdlk_lock", NULL, MTX_DEF);134testproc = NULL;135error = kproc_kthread_add(thr_getsuspended, NULL, &testproc, &newthr,1360, 0, "kthrdlk", "thr_getsuspended");137if (error != 0)138panic("cannot start thr_getsuspended error: %d\n", error);139140error = kproc_kthread_add(thr_resumer, newthr, &testproc, NULL, 0, 0,141"kthrdlk", "thr_resumer");142if (error != 0)143panic("cannot start thr_resumer error: %d\n", error);144145error = kproc_kthread_add(thr_suspender, newthr, &testproc, NULL, 0, 0,146"kthrdlk", "thr_suspender");147if (error != 0)148panic("cannot start thr_suspender error: %d\n", error);149}150151static void152kthrdlk_done(void)153{154int ret;155DPRINTF(("sending QUIT signal to the thrdlk threads\n"));156157/* wait kernel threads end */158mtx_lock(&test_global_lock);159QUIT = 1;160while (test_thrcnt != 0) {161ret = mtx_sleep(&global_condvar, &test_global_lock, 0, "waiting thrs end", 30 * hz);162if (ret == EWOULDBLOCK) {163panic("some threads not die! remaining: %d", test_thrcnt);164break;165}166}167if (test_thrcnt == 0)168DPRINTF(("All test_pause threads die\n"));169170mtx_destroy(&test_global_lock);171}172173static int174kthrdlk_handler(module_t mod, int /*modeventtype_t*/ what,175void *arg)176{177switch (what) {178case MOD_LOAD:179kthrdlk_init();180uprintf("kthrdlk loaded!\n");181return (0);182case MOD_UNLOAD:183kthrdlk_done();184uprintf("Bye Bye! kthrdlk unloaded!\n");185return (0);186}187188return (EOPNOTSUPP);189}190191static moduledata_t mod_data= {192"kthrdlk",193kthrdlk_handler,1940195};196197MODULE_VERSION(kthrdlk, 1);198199DECLARE_MODULE(kthrdlk, mod_data, SI_SUB_EXEC, SI_ORDER_ANY);200201202203