Forums » Programming with the ECS » Oberon »
Coroutine for MainLoop and Task abstraction
Added by Runar Tenfjord about 1 month ago
I made a small test module with an adaption of the obl.generators.mod
code for a MainLoop and Task abstraction.
MODULE Test;
IMPORT SYSTEM, Exceptions IN OBL;
TYPE
    Coroutine = RECORD*
        frame, stack: SYSTEM.PTR
    END;
    Loop = RECORD (Coroutine)
    END;
    Task = RECORD (Coroutine)
        caller: POINTER TO VAR- Loop;
        time : UNSIGNED32;
        status: BOOLEAN
    END;
VAR
    tick : UNSIGNED32;
PROCEDURE* (VAR coroutine: Coroutine) Call;
PROCEDURE- (VAR coroutine: Coroutine) Transfer (VAR target: Coroutine);
CONST StackSize = ASH (16, SIZE (INTEGER) + SIZE (LENGTH));
VAR pointer: SYSTEM.PTR; exception: Exceptions.AllocationFailure;
BEGIN
    SYSTEM.CODE ("mov ptr [$fp + pointer], ptr $fp");
    coroutine.frame := pointer;
    IF target.frame = NIL THEN
        SYSTEM.NEW (target.stack, StackSize);
        pointer := target.stack;
        IF pointer = NIL THEN exception.Raise END;
        SYSTEM.CODE ("add ptr $sp, ptr [$fp + pointer], ptr StackSize - stackdisp");
        target.Call;
        SYSTEM.CODE ("mov ptr $sp, ptr $fp + exception - stackdisp");
        SYSTEM.DISPOSE (target.stack);
        target.frame := NIL;
    ELSE
        pointer := target.frame;
        SYSTEM.CODE ("mov ptr $fp, ptr [$fp + pointer]");
    END;
END Transfer;
PROCEDURE (VAR task: Task) Sleep(time : UNSIGNED32);
VAR caller: Loop;
BEGIN
    task.time := time;
    caller := task.caller^;
    task.Transfer(caller);
END Sleep;
PROCEDURE (VAR task: Task) Finish;
VAR caller: Loop;
BEGIN
    task.time := 0;
    task.status := FALSE;
    caller := task.caller^;
    task.Transfer(caller);
END Finish;
PROCEDURE (VAR task: Task) Call;
BEGIN
    TRACE("Task.Call");
    task.Sleep(50);
    TRACE("Task.Call2");
    task.Sleep(100);
    TRACE("Task.Call3");
    task.Finish;
    TRACE("Not to be reached!");
    HALT(1);
END Call;
PROCEDURE (VAR loop: Loop) Call;
VAR
    task : Task;
    i : INTEGER;
BEGIN
    task.caller := PTR(loop);
    task.status := TRUE;
    task.time := 0;
    TRACE("Loop.Call");
    i := 0;
    LOOP
        IF ~task.status THEN EXIT END;
        loop.Transfer(task);
        TRACE(task.time);
        TRACE(task.status);
        TRACE(i);
        INC(i);
    END;
    TRACE("Loop finished");
END Call;
PROCEDURE Test;
VAR loop : Loop;
BEGIN
    loop.Call;
END Test;
BEGIN
    Test;
END Test.
	In order to get this to work properly I changed the definition of
the field caller to:
caller: POINTER TO VAR- Loop;
Otherwise it will not point to the correct instance of
Loop.
	The code for Sleep and Finish also corrected for this and
these changes might not be optimal.
This could be an issue with obl.generators.mod also.
Replies (2)
RE: Coroutine for MainLoop and Task abstraction - Added by Florian Negele about 1 month ago
I took the liberty and rewrote your module using the existing Generators module:
MODULE Test;
IMPORT Generators IN OBL;
TYPE Task = RECORD (Generators.Generator)
    time: UNSIGNED32;
END;
PROCEDURE (VAR task: Task) Sleep (time: UNSIGNED32);
BEGIN
    task.time := time;
    task.Yield;
END Sleep;
PROCEDURE (VAR task: Task) Finish;
BEGIN
    task.time := 0;
    task.Yield;
END Finish;
PROCEDURE (VAR task: Task) Call;
BEGIN
    TRACE ("Task.Call");
    task.Sleep (50);
    TRACE ("Task.Call2");
    task.Sleep (100);
    TRACE ("Task.Call3");
    task.Finish;
END Call;
PROCEDURE Loop;
VAR task: Task; i: INTEGER;
BEGIN
    task.time := 0;
    TRACE ("Loop.Call");
    i := 0;
    WHILE task.Await () DO
        TRACE (task.time);
        TRACE (i);
        INC (i);
    END;
    TRACE ("Loop finished");
END Loop;
BEGIN
    Loop;
END Test.
	I don't know if this is helpful. The call to Finish is strictly speaking not necessary as the implicit return from Call actually stops the while loop. The same applies to the status and the caller which I therefore removed. I also turned Loop into a procedure as it does not need to be couroutine either.
RE: Coroutine for MainLoop and Task abstraction - Added by Runar Tenfjord about 1 month ago
An almost embarrassing simplification of my version.
Thanks.