home *** CD-ROM | disk | FTP | other *** search
- #
- /*
- */
-
- #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();
- }
-