Research V6 development
authorKen Thompson <ken@research.uucp>
Fri, 18 Jul 1975 13:19:36 +0000 (08:19 -0500)
committerKen Thompson <ken@research.uucp>
Fri, 18 Jul 1975 13:19:36 +0000 (08:19 -0500)
Work on file usr/sys/ken/slp.c

Synthesized-from: v6

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

diff --git a/usr/sys/ken/slp.c b/usr/sys/ken/slp.c
new file mode 100644 (file)
index 0000000..14f60eb
--- /dev/null
@@ -0,0 +1,490 @@
+#
+/*
+ */
+
+#include "../param.h"
+#include "../user.h"
+#include "../proc.h"
+#include "../text.h"
+#include "../systm.h"
+#include "../file.h"
+#include "../inode.h"
+#include "../buf.h"
+
+/*
+ * 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<0 a signal cannot disturb the sleep;
+ * if pri>=0 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)
+{
+       register *rp, s;
+
+       s = PS->integ;
+       rp = u.u_procp;
+       if(pri >= 0) {
+               if(issig())
+                       goto psig;
+               spl6();
+               rp->p_wchan = chan;
+               rp->p_stat = SWAIT;
+               rp->p_pri = pri;
+               spl0();
+               if(runin != 0) {
+                       runin = 0;
+                       wakeup(&runin);
+               }
+               swtch();
+               if(issig())
+                       goto psig;
+       } else {
+               spl6();
+               rp->p_wchan = chan;
+               rp->p_stat = SSLEEP;
+               rp->p_pri = pri;
+               spl0();
+               swtch();
+       }
+       PS->integ = s;
+       return;
+
+       /*
+        * If priority was low (>=0) and
+        * there has been a signal,
+        * execute non-local goto to
+        * the qsav location.
+        * (see trap1/trap.c)
+        */
+psig:
+       aretu(u.u_qsav);
+}
+
+/*
+ * Wake up all processes sleeping on chan.
+ */
+wakeup(chan)
+{
+       register struct proc *p;
+       register c, i;
+
+       c = chan;
+       p = &proc[0];
+       i = NPROC;
+       do {
+               if(p->p_wchan == c) {
+                       setrun(p);
+               }
+               p++;
+       } while(--i);
+}
+
+/*
+ * Set the process running;
+ * arrange for it to be swapped in if necessary.
+ */
+setrun(p)
+{
+       register struct proc *rp;
+
+       rp = p;
+       rp->p_wchan = 0;
+       rp->p_stat = SRUN;
+       if(rp->p_pri < curpri)
+               runrun++;
+       if(runout != 0 && (rp->p_flag&SLOAD) == 0) {
+               runout = 0;
+               wakeup(&runout);
+       }
+}
+
+/*
+ * Set user priority.
+ * The rescheduling flag (runrun)
+ * is set if the priority is higher
+ * than the currently running process.
+ */
+setpri(up)
+{
+       register *pp, p;
+
+       pp = up;
+       p = (pp->p_cpu & 0377)/16;
+       p =+ PUSER + pp->p_nice;
+       if(p > 127)
+               p = 127;
+       if(p > curpri)
+               runrun++;
+       pp->p_pri = p;
+}
+
+/*
+ * The main loop of the scheduling (swapping)
+ * process.
+ * The basic idea is:
+ *  see if anyone wants to be swapped in;
+ *  swap out processes until there is room;
+ *  swap him in;
+ *  repeat.
+ * Although it is not remarkably evident, the basic
+ * synchronization here is on the runin flag, which is
+ * slept on and is set once per second by the clock routine.
+ * Core shuffling therefore takes place once per second.
+ *
+ * panic: swap error -- IO error while swapping.
+ *     this is the one panic that should be
+ *     handled in a less drastic way. Its
+ *     very hard.
+ */
+sched()
+{
+       struct proc *p1;
+       register struct proc *rp;
+       register a, n;
+
+       /*
+        * find user to swap in
+        * of users ready, select one out longest
+        */
+
+       goto loop;
+
+sloop:
+       runin++;
+       sleep(&runin, PSWP);
+
+loop:
+       spl6();
+       n = -1;
+       for(rp = &proc[0]; rp < &proc[NPROC]; rp++)
+       if(rp->p_stat==SRUN && (rp->p_flag&SLOAD)==0 &&
+           rp->p_time > n) {
+               p1 = rp;
+               n = rp->p_time;
+       }
+       if(n == -1) {
+               runout++;
+               sleep(&runout, PSWP);
+               goto loop;
+       }
+
+       /*
+        * see if there is core for that process
+        */
+
+       spl0();
+       rp = p1;
+       a = rp->p_size;
+       if((rp=rp->p_textp) != NULL)
+               if(rp->x_ccount == 0)
+                       a =+ rp->x_size;
+       if((a=malloc(coremap, a)) != NULL)
+               goto found2;
+
+       /*
+        * none found,
+        * look around for easy core
+        */
+
+       spl6();
+       for(rp = &proc[0]; rp < &proc[NPROC]; rp++)
+       if((rp->p_flag&(SSYS|SLOCK|SLOAD))==SLOAD &&
+           (rp->p_stat == SWAIT || rp->p_stat==SSTOP))
+               goto found1;
+
+       /*
+        * no easy core,
+        * if this process is deserving,
+        * look around for
+        * oldest process in core
+        */
+
+       if(n < 3)
+               goto sloop;
+       n = -1;
+       for(rp = &proc[0]; rp < &proc[NPROC]; rp++)
+       if((rp->p_flag&(SSYS|SLOCK|SLOAD))==SLOAD &&
+          (rp->p_stat==SRUN || rp->p_stat==SSLEEP) &&
+           rp->p_time > n) {
+               p1 = rp;
+               n = rp->p_time;
+       }
+       if(n < 2)
+               goto sloop;
+       rp = p1;
+
+       /*
+        * swap user out
+        */
+
+found1:
+       spl0();
+       rp->p_flag =& ~SLOAD;
+       xswap(rp, 1, 0);
+       goto loop;
+
+       /*
+        * swap user in
+        */
+
+found2:
+       if((rp=p1->p_textp) != NULL) {
+               if(rp->x_ccount == 0) {
+                       if(swap(rp->x_daddr, a, rp->x_size, B_READ))
+                               goto swaper;
+                       rp->x_caddr = a;
+                       a =+ rp->x_size;
+               }
+               rp->x_ccount++;
+       }
+       rp = p1;
+       if(swap(rp->p_addr, a, rp->p_size, B_READ))
+               goto swaper;
+       mfree(swapmap, (rp->p_size+7)/8, rp->p_addr);
+       rp->p_addr = a;
+       rp->p_flag =| SLOAD;
+       rp->p_time = 0;
+       goto loop;
+
+swaper:
+       panic("swap error");
+}
+
+/*
+ * 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.
+ */
+swtch()
+{
+       static struct proc *p;
+       register i, n;
+       register struct proc *rp;
+
+       if(p == NULL)
+               p = &proc[0];
+       /*
+        * Remember stack of caller
+        */
+       savu(u.u_rsav);
+       /*
+        * Switch to scheduler's stack
+        */
+       retu(proc[0].p_addr);
+
+loop:
+       runrun = 0;
+       rp = p;
+       p = NULL;
+       n = 128;
+       /*
+        * Search for highest-priority runnable process
+        */
+       i = NPROC;
+       do {
+               rp++;
+               if(rp >= &proc[NPROC])
+                       rp = &proc[0];
+               if(rp->p_stat==SRUN && (rp->p_flag&SLOAD)!=0) {
+                       if(rp->p_pri < n) {
+                               p = rp;
+                               n = rp->p_pri;
+                       }
+               }
+       } while(--i);
+       /*
+        * If no process is runnable, idle.
+        */
+       if(p == NULL) {
+               p = rp;
+               idle();
+               goto loop;
+       }
+       rp = p;
+       curpri = n;
+       /*
+        * Switch to stack of the new process and set up
+        * his segmentation registers.
+        */
+       retu(rp->p_addr);
+       sureg();
+       /*
+        * If the new process paused because it was
+        * swapped out, set the stack level to the last call
+        * to savu(u_ssav).  This means that the return
+        * which is executed immediately after the call to aretu
+        * actually returns from the last routine which did
+        * the savu.
+        *
+        * You are not expected to understand this.
+        */
+       if(rp->p_flag&SSWAP) {
+               rp->p_flag =& ~SSWAP;
+               aretu(u.u_ssav);
+       }
+       /*
+        * The value returned here has many subtle implications.
+        * See the newproc comments.
+        */
+       return(1);
+}
+
+/*
+ * Create a new process-- the internal version of
+ * sys fork.
+ * It returns 1 in the new process.
+ * How this happens is rather hard to understand.
+ * The essential fact is that the new process is created
+ * in such a way that appears to have started executing
+ * in the same call to newproc as the parent;
+ * but in fact the code that runs is that of swtch.
+ * The subtle implication of the returned value of swtch
+ * (see above) is that this is the value that newproc's
+ * caller in the new process sees.
+ */
+newproc()
+{
+       int a1, a2;
+       struct proc *p, *up;
+       register struct proc *rpp;
+       register *rip, 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 < 0) {
+               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)
+                       goto retry;
+       }
+       if ((rpp = p)==NULL)
+               panic("no procs");
+
+       /*
+        * make proc entry for new proc
+        */
+
+       rip = u.u_procp;
+       up = rip;
+       rpp->p_stat = SRUN;
+       rpp->p_flag = SLOAD;
+       rpp->p_uid = rip->p_uid;
+       rpp->p_ttyp = rip->p_ttyp;
+       rpp->p_nice = rip->p_nice;
+       rpp->p_textp = rip->p_textp;
+       rpp->p_pid = mpid;
+       rpp->p_ppid = rip->p_pid;
+       rpp->p_time = 0;
+
+       /*
+        * make duplicate entries
+        * where needed
+        */
+
+       for(rip = &u.u_ofile[0]; rip < &u.u_ofile[NOFILE];)
+               if((rpp = *rip++) != NULL)
+                       rpp->f_count++;
+       if((rpp=up->p_textp) != NULL) {
+               rpp->x_count++;
+               rpp->x_ccount++;
+       }
+       u.u_cdir->i_count++;
+       /*
+        * Partially simulate the environment
+        * of the new process so that when it is actually
+        * created (by copying) it will look right.
+        */
+       savu(u.u_rsav);
+       rpp = p;
+       u.u_procp = rpp;
+       rip = up;
+       n = rip->p_size;
+       a1 = rip->p_addr;
+       rpp->p_size = n;
+       a2 = malloc(coremap, n);
+       /*
+        * If there is not enough core for the
+        * new process, swap out the current process to generate the
+        * copy.
+        */
+       if(a2 == NULL) {
+               rip->p_stat = SIDL;
+               rpp->p_addr = a1;
+               savu(u.u_ssav);
+               xswap(rpp, 0, 0);
+               rpp->p_flag =| SSWAP;
+               rip->p_stat = SRUN;
+       } else {
+       /*
+        * There is core, so just copy.
+        */
+               rpp->p_addr = a2;
+               while(n--)
+                       copyseg(a1++, a2++);
+       }
+       u.u_procp = rip;
+       return(0);
+}
+
+/*
+ * Change the size of the data+stack regions of the process.
+ * If the size is shrinking, it's easy-- just release the extra core.
+ * If it's growing, and there is core, just allocate it
+ * and copy the image, taking care to reset registers to account
+ * for the fact that the system's stack has moved.
+ * If there is no core, arrange for the process to be swapped
+ * out after adjusting the size requirement-- when it comes
+ * in, enough core will be allocated.
+ * Because of the ssave and SSWAP flags, control will
+ * resume after the swap in swtch, which executes the return
+ * from this stack level.
+ *
+ * After the expansion, the caller will take care of copying
+ * the user's stack towards or away from the data area.
+ */
+expand(newsize)
+{
+       int i, n;
+       register *p, a1, a2;
+
+       p = u.u_procp;
+       n = p->p_size;
+       p->p_size = newsize;
+       a1 = p->p_addr;
+       if(n >= newsize) {
+               mfree(coremap, n-newsize, a1+newsize);
+               return;
+       }
+       savu(u.u_rsav);
+       a2 = malloc(coremap, newsize);
+       if(a2 == NULL) {
+               savu(u.u_ssav);
+               xswap(p, 1, n);
+               p->p_flag =| SSWAP;
+               swtch();
+               /* no return */
+       }
+       p->p_addr = a2;
+       for(i=0; i<n; i++)
+               copyseg(a1+i, a2++);
+       mfree(coremap, n, a1);
+       retu(p->p_addr);
+       sureg();
+}