[BACK]Return to kern_synch.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/kern_synch.c, Revision 1.1.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