new calling convension for system calls
[unix-history] / usr / src / sys / kern / kern_synch.c
index a2aaa90..61b3f79 100644 (file)
@@ -1,9 +1,9 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
+ * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
- *     @(#)kern_synch.c        7.9 (Berkeley) %G%
+ *     @(#)kern_synch.c        7.11 (Berkeley) %G%
  */
 
 #include "machine/pte.h"
  */
 
 #include "machine/pte.h"
@@ -211,24 +211,30 @@ struct slpque {
 } slpque[SQSIZE];
 
 /*
 } slpque[SQSIZE];
 
 /*
- * Give up the processor till a wakeup occurs
- * on chan, at which time the process
- * enters the scheduling queue at priority pri.
- * The most important effect of pri is that when
- * pri<=PZERO a signal cannot disturb the sleep;
- * if pri>PZERO signals will be processed.
- * Callers of this routine must be prepared for
- * premature return, and check that the reason for
- * sleeping has gone away.
+ * General sleep call.
+ * Suspends current process until a wakeup is made on chan.
+ * The process will then be made runnable with priority pri.
+ * Sleeps at most timo/hz seconds (0 means no timeout).
+ * If pri includes PCATCH flag, signals are checked
+ * before and after sleeping, else signals are not checked.
+ * Returns 0 if awakened, EWOULDBLOCK if the timeout expires.
+ * If PCATCH is set and a signal needs to be delivered,
+ * ERESTART is returned if the current system call should be restarted
+ * if possible, and EINTR is returned if the system call should
+ * be interrupted by the signal (return EINTR).
  */
  */
-sleep(chan, pri)
+tsleep(chan, pri, wmesg, timo)
        caddr_t chan;
        int pri;
        caddr_t chan;
        int pri;
+       char *wmesg;
+       int timo;
 {
        register struct proc *rp;
        register struct slpque *qp;
        register s;
 {
        register struct proc *rp;
        register struct slpque *qp;
        register s;
+       int sig, catch = pri & PCATCH;
        extern int cold;
        extern int cold;
+       int endtsleep();
 
        rp = u.u_procp;
        s = splhigh();
 
        rp = u.u_procp;
        s = splhigh();
@@ -238,64 +244,142 @@ sleep(chan, pri)
                 * just give interrupts a chance, then just return;
                 * don't run any other procs or panic below,
                 * in case this is the idle process and already asleep.
                 * just give interrupts a chance, then just return;
                 * don't run any other procs or panic below,
                 * in case this is the idle process and already asleep.
-                * The splnet should be spl0 if the network was being used
-                * by the filesystem, but for now avoid network interrupts
-                * that might cause another panic.
                 */
                 */
-               (void) splnet();
+               (void) spl0();
                splx(s);
                splx(s);
-               return;
+               return (0);
        }
        }
-       if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
-               panic("sleep");
+#ifdef DIAGNOSTIC
+       if (chan == 0 || rp->p_stat != SRUN || rp->p_rlink)
+               panic("tsleep");
+#endif
        rp->p_wchan = chan;
        rp->p_wchan = chan;
+       rp->p_wmesg = wmesg;
        rp->p_slptime = 0;
        rp->p_slptime = 0;
-       rp->p_pri = pri;
+       rp->p_pri = pri & PRIMASK;
        qp = &slpque[HASH(chan)];
        if (qp->sq_head == 0)
                qp->sq_head = rp;
        else
                *qp->sq_tailp = rp;
        *(qp->sq_tailp = &rp->p_link) = 0;
        qp = &slpque[HASH(chan)];
        if (qp->sq_head == 0)
                qp->sq_head = rp;
        else
                *qp->sq_tailp = rp;
        *(qp->sq_tailp = &rp->p_link) = 0;
-       if (pri > PZERO) {
-               /*
-                * If we stop in issig(), wakeup may already have happened
-                * when we return (rp->p_wchan will then be 0).
-                */
-               if (ISSIG(rp)) {
+       /*
+        * If we stop in CURSIG/issig(), wakeup may already
+        * have happened when we return.
+        * rp->p_wchan will then be 0.
+        */
+       if (catch) {
+               if (sig = CURSIG(rp)) {
                        if (rp->p_wchan)
                                unsleep(rp);
                        rp->p_stat = SRUN;
                        if (rp->p_wchan)
                                unsleep(rp);
                        rp->p_stat = SRUN;
-                       (void) spl0();
-                       goto psig;
+                       splx(s);
+                       if (u.u_sigintr & sigmask(sig))
+                               return (EINTR);
+                       return (ERESTART);
                }
                }
-               if (rp->p_wchan == 0)
-                       goto out;
-               rp->p_stat = SSLEEP;
-               (void) spl0();
-               u.u_ru.ru_nvcsw++;
-               swtch();
-               if (ISSIG(rp))
-                       goto psig;
-       } else {
-               rp->p_stat = SSLEEP;
-               (void) spl0();
-               u.u_ru.ru_nvcsw++;
-               swtch();
+               if (rp->p_wchan == 0) {
+                       splx(s);
+                       return (0);
+               }
+               rp->p_flag |= SSINTR;
        }
        }
+       rp->p_stat = SSLEEP;
+       if (timo)
+               timeout(endtsleep, (caddr_t)rp, timo);
+       (void) spl0();
+       u.u_ru.ru_nvcsw++;
+       swtch();
        curpri = rp->p_usrpri;
        curpri = rp->p_usrpri;
-out:
        splx(s);
        splx(s);
-       return;
+       rp->p_flag &= ~SSINTR;
+       if (rp->p_flag & STIMO) {
+               rp->p_flag &= ~STIMO;
+               return (EWOULDBLOCK);
+       }
+       if (timo)
+               untimeout(endtsleep, (caddr_t)rp);
+       if (catch && (sig = CURSIG(rp))) {
+               if (u.u_sigintr & sigmask(sig))
+                       return (EINTR);
+               return (ERESTART);
+       }
+       return (0);
+}
+
+/*
+ * Implement timeout for tsleep.
+ * If process hasn't been awakened (wchan non-zero),
+ * set timeout flag and undo the sleep.  If proc
+ * is stopped, just unsleep so it will remain stopped.
+ */
+endtsleep(p)
+       register struct proc *p;
+{
+       int s = splhigh();
+
+       if (p->p_wchan) {
+               if (p->p_stat == SSLEEP)
+                       setrun(p);
+               else
+                       unsleep(p);
+               p->p_flag |= STIMO;
+       }
+       splx(s);
+}
 
 
-       /*
-        * If priority was low (>PZERO) and
-        * there has been a signal, execute non-local goto through
-        * u.u_qsave, aborting the system call in progress (see trap.c)
-        */
-psig:
-       longjmp(&u.u_qsave);
-       /*NOTREACHED*/
+/*
+ * Short-term, non-interruptable sleep.
+ */
+sleep(chan, pri)
+       caddr_t chan;
+       int pri;
+{
+       register struct proc *rp;
+       register struct slpque *qp;
+       register s;
+       extern int cold;
+
+#ifdef DIAGNOSTIC
+       if (pri > PZERO) {
+               printf("sleep called with pri %d > PZERO, wchan: %x\n",
+                       pri, chan);
+               panic("old sleep");
+       }
+#endif
+       rp = u.u_procp;
+       s = splhigh();
+       if (cold || panicstr) {
+               /*
+                * After a panic, or during autoconfiguration,
+                * just give interrupts a chance, then just return;
+                * don't run any other procs or panic below,
+                * in case this is the idle process and already asleep.
+                */
+               (void) spl0();
+               splx(s);
+               return;
+       }
+#ifdef DIAGNOSTIC
+       if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
+               panic("sleep");
+#endif
+       rp->p_wchan = chan;
+       rp->p_wmesg = NULL;
+       rp->p_slptime = 0;
+       rp->p_pri = pri;
+       qp = &slpque[HASH(chan)];
+       if (qp->sq_head == 0)
+               qp->sq_head = rp;
+       else
+               *qp->sq_tailp = rp;
+       *(qp->sq_tailp = &rp->p_link) = 0;
+       rp->p_stat = SSLEEP;
+       (void) spl0();
+       u.u_ru.ru_nvcsw++;
+       swtch();
+       curpri = rp->p_usrpri;
+       splx(s);
 }
 
 /*
 }
 
 /*
@@ -335,8 +419,10 @@ wakeup(chan)
        qp = &slpque[HASH(chan)];
 restart:
        for (q = &qp->sq_head; p = *q; ) {
        qp = &slpque[HASH(chan)];
 restart:
        for (q = &qp->sq_head; p = *q; ) {
+#ifdef DIAGNOSTIC
                if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
                        panic("wakeup");
                if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
                        panic("wakeup");
+#endif
                if (p->p_wchan==chan) {
                        p->p_wchan = 0;
                        *q = p->p_link;
                if (p->p_wchan==chan) {
                        p->p_wchan = 0;
                        *q = p->p_link;