by Elmar Baumgart, ModulaWare
Here are the "final" definitions modules Processes and Semaphores of the ISO Modula-2 Standard Library (some updates/minor renamings by Pat Terry, Jul-92; revised and early 1993). No guarantee is given that these definitions exactly match those of the soon-to-be-released Standard.
___________________________________________________________________
DEFINITION MODULE Processes;
(* This module allows concurrent algorithms to be expressed using processes. A process is
a unit of a program that has the potential to run in parallel with other processes.
*)
IMPORT SYSTEM;
TYPE
ProcessId; (* Used to identify processes *)
Parameter = SYSTEM.ADDRESS; (* Used to pass data between processes *)
Body = PROC; (* Used as the type of a process body *)
Urgency = INTEGER; (* Used by the internal scheduler *)
Sources = CARDINAL; (* Used to identify event sources *)
ProcessesExceptions = (* Exceptions raised by this module *)
(passiveProgram, processError);
(* The following procedures create processes and switch control between them. *)
PROCEDURE Create (procBody: Body; extraSpace: CARDINAL; procUrg: Urgency;
procParams: Parameter; VAR procId: ProcessId);
(* Creates a new process with procBody as its body, and with urgency and parameters
given by procUrg and procParams. At least as much workspace (in units of
SYSTEM.LOC) as is specified by extraSpace is allocated to the process.
An identity for the new process is returned in procId.
The process is created in the passive state; it will not run until activated.
*)
PROCEDURE Start (procBody: Body; extraSpace: CARDINAL; procUrg: Urgency;
procParams: Parameter; VAR procId: ProcessId);
(* Creates a new process, with parameters as for Create.
The process is created in the ready state; it is eligible to run immediately.
*)
PROCEDURE StopMe ();
(* Terminates the calling process.
The process must not be associated with a source of events.
*)
PROCEDURE SuspendMe ();
(* Causes the calling process to enter the passive state. The procedure only returns
when the calling process is again activated by another process.
*)
PROCEDURE Activate (procId: ProcessId);
(* Causes the process identified by procId to enter the ready state, and thus to become
eligible to run again.
*)
PROCEDURE SuspendMeAndActivate (procId: ProcessId);
(* Executes an atomic sequence of SuspendMe() and Activate(procId). *)
PROCEDURE Switch (procId: ProcessId; VAR info: Parameter);
(* Causes the calling process to enter the passive state; the process identified by procId
becomes the currently executing process.
info is used to pass parameter information from the calling to the activated process.
On return, info will contain information from the process that chooses to switch back to
this one (or will be NIL if Activate or SuspendMeAndActivate are used instead of
Switch).
*)
PROCEDURE Wait ();
(* Causes the calling process to enter the waiting state. The procedure will return when
the calling process is activated by another process, or when one of its associated
eventSources has generated an event.
*)
(* The following procedures allow the association of processes with sources of external
events.
*)
PROCEDURE Attach (eventSource: Sources);
(* Associates the specified eventSource with the calling process. *)
PROCEDURE Detach (eventSource: Sources);
(* Dissociates the specified eventSource from the program. *)
PROCEDURE IsAttached (eventSource: Sources): BOOLEAN;
(* Returns TRUE if and only if the specified eventSource is currently associated with
one of the processes of the program.
*)
PROCEDURE Handler (eventSource: Sources): ProcessId;
(* Returns the identity of the process, if any, that is associated with the specified
eventSource.
*)
(* The following procedures allow processes to obtain their identity, parameters, and
urgency.
*)
PROCEDURE Me (): ProcessId;
(* Returns the identity of the calling process (as assigned when the process was first
created).
*)
PROCEDURE MyParam (): Parameter;
(* Returns the value specified as procParams when the calling process was created. *)
PROCEDURE UrgencyOf (procId: ProcessId): Urgency;
(* Returns the urgency established when the process identified by procId was first
created.
*)
(* The following procedure provides facilities for exception handlers. *)
PROCEDURE ProcessesException (): ProcessesExceptions;
(* If the current coroutine is in the exceptional execution state because of the raising
of a language exception, returns the corresponding enumeration value, and
otherwise raises an exception.
*)
PROCEDURE IsProcessesException (): BOOLEAN;
(* Returns TRUE if the current coroutine is in the exceptional execution state
because of the raising of an exception in a routine from this module; otherwise
returns FALSE.
*)
END Processes.
___________________________________________________________________
DEFINITION MODULE Semaphores;
(* Provides mutual exclusion facilities for use by processes. *)
TYPE
SEMAPHORE;
PROCEDURE Create (VAR s: SEMAPHORE; initialCount: CARDINAL );
(* Creates and returns s as the identity of a new semaphore that has its associated count
initialized to initialCount, and has no processes yet waiting on it.
*)
PROCEDURE Destroy (VAR s: SEMAPHORE);
(* Recovers the resources used to implement the semaphore s, provided that no process is
waiting for s to become free.
*)
PROCEDURE Claim (s: SEMAPHORE);
(* If the count associated with the semaphore s is non-zero, decrements this count and
allows the calling process to continue; otherwise suspends the calling process until
s is released.
*)
PROCEDURE Release (s: SEMAPHORE);
(* If there are any processes waiting on the semaphore s, allows one of them
to enter the ready state; otherwise increments the count associated with s.
*)
PROCEDURE CondClaim (s: SEMAPHORE): BOOLEAN;
(* Returns TRUE if the call Claim(s) would cause the calling process to be suspended;
in this case the count associated with s is not changed. Otherwise returns TRUE and
the associated count is decremented.
*)
END Semaphores.
Use_Processes is an amazingly short test program. It uses ISO M2's Std I/O-Lib modules SWholeIO and
STextIO to write to the terminal. Use_Processes displays the processes' number (id) on console (see
listing below) and is short enough to be able to describe itself. An attempt to provide a detailed description
would result in a text that is longer than the program itself :-) Just find out how it works!
Module Use_Processes terminates intentionally with an exception. The program was tested under VAX/VMS using ModulaWare's Modula-2 compiler MVR V3.18 and ModulaWare's implementation of the ISO M2 Std Lib, available since Apr-1992.
MODULE Use_Processes; (* Test program for ISO 10154 Modula-2 Standard Library [Extension] of MaX|MVR V4 Modula-2 Compiler for AXP|VAX/OpenVMS Distribution Kit Copyright (1994-1996) Guenter Dotzel, ModulaWare, http://www.modulaware.com/ This software source code constitutes intellectual property rights of Guenter Dotzel, ModulaWare and is furnished under a Non-Disclosure Agreement and may only be used, processed and stored according to the terms and conditions of this agreement. All rights reserved. Modula-2 example & test program for modules Processes and Semaphores. This program displays the processes' number (id) trace on console. Use_Processes is short enough to describe itself; a description of it's functionality would be longer than the source code. Written by Elmar Baumgart/May-1992. *) FROM STextIO IMPORT WriteLn, WriteString, WriteChar; FROM SWholeIO IMPORT WriteCard; FROM Processes IMPORT Start, StopMe, SuspendMe, ProcessId, Parameter, MyParam; FROM Semaphores IMPORT SEMAPHORE, Create, Claim, Release; FROM SYSTEM IMPORT ADR; (* CAST removed by GD/28-Jul-1992 *) CONST WSP = 100000;(*required on AXP; VAX needs 20000; *) Tasks = 25; OutputPerLine = 10; Iterations = 30; VAR G: INTEGER; gSEMA: SEMAPHORE; Params: ARRAY[1..Tasks] OF INTEGER; PROCEDURE P; VAR i: INTEGER; p: POINTER TO INTEGER; BEGIN p:= MyParam(); FOR i:= 1 TO Iterations DO Act(p^); END; Died(p^); END P; PROCEDURE Act(x: INTEGER); BEGIN WriteCard(x, 6); WriteChar(' '); ConditionalWriteLn; END Act; PROCEDURE Died(x: INTEGER); BEGIN WriteCard(x, 6); WriteChar('#'); ConditionalWriteLn; END Died; PROCEDURE ConditionalWriteLn; BEGIN Claim(gSEMA); INC(G); IF (G REM OutputPerLine) = 0 THEN WriteLn; END; Release(gSEMA); END ConditionalWriteLn; PROCEDURE StartProcess(x, prio: INTEGER); VAR id: ProcessId; BEGIN WriteCard(x, 6); WriteChar('+'); ConditionalWriteLn; Start(P, WSP, prio, ADR(Params[x]), id); END StartProcess; VAR i: INTEGER; BEGIN G:= 0; Create(gSEMA, 1); FOR i:= 1 TO Tasks DO Params[i]:= i; StartProcess(i, 0); END; WriteString(" #Mn#"); ConditionalWriteLn; SuspendMe(); END Use_Processes. _____________________________________________________________________ 1+ 1 2+ 1 1 2 3+ 1 2 1 2 3 4+ 1 2 3 1 2 3 4 5+ 1 2 3 4 1 2 3 4 5 6+ 1 2 3 4 5 1 2 3 4 5 6 7+ 1 2 3 4 5 6 1 2 3 4 5 6 7 8+ 1 2 3 4 5 6 7 1 2 3 4 5 6 7 8 9+ 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 9 10+ 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 10 11+ 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 11 12+ 1 2 3 4 5 6 7 8 9 10 11 1 2 3 4 5 6 7 8 9 10 11 12 13+ 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 11 12 13 14+ 1 2 3 4 5 6 7 8 9 10 11 12 13 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1# 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17+ 3 4 5 6 7 8 9 10 11 12 13 14 15 16 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18+ 2# 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19+ 3# 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20+ 4# 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21+ 5# 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22+ 6# 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23+ 7# 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24+ 8# 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25+ 9# 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #Mn# 10# 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 12 13 14 15 16 17 18 19 20 21 22 23 24 25 11# 12 13 14 15 16 17 18 19 20 21 22 23 24 25 13 14 15 16 17 18 19 20 21 22 23 24 25 12# 13 14 15 16 17 18 19 20 21 22 23 24 25 14 15 16 17 18 19 20 21 22 23 24 25 13# 14 15 16 17 18 19 20 21 22 23 24 25 15 16 17 18 19 20 21 22 23 24 25 14# 15 16 17 18 19 20 21 22 23 24 25 16 17 18 19 20 21 22 23 24 25 15# 16 17 18 19 20 21 22 23 24 25 17 18 19 20 21 22 23 24 25 16# 17 18 19 20 21 22 23 24 25 18 19 20 21 22 23 24 25 17# 18 19 20 21 22 23 24 25 19 20 21 22 23 24 25 18# 19 20 21 22 23 24 25 20 21 22 23 24 25 19# 20 21 22 23 24 25 21 22 23 24 25 20# 21 22 23 24 25 22 23 24 25 21# 22 23 24 25 23 24 25 22# 23 24 25 24 25 23# 24 25 25 24# 25 25# EXCEPTION encountered m2-iso-lib-err: passiveProgram %MTK-F-PROCABORT, process 00036718, routine 00065A21 aborted. %MODULA-F-HLTSTMT, HALT statement encountered %TRACE-F-TRACEBACK, symbolic stack dump follows module name routine name line rel PC abs PC EXCEPTIONS RAISEGENERALEXCEPTION 31 00000121 00064B76 PROCESS_SCHEDUL NEXTREADY 266 0000007E 0006590E PROCESS_SCHEDUL STOPTASK 313 000000E8 00065B09 FOREIGN_PROCESS NEWPROCESS 000000B1 000630B1 _____________________________________________________________________________
One of the nice features of VMS is that languages can be mixed in applications. So if one provides Oberon-2 symbol files for the modules Processes and Semaphores, module Use_Processes could also be written in Oberon-2 using ModulaWare's new Oberon-2 Compiler H2O V1.0 on VAX/VMS. Here are the [dummy] interface modules Processes and Semaphores (comments cut out, to keep the paper short) and the example and example and test program UseProcesses - all written in Oberon-2. Note, that in contrast to ISO M2, there are no underscores allowed in Oberon-2 identifiers. ISO M2 even allows "_" to be the first character of an identifier; good that the ISO M2 Std Lib doesn't make use of underscores at all.
MODULE Processes; IMPORT CTR; TYPE ProcessId* = POINTER TO ProcessIdDesc; ProcessIdDesc*= RECORD END; (* hidden type *) Parameter* = CTR.ADDRESS; Body* = PROCEDURE; Urgency* = CTR.INTEGER; Sources* = CTR.CARDINAL; ProcessesExceptions* = CTR.ENUM8; CONST passiveProgram*=0; processError*=1; PROCEDURE Create*(procBody: Body; extraSpace: CTR.CARDINAL; procUrg: Urgency; procParams: Parameter; VAR procId: ProcessId); END Create; PROCEDURE Start*(procBody: Body; extraSpace: CTR.CARDINAL; procUrg: Urgency; procParams: Parameter; VAR procId: ProcessId); END Start; PROCEDURE StopMe*(); END StopMe; PROCEDURE SuspendMe*(); END SuspendMe; PROCEDURE Activate*(procId: ProcessId); END Activate; PROCEDURE SuspendMeAndActivate*(procId: ProcessId); END SuspendMeAndActivate; PROCEDURE Switch*(procId: ProcessId; VAR info: Parameter ); END Switch; PROCEDURE Wait*(); END Wait; PROCEDURE Attach*(eventSource: Sources); END Attach; PROCEDURE Detach*(eventSource: Sources); END Detach; PROCEDURE IsAttached*(eventSource: Sources): BOOLEAN; END IsAttached; PROCEDURE Handler*(eventSource: Sources): ProcessId; END Handler; PROCEDURE Me*(): ProcessId; END Me; PROCEDURE MyParam*(): Parameter; END MyParam; PROCEDURE UrgencyOf*(procId: ProcessId): Urgency; END UrgencyOf; PROCEDURE ProcessesException*(): ProcessesExceptions; END ProcessesException; PROCEDURE IsProcessesException*(): BOOLEAN; END IsProcessesException; END Processes. ___________________________________________________________________ MODULE Semaphores; IMPORT CTR; TYPE SEMAPHORE* = POINTER TO SemaphoreDesc; SemaphoreDesc*=RECORD END; PROCEDURE Create*(VAR s: SEMAPHORE; initialCount: CTR.CARDINAL); END Create; PROCEDURE Destroy*(VAR s: SEMAPHORE); END Destroy; PROCEDURE Claim*(s: SEMAPHORE); END Claim; PROCEDURE Release*(s: SEMAPHORE); END Release; PROCEDURE CondClaim*(s: SEMAPHORE): BOOLEAN; END CondClaim; END Semaphores. ___________________________________________________________________ MODULE UseProcesses; (* Oberon-2 Example & test program for ISO Modula-2 Standard library module Processes and Semaphores. This program displays the processes' number (id) trace on console. Copyright (1994-1996) Guenter Dotzel, ModulaWare, http://www.modulaware.com/ This software source code constitutes intellectual property rights of Guenter Dotzel, ModulaWare and is furnished under a Non-Disclosure Agreement and may only be used, processed and stored according to the terms and conditions of this agreement. All rights reserved. Converted from Modula-2 to Oberon-2 from [m2lib]Use_Processes.Mod by GD/28-Jul-1992, 12-Aug-1992 *) IMPORT STextIO, SWholeIO, Processes, Semaphores, S:=SYSTEM; CONST WSP = 20000; Tasks = 25; OutputPerLine = 10; Iterations = 30; TYPE INTEGER=LONGINT; VAR G: INTEGER; gSEMA: Semaphores.SEMAPHORE; Params: ARRAY Tasks+1 OF INTEGER; VAR i: INTEGER; PROCEDURE ConditionalWriteLn; BEGIN Semaphores.Claim(gSEMA); INC(G); IF (G MOD OutputPerLine) = 0 THEN STextIO.WriteLn; END; Semaphores.Release(gSEMA); END ConditionalWriteLn; PROCEDURE Act(x: INTEGER); BEGIN SWholeIO.WriteCard(x, 6); STextIO.WriteChar(' '); ConditionalWriteLn; END Act; PROCEDURE Died(x: INTEGER); BEGIN SWholeIO.WriteCard(x, 6); STextIO.WriteChar('#'); ConditionalWriteLn; END Died; PROCEDURE P; TYPE IntPtr = POINTER TO RECORD p: INTEGER END; VAR p: IntPtr; i: INTEGER; BEGIN p:= S.VAL(IntPtr, Processes.MyParam()); FOR i:= 1 TO Iterations DO Act(p^.p); END; Died(p^.p); END P; PROCEDURE StartProcess(x, prio: INTEGER); VAR id: Processes.ProcessId; BEGIN SWholeIO.WriteCard(x, 6); STextIO.WriteChar('+'); ConditionalWriteLn; Processes.Start(P, WSP, prio, S.ADR(Params[x]), id); END StartProcess; BEGIN G:= 0; Semaphores.Create(gSEMA, 1); FOR i:= 1 TO Tasks DO Params[i]:= i; StartProcess(i, 0); END; STextIO.WriteString(" #Mn#"); ConditionalWriteLn; Processes.SuspendMe(); END UseProcesses.
$ link useprocesses
When run, UseProcesses executes exactly like it's Modula-2 companion Use_Processes.
END Oberon-2 Excursion
On-top of module Processes and Semaphores we can now define another abstraction layer called CoProcesses, according to Per Brinch Hansen's Parallel Pascal language construct COBEGIN and COEND (see also Roger Henry's MODUS article, Issue 8, May-1988). The example and test module for CoProcesses is called Use_CoProcesses which has the same functionality as Use_Processes above. The output generated is slighty different compared to that of Use_Processes. See listing below. This is due to the fact that the parent process is on hold as long as his childrens are running. The full source code of CoProcesses' implementation module is also provided below.
DEFINITION MODULE CoProcesses;
FROM Processes IMPORT Body, Parameter, Urgency;
TYPE CB;
PROCEDURE CoBEGIN(VAR Block: CB);
PROCEDURE CoStart(
c: CB;
UserProc: Body;
Space: CARDINAL;
UserParam: Parameter;
Importance: Urgency
);
PROCEDURE CoEND(VAR Block: CB);
END CoProcesses.
___________________________________________________________________
MODULE Use_CoProcesses;
(*
Test program for
ISO 10154 Modula-2 Standard Library [Extension] of
MaX|MVR V4 Modula-2 Compiler for AXP|VAX/OpenVMS
Distribution Kit
Copyright (1994) Guenter Dotzel, ModulaWare
http://www.modulaware.com
This software source code constitutes intellectual property
rights of Guenter Dotzel, ModulaWare and is furnished under a
Non-Disclosure Agreement and may only be used, processed
and stored according to the terms and conditions of this agreement.
All rights reserved.
Example & test program for modules Processes and Semaphores
using Per Brinch Hansen's CoBEGIN, CoEND
parallel process abstraction provided by the example layer CoProcesses.
This program displays the processes' number (id) trace on console.
Use_CoProcesses is short enough to describe itself;
a description of it's functionality would be longer than the source
code.
Written by Elmar Baumgart/May-1992.
*)
FROM STextIO IMPORT WriteLn, WriteString, WriteChar;
FROM SWholeIO IMPORT WriteInt;
FROM Processes IMPORT MyParam;
FROM CoProcesses IMPORT CoBEGIN, CoEND, CoStart, CB;
FROM Semaphores IMPORT SEMAPHORE, Create, Claim, Release;
FROM SYSTEM IMPORT ADR;
CONST
WSP = 20000*5;
Tasks = 25;
OutputPerLine = 10;
Iterations = 30;
VAR
G: INTEGER; gSEMA: SEMAPHORE;
Params: ARRAY[1..Tasks] OF INTEGER;
Block: CB;
PROCEDURE P;
VAR i: INTEGER; p: POINTER TO INTEGER;
BEGIN
p:= MyParam();
FOR i:= 1 TO Iterations DO
Act(p^);
END;
Died(p^);
END P;
PROCEDURE Act(x: INTEGER);
BEGIN
WriteInt(x, 6); WriteChar(' ');
ConditionalWriteLn;
END Act;
PROCEDURE Died(x: INTEGER);
BEGIN
WriteInt(x, 6); WriteChar('#');
ConditionalWriteLn;
END Died;
PROCEDURE ConditionalWriteLn;
BEGIN
Claim(gSEMA);
INC(G);
IF (G REM OutputPerLine) = 0 THEN WriteLn; END;
Release(gSEMA);
END ConditionalWriteLn;
VAR i: INTEGER;
BEGIN
G:= 0;
Create(gSEMA, 1);
CoBEGIN(Block);
FOR i:= 1 TO Tasks DO
Params[i]:= i;
CoStart(Block, P, WSP, ADR(Params[i]), 0);
END;
CoEND(Block);
WriteString(" #Mn#");
(*Conditional*)WriteLn;
END Use_CoProcesses.
_____________________________________________________________________
1 1 2 1 2 3 1 2 3 4
1 2 3 4 5 1 2 3 4 5
6 1 2 3 4 5 6 7 1 2
3 4 5 6 7 8 1 2 3 4
5 6 7 8 9 1 2 3 4 5
6 7 8 9 10 1 2 3 4 5
6 7 8 9 10 11 1 2 3 4
5 6 7 8 9 10 11 12 1 2
3 4 5 6 7 8 9 10 11 12
13 1 2 3 4 5 6 7 8 9
10 11 12 13 14 1 2 3 4 5
6 7 8 9 10 11 12 13 14 15
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 1 2 3 4
5 6 7 8 9 10 11 12 13 14
15 16 17 1 2 3 4 5 6 7
8 9 10 11 12 13 14 15 16 17
18 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 1 2 3 4 5 6 7
8 9 10 11 12 13 14 15 16 17
18 19 20 21 22 23 1 2 3 4
5 6 7 8 9 10 11 12 13 14
15 16 17 18 19 20 21 22 23 24
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 1 2 3 4 5
6 7 8 9 10 11 12 13 14 15
16 17 18 19 20 21 22 23 24 25
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 1 2 3 4 5
6 7 8 9 10 11 12 13 14 15
16 17 18 19 20 21 22 23 24 25
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 1 2 3 4 5
6 7 8 9 10 11 12 13 14 15
16 17 18 19 20 21 22 23 24 25
1# 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 2# 3 4 5 6
7 8 9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24 25 3#
4 5 6 7 8 9 10 11 12 13
14 15 16 17 18 19 20 21 22 23
24 25 4# 5 6 7 8 9 10 11
12 13 14 15 16 17 18 19 20 21
22 23 24 25 5# 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 6# 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 7# 8 9 10 11
12 13 14 15 16 17 18 19 20 21
22 23 24 25 8# 9 10 11 12 13
14 15 16 17 18 19 20 21 22 23
24 25 9# 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24 25 10#
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 11# 12 13 14 15
16 17 18 19 20 21 22 23 24 25
12# 13 14 15 16 17 18 19 20 21
22 23 24 25 13# 14 15 16 17 18
19 20 21 22 23 24 25 14# 15 16
17 18 19 20 21 22 23 24 25 15#
16 17 18 19 20 21 22 23 24 25
16# 17 18 19 20 21 22 23 24 25
17# 18 19 20 21 22 23 24 25 18#
19 20 21 22 23 24 25 19# 20 21
22 23 24 25 20# 21 22 23 24 25
21# 22 23 24 25 22# 23 24 25 23#
24 25 24# 25 25# #Mn#
_______________________________________________________________________
IMPLEMENTATION MODULE CoProcesses;
(*
Copyright (1994-1996) Guenter Dotzel, ModulaWare
http://www.modulaware.com/
This software source code constitutes intellectual property
rights of Guenter Dotzel, ModulaWare and is furnished under a
Non-Disclosure Agreement and may only be used, processed
and stored according to the terms and conditions of this agreement.
All rights reserved.
*)
FROM Semaphores IMPORT SEMAPHORE, Create, Destroy, Claim, Release;
FROM Processes IMPORT ProcessId, Body, Parameter, Urgency, Start;
FROM Storage IMPORT ALLOCATE, DEALLOCATE;
FROM SYSTEM IMPORT TSIZE;
TYPE
CoBlock = RECORD
ChildPen : SEMAPHORE;
ChildMinder: SEMAPHORE;
Children : CARDINAL;
END;
CB = POINTER TO CoBlock;
VAR
Parenthood: SEMAPHORE;
Childhood: SEMAPHORE;
Proc: Body;
CurrentCb: CB;
CONST
CoOpTariff = 1024;
PROCEDURE CoBEGIN(VAR c: CB);
BEGIN
ALLOCATE(c, TSIZE(CoBlock));
Create(c^.ChildPen, 0);
Create(c^.ChildMinder, 0); (* initially claimed *)
c^.Children:= 0;
END CoBEGIN;
PROCEDURE CoStart(
c: CB;
UserProc: Body;
Space: CARDINAL;
UserParam: Parameter;
Importance: Urgency
);
VAR id: ProcessId;
BEGIN
Claim(Parenthood);
Proc:= UserProc;
CurrentCb:= c;
INC(c^.Children);
Start(Wrapping, Space + CoOpTariff, Importance, UserParam, id);
END CoStart;
PROCEDURE CoEND(VAR c: CB);
VAR i: CARDINAL;
BEGIN
IF c^.Children > 0 THEN
FOR i:= 1 TO c^.Children DO Release(c^.ChildPen);
END;
Claim(c^.ChildMinder);
END;
Destroy(c^.ChildPen);
Destroy(c^.ChildMinder);
DEALLOCATE(c, TSIZE(CoBlock));
END CoEND;
PROCEDURE Wrapping;
VAR
UserProc: Body;
c: CB;
BEGIN
UserProc:= Proc;
c:= CurrentCb;
Release(Parenthood);
Claim(c^.ChildPen);
UserProc;
Claim(Childhood);
DEC(c^.Children);
IF c^.Children = 0 THEN
Release(c^.ChildMinder);
END;
Release(Childhood);
END Wrapping;
BEGIN
Create(Parenthood, 1);
Create(Childhood, 1);
END CoProcesses.
___________________________________________________________________
All M2/O2 modules above are now part of the ModulaWare's MVR respectively H2O distribution kit. See
directories [m2lib] resp. [oli].
ModulaWare's Oberon-2 Compiler for VAX/VMS by Günter Dotzel, ModulaWare.
Erlangen, Aug-10, 1992
H2O is a new ModulaWare product which belongs to the Moderon-, Obula, Obulon-family of programming languages :-) designed at ETH-Zuerich.
ModulaWare GmbH proudly announces the first version V1.0 of the Oberon-2 Compiler H2O for DEC VAX/VMS. The main features of Oberon-2 are strong type checking, modules with type checked interfaces and separate compilation, type extension (object-orientedness), type-bound procedures (methods), read-only export of variables, support for run-time type tests, compatibility between all numeric types (mixed expressions), and string operations.
H2O is a native-code Oberon-2 compiler for DEC VAX/VMS. The front-end is ETH-Zuerich's portable Oberon-2 compiler OP2 written in an almost Oberon- compatible subset of Modula-2. The back-end of H2O is based upon the proven VAX code-generator of ModulaWare's Modula-2 compiler MVR also written in a subset of Modula-2.
H2O produces standard VAX/VMS object code files with standard call- interface and VMS-debugger information. As with Modula-2, debugger mode/language is set to Pascal. There is no dedicated Oberon-2 [I/O]-library in H2O. However, since H2O generated code can be called from any other language and vice versa under VMS, it is possible to use the ISO Modula-2 Standard Library in Oberon-2. See below. H2O's compilation qualifiers include
/noLog show compilation progress, names of imported modules and file names,
/noQuery explicitly asks for name of symbolic files,
/noSym[=filespec] allow generation of a new symbolic file (only if the export changed) and optionally accepts another file name. The default extension is .SYN,
/noCheck generate run-time tests for array indices, case-statement index, and type-checked pointers,
/noDebug generate VMS-debugger symbolic data into object file,
/noOmit_module_name omit the "ModuleName." prefix for exported procedures (external references),
/noForeign_code generate code which is AST-save,
/noModule_name_separator[="x"] use "x" instead of "." in ModuleName.ProcedureName for external references of exported procedures.
/noMachine_code generate symbolic assembly listing of the code generated in addition to source code listing (use with /Listing)
/noCross_reference generate cross reference listing in addition to the source code listing (not yet implemented),
/noListing[=filespec] generate source code listing into an optionally specified filespec,
/noObject[=filespec] generate object file into optionally specified filespec,
/noTransfer_vectors generate transfer vectors for VMS' shareable images.
In the first version of H2O it is only possible to import Oberon-2 modules in Modula-2 via dummy definition modules/symbol files or via so-called foreign definition modules, because MVR can't process H2O's symbol-files and vice versa. Note, Oberon-2's symbol files are produced from marked identifiers in the [implementation-]module; there is no direct equivalent of Modula-2's definition module in Oberon-2.
Most Modula-2 definition modules are easily converted to Oberon-2 symbol files by deleting the keyword DEFINITION, adding an asterisk "*" after each identifier, converting enumeration types to constants, adding END procname after each PROCEDURE procname( ... ): ... declaration and finally compiling this new module using H2O which generates an Oberon-2 symbol file. Such modules can be imported in Oberon-2 modules. At link time, the object code of the corresponding Modula-2 implementation module from LNK$LIBRARY (e.g.: from MOD$SYSTEM:Modula.OLB) is used.
This allows to import the ISO Modula-2 Standard I/O-, string conversions-, mathematical-, string handling-, system clock-, and last but not least the concurrent processes- Library in Oberon-2 programs.
An example serves to illustrate the conversion of a Modula-2 definition module to an Oberon-2 dummy (means no implementation) interface module. First an M2 definition module x.def then the corresponding O2 dummy interface module called x.mod is shown. x.mod must be compiled with the O2 compiler to produce an O2 symbol file x.syn):
DEFINITION MODULE x; CONST y=123; TYPE e=(a,b,c); PROCEDURE z(x: INTEGER): REAL; END x. MODULE x; CONST y*=123; TYPE e*=SHORTINT; (* enumeration type *) CONST a*=0; b*=1; c*=2; PROCEDURE z*(x: LONGINT): REAL; END z; END x.Example import of module x into the O-2 module usex:
MODULE usex;
IMPORT M2lib:=x;
VAR r: LONGREAL;
BEGIN
r:=M2lib.z(M2lib.y)
END usex.
Example command sequence to compile, link and execute usex:
$copy [m2lib]x.def x.mod
$edit x.mod ! manual conversions from M2 def. to O2 mod.
$h2o x.mod/sym/noobj! invoke the VAX/VMS Oberon-2 compiler;
! generates file x.syn
$h2o usex ! compiles usex.mod, imports x.syn and
! generates [usex.syn,] usex.obj
$link usex,[m2lib]x ! link usex.obj to module [m2lib]x.obj
$run usex ! execute usex.exe
H2O supports the interface definition of so-called foreign definition modules that have no corresponding Modula-2 or Oberon-2 implementation module. M2/O2 entities have at link time the following syntax (object file references)
ModuleName "NameSeparatorChar" EntityName
where entity is either a procedure, or variable or additionally in O2, the type descriptor section name. Constants, strings and types are completely handled by the M2/O2 compilers.
The NameSeparatorChar can be freely choosen with the
/[No]Module_Name_Separator[="x"] compilation qualifier.
The import of a module forces the compiler to produce a call to the module body, i.e. the initialization procedure with the name of the module. For foreign interface module references, only the object file references contain the EntityName.
VMS's parameter passing mechanisms %IMMED, %REF and %STDESCR (immediate value, per reference and per string descriptor) are supported. Syntactically we decided not to introduce additional keywords as in Modula-2 (MVR). Instead we did only one change in the front-end of the Oberon-2 compiler:
H2O's parameter passing specifications for foreign interfaces:
Allow "$" in the module name. If it contains a "$", then the entity names are also allowed to contain dollar signs. Names of procedure parameters are don't care names at link time (even at compile time), so a parameter name suffix of either "$I", "$R", or "$S" could serve to indicate its parameter passing mechanism. By default all parameters, even value parameters are passed by reference as in Modula-2 (MVR). Note, that the module name of foreign modules is nowhere used at link time, hence it can be cheated with a "$"
So for example, the M2 definition
%FOREIGN DEFINITION MODULE StrHanProcs;
PROCEDURE STR$InsertStringAtPos (
VAR %STDESCR str: ARRAY OF CHAR;
pos: INTEGER;
%REF ins: ARRAY OF CHAR;
%IMMED insLength: INTEGER): INTEGER;
END StrHanProcs.
is defined in Oberon-2 (H2O) as follows:
MODULE StrHanProcs$;
TYPE INTEGER*=LONGINT;
PROCEDURE STR$InsertStringAtPos* (
VAR str$S: ARRAY OF CHAR;
pos: INTEGER;
ins$R: ARRAY OF CHAR;
insLength$I: INTEGER): INTEGER;
END StrHanProcs.
Parameters with the "$R" suffix make sense only in combination with open array parameters; in this
case, the pushing of the array descriptors LEN(array) value is suppressed; only the address of the
array is pushed.
$R mechanisms are heavily used for example in the OSF/Motif interface (DECW$MOTIF) which doesn't make use of string descriptors. That's all that's needed to create any interface to VMS callable routines. The compiler guarantees the correct passing mechanism while retaining the full type check.
When doing an interface conversion from M2 syntax to O2 syntax, the change of the parameter passing specification as illustrated in the StrHanProcs module above, could be securely done using an editor macro. An additional suffix "$O" indicates an optional parameter. NIL is used to indicate an omitted actual parameter.
The following modules of ISO Modula-2 Standard I/O Library are part of the H2O distribution kit:
Channels, reading program arguments and enumerations: StdChans, ProgramArgs, IOConsts
I/O-channel operations (reading, writing): TextIO, WholeIO, WholeLIO, RealIO, RealSIO, LongIO, LongGIO, LongTIO, RawIO, IOResult
Simple I/O operations with default channel: STextIO, SWholeIO, SWholeLIO, SRealIO, SRealSIO, SLongIO, SLongGIO, SLongTIO, SRawIO, SIOResult
Device modules (opening, closing, positioning): ChanConsts, StreamFile, SeqFile, RndFile, TermFile
Interfaces: IOChan, IOLink
Concurrent processing: Processes, Semaphores
String handling and number conversions: CharClass, Strings, ConvTypes, WholeConv, WholeLConv, RealConv, RealSConv, LongConv, LongGConv, LongTConv, WholeStr, WholeLStr, RealStr, RealSStr, LongStr, LongGStr, LongTStr, LongStr
System clock routines: SysClock
Mathematics: RealMath, RealSMath, LongMath, LongGMath, LongTMath, ComplexMath, ComplexSMath, LongComplexMath, LongComplexGMath, LongComplexTMath
Low level: LowReal, LowRealS, LowLongG, LowLongT
The ModulaTor Vol 2, Nr 8, Sep-92 (http://www.modulaware.com/mdlt26.htm) contains a complete collection of the ISO M2 Std Lib interface modules for Oberon-2, including source code of Oberon-2 example programs. This issue also contains a detailed description how programming language constructs, such as enumeration types, used in the ISO M2 definitions have been converted to Oberon-2 to be able to use the ISO M2 Std Lib in Oberon-2 just as in M2. H2O uses the same implementation modules as ModulaWare's Modula-2 compiler MVR under VMS.
This interoperability of the ISO M2 Lib with O2 was not a design goal of the ISO M2 committee. But the O2 programmers can take advantage of a formally specified (VDM-SL) library. For more information about VDM-SL see the article of Nico Plat and Peter Gorm Larsen, entitled An Overview of the ISO VDM-SL Standard, in ACM SigPlan, Vol 27, Nr 8, Aug-92, pp 76..82).
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 | Contact | Legal | Buy_products | OpenVMS_compiler | Alpha_Oberon_System | XDS_family | DOS_compiler | ModulaTor | Bibliography | Oberon[-2]_links | Modula-2_links | Onduleurs