by Günter Dotzel, ModulaWare
The Oberon-2 coroutine examples, part II are a follow up from part I in The ModulaTor, Feb-1995. This issue also contains the bibliographic references for part I in chapter 7.
MODULE LEE; (*A Simulation: An inactive optimizing algorithm in Oberon-2: Find the shortest path between two cities.
Reference: see [Hoar 72] below.
As a simple but unexpected example of the use of simulated time, we take the Lee algorithm for finding the shortest path between a city A and a city B connected by a network of one-way roads. The algorithm may be envisaged as the propagation of a pulse from the destination city B at equal speed along all roads leading into it. Each time a pulse reaches a city not reached by a previous pulse, it records the road it has come along, and then sends pulses outward along all roads leading into the city. When a pulse reaches a city which has already been reached by another pulse, it dies. When a pulse reaches the city A, the task is completed.
City and road form a recursive data structure. The variable WayOut holds the recommended wayout from the city towards B. For an unvisited city, its value is NIL.
The process representing a pulse takes as parameter the road along which it is first to pass. The WayOut of every city is initially NIL.
First written by Guenter Dotzel, May-82.
GD/AS/03-Feb-1995 transpiled from Modula-2 to Oberon-2.
http://www.modulaware.com/
*)
IMPORT CTR, STextIO, SWholeIO, SIOResult, PS:=PROCESSSCHEDULER;
TYPE
City = POINTER TO CityType;
Road = POINTER TO RoadType;
STRING = ARRAY 16 OF CHAR;
CityType = RECORD
Name: STRING;
RoadsIn,
WayOut: Road;
NextCity: City;
END;
RoadType = RECORD
Length: CTR.CARDINAL;
NextIn: Road;
Destination, Source: City;
END;
WSP = ARRAY 4096 OF LONGINT;
VAR
WorkSpace: POINTER TO WSP;
c, ct,
A, B,
RefCity,
SourceCity,
DestinationCity: City;
rd, rt: Road;
x: CTR.CARDINAL;
SimulationDuration: CTR.CARDINAL;
s: STRING;
PulsePrint: BOOLEAN;
IsNumber : BOOLEAN;
termch: CHAR;
PROCEDURE ReadCardinal (VAR i: CTR.CARDINAL; VAR isnumber: BOOLEAN);
BEGIN
SWholeIO.ReadCard(i);
STextIO.SkipLine;
isnumber := SIOResult.ReadResult() = SIOResult.allRight;
END ReadCardinal;
PROCEDURE ReadString (VAR in: ARRAY OF CHAR);
BEGIN
STextIO.ReadString (in);
STextIO.SkipLine;
END ReadString;
PROCEDURE WL (str: ARRAY OF CHAR);
BEGIN
STextIO.WriteLn; STextIO.WriteString(str);
END WL;
PROCEDURE Hold (Ticks: CTR.CARDINAL);
BEGIN
(* next reactivation after specified number of Ticks *)
PS.PAUSE (Ticks*20);
END Hold;
PROCEDURE MakeProcess (p: PS.PROC);
BEGIN
NEW (WorkSpace);
PS.STARTPROCESS (p, WorkSpace, SIZE(WSP));
END MakeProcess;
PROCEDURE MakePulseProcess (p: PS.PROC; r: Road);
BEGIN
rd := r; (* road parameter *)
MakeProcess (p);
END MakePulseProcess;
PROCEDURE DEALLOCATE(VAR a: PS.ADDRESS; size: PS.CARDINAL);
BEGIN
a:=NIL;
END DEALLOCATE;
PROCEDURE StopProcess;
BEGIN
(* remove myself and all my garbage with specified proc *)
PS.TERMINATEPROCESS (DEALLOCATE);
END StopProcess;
PROCEDURE PrintWayOut; (* P R O C E S S *)
VAR c: City;
l: CTR.CARDINAL;
BEGIN
(* activated from PULSE, which reached city A *)
(* print existing path: *)
WL (' The shortest path: ');
WL ( A^.Name);
l := A^.WayOut^.Length;
c := A^.WayOut^.Destination;
WHILE c # B DO
WL ( c^.Name);
INC (l, c^.WayOut^.Length);
c := c^.WayOut^.Destination;
END;
WL ( B^.Name);
WL (' Path length = ');
SWholeIO.WriteCard (l, 1);
WL ('End of Simulation.');
STextIO.WriteLn;
(* and terminate by going out of process *)
END PrintWayOut;
PROCEDURE PULSE; (* P R O C E S S *)
VAR c: City;
r: Road;
BEGIN
r := rd; (* take road parameter *)
c := r^.Source;
IF PulsePrint THEN
WL (' City = ' );
STextIO.WriteString (r^.Destination^.Name);
STextIO.WriteString ( ' sends pulse to City ---> ');
STextIO.WriteString ( c^.Name); STextIO.WriteString (', length=');
SWholeIO.WriteCard ( r^.Length,5);
END;
Hold (r^.Length); (* walk along the road and consume time *)
IF PulsePrint THEN
WL (' The pulse from ');
STextIO.WriteString ( r^.Destination^.Name );
STextIO.WriteString ( ' reached City --->');
STextIO.WriteString ( c^.Name);
END;
(* now we reached the next city: *)
IF c^.WayOut = NIL THEN
(* not yet reached by another pulse *)
c^.WayOut := r; (* record road *)
IF c = A THEN (* city A reached *)
MakeProcess (PrintWayOut);
StopProcess;
END;
r := c^.RoadsIn;
WHILE r # NIL DO
(* send pulses along all roads leading into city: *)
MakePulseProcess (PULSE, r);
r := r^.NextIn;
END; (* propagation of pulses *)
END;
StopProcess;
END PULSE;
PROCEDURE STARTER; (* P R O C E S S *)
VAR rd: Road;
BEGIN
rd := B^.RoadsIn;
WHILE rd # NIL DO
MakePulseProcess (PULSE, rd);
rd := rd^.NextIn;
END;
StopProcess;
END STARTER;
PROCEDURE Lee (At, Bt: City);
BEGIN
A := At;
B := Bt;
MakeProcess (STARTER);
END Lee;
PROCEDURE LegalCity (s: STRING): City;
VAR c: City;
BEGIN
(* go along city list and look for the named city,
return the City pointer *)
c := RefCity;
LOOP
IF s = c^.Name THEN RETURN c (* city found *)
ELSIF c^.NextCity = NIL THEN RETURN NIL
END;
c := c^.NextCity;
END;
END LegalCity;
BEGIN
(* read in
o all city names
o for each city: city names for all RoadsIn
o SourceCity
o DestinationCity
o SimulationDuration
*)
RefCity := NIL; (* create (empty) city list head *)
ct := NIL;
LOOP
NEW (c);
WL (' Type city name <ret> ');
ReadString (c^.Name);
IF c^.Name[0] = CHR(0) THEN (* empty string *) EXIT END;
IF ct = NIL THEN RefCity := c;
ELSE ct^.NextCity := c;
END;
c^.RoadsIn := NIL;
c^.WayOut := NIL;
c^.NextCity := NIL;
ct := c;
END; (* LOOP *)
IF RefCity=NIL THEN RETURN (* leave module *)
END;
(* read in RoadsIn for each city: *)
c := RefCity;
LOOP
rd := NIL;
LOOP
WL ('--->' );
STextIO.WriteString ( c^.Name);
STextIO.WriteString ( ', type City.Name for RoadsIn <ret> ');
ReadString (s);
IF s[0]=CHR(0) THEN EXIT (* no more roads for city c *)
END;
ct := LegalCity (s);
IF ct # NIL THEN
NEW (rd);
IF c^.RoadsIn = NIL THEN c^.RoadsIn := rd
ELSE (* previous road: *) rt^.NextIn := rd
END;
rd^.Destination := c;
rd^.NextIn := NIL;
rd^.Source := ct;
(* Get length of road: *)
REPEAT
WL ('-----> type length of this road <ret> ');
ReadCardinal (rd^.Length, IsNumber)
UNTIL IsNumber & (rd^.Length>0);
rt := rd;
ELSE
END; (* IF LegalCity *)
END; (* LOOP *)
IF c^.NextCity # NIL THEN c :=c^.NextCity
ELSE EXIT;
END;
END; (* City LOOP *)
WL (' Type Source City Name <ret> ');
REPEAT
ReadString (s);
SourceCity := LegalCity(s);
UNTIL SourceCity # NIL;
WL (' Type Destination City Name <ret> ');
REPEAT
ReadString (s);
DestinationCity := LegalCity(s);
UNTIL DestinationCity # NIL;
WL (' Type max. simulation duration in ticks * 20ms<ret> ');
REPEAT
ReadCardinal (x, IsNumber)
UNTIL IsNumber & (x>0);
SimulationDuration := x;
WL (' Print pulse trace (Y/N) [default: Y]');
STextIO.ReadChar (termch); PulsePrint := CAP (termch) # 'N';
Lee (SourceCity, DestinationCity);
Hold (SimulationDuration);
WL (' --- Time limit reached, no road connection within limit.');
WL ("");
END LEE.
Example graph:
10 6
+------------->G<----------+
/ ^ 5 |
/ 2 | +----->-+ |
/ 4 |/ 1 \|
->A --------------->+D<----------F
/ ^ / ^ ^
7/ | / | |
/ | 8 / | +-----+
B 4| +------->+ 3| /
\ | / | / 7
2\ | / | /
\ | / 5 | /
->C+---------------->E/
Type city name <ret> A
Type city name <ret> B
Type city name <ret> C
Type city name <ret> D
Type city name <ret> E
Type city name <ret> F
Type city name <ret> G
Type city name <ret>
--->A, type City.Name for RoadsIn <ret> B
-----> type length of this road <ret> 700
--->A, type City.Name for RoadsIn <ret> C
-----> type length of this road <ret> 400
--->A, type City.Name for RoadsIn <ret>
--->B, type City.Name for RoadsIn <ret>
--->C, type City.Name for RoadsIn <ret> B
-----> type length of this road <ret> 200
--->C, type City.Name for RoadsIn <ret> D
-----> type length of this road <ret> 800
--->C, type City.Name for RoadsIn <ret>
--->D, type City.Name for RoadsIn <ret> A
-----> type length of this road <ret> 400
--->D, type City.Name for RoadsIn <ret> E
-----> type length of this road <ret> 300
--->D, type City.Name for RoadsIn <ret> F
-----> type length of this road <ret> 100
--->D, type City.Name for RoadsIn <ret>
--->E, type City.Name for RoadsIn <ret> C
-----> type length of this road <ret> 500
--->E, type City.Name for RoadsIn <ret>
--->F, type City.Name for RoadsIn <ret> D
-----> type length of this road <ret> 500
--->F, type City.Name for RoadsIn <ret> E
-----> type length of this road <ret> 700
--->F, type City.Name for RoadsIn <ret>
--->G, type City.Name for RoadsIn <ret> A
-----> type length of this road <ret> 1000
--->G, type City.Name for RoadsIn <ret> D
-----> type length of this road <ret> 200
--->G, type City.Name for RoadsIn <ret> F
-----> type length of this road <ret> 600
--->G, type City.Name for RoadsIn <ret>
Type Source City Name <ret> B
Type Destination City Name <ret> G
Type max. simulation duration in ticks * 20ms<ret> 10000
Print pulse trace (Y/N) [default: Y]Y
City = G sends pulse to City ---> A, length= 1000
City = G sends pulse to City ---> D, length= 200
City = G sends pulse to City ---> F, length= 600
The pulse from G reached City --->D
City = D sends pulse to City ---> A, length= 400
City = D sends pulse to City ---> E, length= 300
City = D sends pulse to City ---> F, length= 100
The pulse from D reached City --->F
City = F sends pulse to City ---> D, length= 500
City = F sends pulse to City ---> E, length= 700
The pulse from D reached City --->E
City = E sends pulse to City ---> C, length= 500
The pulse from D reached City --->A
City = A sends pulse to City ---> B, length= 700
The pulse from G reached City --->F
City = A sends pulse to City ---> C, length= 400
The pulse from G reached City --->A
The pulse from F reached City --->D
The pulse from E reached City --->C
City = C sends pulse to City ---> B, length= 200
The pulse from A reached City --->C
City = C sends pulse to City ---> D, length= 800
The pulse from F reached City --->E
The pulse from C reached City --->B
The shortest path:
B
C
E
D
G
Path length = 1200
End of Simulation.
MODULE PROCESSSCHEDULER(*[6]*);
(*
ETH Zuerich: NW, CJ, SEK, HHN 30-Aug-79,
additional procedure INITSIGNAL CJ dec-79,
elimination of import of storage handler CJ dec-79,
error correction, awaited CJ, BP, LB 30.3.81.
GD/18-May-1982: added process termination
GD/ Aug-1987 for VAX/VMS
GD/28-May-1994 for AXP/OpenVMS, wsp size enlarged
GD/AS/03-Feb-1995 simplified and transpiled from Modula-2 to Oberon-2.
http://www.modulaware.com/
*)
IMPORT SYSTEM, VMS:=VMS$, CTR, M2C := M2Coroutines;
TYPE
PROCESS *= M2C.PROCESS;
ADDRESS *= SYSTEM.PTR;(*CTR.ADDRESS;*)
CARDINAL*= CTR.CARDINAL;
PROC *= M2C.PROC;
QUADWORD = SYSTEM.QUADWORD;
SHORTWORD= SYSTEM.SHORTWORD;
WORD = SYSTEM.WORD;
DisposeType * = PROCEDURE (VAR a: ADDRESS; c: CARDINAL);
SIGNAL * = POINTER TO ProcessDescriptor;
ProcessDescriptor = RECORD
pp: PROCESS;
postponement: CARDINAL;
(* postponement=0 means that the process is ready
postponement>0 means that the process is waiting
for a signal. postponement>1 is used for PAUSE only *)
next: SIGNAL; (* ties the descriptors in the ring *)
queue: SIGNAL;
(* ties the descriptors waiting for the same signal *)
WSPadr: ADDRESS;
WSPsize: CARDINAL; (* used for TERMINATEPROCESS *)
END;
idleWSPtype= ARRAY 1001 OF WORD; (* work space for idle process
*)
VAR cp: SIGNAL; (* current process *)
tick: SIGNAL; (* head of the queue of the PAUSing processes*)
idleWSP: POINTER TO idleWSPtype;
idleSignal: SIGNAL;
OldTime: LONGINT;
recover: RECORD
disp: DisposeType;
adr: ADDRESS;
size: CARDINAL;
END;
PROCEDURE GetTime(VAR tim : LONGINT);
VAR status: CARDINAL;
quad: QUADWORD;
t: ARRAY 7 OF INTEGER(*_16*); (* t[3,4,5,6]=[h,m,s,s/100] *)
BEGIN
status := VMS.SYS$GETTIM (quad);
status := VMS.SYS$NUMTIM (SYSTEM.ADR(t), quad);
tim:= (t[3]*60+t[4])*60000+t[5]*1000+t[6]*10;
END GetTime;
PROCEDURE UpdateTicks;
VAR this,last: SIGNAL;
Time: LONGINT;
Diff: CARDINAL;
BEGIN
this := tick; last := NIL;
GetTime (Time); Diff := (Time - OldTime); OldTime := Time;
IF Diff > 0 THEN
WHILE this # NIL DO
IF Diff >= this^.postponement THEN
this^.postponement := 0;
IF last = NIL THEN tick := this^.queue
ELSE last^.queue := this^.queue
END;
ELSE DEC(this^.postponement, Diff); last := this;
END;
this := this^.queue;
END;
END;
END UpdateTicks;
PROCEDURE STARTPROCESS * (P: PROC; A: ADDRESS; n: CARDINAL);
(* start P with workspace A of length n *)
VAR t: SIGNAL;
BEGIN t := cp; NEW(cp);
cp^.next := t^.next; cp^.postponement := 0;
cp^.WSPadr := A;
cp^.WSPsize := n;
t^.next := cp;
M2C.NEWPROCESS(P, SYSTEM.VAL(LONGINT,A), n, cp^.pp);
M2C.TRANSFER(t^.pp, cp^.pp);
END STARTPROCESS;
PROCEDURE TERMINATEPROCESS * (Dispose: DisposeType);
VAR t, s: SIGNAL; p: PROCESS;
BEGIN
(* myself (cp) is unlinked,
cp is temporarily maintained for NextReady,
cp is not in the PAUSing queue,
hence cp's workspace could be disposed and
the NextReady process is scheduled
*)
t:=cp;
REPEAT
t:=t^.next
UNTIL t^.next=cp;
t^.next:=cp^.next;
s:=cp; (* maintain cp for Dispose *)
(* NextReady: *)
cp:=cp^.next;
LOOP
UpdateTicks;
IF cp^.postponement=0 THEN EXIT END;
t:=cp;
REPEAT cp:=cp^.next;
UNTIL (cp^.postponement=0) OR (t=cp);
END;
IF recover.disp # NIL THEN
recover.disp(recover.adr,recover.size);
END;
recover.disp := Dispose;
recover.adr := s^.WSPadr;
recover.size := s^.WSPsize;
s:=NIL;
M2C.TRANSFER(p, cp^.pp);
END TERMINATEPROCESS;
PROCEDURE SEND(VAR s: SIGNAL);
(* resume first process waiting for s *)
VAR t: SIGNAL;
BEGIN
UpdateTicks;
IF s # NIL THEN
t := cp; cp := s; cp^.postponement := 0; s := cp^.queue;
M2C.TRANSFER(t^.pp, cp^.pp)
END
END SEND;
PROCEDURE SENDDOWN(VAR s: SIGNAL);
(* mark first process waiting for s as ready *)
BEGIN
UpdateTicks;
IF s # NIL THEN
s^.postponement := 0; s := s^.queue
END
END SENDDOWN;
PROCEDURE NextReady;
(* activate next ready process *)
VAR this, strt: SIGNAL;
BEGIN
this := cp;
UpdateTicks;
LOOP strt := cp;
UpdateTicks;
REPEAT cp := cp^.next
UNTIL (cp^.postponement=0) OR (cp=strt);
IF cp^.postponement = 0 THEN EXIT
END;
END;
M2C.TRANSFER(this^.pp,cp^.pp);
END NextReady;
PROCEDURE WAIT* (VAR s: SIGNAL);
VAR this, next: SIGNAL;
BEGIN (* insert current process at end of queue s *)
IF s = NIL THEN s := cp
ELSE
this := s;
LOOP next := this^.queue;
IF next = NIL THEN EXIT END ;
this := next
END ;
this^.queue := cp
END ;
cp^.postponement := 1; cp^.queue := NIL;
NextReady;
END WAIT;
PROCEDURE PAUSE * (n: CARDINAL);
VAR this: SIGNAL;
BEGIN
IF n > 0 THEN
cp^.queue := tick; tick := cp;
END;
cp^.postponement := n;
NextReady;
END PAUSE;
PROCEDURE AWAITED* (s: SIGNAL): BOOLEAN;
BEGIN
RETURN s#NIL
END AWAITED;
PROCEDURE INITSIGNAL* (VAR s: SIGNAL);
(* Initialisation of a SIGNAL *)
BEGIN
s := NIL;
END INITSIGNAL;
PROCEDURE Idle;
BEGIN
INITSIGNAL(idleSignal);
LOOP
WAIT(idleSignal);
END
END Idle;
PROCEDURE INITSCHEDULER *;
BEGIN
NEW(cp);
cp^.postponement := 0; cp^.next := cp;
tick := NIL;
recover.disp:=NIL;
END INITSCHEDULER;
BEGIN
INITSCHEDULER;
GetTime (OldTime);
NEW(idleWSP);
STARTPROCESS(Idle, idleWSP, SIZE(idleWSPtype))
END PROCESSSCHEDULER.
In [Henr 86] an alternative definition of the procedures for the handling of processes is given. The method shown in NewKernel automatically handles the first parameter of the TRANSFER and IOTRANSFER procedures and is implemented using the features provided by module SYSTEM. Then NewKernel is used to implement OldKernel which provides the features of module SYSTEM. An application example is given in module Queens and Board.
MODULE Queens;
(* see Roger Henry, Coroutines and Processes.
transpiled from Modula-2 to Oberon-2, ModulaWare/AS/Jan-1995
*)
IMPORT B:= Board, NK:= NewKernel, SYSTEM;
CONST Arow= 8;
Acol= 8;
CONST wkspsize=4000;
TYPE
WORD = ARRAY 4 OF SYSTEM.BYTE;
wksp_t = ARRAY wkspsize OF WORD;
VAR colData: ARRAY Acol OF
RECORD
cr: NK.COROUTINE;
wksp: wksp_t;
END;
initCol: INTEGER;
main: NK.COROUTINE;
done: BOOLEAN;
PROCEDURE Placer;
VAR myCol: INTEGER;
myRow: INTEGER;
BEGIN
myCol:=initCol; NK.TRANSFER(main);
LOOP
FOR myRow:=0 TO 7 DO
IF B.Safe(myCol,myRow) THEN
B.Occupy(myCol,myRow);
IF myCol < 7 THEN NK.TRANSFER (colData[myCol+1].cr);
ELSE done:=TRUE;NK.TRANSFER(main);
END;
B.Vacate(myCol,myRow);
END;
END;
IF myCol > 0 THEN NK.TRANSFER(colData[myCol-1].cr);
ELSE done:=FALSE; NK.TRANSFER(main);
END;
END;
END Placer;
PROCEDURE Init;
BEGIN
main:=NK.SELF();
FOR initCol:= 0 TO 7 DO
NK.NEWCOROUTINE(Placer,SYSTEM.ADR(colData[initCol].wksp),
SIZE(wksp_t), colData[initCol].cr);
NK.TRANSFER(colData[initCol].cr);
END;
END Init;
BEGIN
Init;
NK.TRANSFER(colData[0].cr);
WHILE done DO
B.Display;
NK.TRANSFER(colData[7].cr);
END;
END Queens.
MODULE Board;
(* transpiled from Modula-2 to Oberon-2, AS/Jan-1995
http://www.modulaware.com/
*)
IMPORT ST:= STextIO, SW:=SWholeIO;
VAR board: ARRAY 8,8 OF BOOLEAN;
c,r: ARRAY 8 OF BOOLEAN;
d1: ARRAY 15 OF BOOLEAN;
d2: ARRAY 15 OF BOOLEAN;
m,n,b: INTEGER;
PROCEDURE Safe * (i,j:INTEGER): BOOLEAN;
BEGIN
IF c[i] THEN RETURN FALSE;
ELSIF r[j] THEN RETURN FALSE;
ELSIF d1[i+j] THEN RETURN FALSE;
ELSIF d2[7+j-i] THEN RETURN FALSE;
ELSE RETURN TRUE;
END;
END Safe;
PROCEDURE Occupy * (i,j: INTEGER);
BEGIN
c[i]:=TRUE;r[j]:=TRUE;d1[i+j]:=TRUE;d2[7+j-i]:=TRUE;
board[i,j]:=TRUE;
END Occupy;
PROCEDURE Vacate * (i,j: INTEGER);
BEGIN
c[i]:=FALSE;r[j]:=FALSE;d1[i+j]:=FALSE;d2[7+j-i]:=FALSE;
board[i,j]:=FALSE;
END Vacate;
PROCEDURE Display *;
BEGIN
ST.WriteLn;SW.WriteInt(b,3);INC(b);
FOR m:=0 TO 7 DO
ST.WriteLn;SW.WriteInt(m+1,4);
FOR n:=0 TO 7 DO
IF board[n,m] THEN ST.WriteString(' 0');
ELSE ST.WriteString(' .');
END;
END;
END;
ST.WriteLn;ST.WriteString(' 1 2 3 4 5 6 7 8');
ST.WriteLn;
END Display;
BEGIN
FOR m:=0 TO 7 DO
FOR n:=0 TO 7 DO
board[n,m]:=FALSE;
END;
c[m]:=FALSE;r[m]:=FALSE;
END;
FOR m:=0 TO 14 DO
d1[m]:=FALSE;
d2[m]:=FALSE;
END;
b:=1;
END Board.
MODULE NewKernel;
(* Modula-2 implementation derived from [Henr 86].
transpiled from Modula-2 to Oberon-2 by AS/Jan-1995.
http://www.modulaware.com
*)
IMPORT M2C:=M2Coroutines, CTR;
CONST NILVector=0;
TYPE
CARDINAL *= CTR.CARDINAL;
ADDRESS *= CTR.ADDRESS;
PROCESS *= M2C.PROCESS;
PROC *= M2C.PROC;
COROUTINE*= POINTER TO
RECORD
Worksp: PROCESS;
IOVector: CARDINAL;
END;
VAR CurrentRoutine: COROUTINE;
PROCEDURE NEWCOROUTINE * (Body: PROC; WorkSpace: ADDRESS;
WsSize: CARDINAL;VAR cr: COROUTINE);
BEGIN
NEW(cr);
cr^.IOVector:=NILVector;
M2C.NEWPROCESS(Body,WorkSpace,WsSize,cr^.Worksp);
END NEWCOROUTINE;
PROCEDURE SELF *():COROUTINE;
BEGIN
RETURN CurrentRoutine
END SELF;
PROCEDURE TRANSFER * (To: COROUTINE);
VAR MySelf: COROUTINE;
BEGIN
MySelf:=CurrentRoutine;
CurrentRoutine:=To;
M2C.TRANSFER(MySelf^.Worksp, To^.Worksp);
END TRANSFER;
PROCEDURE IOTRANSFER * (To: COROUTINE; VAR From: COROUTINE);
VAR MySelf: COROUTINE;
temp: PROCESS;
BEGIN
HALT(20);
(*
MySelf:=CurrentRoutine;
temp:=To^.Worksp;
CurrentRoutine:=To;
SYSTEM.IOTRANSFER(MySelf^.Worksp,temp,MySelf^.IOVector);
(* not available under multi-user operating system! *)
CurrentRoutine^.Worksp:=temp;
From:=CurrentRoutine;
CurrentRoutine:=MySelf;
*)
END IOTRANSFER;
PROCEDURE ATTACH* (Vector: CARDINAL);
BEGIN
CurrentRoutine^.IOVector:=Vector;
END ATTACH;
BEGIN
NEW(CurrentRoutine);
CurrentRoutine^.IOVector:=NILVector;
END NewKernel.
MODULE OldKernel;
(* see [Henr 86].
transpiled from Modula-2 to Oberon-2 by ModulaWare/AS/Jan-1995.
*)
IMPORT NewKernel, CTR;
TYPE
PROCESS*=NewKernel.COROUTINE;
PROC*=NewKernel.PROC;
ADDRESS*=CTR.ADDRESS;
CARDINAL*=CTR.CARDINAL;
PROCEDURE NEWPROCESS* (Body: PROC; WorkSpace: ADDRESS;
WsSize: CARDINAL;VAR pr: PROCESS);
BEGIN
NewKernel.NEWCOROUTINE(Body,WorkSpace,WsSize,pr);
END NEWPROCESS;
PROCEDURE TRANSFER* (VAR From,To: PROCESS);
VAR temp: PROCESS;
BEGIN
temp:=To;
From:=NewKernel.SELF();
NewKernel.TRANSFER(temp);
END TRANSFER;
END OldKernel.
[Baum 92] Baumgart, Elmar: The ISO Modula-2 for Oberon-2 - Definition of Interface Modules with example and test programs. The ModulaTor, Vol. 2, Nr. 8, ModulaWare, Sep-1992 (http://www.modulaware.com/mdlt26)
[Grun 77] Grune, D.: A View of Coroutines. In: ACM Sigplan Notices. Vol. 12, No. 7, ACM, 1977, pp. 75..81
[Henr 86] Henry, Roger: Coroutines and Processes. British Standards Institute Modula-2 Working Group, 1986
[Hoar 72] Hoare, C.A.R.: Structured Programming - Hierarchical Program Structures. Academic Press, London, 1972
[ISO 94] ISO/IEC/IEEE Modula-2 DIS 10154, JTC1.SC22.WG13, Jun-1994
[Lynn 78] Lynn, E.: Letter to the Editor. In: ACM Sigplan Notices. Vol. 13, No. 2, ACM, 1978, pp. 12..14
[Marl 80] Marlin, C. D.: A Programming Methodology - A Language and an Implementation. Springer Verlag, New York, 1980
[Moes 93] Moessenboeck, H.: "Object Oriented Programming in Oberon-2", Springer-Verlag 1993
[Poun 93] Pountain, Dick: "Oberon: A Glimpse at the Future", BYTE, May 1993
[Reis 92] Reiser M.; Wirth, Niklaus, "Programming in Oberon: Steps Beyond Pascal and Modula-2", ACM Press 1992
[Wirt 84a] Wirth, Niklaus: Schemes for Multiprogramming and their Implementation in Modula-2. In: Report No. 59. Eidgen~ossische Technische Hochschule (ETH) Zuerich, Institut fuer Informatik, 1984, pp. 1..25
IMPRESSUM: The ModulaTor is an unrefereed journal. Technical papers are to be taken as working papers and personal rather than organizational statements. Items are printed at the discretion of the Editor based upon his judgement on the interest and relevancy to the readership. Letters, announcements, and other items of professional interest are selected on the same basis. Office of publication. The Editor of The ModulaTor is Günter Dotzel; he can be reached at mailto:[email deleted due to spam]
Home | Site_index | Legal | OpenVMS_compiler | Alpha_Oberon_System | ModulaTor | Bibliography | Oberon[-2]_links | Modula-2_links |