The ModulaTor logo 7KB

The ModulaTor

Oberon-2 and Modula-2 Technical Publication

Ubaye's First Independent Modula-2 & Oberon-2 Journal! Nr. 2, Mar-1995


Using Coroutines in Oberon-2, Part II

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.

5. The Lee algorithm



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.

6. Coroutines versus Processees

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.

7. References

[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 |

Amazon.com [3KB] [Any browser]

Books Music Video Enter keywords...


Amazon.com logo

Webdesign by www.otolo.com/webworx, 16-Dec-1998