BSD 3 development
authorBill Joy <wnj@ucbvax.Berkeley.EDU>
Wed, 16 Jan 1980 05:35:51 +0000 (21:35 -0800)
committerBill Joy <wnj@ucbvax.Berkeley.EDU>
Wed, 16 Jan 1980 05:35:51 +0000 (21:35 -0800)
Work on file usr/src/sys/sys/slp.c

Synthesized-from: 3bsd

usr/src/sys/sys/slp.c [new file with mode: 0644]

diff --git a/usr/src/sys/sys/slp.c b/usr/src/sys/sys/slp.c
new file mode 100644 (file)
index 0000000..36fcaa2
--- /dev/null
@@ -0,0 +1,418 @@
+/*     slp.c   2.2     1/15/80 */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/file.h"
+#include "../h/inode.h"
+#include "../h/vm.h"
+#include "../h/pte.h"
+
+
+#define SQSIZE 0100    /* Must be power of 2 */
+#define HASH(x)        (( (int) x >> 5) & (SQSIZE-1))
+struct proc *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.
+ */
+sleep(chan, pri)
+caddr_t chan;
+{
+       register struct proc *rp;
+       register s, h;
+
+       rp = u.u_procp;
+       s = spl6();
+       if (chan==0)
+               panic("zero wchan");
+       rp->p_stat = SSLEEP;
+       rp->p_wchan = chan;
+       rp->p_slptime = 0;
+       rp->p_pri = pri;
+       h = HASH(chan);
+       rp->p_link = slpque[h];
+       slpque[h] = rp;
+       if(pri > PZERO) {
+               if(issig()) {
+                       rp->p_wchan = 0;
+                       rp->p_stat = SRUN;
+                       slpque[h] = rp->p_link;
+                       VOID spl0();
+                       goto psig;
+               }
+               VOID spl0();
+               if(runin != 0) {
+                       runin = 0;
+                       wakeup((caddr_t)&runin);
+               }
+               swtch();
+               if(issig())
+                       goto psig;
+       } else {
+               VOID spl0();
+               swtch();
+       }
+       splx(s);
+       return;
+
+       /*
+        * If priority was low (>PZERO) and
+        * there has been a signal,
+        * execute non-local goto to
+        * the qsav location.
+        * (see trap1/trap.c)
+        */
+psig:
+       resume(u.u_procp->p_addr, u.u_qsav);
+       /*NOTREACHED*/
+}
+
+/*
+ * Wake up all processes sleeping on chan.
+ */
+wakeup(chan)
+register caddr_t chan;
+{
+       register struct proc *p, *q;
+       register i;
+       int s;
+
+       s = spl6();
+       i = HASH(chan);
+restart:
+       p = slpque[i];
+       q = NULL;
+       while(p != NULL) {
+               if(p->p_wchan==chan && p->p_stat!=SZOMB) {
+                       if (q == NULL)
+                               slpque[i] = p->p_link;
+                       else
+                               q->p_link = p->p_link;
+                       p->p_wchan = 0;
+                       p->p_slptime = 0;
+                       setrun(p);
+                       goto restart;
+               }
+               q = p;
+               p = p->p_link;
+       }
+       splx(s);
+}
+
+/*
+ * when you are sure that it
+ * is impossible to get the
+ * 'proc on q' diagnostic, the
+ * diagnostic loop can be removed.
+ */
+setrq(p)
+struct proc *p;
+{
+       register struct proc *q;
+       register s;
+
+       s = spl6();
+       for(q=runq; q!=NULL; q=q->p_link)
+               if(q == p) {
+                       printf("proc on q\n");
+                       goto out;
+               }
+       p->p_link = runq;
+       runq = p;
+out:
+       splx(s);
+}
+
+/*
+ * Set the process running;
+ * arrange for it to be swapped in if necessary.
+ */
+setrun(p)
+register struct proc *p;
+{
+       register caddr_t w;
+
+       if (p->p_stat==0 || p->p_stat==SZOMB)
+               panic("Running a dead proc");
+       /*
+        * The assignment to w is necessary because of
+        * race conditions. (Interrupt between test and use)
+        */
+       if (w = p->p_wchan) {
+               wakeup(w);
+               return;
+       }
+       p->p_stat = SRUN;
+       setrq(p);
+       if(p->p_pri < curpri)
+               runrun++;
+       if(runout != 0 && (p->p_flag&SLOAD) == 0) {
+               runout = 0;
+               wakeup((caddr_t)&runout);
+       }
+}
+
+/*
+ * Set user priority.
+ * The rescheduling flag (runrun)
+ * is set if the priority is better
+ * than the currently running process.
+ */
+setpri(pp)
+register struct proc *pp;
+{
+       register p;
+
+       p = (pp->p_cpu & 0377)/16;
+       p += PUSER + pp->p_nice - NZERO;
+       if(p > 127)
+               p = 127;
+       if(p < curpri)
+               runrun++;
+       pp->p_pri = p;
+       return(p);
+}
+
+/*
+ * put the current process on
+ * the Q of running processes and
+ * call the scheduler.
+ */
+qswtch()
+{
+
+       setrq(u.u_procp);
+       swtch();
+}
+
+/*
+ * This routine is called to reschedule the CPU.
+ * if the calling process is not in RUN state,
+ * arrangements for it to restart must have
+ * been made elsewhere, usually by calling via sleep.
+ * There is a race here. A process may become
+ * ready after it has been examined.
+ * In this case, idle() will be called and
+ * will return in at most 1HZ time.
+ * i.e. its not worth putting an spl() in.
+ */
+swtch()
+{
+       register n;
+       register struct proc *p, *q, *pp, *pq;
+
+
+       /*
+        * If not the idle process, resume the idle process.
+        */
+       if (u.u_procp != &proc[0]) {
+               if (save(u.u_rsav)) {
+                       return;
+               }
+               resume(proc[0].p_addr, u.u_qsav);
+       }
+       /*
+        * The first save returns nonzero when proc 0 is resumed
+        * by another process (above); then the second is not done
+        * and the process-search loop is entered.
+        *
+        * The first save returns 0 when swtch is called in proc 0
+        * from sched().  The second save returns 0 immediately, so
+        * in this case too the process-search loop is entered.
+        * Thus when proc 0 is awakened by being made runnable, it will
+        * find itself and resume itself at rsav, and return to sched().
+        */
+       if (save(u.u_qsav)==0 && save(u.u_rsav))
+               return;
+loop:
+       VOID spl6();
+       runrun = 0;
+       pp = NULL;
+       q = NULL;
+       n = 128;
+       /*
+        * Search for highest-priority runnable process
+        */
+       for(p=runq; p!=NULL; p=p->p_link) {
+               if((p->p_stat==SRUN) && (p->p_flag&SLOAD)) {
+                       if(p->p_pri < n) {
+                               pp = p;
+                               pq = q;
+                               n = p->p_pri;
+                       }
+               }
+               q = p;
+       }
+       /*
+        * If no process is runnable, idle.
+        */
+       p = pp;
+       if(p == NULL) {
+               idle();
+               goto loop;
+       }
+       q = pq;
+       if(q == NULL)
+               runq = p->p_link;
+       else
+               q->p_link = p->p_link;
+       curpri = n;
+       VOID spl0();
+       /*
+        * The rsav (ssav) contents are interpreted in the new address space
+        */
+       n = p->p_flag&SSWAP;
+       p->p_flag &= ~SSWAP;
+       cnt.v_swtch++;
+       resume(p->p_addr, n? u.u_ssav: u.u_rsav);
+       /*NOTREACHED*/
+}
+
+/*
+ * Create a new process-- the internal version of
+ * sys fork.
+ * It returns 1 in the new process, 0 in the old.
+ */
+newproc(isvfork)
+{
+       register struct proc *p;
+       register struct proc *rpp, *rip;
+       register int n;
+
+       p = NULL;
+       /*
+        * First, just locate a slot for a process
+        * and copy the useful info from this process into it.
+        * The panic "cannot happen" because fork has already
+        * checked for the existence of a slot.
+        */
+retry:
+       mpid++;
+       if(mpid >= 30000) {
+               mpid = 0;
+               goto retry;
+       }
+       for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) {
+               if(rpp->p_stat == NULL && p==NULL)
+                       p = rpp;
+               if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
+                       goto retry;
+       }
+       if ((rpp = p)==NULL)
+               panic("no procs");
+
+       /*
+        * make proc entry for new proc
+        */
+
+       rip = u.u_procp;
+       rpp->p_stat = SIDL;
+       rpp->p_clktim = 0;
+       rpp->p_flag = SLOAD | (rip->p_flag & SPAGI);
+       if (isvfork) {
+               rpp->p_flag |= SVFORK;
+               rpp->p_ndx = rip->p_ndx;
+       } else
+               rpp->p_ndx = rpp - proc;
+       rpp->p_uid = rip->p_uid;
+       rpp->p_pgrp = rip->p_pgrp;
+       rpp->p_nice = rip->p_nice;
+       rpp->p_textp = isvfork ? 0 : rip->p_textp;
+       rpp->p_pid = mpid;
+       rpp->p_ppid = rip->p_pid;
+       rpp->p_time = 0;
+       rpp->p_cpu = 0;
+       if (isvfork) {
+               rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
+               rpp->p_szpt = 0;
+               forkstat.cntvfork++;
+               forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
+       } else {
+               rpp->p_tsize = rip->p_tsize;
+               rpp->p_dsize = rip->p_dsize;
+               rpp->p_ssize = rip->p_ssize;
+               rpp->p_szpt = rip->p_szpt;
+               forkstat.cntfork++;
+               forkstat.sizfork += rip->p_dsize + rip->p_ssize;
+       }
+       rpp->p_rssize = 0;
+       rpp->p_wchan = 0;
+       rpp->p_slptime = 0;
+       rpp->p_aveflt = rip->p_aveflt;
+       rate.v_pgin += rip->p_aveflt;
+       rpp->p_faults = 0;
+
+       /*
+        * make duplicate entries
+        * where needed
+        */
+
+       multprog++;
+
+       for(n=0; n<NOFILE; n++)
+               if(u.u_ofile[n] != NULL) {
+                       u.u_ofile[n]->f_count++;
+                       if(!isvfork && u.u_vrpages[n])
+                               u.u_ofile[n]->f_inode->i_vfdcnt++;
+               }
+
+       u.u_cdir->i_count++;
+       if (u.u_rdir)
+               u.u_rdir->i_count++;
+       /*
+        * Partially simulate the environment
+        * of the new process so that when it is actually
+        * created (by copying) it will look right.
+        */
+
+       rip->p_flag |= SKEEP;   /* prevent parent from being swapped */
+
+       /*
+        * When the resume is executed for the new process,
+        * here is where it will resume.
+        */
+
+       if (save(u.u_ssav))
+               return(1);
+
+       procdup(rpp, isvfork);
+        
+       rpp->p_stat = SRUN;
+       rpp->p_flag |= SSWAP;
+       setrq(rpp);
+       rip->p_flag &= ~SKEEP;
+       if (isvfork) {
+               u.u_procp->p_xlink = rpp;
+               u.u_procp->p_flag |= SNOVM;
+               while (rpp->p_flag & SVFORK)
+                       sleep((caddr_t)rpp, PZERO - 1);
+               if ((rpp->p_flag & SLOAD) == 0)
+                       panic("newproc vfork");
+               uaccess(rpp, Vfmap, &vfutl);
+               u.u_procp->p_xlink = 0;
+               vpassvm(rpp, u.u_procp, &vfutl, &u);
+               for (n = 0; n < NOFILE; n++)
+                       if (vfutl.u_vrpages[n]) {
+                               if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0)
+                                       if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0)
+                                               panic("newproc i_vfdcnt");
+                               vfutl.u_vrpages[n] = 0;
+                       }
+               u.u_procp->p_flag &= ~SNOVM;
+               rpp->p_ndx = rpp - proc;
+               rpp->p_flag |= SVFDONE;
+               wakeup((caddr_t)rpp);
+       }
+       return (0);
+}