1/*- 2 * Copyright (c) 2010 Giovanni Trematerra <giovanni.trematerra@gmail.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27/* 28 * PURPOSE: 29 * 30 * This kernel module helped to identify a deadlock in kthread 31 * interface, also pointed out a race in kthread_exit function. 32 * 33 */ 34 35#include <sys/param.h> 36#include <sys/kernel.h> 37#include <sys/kthread.h> 38#include <sys/lock.h> 39#include <sys/module.h> 40#include <sys/mutex.h> 41#include <sys/systm.h> 42#include <sys/time.h> 43 44#ifdef TESTPAUSE_DEBUG 45#define DPRINTF(x) do { \ 46 printf (x); \ 47} while (0) 48#else 49#define DPRINTF(x) 50#endif 51 52static struct mtx test_global_lock; 53static int global_condvar; 54static int test_thrcnt; 55volatile int QUIT; 56 57static void 58thr_suspender(void *arg) 59{ 60 struct thread *td = (struct thread *) arg; 61 int error; 62 63 for (;;) { 64 if (QUIT == 1) 65 break; 66 error = kthread_suspend(td, 10*hz); 67 if (error != 0 && QUIT == 0) { 68 if (error == EWOULDBLOCK) 69 panic("Ooops: kthread deadlock\n"); 70 else 71 panic("kthread_suspend error: %d\n", error); 72 break; 73 } 74 } 75 76 mtx_lock(&test_global_lock); 77 test_thrcnt--; 78 wakeup(&global_condvar); 79 mtx_unlock(&test_global_lock); 80 81 kthread_exit(); 82} 83 84static void 85thr_resumer(void *arg) 86{ 87 struct thread *td = (struct thread *) arg; 88 int error; 89 90 for (;;) { 91 /* must be the last thread to exit */ 92 if (QUIT == 1 && test_thrcnt == 1) 93 break; 94 error = kthread_resume(td); 95 if (error != 0) 96 panic("%s: error on kthread_resume. error: %d\n", 97 __func__, error); 98 } 99 100 mtx_lock(&test_global_lock); 101 test_thrcnt--; 102 wakeup(&global_condvar); 103 mtx_unlock(&test_global_lock); 104 105 kthread_exit(); 106} 107 108static void 109thr_getsuspended(void *arg) 110{ 111 for (;;) { 112 if (QUIT == 1) 113 break; 114 kthread_suspend_check(); 115 } 116 117 mtx_lock(&test_global_lock); 118 test_thrcnt--; 119 wakeup(&global_condvar); 120 mtx_unlock(&test_global_lock); 121 122 kthread_exit(); 123} 124 125static void 126kthrdlk_init(void) 127{ 128 struct proc *testproc; 129 struct thread *newthr; 130 int error; 131 132 QUIT = 0; 133 test_thrcnt = 3; 134 mtx_init(&test_global_lock, "kthrdlk_lock", NULL, MTX_DEF); 135 testproc = NULL; 136 error = kproc_kthread_add(thr_getsuspended, NULL, &testproc, &newthr, 137 0, 0, "kthrdlk", "thr_getsuspended"); 138 if (error != 0) 139 panic("cannot start thr_getsuspended error: %d\n", error); 140 141 error = kproc_kthread_add(thr_resumer, newthr, &testproc, NULL, 0, 0, 142 "kthrdlk", "thr_resumer"); 143 if (error != 0) 144 panic("cannot start thr_resumer error: %d\n", error); 145 146 error = kproc_kthread_add(thr_suspender, newthr, &testproc, NULL, 0, 0, 147 "kthrdlk", "thr_suspender"); 148 if (error != 0) 149 panic("cannot start thr_suspender error: %d\n", error); 150} 151 152static void 153kthrdlk_done(void) 154{ 155 int ret; 156 DPRINTF(("sending QUIT signal to the thrdlk threads\n")); 157 158 /* wait kernel threads end */ 159 mtx_lock(&test_global_lock); 160 QUIT = 1; 161 while (test_thrcnt != 0) { 162 ret = mtx_sleep(&global_condvar, &test_global_lock, 0, "waiting thrs end", 30 * hz); 163 if (ret == EWOULDBLOCK) { 164 panic("some threads not die! remaining: %d", test_thrcnt); 165 break; 166 } 167 } 168 if (test_thrcnt == 0) 169 DPRINTF(("All test_pause threads die\n")); 170 171 mtx_destroy(&test_global_lock); 172} 173 174static int 175kthrdlk_handler(module_t mod, int /*modeventtype_t*/ what, 176 void *arg) 177{ 178 switch (what) { 179 case MOD_LOAD: 180 kthrdlk_init(); 181 uprintf("kthrdlk loaded!\n"); 182 return (0); 183 case MOD_UNLOAD: 184 kthrdlk_done(); 185 uprintf("Bye Bye! kthrdlk unloaded!\n"); 186 return (0); 187 } 188 189 return (EOPNOTSUPP); 190} 191 192static moduledata_t mod_data= { 193 "kthrdlk", 194 kthrdlk_handler, 195 0 196 }; 197 198MODULE_VERSION(kthrdlk, 1); 199 200DECLARE_MODULE(kthrdlk, mod_data, SI_SUB_EXEC, SI_ORDER_ANY); 201 202