| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- (* Copyright (C) 1987 Jensen & Partners International *)
- (*$V-,S-,R-,I-*)
- IMPLEMENTATION MODULE Process;
- FROM SYSTEM IMPORT PROCESS,NEWPROCESS,TRANSFER,IOTRANSFER,EI,DI,
- GetFlags,SetFlags,CurrentProcess,Out;
- FROM Storage IMPORT ALLOCATE;
- FROM Lib IMPORT Terminate;
- TYPE
- Task = POINTER TO TaskDescriptor;
- SIGNAL = POINTER TO SigRec;
- SigRec = RECORD
- count : INTEGER;
- waiting : Task;
- END;
- TaskDescriptor = RECORD
- next : Task; (* queue of waiting Process *)
- priority : CARDINAL;
- cor : PROCESS;
- due : CARDINAL;
- nextdue : Task;
- END;
- VAR
- cp : Task; (* currently active task + ready queue *)
- dq : Task; (* queue of delayed tasks *)
- wq : Task; (* queue of tasks that have reached thier delay time
- but haven't been placed on the ready queue *)
- SchedProc : PROCESS;
- SchedStack : ADDRESS;
- Started : BOOLEAN;
- (*$W+*) (* Volatile variables *)
- VAR
- Stop : BOOLEAN;
- LockNest : CARDINAL; (* No of nested locks *)
- (* only safe to slice if zero *)
- SchedTime : CARDINAL;
- (*$W-*)
- PROCEDURE QInsert(T: Task; VAR Q: Task);
- (* inserts task after last task in Q with greater or equal priority *)
- VAR
- q,qb : Task;
- BEGIN
- q := Q;
- qb := NIL;
- WHILE (q<>NIL)AND(T^.priority<=q^.priority) DO
- qb := q;
- q := q^.next;
- END;
- IF qb=NIL THEN
- Q := T;
- ELSE
- qb^.next := T;
- END;
- T^.next := q;
- END QInsert;
- PROCEDURE AddReadyProcess(T: Task);
- (* adds new process to ready list
- NB gets added ahead of current process if at same priority
- *)
- VAR
- mp : PROCESS;
- oldcp : Task;
- ie : CARDINAL;
- BEGIN
- ie := GetFlags(); DI;
- IF cp=NIL THEN
- QInsert(T,cp); (* add new process *)
- ELSE
- oldcp := cp; (* remove current process *)
- cp := cp^.next;
- QInsert(T,cp); (* add new process *)
- QInsert(oldcp,cp); (* add current process *)
- END;
- mp := cp^.cor;
- TRANSFER (mp,mp);
- SetFlags(ie);
- END AddReadyProcess;
- PROCEDURE StartProcess(P: PROC; N: CARDINAL; Pr: CARDINAL);
- VAR
- t0 : Task; wsp: ADDRESS;
- np : Task;
- BEGIN
- t0 := cp;
- ALLOCATE (wsp, N);
- ALLOCATE (np, SIZE(TaskDescriptor));
- np^.priority := Pr;
- NEWPROCESS (P, wsp, N , np^.cor);
- AddReadyProcess(np);
- END StartProcess;
- PROCEDURE SEND(s: SIGNAL);
- VAR
- t0 : Task;
- ie : CARDINAL;
- BEGIN
- ie := GetFlags(); DI;
- IF s^.count <> MAX(INTEGER) THEN
- INC(s^.count);
- IF s^.count <= 0 THEN (* somebody waiting *)
- t0 := s^.waiting;
- s^.waiting := t0^.next;
- AddReadyProcess(t0);
- END;
- END;
- SetFlags(ie);
- END SEND;
- PROCEDURE Notify(s: SIGNAL);
- VAR
- t0 : Task;
- ie : CARDINAL;
- BEGIN
- ie := GetFlags(); DI;
- IF s^.count < 0 THEN (* somebody waiting *)
- INC(s^.count);
- t0 := s^.waiting;
- s^.waiting := t0^.next;
- (* add to waiting q *)
- t0^.nextdue := wq;
- wq := t0;
- END;
- SetFlags(ie);
- END Notify;
- PROCEDURE WAIT (s: SIGNAL);
- VAR
- t0 : Task;
- mp : PROCESS;
- ie : CARDINAL;
- BEGIN (* insert cp in queue s *)
- ie := GetFlags(); DI;
- DEC(s^.count);
- IF s^.count < 0 THEN (* wait *)
- t0 := cp;
- cp := cp^.next;
- QInsert(t0,s^.waiting);
- mp := cp^.cor;
- TRANSFER (mp,mp);
- END;
- SetFlags(ie);
- END WAIT;
- PROCEDURE Awaited(s: SIGNAL) : BOOLEAN;
- BEGIN
- RETURN (s^.count<0);
- END Awaited;
- PROCEDURE Init(VAR s: SIGNAL);
- BEGIN
- NEW(s);
- s^.waiting := NIL;
- s^.count := 0;
- END Init;
- PROCEDURE CheckTimeQ;
- VAR
- ta,tb,tn : Task;
- BEGIN
- ta := dq;
- tb := NIL;
- WHILE ta <> NIL DO
- tn := ta^.nextdue;
- IF ta^.due = SchedTime THEN
- IF tb = NIL THEN dq := tn ELSE tb^.nextdue := tn END;
- ta^.nextdue := wq;
- wq := ta;
- ELSE
- tb := ta;
- END;
- ta := tn;
- END;
- END CheckTimeQ;
- PROCEDURE Slice;
- (* Clears waiting queue *)
- (* Then schedules next ready process if it is of equal priority *)
- VAR
- nextt,oldt,ta : Task;
- BEGIN
- IF LockNest = 0 THEN
- (* move waiting queue to the ready queue *)
- (* set up by CheckTimeQueue *)
- WHILE wq <> NIL DO
- ta := wq; wq := wq^.nextdue;
- QInsert(ta,cp);
- END;
- (* now do slice *)
- nextt := cp^.next;
- IF (nextt <> NIL) AND (nextt^.priority = cp^.priority) THEN (* slice *)
- oldt := cp; cp := nextt;
- QInsert(oldt,cp); (* insert old cp at end of processes *)
- END;
- END;
- END Slice;
- MODULE SS[1]; (* IRQ 1: timer interrupt *)
- IMPORT Stop,Task,PROCESS,IOTRANSFER,TRANSFER,SchedTime,cp,DI,
- Slice,CheckTimeQ;
- EXPORT Scheduler;
- PROCEDURE Scheduler;
- VAR
- nextt,
- oldt : Task;
- op,np : PROCESS;
- Int8 : PROC;
- TYPE
- code = ARRAY[0..2] OF SHORTCARD;
- CONST
- Int8code = code(0CDH,08H,0CBH); (* INT 08H / RETF *)
- BEGIN
- DI;
- Int8 := PROC(ADR(Int8code));
- Stop := FALSE;
- SchedTime := 0;
- LOOP
- np := cp^.cor;
- LOOP
- IOTRANSFER(op,np,8);
- Int8;
- INC(SchedTime);
- IF Stop THEN EXIT END;
- CheckTimeQ;
- Slice;
- np := cp^.cor;
- END;
- Stop := FALSE;
- TRANSFER(op,np); (* no return until restarted *)
- END;
- END Scheduler;
- END SS;
- PROCEDURE Idler; (* always on cp chain *)
- VAR
- i : CARDINAL;
- BEGIN
- LOOP INC(i);
- END;
- END Idler;
- PROCEDURE StartScheduler;
- VAR
- ie : CARDINAL;
- BEGIN
- ie := GetFlags(); DI;
- IF NOT Started THEN
- Started := TRUE;
- IF SchedStack = NIL THEN (* first time *)
- ALLOCATE( SchedStack, 512 );
- NEWPROCESS( Scheduler, SchedStack, 512, SchedProc );
- END;
- TRANSFER( cp^.cor, SchedProc );
- END;
- SetFlags(ie);
- END StartScheduler;
- PROCEDURE StopScheduler;
- VAR
- ie : CARDINAL;
- BEGIN
- ie := GetFlags();
- IF Started THEN
- EI ;
- Started := FALSE;
- Stop := TRUE;
- WHILE Stop DO END;
- END;
- SetFlags(ie);
- END StopScheduler;
- PROCEDURE Delay(T: CARDINAL);
- (* Waits T time slices *)
- (* 0 will swap to next process of equal priority, without delaying *)
- VAR
- mp : PROCESS;
- ie : CARDINAL;
- BEGIN
- ie := GetFlags(); DI;
- IF T = 0 THEN
- mp := cp^.cor;
- Slice;
- IF mp = cp^.cor THEN
- SetFlags(ie);
- RETURN
- END; (* no other processes ready *)
- ELSE
- cp^.due := SchedTime + T;
- cp^.nextdue := dq;
- dq := cp;
- cp := cp^.next;
- END;
- mp := cp^.cor;
- TRANSFER(mp,mp);
- SetFlags(ie);
- END Delay;
- PROCEDURE Lock;
- (* Critical region lock - prevents timeslicing *)
- (* may be nested *)
- BEGIN
- INC(LockNest);
- END Lock;
- PROCEDURE Unlock;
- (* Unlock procedure, always paired with a call to Lock.
- Will de-schedule current process if there are ready processes
- of equal priority *)
- VAR
- ie : CARDINAL;
- BEGIN
- ie := GetFlags(); DI;
- IF LockNest <= 1 THEN
- LockNest := 0; Delay(0);
- ELSE
- DEC(LockNest);
- END;
- SetFlags(ie);
- END Unlock;
- VAR
- Continue : PROC;
- PROCEDURE CloseDown;
- BEGIN
- StopScheduler;
- Continue;
- END CloseDown;
- BEGIN
- dq := NIL;
- wq := NIL;
- NEW(cp);
- cp^.next := NIL;
- cp^.priority := 1;
- cp^.cor := CurrentProcess();
- StartProcess( Idler, 512 , 0 );
- SchedStack := NIL;
- Started := FALSE;
- LockNest := 0;
- Terminate(CloseDown,Continue);
- END Process.
|