Simpler Solution
Here’s a simpler scheduling solution with process priorities.
Process Priorities
Process priorities are added using one single, NIL-terminated list of processes.
-
The process list is sorted by
- process priority, with higher priorities closer to the head in the list
- process period, with shorter periods closer to the head in the list
-
It is assumed that the lower timer number means shorter period. As any specific timer can be selected for a period, this is not a relevant restriction, but results is simpler code.
-
Priority and period are not connected. A high priority process can have a long period.
-
If its run-time exceeds the period, a process can lock out all processes of lower priority, as well as processes of the same prio, but with longer periods, but not processes of higher priority.
-
The number of priority levels is not restricted by the concept and implementation. Priorities are positive integers, including zero, with lower priority numbers meaning higher process priority.
Regarding the lockout aspect, the solution described here prevents lockouts of processes of the same prio as the locking process, but at some conceptual and code complexity cost, also restricting the number of priority levels to the number of process rings fixed in code. To detect erroneous permanent or temporary lockouts of lower priorities, other measures have to be implemented anyway. Hence, this solution here is not substantially restricted from a practical point of view, but more lightweight.
Oberon.Loop
The algorithm in Oberon.Loop is basically a simplification of the solution with the rings. All remarks there also apply, mutatis mutandis.
MODULE Oberon;
VAR
procs: Process; (* list of processes *)
cp: Process; (* current process *)
PROCEDURE Loop*;
VAR
res: INTEGER;
ch: CHAR;
done: BOOLEAN;
p: Process;
BEGIN
REPEAT
IF Console.Available() > 0 THEN
(* command and upload handling *)
ELSE
(* load ready bits *)
ProcTimers.LoadReadyStatus;
ProcDevSig.LoadReadyStatus;
(* GC timing ... *)
(* check the processes *)
done := FALSE;
IF procs # NIL THEN
p := procs;
REPEAT
IF ProcDevSig.ProcessReady(p.pcNo) THEN (* device signals *)
ProcDevSig.ResetSignals(p.pcNo);
IF p.state = AwaitDevsigTo THEN
ProcTimers.CancelDelay(p.pcNo)
END;
p.retVal := OK;
p.state := Active; cp := p; Coroutines.Transfer(loop, p.cor); cp := NIL;
done := TRUE
ELSIF ProcTimers.ProcessReady(p.pcNo) THEN (* timing *)
ProcTimers.SetPeriod(p.pcNo, p.period);
p.retVal := OK;
IF p.state = AwaitDevsigTo THEN
ProcDevSig.ResetSignals(p.pcNo);
p.retVal := Timeout
END;
IF ~(p.state IN {Suspended, AwaitDevsig}) THEN
p.state := Active; cp := p; Coroutines.Transfer(loop, p.cor); cp := NIL;
done := TRUE
END
END;
p := p.next
UNTIL done OR (p = NIL)
END
END
UNTIL FALSE
END Loop;
END Oberon.