Add original unix v6
This commit is contained in:
+490
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user