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 52 static struct mtx test_global_lock; 53 static int global_condvar; 54 static int test_thrcnt; 55 volatile int QUIT; 56 57 static void 58 thr_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 84 static void 85 thr_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 108 static void 109 thr_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 125 static void 126 kthrdlk_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 152 static void 153 kthrdlk_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 174 static int 175 kthrdlk_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 192 static moduledata_t mod_data= { 193 "kthrdlk", 194 kthrdlk_handler, 195 0 196 }; 197 198 MODULE_VERSION(kthrdlk, 1); 199 200 DECLARE_MODULE(kthrdlk, mod_data, SI_SUB_EXEC, SI_ORDER_ANY); 201 202