Example of Event Usage

The following is a simplified example of an online application that has one driver process and three servers. The driver process reads input from users and passes it on to whichever server is not currently busy. The underlying assumption is that the user is capable of submitting input faster than any single server can process it; this could be the case if the server has to perform many time-consuming actions, such as disk I/Os, to process the input. However, this example concentrates on the timing and resource control aspects of this situation, and so the servers in the example do not really do any useful work.

100 BEGIN
110 FILE TERM(KIND=REMOTE);
120 BOOLEAN FINISHED;
130 EBCDIC ARRAY MSG[0:71];
140 EVENT INMSG_EVENT, MSG_READ;
150 INTEGER I, READNUM;
160 TASK T1, T2, T3;
170
180 PROCEDURE SERVER;
190 BEGIN
200   BOOLEAN DONE;
210   EBCDIC ARRAY MSGCOPY[0:71];
220   WHILE NOT DONE DO
230   BEGIN
240     PROCURE(INMSG_EVENT);
250     REPLACE MSGCOPY BY MSG FOR 72;
260     CAUSE(MSG_READ);
270     IF MSGCOPY = “QUIT” THEN
280        DONE:= TRUE
290     ELSE BEGIN
300            REPLACE MSGCOPY[66] BY MYSELF.MIXNUMBER FOR * DIGITS;
310            WRITE(TERM,72,MSGCOPY);
320          END;
330   END;
340 END;
350
360 PROCURE(INMSG_EVENT);
370 PROCESS SERVER [T1];
380 PROCESS SERVER [T2];
390 PROCESS SERVER [T3];
400
410 OPEN(TERM);
420 WHILE NOT FINISHED DO
430 BEGIN
440   WAIT(TERM.INPUTEVENT);
450   READ(TERM,72,MSG);
460   IF MSG = “QUIT” THEN
470      BEGIN
480        FINISHED:= TRUE;
490        READNUM:= 3;
500      END
510   ELSE READNUM:= 1;
520   I:= 1;
530   WHILE I LEQ READNUM DO
540     BEGIN
550       LIBERATE(INMSG_EVENT);
560       WAITANDRESET(MSG_READ);
570       I:= * + 1;
580     END;
590 END;
600
610 WHILE T1.STATUS GTR VALUE(TERMINATED) OR
620       T2.STATUS GTR VALUE(TERMINATED) OR
630       T3.STATUS GTR VALUE(TERMINATED) DO
640       WAITANDRESET(MYSELF.EXCEPTIONEVENT);
650
660 END.

The communication in this example takes place between the parent process and three asynchronous tasks that are instances of procedure SERVER. The communication takes place by way of the array MSG and the events INMSG_EVENT and MSG_READ. Of these, MSG is used to convey messages from the parent process to the servers. The parent process uses INMSG_EVENT to inform the servers that there is a message waiting to be read. A server uses MSG_READ to inform the parent that it has successfully read the message, so the parent can now reuse the MSG array.

When this program is initiated, the driver process procures INMSG_EVENT and initiates three instances of the SERVER procedure. Each of these servers begins by attempting to procure INMSG_EVENT; since the driver has already procured this event, all the servers wait.

The driver process then enters the loop on lines 420-590. Within this loop, the driver waits for input from a user to appear in the remote file, and then reads the input into MSG. In most cases, the driver then liberates INMSG_EVENT and waits on the MSG_READ event. When the driver liberates INMSG_EVENT, one of the servers succeeds in procuring the event and copies the contents of MSG to the local array MSGCOPY. The server then causes MSG_READ, informing the driver that MSG is again available for use as a buffer. The server then performs some processing on the input in MSGCOPY and notifies the user of the result by writing a message to the remote file.

If the input received from the user is the command QUIT, then the driver takes some special actions. It liberates INMSG_EVENT and waits on MSG_READ three times without performing any more read operations. This allows the contents of the MSG array to be read by each of the three servers. Each server recognizes the QUIT command and terminates gracefully. Then the driver terminates as well.

Note that this program uses the available state of INMSG_EVENT, but uses the happened state of MSG_READ. This difference reflects the different purposes for which these events are used. The program alternates between two phases: a phase in which the driver uses the MSG array, and a phase in which any single one of the servers can use the MSG array. Causing MSG_READ initiates the phase in which the driver uses MSG; liberating INMSG_EVENT initiates the phase in which one of the waiting servers is allowed to use MSG.