1 /* 2 * Copyright (c) 1999 Peter Wemm <peter@FreeBSD.org> 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 #include <sys/param.h> 28 #include <sys/systm.h> 29 #include <sys/proc.h> 30 #include <sys/kthread.h> 31 #include <sys/ptrace.h> 32 #include <sys/resourcevar.h> 33 #include <sys/signalvar.h> 34 #include <sys/unistd.h> 35 #include <sys/wait.h> 36 37 #include <machine/stdarg.h> 38 39 static struct lwkt_token kpsus_token = LWKT_TOKEN_INITIALIZER(kpsus_token); 40 41 42 /* 43 * Create a new lightweight kernel thread. 44 */ 45 static int __printflike(6, 0) 46 _kthread_create(void (*func)(void *), void *arg, 47 struct thread **tdp, int cpu, bool schedule_now, const char *fmt, __va_list ap) 48 { 49 thread_t td; 50 int flags = 0; 51 52 td = lwkt_alloc_thread(NULL, LWKT_THREAD_STACK, cpu, flags); 53 if (tdp) 54 *tdp = td; 55 cpu_set_thread_handler(td, kthread_exit, func, arg); 56 57 /* 58 * Set up arg0 for 'ps' etc 59 */ 60 kvsnprintf(td->td_comm, sizeof(td->td_comm), fmt, ap); 61 62 td->td_ucred = crhold(proc0.p_ucred); 63 64 /* 65 * Schedule the thread to run 66 */ 67 if (schedule_now) 68 lwkt_schedule(td); 69 70 return 0; 71 } 72 73 /* Create a new lightweight kernel thread and do not schedule it */ 74 int 75 kthread_alloc(void (*func)(void *), void *arg, 76 struct thread **tdp, const char *fmt, ...) 77 { 78 __va_list ap; 79 int ret; 80 81 __va_start(ap, fmt); 82 ret = _kthread_create(func, arg, tdp, -1, false, fmt, ap); 83 __va_end(ap); 84 85 return ret; 86 } 87 88 /* 89 * Creates a lwkt. No CPU preference. 90 */ 91 int 92 kthread_create(void (*func)(void *), void *arg, 93 struct thread **tdp, const char *fmt, ...) 94 { 95 __va_list ap; 96 int ret; 97 98 __va_start(ap, fmt); 99 ret = _kthread_create(func, arg, tdp, -1, true, fmt, ap); 100 __va_end(ap); 101 102 return ret; 103 } 104 105 /* 106 * Creates a lwkt and schedule it to run in a specific CPU. 107 * 108 */ 109 int 110 kthread_create_cpu(void (*func)(void *), void *arg, 111 struct thread **tdp, int cpu, const char *fmt, ...) 112 { 113 __va_list ap; 114 int ret; 115 116 __va_start(ap, fmt); 117 ret = _kthread_create(func, arg, tdp, cpu, true, fmt, ap); 118 __va_end(ap); 119 120 return ret; 121 } 122 123 #if 0 124 /* 125 * Same as kthread_create() but you can specify a custom stack size. 126 */ 127 int 128 kthread_create_stk(void (*func)(void *), void *arg, 129 struct thread **tdp, int stksize, const char *fmt, ...) 130 { 131 thread_t td; 132 __va_list ap; 133 134 td = lwkt_alloc_thread(NULL, stksize, -1, 0); 135 if (tdp) 136 *tdp = td; 137 cpu_set_thread_handler(td, kthread_exit, func, arg); 138 139 __va_start(ap, fmt); 140 kvsnprintf(td->td_comm, sizeof(td->td_comm), fmt, ap); 141 __va_end(ap); 142 143 lwkt_schedule(td); 144 return 0; 145 } 146 #endif 147 148 /* 149 * Destroy an LWKT thread. Warning! This function is not called when 150 * a process exits, cpu_proc_exit() directly calls cpu_thread_exit() and 151 * uses a different reaping mechanism. 152 * 153 * XXX duplicates lwkt_exit() 154 */ 155 void 156 kthread_exit(void) 157 { 158 lwkt_exit(); 159 } 160 161 /* 162 * Start a kernel process. This is called after a fork() call in 163 * mi_startup() in the file kern/init_main.c. 164 * 165 * This function is used to start "internal" daemons and intended 166 * to be called from SYSINIT(). 167 * 168 * These threads are created MPSAFE. 169 */ 170 void 171 kproc_start(const void *udata) 172 { 173 const struct kproc_desc *kp = udata; 174 int error; 175 176 error = kthread_create((void (*)(void *))kp->func, NULL, 177 kp->global_threadpp, "%s", kp->arg0); 178 lwkt_setpri(*kp->global_threadpp, TDPRI_KERN_DAEMON); 179 if (error) 180 panic("kproc_start: %s: error %d", kp->arg0, error); 181 } 182 183 /* 184 * Advise a kernel process to suspend (or resume) in its main loop. 185 * Participation is voluntary. 186 */ 187 int 188 suspend_kproc(struct thread *td, int timo) 189 { 190 if (td->td_proc == NULL) { 191 lwkt_gettoken(&kpsus_token); 192 /* request thread pause */ 193 atomic_set_int(&td->td_mpflags, TDF_MP_STOPREQ); 194 wakeup(td); 195 while (td->td_mpflags & TDF_MP_STOPREQ) { 196 int error = tsleep(td, 0, "suspkp", timo); 197 if (error == EWOULDBLOCK) 198 break; 199 } 200 atomic_clear_int(&td->td_mpflags, TDF_MP_STOPREQ); 201 lwkt_reltoken(&kpsus_token); 202 return(0); 203 } else { 204 return(EINVAL); /* not a kernel thread */ 205 } 206 } 207 208 void 209 kproc_suspend_loop(void) 210 { 211 struct thread *td = curthread; 212 213 if (td->td_mpflags & TDF_MP_STOPREQ) { 214 lwkt_gettoken(&kpsus_token); 215 atomic_clear_int(&td->td_mpflags, TDF_MP_STOPREQ); 216 while ((td->td_mpflags & TDF_MP_WAKEREQ) == 0) { 217 wakeup(td); 218 tsleep(td, 0, "kpsusp", 0); 219 } 220 atomic_clear_int(&td->td_mpflags, TDF_MP_WAKEREQ); 221 wakeup(td); 222 lwkt_reltoken(&kpsus_token); 223 } 224 } 225 226