1 /* $OpenBSD: kern_synch.c,v 1.89 2009/04/14 09:13:25 art Exp $ */ 2 /* $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1982, 1986, 1990, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)kern_synch.c 8.6 (Berkeley) 1/21/94 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/proc.h> 43 #include <sys/kernel.h> 44 #include <sys/buf.h> 45 #include <sys/signalvar.h> 46 #include <sys/resourcevar.h> 47 #include <uvm/uvm_extern.h> 48 #include <sys/sched.h> 49 #include <sys/timeout.h> 50 #include <sys/mount.h> 51 #include <sys/syscallargs.h> 52 #include <sys/pool.h> 53 54 #include <machine/spinlock.h> 55 56 #ifdef KTRACE 57 #include <sys/ktrace.h> 58 #endif 59 60 void updatepri(struct proc *); 61 void endtsleep(void *); 62 63 /* 64 * We're only looking at 7 bits of the address; everything is 65 * aligned to 4, lots of things are aligned to greater powers 66 * of 2. Shift right by 8, i.e. drop the bottom 256 worth. 67 */ 68 #define TABLESIZE 128 69 #define LOOKUP(x) (((long)(x) >> 8) & (TABLESIZE - 1)) 70 TAILQ_HEAD(slpque,proc) slpque[TABLESIZE]; 71 72 void 73 sleep_queue_init(void) 74 { 75 int i; 76 77 for (i = 0; i < TABLESIZE; i++) 78 TAILQ_INIT(&slpque[i]); 79 } 80 81 82 /* 83 * During autoconfiguration or after a panic, a sleep will simply 84 * lower the priority briefly to allow interrupts, then return. 85 * The priority to be used (safepri) is machine-dependent, thus this 86 * value is initialized and maintained in the machine-dependent layers. 87 * This priority will typically be 0, or the lowest priority 88 * that is safe for use on the interrupt stack; it can be made 89 * higher to block network software interrupts after panics. 90 */ 91 int safepri; 92 93 /* 94 * General sleep call. Suspends the current process until a wakeup is 95 * performed on the specified identifier. The process will then be made 96 * runnable with the specified priority. Sleeps at most timo/hz seconds 97 * (0 means no timeout). If pri includes PCATCH flag, signals are checked 98 * before and after sleeping, else signals are not checked. Returns 0 if 99 * awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a 100 * signal needs to be delivered, ERESTART is returned if the current system 101 * call should be restarted if possible, and EINTR is returned if the system 102 * call should be interrupted by the signal (return EINTR). 103 */ 104 int 105 tsleep(void *ident, int priority, const char *wmesg, int timo) 106 { 107 struct sleep_state sls; 108 int error, error1; 109 110 if (cold || panicstr) { 111 int s; 112 /* 113 * After a panic, or during autoconfiguration, 114 * just give interrupts a chance, then just return; 115 * don't run any other procs or panic below, 116 * in case this is the idle process and already asleep. 117 */ 118 s = splhigh(); 119 splx(safepri); 120 splx(s); 121 return (0); 122 } 123 124 sleep_setup(&sls, ident, priority, wmesg); 125 sleep_setup_timeout(&sls, timo); 126 sleep_setup_signal(&sls, priority); 127 128 sleep_finish(&sls, 1); 129 error1 = sleep_finish_timeout(&sls); 130 error = sleep_finish_signal(&sls); 131 132 /* Signal errors are higher priority than timeouts. */ 133 if (error == 0 && error1 != 0) 134 error = error1; 135 136 return (error); 137 } 138 139 /* 140 * Same as tsleep, but if we have a mutex provided, then once we've 141 * entered the sleep queue we drop the mutex. After sleeping we re-lock. 142 */ 143 int 144 msleep(void *ident, struct mutex *mtx, int priority, const char *wmesg, int timo) 145 { 146 struct sleep_state sls; 147 int error, error1, spl; 148 149 sleep_setup(&sls, ident, priority, wmesg); 150 sleep_setup_timeout(&sls, timo); 151 sleep_setup_signal(&sls, priority); 152 153 if (mtx) { 154 /* XXX - We need to make sure that the mutex doesn't 155 * unblock splsched. This can be made a bit more 156 * correct when the sched_lock is a mutex. 157 */ 158 spl = MUTEX_OLDIPL(mtx); 159 MUTEX_OLDIPL(mtx) = splsched(); 160 mtx_leave(mtx); 161 } 162 163 sleep_finish(&sls, 1); 164 error1 = sleep_finish_timeout(&sls); 165 error = sleep_finish_signal(&sls); 166 167 if (mtx && (priority & PNORELOCK) == 0) { 168 mtx_enter(mtx); 169 MUTEX_OLDIPL(mtx) = spl; /* put the ipl back */ 170 } 171 /* Signal errors are higher priority than timeouts. */ 172 if (error == 0 && error1 != 0) 173 error = error1; 174 175 return (error); 176 } 177 178 void 179 sleep_setup(struct sleep_state *sls, void *ident, int prio, const char *wmesg) 180 { 181 struct proc *p = curproc; 182 183 #ifdef DIAGNOSTIC 184 if (ident == NULL) 185 panic("tsleep: no ident"); 186 if (p->p_stat != SONPROC) 187 panic("tsleep: not SONPROC"); 188 #endif 189 190 #ifdef KTRACE 191 if (KTRPOINT(p, KTR_CSW)) 192 ktrcsw(p, 1, 0); 193 #endif 194 195 sls->sls_catch = 0; 196 sls->sls_do_sleep = 1; 197 sls->sls_sig = 1; 198 199 SCHED_LOCK(sls->sls_s); 200 201 p->p_wchan = ident; 202 p->p_wmesg = wmesg; 203 p->p_slptime = 0; 204 p->p_priority = prio & PRIMASK; 205 TAILQ_INSERT_TAIL(&slpque[LOOKUP(ident)], p, p_runq); 206 } 207 208 void 209 sleep_finish(struct sleep_state *sls, int do_sleep) 210 { 211 struct proc *p = curproc; 212 213 if (sls->sls_do_sleep && do_sleep) { 214 p->p_stat = SSLEEP; 215 p->p_stats->p_ru.ru_nvcsw++; 216 SCHED_ASSERT_LOCKED(); 217 mi_switch(); 218 } else if (!do_sleep) { 219 unsleep(p); 220 } 221 222 #ifdef DIAGNOSTIC 223 if (p->p_stat != SONPROC) 224 panic("sleep_finish !SONPROC"); 225 #endif 226 227 p->p_cpu->ci_schedstate.spc_curpriority = p->p_usrpri; 228 SCHED_UNLOCK(sls->sls_s); 229 230 /* 231 * Even though this belongs to the signal handling part of sleep, 232 * we need to clear it before the ktrace. 233 */ 234 atomic_clearbits_int(&p->p_flag, P_SINTR); 235 236 #ifdef KTRACE 237 if (KTRPOINT(p, KTR_CSW)) 238 ktrcsw(p, 0, 0); 239 #endif 240 } 241 242 void 243 sleep_setup_timeout(struct sleep_state *sls, int timo) 244 { 245 if (timo) 246 timeout_add(&curproc->p_sleep_to, timo); 247 } 248 249 int 250 sleep_finish_timeout(struct sleep_state *sls) 251 { 252 struct proc *p = curproc; 253 254 if (p->p_flag & P_TIMEOUT) { 255 atomic_clearbits_int(&p->p_flag, P_TIMEOUT); 256 return (EWOULDBLOCK); 257 } else if (timeout_pending(&p->p_sleep_to)) { 258 timeout_del(&p->p_sleep_to); 259 } 260 261 return (0); 262 } 263 264 void 265 sleep_setup_signal(struct sleep_state *sls, int prio) 266 { 267 struct proc *p = curproc; 268 269 if ((sls->sls_catch = (prio & PCATCH)) == 0) 270 return; 271 272 /* 273 * We put ourselves on the sleep queue and start our timeout 274 * before calling CURSIG, as we could stop there, and a wakeup 275 * or a SIGCONT (or both) could occur while we were stopped. 276 * A SIGCONT would cause us to be marked as SSLEEP 277 * without resuming us, thus we must be ready for sleep 278 * when CURSIG is called. If the wakeup happens while we're 279 * stopped, p->p_wchan will be 0 upon return from CURSIG. 280 */ 281 atomic_setbits_int(&p->p_flag, P_SINTR); 282 if ((sls->sls_sig = CURSIG(p)) != 0) { 283 if (p->p_wchan) 284 unsleep(p); 285 p->p_stat = SONPROC; 286 sls->sls_do_sleep = 0; 287 } else if (p->p_wchan == 0) { 288 sls->sls_catch = 0; 289 sls->sls_do_sleep = 0; 290 } 291 } 292 293 int 294 sleep_finish_signal(struct sleep_state *sls) 295 { 296 struct proc *p = curproc; 297 298 if (sls->sls_catch != 0) { 299 if (sls->sls_sig != 0 || (sls->sls_sig = CURSIG(p)) != 0) { 300 if (p->p_sigacts->ps_sigintr & sigmask(sls->sls_sig)) 301 return (EINTR); 302 return (ERESTART); 303 } 304 } 305 306 return (0); 307 } 308 309 /* 310 * Implement timeout for tsleep. 311 * If process hasn't been awakened (wchan non-zero), 312 * set timeout flag and undo the sleep. If proc 313 * is stopped, just unsleep so it will remain stopped. 314 */ 315 void 316 endtsleep(void *arg) 317 { 318 struct proc *p = arg; 319 int s; 320 321 SCHED_LOCK(s); 322 if (p->p_wchan) { 323 if (p->p_stat == SSLEEP) 324 setrunnable(p); 325 else 326 unsleep(p); 327 atomic_setbits_int(&p->p_flag, P_TIMEOUT); 328 } 329 SCHED_UNLOCK(s); 330 } 331 332 /* 333 * Remove a process from its wait queue 334 */ 335 void 336 unsleep(struct proc *p) 337 { 338 if (p->p_wchan) { 339 TAILQ_REMOVE(&slpque[LOOKUP(p->p_wchan)], p, p_runq); 340 p->p_wchan = NULL; 341 } 342 } 343 344 /* 345 * Make a number of processes sleeping on the specified identifier runnable. 346 */ 347 void 348 wakeup_n(void *ident, int n) 349 { 350 struct slpque *qp; 351 struct proc *p; 352 struct proc *pnext; 353 int s; 354 355 SCHED_LOCK(s); 356 qp = &slpque[LOOKUP(ident)]; 357 for (p = TAILQ_FIRST(qp); p != NULL && n != 0; p = pnext) { 358 pnext = TAILQ_NEXT(p, p_runq); 359 #ifdef DIAGNOSTIC 360 if (p->p_stat != SSLEEP && p->p_stat != SSTOP) 361 panic("wakeup: p_stat is %d", (int)p->p_stat); 362 #endif 363 if (p->p_wchan == ident) { 364 --n; 365 p->p_wchan = 0; 366 TAILQ_REMOVE(qp, p, p_runq); 367 if (p->p_stat == SSLEEP) { 368 /* OPTIMIZED EXPANSION OF setrunnable(p); */ 369 if (p->p_slptime > 1) 370 updatepri(p); 371 p->p_slptime = 0; 372 p->p_stat = SRUN; 373 p->p_cpu = sched_choosecpu(p); 374 setrunqueue(p); 375 need_resched(p->p_cpu); 376 /* END INLINE EXPANSION */ 377 378 } 379 } 380 } 381 SCHED_UNLOCK(s); 382 } 383 384 /* 385 * Make all processes sleeping on the specified identifier runnable. 386 */ 387 void 388 wakeup(void *chan) 389 { 390 wakeup_n(chan, -1); 391 } 392 393 int 394 sys_sched_yield(struct proc *p, void *v, register_t *retval) 395 { 396 yield(); 397 return (0); 398 } 399 400 #ifdef RTHREADS 401 402 int 403 sys_thrsleep(struct proc *p, void *v, register_t *revtal) 404 { 405 struct sys_thrsleep_args *uap = v; 406 long ident = (long)SCARG(uap, ident); 407 int timo = SCARG(uap, timeout); 408 _spinlock_lock_t *lock = SCARG(uap, lock); 409 _spinlock_lock_t unlocked = _SPINLOCK_UNLOCKED; 410 int error; 411 412 p->p_thrslpid = ident; 413 414 if (lock) 415 copyout(&unlocked, lock, sizeof(unlocked)); 416 if (hz > 1000) 417 timo = timo * (hz / 1000); 418 else 419 timo = timo / (1000 / hz); 420 if (timo < 0) 421 timo = 0; 422 error = tsleep(&p->p_thrslpid, PUSER | PCATCH, "thrsleep", timo); 423 424 if (error == ERESTART) 425 error = EINTR; 426 427 return (error); 428 429 } 430 431 int 432 sys_thrwakeup(struct proc *p, void *v, register_t *retval) 433 { 434 struct sys_thrwakeup_args *uap = v; 435 long ident = (long)SCARG(uap, ident); 436 int n = SCARG(uap, n); 437 struct proc *q; 438 int found = 0; 439 440 TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) { 441 if (q->p_thrslpid == ident) { 442 wakeup_one(&q->p_thrslpid); 443 q->p_thrslpid = 0; 444 if (++found == n) 445 return (0); 446 } 447 } 448 if (!found) 449 return (ESRCH); 450 451 return (0); 452 } 453 #endif 454