Tom Kelliher, CS42
Feb. 23, 1998
The following is from the Xinu system, designed by Douglas Comer.
/* declarations */ #define QUANTUM 10 /* clock ticks until preemption */ #define SP 6 /* reg. 6 is stack pointer */ #define PC 7 /* reg. 7 is program counter */ #define PS 8 /* proc. status stored in 8th loc. */ #define NPROC 10 /* max number of processes */ #define PRCURR 0x01 /* process is running */ #define PRFREE 0x02 /* table entry is free */ #define PRREADY 0x03 /* process is on ready queue */ #define PRRECV 0x04 /* process is waiting for message */ #define PRSLEEP 0x05 /* process is sleeping */ #define PRSUSP 0x06 /* process is suspended */ #define PRWAIT 0x07 /* process is on semaphore queue */ #define PNREGS 9 /* number of CPU registers */ #define PNMLEN 8 /* process name length */ /* process table entry */ struct pentry \{ char pstate; /* state of process */ short pprio; /* process priority */ short pregs[PNREGS]; /* saved registers: R0-R5, SP, PC, PS */ short psem; /* semaphore process waiting on */ short pmsg; /* message sent to process */ short phasmsg; /* nonzero iff pmsg is valid */ short pbase; /* base of runtime stack */ short pstklen; /* stack length */ short plimit; /* lowest extent of stack */ char name[PNMLEN]; /* process name */ short pargs; /* number of arguments */ short paddr; /* initial code address */ \}; extern struct pentry proctab[NPROC]; extern int currpid; /* currently executing process */ extern int rdyhead, rdytail; extern int preempt; /*----------------------------------------------------------------------------- * resched -- reschedule processor to highest priority ready process * * Notes: Upon entry, currpid gives current process id. * Proctab[currpid].pstate gives correct NEXT state for current * process if other than PRCURR. *----------------------------------------------------------------------------- */ int resched() \{ register struct pentry *optr; /* pointer to old process entry */ register struct pentry *nptr; /* pointer to new process entry */ /* no switch needed if current process priority HIGHER than next */ if ( ( (optr = &proctab[currpid])->pstate == PRCURR) && (lastkey(rdytail) < optr->pprio) ) return(OK); /* force context switch */ if (optr->pstate == PRCURR) \{ optr->pstate = PREADY; insert(currpid, rdyhead, optr->pprio); \} /* remove highest priority process at end of ready list */ nptr = &proctab[ (currpid = getlast(rdytail) ) ]; nptr->pstate = PRCURR; preempt = QUANTUM; /* reset preemption counter */ ctxsw(optr->pregs, nptr->pregs); /* do context switch */ /* the OLD process returns here when resumed */ return(OK); \} /*----------------------------------------------------------------------------- * ctxsw -- assembler routine for performing context switch, * saving/loading registers * * The stack contains three items upon entry to this routine: * * SP+4 => address of 9 word save area with new registers + PS * SP+2 => address of 9 word save area for old registers + PS * SP => return address * * The saved state consists of: the values of R0-R5 upon entry, SP+2, PC * equal to the return address, and the PS (i.e., the PC and SP are saved * as if the calling process had returned to its caller. *----------------------------------------------------------------------------- */ .globl _ctxsw /* declare name global */ _ctxsw: /* entry point to proc. */ mov r0,*2(sp) /* save old R0 in old register area */ mov 2(sp),r0 /* get address of old register area in R0 */ add $2,r0 /* increment to saved pos. of R1 */ mov r1,(r0)+ /* save R1-R5 in successive locations of old mov r2,(r0)+ /* process register save are */ mov r3,(r0)+ mov r4,(r0)+ mov r5,(r0)+ add $2,sp /* move SP beyond the return address, as if a */ /* return had occurred */ mov sp,(r0)+ /* save stack pointer */ mov -(sp),(r0)+ /* save caller's return address as PC */ mfps (r0) /* save processor status beyond registers */ mov 4(sp),r0 /* get address of start of new register area */ /* ready to load registers for the new process */ /* and abandon the old stack */ mov 2(r0),r1 /* load R1-R5 and SP from the new area */ mov 4(r0),r2 mov 6(r0),r3 mov 8.(r0),r4 /* dot following a number makes it decimal; */ mov 10.(r0),r5 /* otherwise it is octal */ mov 12.(r0),sp /* have switched stacks now */ mov 16.(r0),-(sp) /* push new process PS on new process stack */ mov 14.(r0),-(sp) /* push new process PC on new process stack */ mov (r0),r0 /* load R0 from new area */ rtt /* load PC, PS, and reset SP all at once */