Annotation of sys/kern/kern_synch.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: kern_synch.c,v 1.80 2007/05/16 17:27:30 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: struct slpque {
! 71: struct proc *sq_head;
! 72: struct proc **sq_tailp;
! 73: } slpque[TABLESIZE];
! 74:
! 75: /*
! 76: * During autoconfiguration or after a panic, a sleep will simply
! 77: * lower the priority briefly to allow interrupts, then return.
! 78: * The priority to be used (safepri) is machine-dependent, thus this
! 79: * value is initialized and maintained in the machine-dependent layers.
! 80: * This priority will typically be 0, or the lowest priority
! 81: * that is safe for use on the interrupt stack; it can be made
! 82: * higher to block network software interrupts after panics.
! 83: */
! 84: int safepri;
! 85:
! 86: /*
! 87: * General sleep call. Suspends the current process until a wakeup is
! 88: * performed on the specified identifier. The process will then be made
! 89: * runnable with the specified priority. Sleeps at most timo/hz seconds
! 90: * (0 means no timeout). If pri includes PCATCH flag, signals are checked
! 91: * before and after sleeping, else signals are not checked. Returns 0 if
! 92: * awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a
! 93: * signal needs to be delivered, ERESTART is returned if the current system
! 94: * call should be restarted if possible, and EINTR is returned if the system
! 95: * call should be interrupted by the signal (return EINTR).
! 96: */
! 97: int
! 98: tsleep(void *ident, int priority, const char *wmesg, int timo)
! 99: {
! 100: struct sleep_state sls;
! 101: int error, error1;
! 102:
! 103: if (cold || panicstr) {
! 104: int s;
! 105: /*
! 106: * After a panic, or during autoconfiguration,
! 107: * just give interrupts a chance, then just return;
! 108: * don't run any other procs or panic below,
! 109: * in case this is the idle process and already asleep.
! 110: */
! 111: s = splhigh();
! 112: splx(safepri);
! 113: splx(s);
! 114: return (0);
! 115: }
! 116:
! 117: sleep_setup(&sls, ident, priority, wmesg);
! 118: sleep_setup_timeout(&sls, timo);
! 119: sleep_setup_signal(&sls, priority);
! 120:
! 121: sleep_finish(&sls, 1);
! 122: error1 = sleep_finish_timeout(&sls);
! 123: error = sleep_finish_signal(&sls);
! 124:
! 125: /* Signal errors are higher priority than timeouts. */
! 126: if (error == 0 && error1 != 0)
! 127: error = error1;
! 128:
! 129: return (error);
! 130: }
! 131:
! 132: void
! 133: sleep_setup(struct sleep_state *sls, void *ident, int prio, const char *wmesg)
! 134: {
! 135: struct proc *p = curproc;
! 136: struct slpque *qp;
! 137:
! 138: #ifdef DIAGNOSTIC
! 139: if (ident == NULL)
! 140: panic("tsleep: no ident");
! 141: if (p->p_stat != SONPROC)
! 142: panic("tsleep: not SONPROC");
! 143: if (p->p_back != NULL)
! 144: panic("tsleep: p_back not NULL");
! 145: #endif
! 146:
! 147: #ifdef KTRACE
! 148: if (KTRPOINT(p, KTR_CSW))
! 149: ktrcsw(p, 1, 0);
! 150: #endif
! 151:
! 152: sls->sls_catch = 0;
! 153: sls->sls_do_sleep = 1;
! 154: sls->sls_sig = 1;
! 155:
! 156: SCHED_LOCK(sls->sls_s);
! 157:
! 158: p->p_wchan = ident;
! 159: p->p_wmesg = wmesg;
! 160: p->p_slptime = 0;
! 161: p->p_priority = prio & PRIMASK;
! 162: qp = &slpque[LOOKUP(ident)];
! 163: if (qp->sq_head == 0)
! 164: qp->sq_head = p;
! 165: else
! 166: *qp->sq_tailp = p;
! 167: *(qp->sq_tailp = &p->p_forw) = NULL;
! 168: }
! 169:
! 170: void
! 171: sleep_finish(struct sleep_state *sls, int do_sleep)
! 172: {
! 173: struct proc *p = curproc;
! 174:
! 175: if (sls->sls_do_sleep && do_sleep) {
! 176: p->p_stat = SSLEEP;
! 177: p->p_stats->p_ru.ru_nvcsw++;
! 178: SCHED_ASSERT_LOCKED();
! 179: mi_switch();
! 180: } else if (!do_sleep) {
! 181: unsleep(p);
! 182: #ifdef DIAGNOSTIC
! 183: if (p->p_stat != SONPROC)
! 184: panic("sleep_finish !SONPROC");
! 185: #endif
! 186: }
! 187:
! 188: p->p_cpu->ci_schedstate.spc_curpriority = p->p_usrpri;
! 189: SCHED_UNLOCK(sls->sls_s);
! 190:
! 191: /*
! 192: * Even though this belongs to the signal handling part of sleep,
! 193: * we need to clear it before the ktrace.
! 194: */
! 195: atomic_clearbits_int(&p->p_flag, P_SINTR);
! 196:
! 197: #ifdef KTRACE
! 198: if (KTRPOINT(p, KTR_CSW))
! 199: ktrcsw(p, 0, 0);
! 200: #endif
! 201: }
! 202:
! 203: void
! 204: sleep_setup_timeout(struct sleep_state *sls, int timo)
! 205: {
! 206: if (timo)
! 207: timeout_add(&curproc->p_sleep_to, timo);
! 208: }
! 209:
! 210: int
! 211: sleep_finish_timeout(struct sleep_state *sls)
! 212: {
! 213: struct proc *p = curproc;
! 214:
! 215: if (p->p_flag & P_TIMEOUT) {
! 216: atomic_clearbits_int(&p->p_flag, P_TIMEOUT);
! 217: return (EWOULDBLOCK);
! 218: } else if (timeout_pending(&p->p_sleep_to)) {
! 219: timeout_del(&p->p_sleep_to);
! 220: }
! 221:
! 222: return (0);
! 223: }
! 224:
! 225: void
! 226: sleep_setup_signal(struct sleep_state *sls, int prio)
! 227: {
! 228: struct proc *p = curproc;
! 229:
! 230: if ((sls->sls_catch = (prio & PCATCH)) == 0)
! 231: return;
! 232:
! 233: /*
! 234: * We put ourselves on the sleep queue and start our timeout
! 235: * before calling CURSIG, as we could stop there, and a wakeup
! 236: * or a SIGCONT (or both) could occur while we were stopped.
! 237: * A SIGCONT would cause us to be marked as SSLEEP
! 238: * without resuming us, thus we must be ready for sleep
! 239: * when CURSIG is called. If the wakeup happens while we're
! 240: * stopped, p->p_wchan will be 0 upon return from CURSIG.
! 241: */
! 242: atomic_setbits_int(&p->p_flag, P_SINTR);
! 243: if ((sls->sls_sig = CURSIG(p)) != 0) {
! 244: if (p->p_wchan)
! 245: unsleep(p);
! 246: p->p_stat = SONPROC;
! 247: sls->sls_do_sleep = 0;
! 248: } else if (p->p_wchan == 0) {
! 249: sls->sls_catch = 0;
! 250: sls->sls_do_sleep = 0;
! 251: }
! 252: }
! 253:
! 254: int
! 255: sleep_finish_signal(struct sleep_state *sls)
! 256: {
! 257: struct proc *p = curproc;
! 258:
! 259: if (sls->sls_catch != 0) {
! 260: if (sls->sls_sig != 0 || (sls->sls_sig = CURSIG(p)) != 0) {
! 261: if (p->p_sigacts->ps_sigintr & sigmask(sls->sls_sig))
! 262: return (EINTR);
! 263: return (ERESTART);
! 264: }
! 265: }
! 266:
! 267: return (0);
! 268: }
! 269:
! 270: /*
! 271: * Implement timeout for tsleep.
! 272: * If process hasn't been awakened (wchan non-zero),
! 273: * set timeout flag and undo the sleep. If proc
! 274: * is stopped, just unsleep so it will remain stopped.
! 275: */
! 276: void
! 277: endtsleep(void *arg)
! 278: {
! 279: struct proc *p = arg;
! 280: int s;
! 281:
! 282: SCHED_LOCK(s);
! 283: if (p->p_wchan) {
! 284: if (p->p_stat == SSLEEP)
! 285: setrunnable(p);
! 286: else
! 287: unsleep(p);
! 288: atomic_setbits_int(&p->p_flag, P_TIMEOUT);
! 289: }
! 290: SCHED_UNLOCK(s);
! 291: }
! 292:
! 293: /*
! 294: * Remove a process from its wait queue
! 295: */
! 296: void
! 297: unsleep(struct proc *p)
! 298: {
! 299: struct slpque *qp;
! 300: struct proc **hp;
! 301:
! 302: if (p->p_wchan) {
! 303: hp = &(qp = &slpque[LOOKUP(p->p_wchan)])->sq_head;
! 304: while (*hp != p)
! 305: hp = &(*hp)->p_forw;
! 306: *hp = p->p_forw;
! 307: if (qp->sq_tailp == &p->p_forw)
! 308: qp->sq_tailp = hp;
! 309: p->p_wchan = 0;
! 310: }
! 311: }
! 312:
! 313: /*
! 314: * Make a number of processes sleeping on the specified identifier runnable.
! 315: */
! 316: void
! 317: wakeup_n(void *ident, int n)
! 318: {
! 319: struct slpque *qp;
! 320: struct proc *p, **q;
! 321: int s;
! 322:
! 323: SCHED_LOCK(s);
! 324: qp = &slpque[LOOKUP(ident)];
! 325: restart:
! 326: for (q = &qp->sq_head; (p = *q) != NULL; ) {
! 327: #ifdef DIAGNOSTIC
! 328: if (p->p_back)
! 329: panic("wakeup: p_back not NULL");
! 330: if (p->p_stat != SSLEEP && p->p_stat != SSTOP)
! 331: panic("wakeup: p_stat is %d", (int)p->p_stat);
! 332: #endif
! 333: if (p->p_wchan == ident) {
! 334: --n;
! 335: p->p_wchan = 0;
! 336: *q = p->p_forw;
! 337: if (qp->sq_tailp == &p->p_forw)
! 338: qp->sq_tailp = q;
! 339: if (p->p_stat == SSLEEP) {
! 340: /* OPTIMIZED EXPANSION OF setrunnable(p); */
! 341: if (p->p_slptime > 1)
! 342: updatepri(p);
! 343: p->p_slptime = 0;
! 344: p->p_stat = SRUN;
! 345:
! 346: /*
! 347: * Since curpriority is a user priority,
! 348: * p->p_priority is always better than
! 349: * curpriority on the last CPU on
! 350: * which it ran.
! 351: *
! 352: * XXXSMP See affinity comment in
! 353: * resched_proc().
! 354: */
! 355: setrunqueue(p);
! 356: KASSERT(p->p_cpu != NULL);
! 357: need_resched(p->p_cpu);
! 358: /* END INLINE EXPANSION */
! 359:
! 360: if (n != 0)
! 361: goto restart;
! 362: else
! 363: break;
! 364: }
! 365: } else
! 366: q = &p->p_forw;
! 367: }
! 368: SCHED_UNLOCK(s);
! 369: }
! 370:
! 371: /*
! 372: * Make all processes sleeping on the specified identifier runnable.
! 373: */
! 374: void
! 375: wakeup(void *chan)
! 376: {
! 377: wakeup_n(chan, -1);
! 378: }
! 379:
! 380: int
! 381: sys_sched_yield(struct proc *p, void *v, register_t *retval)
! 382: {
! 383: yield();
! 384: return (0);
! 385: }
! 386:
! 387: #ifdef RTHREADS
! 388:
! 389: int
! 390: sys_thrsleep(struct proc *p, void *v, register_t *revtal)
! 391: {
! 392: struct sys_thrsleep_args *uap = v;
! 393: long ident = (long)SCARG(uap, ident);
! 394: int timo = SCARG(uap, timeout);
! 395: _spinlock_lock_t *lock = SCARG(uap, lock);
! 396: _spinlock_lock_t unlocked = _SPINLOCK_UNLOCKED;
! 397: int error;
! 398:
! 399: p->p_thrslpid = ident;
! 400:
! 401: if (lock)
! 402: copyout(&unlocked, lock, sizeof(unlocked));
! 403: if (hz > 1000)
! 404: timo = timo * (hz / 1000);
! 405: else
! 406: timo = timo / (1000 / hz);
! 407: if (timo < 0)
! 408: timo = 0;
! 409: error = tsleep(&p->p_thrslpid, PUSER | PCATCH, "thrsleep", timo);
! 410:
! 411: if (error == ERESTART)
! 412: error = EINTR;
! 413:
! 414: return (error);
! 415:
! 416: }
! 417:
! 418: int
! 419: sys_thrwakeup(struct proc *p, void *v, register_t *retval)
! 420: {
! 421: struct sys_thrwakeup_args *uap = v;
! 422: long ident = (long)SCARG(uap, ident);
! 423: int n = SCARG(uap, n);
! 424: struct proc *q;
! 425: int found = 0;
! 426:
! 427: TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) {
! 428: if (q->p_thrslpid == ident) {
! 429: wakeup(&q->p_thrslpid);
! 430: q->p_thrslpid = 0;
! 431: if (++found == n)
! 432: return (0);
! 433: }
! 434: }
! 435: if (!found)
! 436: return (ESRCH);
! 437:
! 438: return (0);
! 439: }
! 440: #endif
CVSweb