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/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <sys/param.h> 39 #include <sys/kernel.h> 40 #include <sys/kthread.h> 41 #include <sys/lock.h> 42 #include <sys/module.h> 43 #include <sys/mutex.h> 44 #include <sys/systm.h> 45 #include <sys/time.h> 46 47 #ifdef TESTPAUSE_DEBUG 48 #define DPRINTF(x) do { \ 49 printf (x); \ 50 } while (0) 51 #else 52 #define DPRINTF(x) 53 #endif 54 55 static struct mtx test_global_lock; 56 static int global_condvar; 57 static int test_thrcnt; 58 volatile int QUIT; 59 60 static void 61 thr_suspender(void *arg) 62 { 63 struct thread *td = (struct thread *) arg; 64 int error; 65 66 for (;;) { 67 if (QUIT == 1) 68 break; 69 error = kthread_suspend(td, 10*hz); 70 if (error != 0 && QUIT == 0) { 71 if (error == EWOULDBLOCK) 72 panic("Ooops: kthread deadlock\n"); 73 else 74 panic("kthread_suspend error: %d\n", error); 75 break; 76 } 77 } 78 79 mtx_lock(&test_global_lock); 80 test_thrcnt--; 81 wakeup(&global_condvar); 82 mtx_unlock(&test_global_lock); 83 84 kthread_exit(); 85 } 86 87 static void 88 thr_resumer(void *arg) 89 { 90 struct thread *td = (struct thread *) arg; 91 int error; 92 93 for (;;) { 94 /* must be the last thread to exit */ 95 if (QUIT == 1 && test_thrcnt == 1) 96 break; 97 error = kthread_resume(td); 98 if (error != 0) 99 panic("%s: error on kthread_resume. error: %d\n", 100 __func__, error); 101 } 102 103 mtx_lock(&test_global_lock); 104 test_thrcnt--; 105 wakeup(&global_condvar); 106 mtx_unlock(&test_global_lock); 107 108 kthread_exit(); 109 } 110 111 static void 112 thr_getsuspended(void *arg) 113 { 114 for (;;) { 115 if (QUIT == 1) 116 break; 117 kthread_suspend_check(); 118 } 119 120 mtx_lock(&test_global_lock); 121 test_thrcnt--; 122 wakeup(&global_condvar); 123 mtx_unlock(&test_global_lock); 124 125 kthread_exit(); 126 } 127 128 static void 129 kthrdlk_init(void) 130 { 131 struct proc *testproc; 132 struct thread *newthr; 133 int error; 134 135 QUIT = 0; 136 test_thrcnt = 3; 137 mtx_init(&test_global_lock, "kthrdlk_lock", NULL, MTX_DEF); 138 testproc = NULL; 139 error = kproc_kthread_add(thr_getsuspended, NULL, &testproc, &newthr, 140 0, 0, "kthrdlk", "thr_getsuspended"); 141 if (error != 0) 142 panic("cannot start thr_getsuspended error: %d\n", error); 143 144 error = kproc_kthread_add(thr_resumer, newthr, &testproc, NULL, 0, 0, 145 "kthrdlk", "thr_resumer"); 146 if (error != 0) 147 panic("cannot start thr_resumer error: %d\n", error); 148 149 error = kproc_kthread_add(thr_suspender, newthr, &testproc, NULL, 0, 0, 150 "kthrdlk", "thr_suspender"); 151 if (error != 0) 152 panic("cannot start thr_suspender error: %d\n", error); 153 } 154 155 static void 156 kthrdlk_done(void) 157 { 158 int ret; 159 DPRINTF(("sending QUIT signal to the thrdlk threads\n")); 160 161 /* wait kernel threads end */ 162 mtx_lock(&test_global_lock); 163 QUIT = 1; 164 while (test_thrcnt != 0) { 165 ret = mtx_sleep(&global_condvar, &test_global_lock, 0, "waiting thrs end", 30 * hz); 166 if (ret == EWOULDBLOCK) { 167 panic("some threads not die! remaining: %d", test_thrcnt); 168 break; 169 } 170 } 171 if (test_thrcnt == 0) 172 DPRINTF(("All test_pause threads die\n")); 173 174 mtx_destroy(&test_global_lock); 175 } 176 177 static int 178 kthrdlk_handler(module_t mod, int /*modeventtype_t*/ what, 179 void *arg) 180 { 181 switch (what) { 182 case MOD_LOAD: 183 kthrdlk_init(); 184 uprintf("kthrdlk loaded!\n"); 185 return (0); 186 case MOD_UNLOAD: 187 kthrdlk_done(); 188 uprintf("Bye Bye! kthrdlk unloaded!\n"); 189 return (0); 190 } 191 192 return (EOPNOTSUPP); 193 } 194 195 static moduledata_t mod_data= { 196 "kthrdlk", 197 kthrdlk_handler, 198 0 199 }; 200 201 MODULE_VERSION(kthrdlk, 1); 202 203 DECLARE_MODULE(kthrdlk, mod_data, SI_SUB_EXEC, SI_ORDER_ANY); 204 205