ð‰Syntax10.Scn.FntSyntax10i.Scn.Fnt$Px• MODULE Tasks; (* gri/cas 18.9.90 / 4.9.91 *) IMPORT Oberon; CONST sleeping* = 0; ready* = -1; suspended* = -2; infinity = MAX(LONGINT); TYPE Task* = POINTER TO TaskDesc; TaskDesc* = RECORD safe*: BOOLEAN; prev, next: Task; wakeUp: LONGINT END; VAR Ticks-: LONGINT; (* no. of ticks per second *) root: Task; (* tail of doubly-linked ring *) resumed: Task; (* tail of doubly-linked priority queue *) obTask: Oberon.Task; PROCEDURE Remove(t: Task); BEGIN t.prev.next := t.next; t.next.prev := t.prev; t.next := t; t.prev := t END Remove; PROCEDURE Insert(t, p: Task); BEGIN t.next := p.next; t.prev := p; p.next := t; t.next.prev := t END Insert; PROCEDURE SortIn(t, p: Task); BEGIN WHILE p.next.wakeUp <= t.wakeUp DO p := p.next END; Insert(t, p) END SortIn; PROCEDURE Merge(resumed, root: Task); VAR T: LONGINT; t: Task; BEGIN T := Oberon.Time(); t := resumed.next; WHILE t.wakeUp < T DO Remove(t); Insert(t, root); t := resumed.next END END Merge; (* tasks *) PROCEDURE (T: Task) Job*; END Job; PROCEDURE (T: Task) Suspend*; BEGIN Remove(T); T.wakeUp := infinity END Suspend; PROCEDURE (T: Task) Resume*; BEGIN Remove(T); T.wakeUp := 0; SortIn(T, resumed) END Resume; PROCEDURE (T: Task) Sleep*(dT: LONGINT); VAR t: LONGINT; BEGIN t := Oberon.Time() + dT; IF (t < 0) OR (t = infinity) THEN T.Suspend ELSE Remove(T); T.wakeUp := t; SortIn(T, resumed) END END Sleep; PROCEDURE (T: Task) State*(): LONGINT; BEGIN IF T.wakeUp = infinity THEN RETURN suspended ELSIF T.wakeUp > Oberon.Time() THEN RETURN T.wakeUp ELSE RETURN ready END END State; PROCEDURE (T: Task) Open* (safe: BOOLEAN); BEGIN T.safe := safe; T.wakeUp := infinity; T.prev := T; T.next := T END Open; PROCEDURE* Step; (* time-slice for idle tasks *) VAR t: Task; safe: BOOLEAN; BEGIN Merge(resumed, root); t := root.prev; IF t # root THEN safe := t.safe; Remove(t); IF safe THEN Insert(t, root) END; t.Job; IF ~safe & (t.wakeUp # infinity) THEN Remove(t); SortIn(t, resumed) END END END Step; PROCEDURE Start*; BEGIN IF obTask = NIL THEN NEW(obTask); obTask.safe := TRUE; obTask.handle := Step; Oberon.Install(obTask) END END Start; PROCEDURE Stop*; BEGIN IF obTask # NIL THEN Oberon.Remove(obTask); obTask := NIL END END Stop; BEGIN Ticks := 300; NEW(root); root.Open(FALSE); NEW(resumed); resumed.Open(FALSE); obTask := NIL; Start END Tasks.