wakeup: / wakeup processes waiting for an event by linking them to the / queue mov r1,-(sp) / put char on stack mov (r0)+,r2 / r2 points to a queue mov (r0)+,r3 / r3 = wait channel number movb wlist(r3),r1 / r1 contains process number in that wait / channel that was sleeping beq 2f / if 0 return, nothing to wakeup cmp r2,u.pri / is runq >= users priority bhis 1f / yes, don't set time quantum to zero clrb uquant / time quantum = 0 1: clrb wlist(r3) / zero wait channel entry jsr r0,putlu / create a link from the last user on the Q / to this process number that got woken 2: mov (sp)+,r1 / restore r1 rts r0
sleep: / wait for event jsr r0,isintr / check to see if interrupt or quit from user br 2f / user interrupt? return mov (r0)+,r1 / put number of wait channel in r1 movb wlist(r1),-(sp) / put old pid on stack movb u.uno,wlist(r1) / put process number of process to put / to sleep in there mov cdev,-(sp) / nothing happened in isintr so jsr r0,swap / swap out process that needs to sleep mov (sp)+,cdev / restore device jsr r0,isintr / check for interrupt of new process br 2f / yes, return to new user movb (sp)+,r1 / no, r1 = original pid in wchan beq 1f / if 0 branch mov runq+4,r2 / r2 points to lowest priority queue mov 300,*ps / processor priority = 6 jsr r0,putlu / create link to old process number clr *ps / clear the status; process priority = 0 1: rts r0 / return 2: jmp sysret / return to user
/*
* 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);
}
/*
* sleep if a condition is not true. Another process will
* awaken us after it sets the condition. When we awaken
* the condition may no longer be true.
*
* we lock both the process and the rendezvous to keep r->p
* and p->r synchronized.
*/
void
sleep(Rendez *r, int (*f)(void*), void *arg)
{
int s;
void (*pt)(Proc*, int, vlong);
s = splhi();
if(up->nlocks.ref)
panic("process %lud sleeps locks held0, up->pid);
lock(r);
lock(&up->rlock);
if(r->p)
panic("double sleep");
/*
* Wakeup only knows there may be something to do by testing
* r->p in order to get something to lock on.
*/
r->p = up;
if((*f)(arg) || up->notepending){
r->p = nil;
unlock(&up->rlock);
unlock(r);
} else {
/* change state and call scheduler */
up->state = Wakeme;
up->r = r;
procsave(up);
if(setlabel(&up->sched)) {
/* here when the process is awakened */
procrestore(up);
spllo();
} else {
/* here to go to sleep (i.e. stop Running) */
unlock(&up->rlock);
unlock(r);
gotolabel(&m->sched);
}
}
if(up->notepending) {
up->notepending = 0;
splx(s);
if(up->procctl == Proc_exitme && up->closingfgrp)
forceclosefgrp();
error(Eintr);
}
splx(s);
}
Proc*
wakeup(Rendez *r)
{
Proc *p;
int s;
s = splhi();
lock(r);
p = r->p;
if(p != nil){
lock(&p->rlock);
if(p->state != Wakeme || p->r != r)
panic("wakeup: state");
r->p = nil;
p->r = nil;
ready(p);
unlock(&p->rlock);
}
unlock(r);
splx(s);
return p;
}
typedef struct Io {
Rendez;
int cond;
};
void
dowake(Io *i)
{
i->cond = 1; /* unique assignment */
wakeup(i);
}
int
iodone(void *v)
{
return ((Io*)v)->cond;
}
void
doio(void)
{
Io *i;
dispatch(i = malloc(sizeof *i));
sleep(i, iodone, i);
free(i);
}
void
doio(void)
{
Io *i;
dispatch(i = malloc(sizeof *i));
while(waserror())
/* ignore notes */;
sleep(i, iodone, i);
poperror();
free(i);
}
void
dowake(Io *i)
{
i->cond = 1;
wakeup(i);
i->cond = 2; /* atomic */
/* hands off i now */
}
void
doio(void)
{
Io *i;
dispatch(i = malloc(sizeof *i));
while(waserror())
/* eat note */;
sleep(i, iodone, i);
poperror();
while(i->cond != 2)
/* rendez not done */;
free(i);
}