kern_synch.c revision 1.86
1/* $OpenBSD: kern_synch.c,v 1.86 2008/09/05 14:38:15 oga 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 60void updatepri(struct proc *); 61void 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)) 70TAILQ_HEAD(slpque,proc) slpque[TABLESIZE]; 71 72void 73sleep_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 */ 91int 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 */ 104int 105tsleep(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 */ 143int 144msleep(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 178void 179sleep_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 208void 209sleep_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 242void 243sleep_setup_timeout(struct sleep_state *sls, int timo) 244{ 245 if (timo) 246 timeout_add(&curproc->p_sleep_to, timo); 247} 248 249int 250sleep_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 264void 265sleep_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 293int 294sleep_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 */ 315void 316endtsleep(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 */ 335void 336unsleep(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 */ 347void 348wakeup_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 374 /* 375 * Since curpriority is a user priority, 376 * p->p_priority is always better than 377 * curpriority on the last CPU on 378 * which it ran. 379 * 380 * XXXSMP See affinity comment in 381 * resched_proc(). 382 */ 383 setrunqueue(p); 384 KASSERT(p->p_cpu != NULL); 385 need_resched(p->p_cpu); 386 /* END INLINE EXPANSION */ 387 388 } 389 } 390 } 391 SCHED_UNLOCK(s); 392} 393 394/* 395 * Make all processes sleeping on the specified identifier runnable. 396 */ 397void 398wakeup(void *chan) 399{ 400 wakeup_n(chan, -1); 401} 402 403int 404sys_sched_yield(struct proc *p, void *v, register_t *retval) 405{ 406 yield(); 407 return (0); 408} 409 410#ifdef RTHREADS 411 412int 413sys_thrsleep(struct proc *p, void *v, register_t *revtal) 414{ 415 struct sys_thrsleep_args *uap = v; 416 long ident = (long)SCARG(uap, ident); 417 int timo = SCARG(uap, timeout); 418 _spinlock_lock_t *lock = SCARG(uap, lock); 419 _spinlock_lock_t unlocked = _SPINLOCK_UNLOCKED; 420 int error; 421 422 p->p_thrslpid = ident; 423 424 if (lock) 425 copyout(&unlocked, lock, sizeof(unlocked)); 426 if (hz > 1000) 427 timo = timo * (hz / 1000); 428 else 429 timo = timo / (1000 / hz); 430 if (timo < 0) 431 timo = 0; 432 error = tsleep(&p->p_thrslpid, PUSER | PCATCH, "thrsleep", timo); 433 434 if (error == ERESTART) 435 error = EINTR; 436 437 return (error); 438 439} 440 441int 442sys_thrwakeup(struct proc *p, void *v, register_t *retval) 443{ 444 struct sys_thrwakeup_args *uap = v; 445 long ident = (long)SCARG(uap, ident); 446 int n = SCARG(uap, n); 447 struct proc *q; 448 int found = 0; 449 450 TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) { 451 if (q->p_thrslpid == ident) { 452 wakeup(&q->p_thrslpid); 453 q->p_thrslpid = 0; 454 if (++found == n) 455 return (0); 456 } 457 } 458 if (!found) 459 return (ESRCH); 460 461 return (0); 462} 463#endif 464