1 /* $OpenBSD: kern_synch.c,v 1.102 2012/04/10 11:33:58 guenther 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 61 /* 62 * We're only looking at 7 bits of the address; everything is 63 * aligned to 4, lots of things are aligned to greater powers 64 * of 2. Shift right by 8, i.e. drop the bottom 256 worth. 65 */ 66 #define TABLESIZE 128 67 #define LOOKUP(x) (((long)(x) >> 8) & (TABLESIZE - 1)) 68 TAILQ_HEAD(slpque,proc) slpque[TABLESIZE]; 69 70 void 71 sleep_queue_init(void) 72 { 73 int i; 74 75 for (i = 0; i < TABLESIZE; i++) 76 TAILQ_INIT(&slpque[i]); 77 } 78 79 80 /* 81 * During autoconfiguration or after a panic, a sleep will simply 82 * lower the priority briefly to allow interrupts, then return. 83 * The priority to be used (safepri) is machine-dependent, thus this 84 * value is initialized and maintained in the machine-dependent layers. 85 * This priority will typically be 0, or the lowest priority 86 * that is safe for use on the interrupt stack; it can be made 87 * higher to block network software interrupts after panics. 88 */ 89 extern int safepri; 90 91 /* 92 * General sleep call. Suspends the current process until a wakeup is 93 * performed on the specified identifier. The process will then be made 94 * runnable with the specified priority. Sleeps at most timo/hz seconds 95 * (0 means no timeout). If pri includes PCATCH flag, signals are checked 96 * before and after sleeping, else signals are not checked. Returns 0 if 97 * awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a 98 * signal needs to be delivered, ERESTART is returned if the current system 99 * call should be restarted if possible, and EINTR is returned if the system 100 * call should be interrupted by the signal (return EINTR). 101 */ 102 int 103 tsleep(const volatile void *ident, int priority, const char *wmesg, int timo) 104 { 105 struct sleep_state sls; 106 int error, error1; 107 108 if (cold || panicstr) { 109 int s; 110 /* 111 * After a panic, or during autoconfiguration, 112 * just give interrupts a chance, then just return; 113 * don't run any other procs or panic below, 114 * in case this is the idle process and already asleep. 115 */ 116 s = splhigh(); 117 splx(safepri); 118 splx(s); 119 return (0); 120 } 121 122 sleep_setup(&sls, ident, priority, wmesg); 123 sleep_setup_timeout(&sls, timo); 124 sleep_setup_signal(&sls, priority); 125 126 sleep_finish(&sls, 1); 127 error1 = sleep_finish_timeout(&sls); 128 error = sleep_finish_signal(&sls); 129 130 /* Signal errors are higher priority than timeouts. */ 131 if (error == 0 && error1 != 0) 132 error = error1; 133 134 return (error); 135 } 136 137 /* 138 * Same as tsleep, but if we have a mutex provided, then once we've 139 * entered the sleep queue we drop the mutex. After sleeping we re-lock. 140 */ 141 int 142 msleep(const volatile void *ident, struct mutex *mtx, int priority, 143 const char *wmesg, int timo) 144 { 145 struct sleep_state sls; 146 int error, error1, spl; 147 148 sleep_setup(&sls, ident, priority, wmesg); 149 sleep_setup_timeout(&sls, timo); 150 sleep_setup_signal(&sls, priority); 151 152 if (mtx) { 153 /* XXX - We need to make sure that the mutex doesn't 154 * unblock splsched. This can be made a bit more 155 * correct when the sched_lock is a mutex. 156 */ 157 spl = MUTEX_OLDIPL(mtx); 158 MUTEX_OLDIPL(mtx) = splsched(); 159 mtx_leave(mtx); 160 } 161 162 sleep_finish(&sls, 1); 163 error1 = sleep_finish_timeout(&sls); 164 error = sleep_finish_signal(&sls); 165 166 if (mtx) { 167 if ((priority & PNORELOCK) == 0) { 168 mtx_enter(mtx); 169 MUTEX_OLDIPL(mtx) = spl; /* put the ipl back */ 170 } else 171 splx(spl); 172 } 173 /* Signal errors are higher priority than timeouts. */ 174 if (error == 0 && error1 != 0) 175 error = error1; 176 177 return (error); 178 } 179 180 void 181 sleep_setup(struct sleep_state *sls, const volatile void *ident, int prio, 182 const char *wmesg) 183 { 184 struct proc *p = curproc; 185 186 #ifdef DIAGNOSTIC 187 if (ident == NULL) 188 panic("tsleep: no ident"); 189 if (p->p_stat != SONPROC) 190 panic("tsleep: not SONPROC"); 191 #endif 192 193 #ifdef KTRACE 194 if (KTRPOINT(p, KTR_CSW)) 195 ktrcsw(p, 1, 0); 196 #endif 197 198 sls->sls_catch = 0; 199 sls->sls_do_sleep = 1; 200 sls->sls_sig = 1; 201 202 SCHED_LOCK(sls->sls_s); 203 204 p->p_wchan = ident; 205 p->p_wmesg = wmesg; 206 p->p_slptime = 0; 207 p->p_priority = prio & PRIMASK; 208 TAILQ_INSERT_TAIL(&slpque[LOOKUP(ident)], p, p_runq); 209 } 210 211 void 212 sleep_finish(struct sleep_state *sls, int do_sleep) 213 { 214 struct proc *p = curproc; 215 216 if (sls->sls_do_sleep && do_sleep) { 217 p->p_stat = SSLEEP; 218 p->p_ru.ru_nvcsw++; 219 SCHED_ASSERT_LOCKED(); 220 mi_switch(); 221 } else if (!do_sleep) { 222 unsleep(p); 223 } 224 225 #ifdef DIAGNOSTIC 226 if (p->p_stat != SONPROC) 227 panic("sleep_finish !SONPROC"); 228 #endif 229 230 p->p_cpu->ci_schedstate.spc_curpriority = p->p_usrpri; 231 SCHED_UNLOCK(sls->sls_s); 232 233 /* 234 * Even though this belongs to the signal handling part of sleep, 235 * we need to clear it before the ktrace. 236 */ 237 atomic_clearbits_int(&p->p_flag, P_SINTR); 238 239 #ifdef KTRACE 240 if (KTRPOINT(p, KTR_CSW)) 241 ktrcsw(p, 0, 0); 242 #endif 243 } 244 245 void 246 sleep_setup_timeout(struct sleep_state *sls, int timo) 247 { 248 if (timo) 249 timeout_add(&curproc->p_sleep_to, timo); 250 } 251 252 int 253 sleep_finish_timeout(struct sleep_state *sls) 254 { 255 struct proc *p = curproc; 256 257 if (p->p_flag & P_TIMEOUT) { 258 atomic_clearbits_int(&p->p_flag, P_TIMEOUT); 259 return (EWOULDBLOCK); 260 } else if (timeout_pending(&p->p_sleep_to)) { 261 timeout_del(&p->p_sleep_to); 262 } 263 264 return (0); 265 } 266 267 void 268 sleep_setup_signal(struct sleep_state *sls, int prio) 269 { 270 struct proc *p = curproc; 271 272 if ((sls->sls_catch = (prio & PCATCH)) == 0) 273 return; 274 275 /* 276 * We put ourselves on the sleep queue and start our timeout 277 * before calling CURSIG, as we could stop there, and a wakeup 278 * or a SIGCONT (or both) could occur while we were stopped. 279 * A SIGCONT would cause us to be marked as SSLEEP 280 * without resuming us, thus we must be ready for sleep 281 * when CURSIG is called. If the wakeup happens while we're 282 * stopped, p->p_wchan will be 0 upon return from CURSIG. 283 */ 284 atomic_setbits_int(&p->p_flag, P_SINTR); 285 if (p->p_p->ps_single != NULL || (sls->sls_sig = CURSIG(p)) != 0) { 286 if (p->p_wchan) 287 unsleep(p); 288 p->p_stat = SONPROC; 289 sls->sls_do_sleep = 0; 290 } else if (p->p_wchan == 0) { 291 sls->sls_catch = 0; 292 sls->sls_do_sleep = 0; 293 } 294 } 295 296 int 297 sleep_finish_signal(struct sleep_state *sls) 298 { 299 struct proc *p = curproc; 300 int error; 301 302 if (sls->sls_catch != 0) { 303 if ((error = single_thread_check(p, 1))) 304 return (error); 305 if (sls->sls_sig != 0 || (sls->sls_sig = CURSIG(p)) != 0) { 306 if (p->p_sigacts->ps_sigintr & sigmask(sls->sls_sig)) 307 return (EINTR); 308 return (ERESTART); 309 } 310 } 311 312 return (0); 313 } 314 315 /* 316 * Implement timeout for tsleep. 317 * If process hasn't been awakened (wchan non-zero), 318 * set timeout flag and undo the sleep. If proc 319 * is stopped, just unsleep so it will remain stopped. 320 */ 321 void 322 endtsleep(void *arg) 323 { 324 struct proc *p = arg; 325 int s; 326 327 SCHED_LOCK(s); 328 if (p->p_wchan) { 329 if (p->p_stat == SSLEEP) 330 setrunnable(p); 331 else 332 unsleep(p); 333 atomic_setbits_int(&p->p_flag, P_TIMEOUT); 334 } 335 SCHED_UNLOCK(s); 336 } 337 338 /* 339 * Remove a process from its wait queue 340 */ 341 void 342 unsleep(struct proc *p) 343 { 344 if (p->p_wchan) { 345 TAILQ_REMOVE(&slpque[LOOKUP(p->p_wchan)], p, p_runq); 346 p->p_wchan = NULL; 347 } 348 } 349 350 /* 351 * Make a number of processes sleeping on the specified identifier runnable. 352 */ 353 void 354 wakeup_n(const volatile void *ident, int n) 355 { 356 struct slpque *qp; 357 struct proc *p; 358 struct proc *pnext; 359 int s; 360 361 SCHED_LOCK(s); 362 qp = &slpque[LOOKUP(ident)]; 363 for (p = TAILQ_FIRST(qp); p != NULL && n != 0; p = pnext) { 364 pnext = TAILQ_NEXT(p, p_runq); 365 #ifdef DIAGNOSTIC 366 if (p->p_stat != SSLEEP && p->p_stat != SSTOP) 367 panic("wakeup: p_stat is %d", (int)p->p_stat); 368 #endif 369 if (p->p_wchan == ident) { 370 --n; 371 p->p_wchan = 0; 372 TAILQ_REMOVE(qp, p, p_runq); 373 if (p->p_stat == SSLEEP) { 374 /* OPTIMIZED EXPANSION OF setrunnable(p); */ 375 if (p->p_slptime > 1) 376 updatepri(p); 377 p->p_slptime = 0; 378 p->p_stat = SRUN; 379 p->p_cpu = sched_choosecpu(p); 380 setrunqueue(p); 381 need_resched(p->p_cpu); 382 /* END INLINE EXPANSION */ 383 384 } 385 } 386 } 387 SCHED_UNLOCK(s); 388 } 389 390 /* 391 * Make all processes sleeping on the specified identifier runnable. 392 */ 393 void 394 wakeup(const volatile void *chan) 395 { 396 wakeup_n(chan, -1); 397 } 398 399 int 400 sys_sched_yield(struct proc *p, void *v, register_t *retval) 401 { 402 yield(); 403 return (0); 404 } 405 406 int 407 sys___thrsleep(struct proc *p, void *v, register_t *retval) 408 { 409 struct sys___thrsleep_args /* { 410 syscallarg(const volatile void *) ident; 411 syscallarg(clockid_t) clock_id; 412 syscallarg(struct timespec *) tp; 413 syscallarg(void *) lock; 414 syscallarg(const int *) abort; 415 } */ *uap = v; 416 long ident = (long)SCARG(uap, ident); 417 _spinlock_lock_t *lock = SCARG(uap, lock); 418 static _spinlock_lock_t unlocked = _SPINLOCK_UNLOCKED; 419 long long to_ticks = 0; 420 int abort, error; 421 422 if (!rthreads_enabled) { 423 *retval = ENOTSUP; 424 return (0); 425 } 426 if (ident == 0) { 427 *retval = EINVAL; 428 return (0); 429 } 430 if (SCARG(uap, tp) != NULL) { 431 struct timespec now, ats; 432 433 if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) || 434 (error = clock_gettime(p, SCARG(uap, clock_id), &now))) { 435 *retval = error; 436 return (0); 437 } 438 #ifdef KTRACE 439 if (KTRPOINT(p, KTR_STRUCT)) 440 ktrabstimespec(p, &ats); 441 #endif 442 443 if (timespeccmp(&ats, &now, <)) { 444 /* already passed: still do the unlock */ 445 if (lock) { 446 if ((error = copyout(&unlocked, lock, 447 sizeof(unlocked))) != 0) { 448 *retval = error; 449 return (0); 450 } 451 } 452 *retval = EWOULDBLOCK; 453 return (0); 454 } 455 456 timespecsub(&ats, &now, &ats); 457 to_ticks = (long long)hz * ats.tv_sec + 458 (ats.tv_nsec + tick * 1000 - 1) / (tick * 1000) + 1; 459 if (to_ticks > INT_MAX) 460 to_ticks = INT_MAX; 461 } 462 463 p->p_thrslpid = ident; 464 465 if (lock) { 466 if ((error = copyout(&unlocked, lock, sizeof(unlocked))) != 0) 467 goto out; 468 } 469 470 if (SCARG(uap, abort) != NULL) { 471 if ((error = copyin(SCARG(uap, abort), &abort, 472 sizeof(abort))) != 0) 473 goto out; 474 if (abort) { 475 error = EINTR; 476 goto out; 477 } 478 } 479 480 if (p->p_thrslpid == 0) 481 error = 0; 482 else 483 error = tsleep(&p->p_thrslpid, PUSER | PCATCH, "thrsleep", 484 (int)to_ticks); 485 486 out: 487 p->p_thrslpid = 0; 488 489 if (error == ERESTART) 490 error = EINTR; 491 492 *retval = error; 493 return (0); 494 495 } 496 497 int 498 sys___thrwakeup(struct proc *p, void *v, register_t *retval) 499 { 500 struct sys___thrwakeup_args /* { 501 syscallarg(const volatile void *) ident; 502 syscallarg(int) n; 503 } */ *uap = v; 504 long ident = (long)SCARG(uap, ident); 505 int n = SCARG(uap, n); 506 struct proc *q; 507 int found = 0; 508 509 if (!rthreads_enabled) 510 *retval = ENOTSUP; 511 else if (ident == 0) 512 *retval = EINVAL; 513 else { 514 TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) { 515 if (q->p_thrslpid == ident) { 516 wakeup_one(&q->p_thrslpid); 517 q->p_thrslpid = 0; 518 if (++found == n) 519 break; 520 } 521 } 522 *retval = found ? 0 : ESRCH; 523 } 524 525 return (0); 526 } 527