@X @~
~V7 56 2 -5
~D10
~H                    MUSS
~
~
~D10
~H             LIB081
~D10
~MMANCHESTER UNIVERSITY  -  CONFIDENTIAL
~
~
                                                           ISSUE 11~
~V9 -1
~P
~V9 1
~YLIB081
~S1~M~OLIB IMPLEMENTATION DESCRIPTION~
~S1~M~OSection 8  Version 1~
~S1~OSection 8.1 Performance Monitoring~
~S1~O1. General Description~
~BThis module provides procedures for monitoring
the performance of the system.~
~S1~O2. Interfaces~
~BLibrary procedures~
~
   READ.STATS()~
   OUT.STATS(TOTAL/DIFFERENCE)~
   INT.JOB.JOB(SUPERVISOR,MONITOR,NUMERIC DELIMITER)~
~S1~O3. Implementation~
~S1~O3.1 Outline of Operation~
~BThe operation of the procedures in this module is straightforward.~
~S1~O3.2 Data Structures~
~
~T% 12
STATS.SEG~IThis integer variable notes the number of the
segment holding the system statistics after the last call of
READ.STATS. If zero or negative, it is assumed that READ.STATS
has not previously been called.~
~S1~O3.3 Special Notes~
~BNone.~
~Y
~V9 -1
~P
~V9 -1
~D15
~HFLOWCHARTS
~
~
~H                LIB081
~V9 -1
~F
@TITLE LIB08(1,11)

@COL 1S-2R-3R-4R-5R-6F

@FLOW 1-2-3-4-5-6

@BOX 1.0
PERFORMANCE MONITORING
@BOX 4.0
1 READ STATS
2 OUT STATS
3 INT JOB JOB
@BOX 6.0
END
@BOX 1.1
   #LIB08/1
MODULE (READ.STATS, OUT.STATS, iNT.jOB.jOB);
@BOX 3.1
LITERAL / INTEGER BYTES.PER.ITEM = 4;
*GLOBAL 9;
INTEGER STATS.SEG;
@BOX 4.1
*CODE 1;
LSPEC READ.STATS ();
LSPEC OUT.STATS (INTEGER);
LSPEC INT.JOB.JOB (ADDR [LOGICAL8], ADDR [LOGICAL8], LOGICAL8);
   #LIB08.1
   #LIB08.2
   #LIB08.3
@BOX 6.1
*END
@END


@TITLE LIB08/1(1,11)

@COL 1S-2R-3R-4R

@FLOW 1-2-3-4

@BOX 1.0
EXTERNAL ENVIRONMENT
@BOX 1.1
::EXTERNAL ENVIRONMENT
@BOX 3.1
IMPORT LITERAL INTEGER SYS14.PAGE.SIZE,
   BYTES.PER.WORD, SYS13.NO.OF.PROCS, SYS21.NO.OF.STATS, NO.OF.SCRIPTS;
IMPORT LITERAL ADDR SYS14.SEG.SIZE;
ADDR [LOGICAL8] [SYS21.NO.OF.STATS] STATS.MESSAGES;
@BOX 4.1
PSPEC OUT.NAME (LOGICAL64);
PSPEC IN.CH () / INTEGER;
PSPEC OUT.CH (INTEGER);
PSPEC NEXT.CH () / INTEGER;
PSPEC IN.I () / ADDR;
PSPEC IN.STR (ADDR [LOGICAL8]) / INTEGER;
PSPEC SELECT.INPUT (INTEGER);
PSPEC SELECT.OUTPUT (INTEGER);
PSPEC CURRENT.INPUT () / INTEGER;
PSPEC BREAK.INPUT (INTEGER);
PSPEC CURRENT.OUT.PUT () / INTEGER;
PSPEC DEFINE.INPUT (INTEGER, ADDR [LOGICAL8], INTEGER32) / INTEGER;
PSPEC DEFINE.OUTPUT (INTEGER, ADDR [LOGICAL8], INTEGER32, INTEGER32) / INTEGER;
PSPEC PROCESS.NAME (ADDR [LOGICAL8]) / ADDR [LOGICAL8];
PSPEC PROMPT (ADDR [LOGICAL8]);
PSPEC CAPTION (ADDR [LOGICAL8]);
PSPEC OUT.I (INTEGER32, INTEGER);
PSPEC OUT.TIME ();
PSPEC SPACES (INTEGER);
PSPEC I.ENQ () / INTEGER;
PSPEC I.SOURCE (ADDR [INTEGER]);
PSPEC BREAK.OUTPUT (INTEGER);
PSPEC END.INPUT (INTEGER, INTEGER);
PSPEC END.OUTPUT (INTEGER, INTEGER);
PSPEC OUT.FN (ADDR [LOGICAL8]);
PSPEC NEWLINES (INTEGER);
PSPEC PROMPT.CH (INTEGER);
LSPEC TIME.AND.DATE ();
LSPEC NAMES ();
LSPEC KILL (LOGICAL64, INTEGER);
LSPEC LOOK.UP.PROCESS (LOGICAL64, LOGICAL64);
LSPEC CREATE.SEGMENT (INTEGER, ADDR);
LSPEC RELEASE.SEGMENT (INTEGER);
LSPEC MAP (INTEGER, INTEGER, INTEGER);
LSPEC COPY.BLOCK (INTEGER, INTEGER, INTEGER, INTEGER);
LSPEC SET.CH.STATUS (INTEGER, INTEGER, INTEGER, INTEGER);
LSPEC READ.CH.STATUS (INTEGER);
LSPEC SEND.MESSAGE (ADDR [LOGICAL8], ADDR [INTEGER], INTEGER, INTEGER,
   INTEGER, LOGICAL);
LSPEC READ.MESSAGE (ADDR [LOGICAL8], ADDR [INTEGER], INTEGER, INTEGER);
LSPEC WAIT (LOGICAL, INTEGER);
LSPEC OPEN.FILE (ADDR [LOGICAL8], LOGICAL64, INTEGER, LOGICAL);
LSPEC SYSTEM.STATS ();
ADDR PW0, PW1, PW2, PW3, PW4, PW5, PW6;
LOGICAL64 PWW1, PWW2, PWW3, PWW4;
@END

@TITLE LIB08.1(1,11)

@COL 1S-2R-3R-4F

@FLOW 1-2-3-4

@BOX 1.0
READ STATS
@BOX 2.0
READ SYSTEM STATS
@BOX 3.0
NOTE SEGMENT CONTAINING STATS
@BOX 4.0
END
@BOX 1.1
PROC READ.STATS;
@BOX 2.1
RELEASE.SEGMENT (STATS.SEG);
SYSTEM.STATS ();
@BOX 3.1
IF PW0 /= 0 THEN
   0 => STATS.SEG;
ELSE
   PW1 => STATS.SEG;
FI
@BOX 4.1
END
@END


@TITLE LIB08.2(1,11)

@COL 1S-2R-3R-4R-5F

@FLOW 1-2-3-4-5

@BOX 1.0
OUT STATS (TOTAL / DIFFERENCE)
@BOX 2.0
READ SYSTEM STATS
@BOX 3.0
FIND DIFFERENCE IN STATS
IF REQUIRED
@BOX 4.0
PRINT STATISTICS
@BOX 5.0
END
@BOX 1.1
PROC OUT.STATS (AMOUNT);
INTEGER STATS.SEG2, TEMP.SEG, OLD.MAPPED.SEG, NO.OF.ITEMS, I;
ADDR [INTEGER32] PTR;
@BOX 2.1
SYSTEM.STATS ();
@BOX 3.1
IF STATS.SEG =< 0 OR AMOUNT /= 0 THEN
   PW1 => TEMP.SEG;
   MAP (TEMP.SEG, 1, 0);
   PW1 => OLD.MAPPED.SEG;
   MAKE (INTEGER32, SYS21.NO.OF.STATS, PW6 * SYS14.SEG.SIZE) => PTR;
ELSE
   PW1 => STATS.SEG2;
   CREATE.SEGMENT (-1, SYS14.PAGE.SIZE * 2);
   PW1 => TEMP.SEG;
   COPY.BLOCK (STATS.SEG2, 0, TEMP.SEG, 0);
   COPY.BLOCK (STATS.SEG, 0, TEMP.SEG, 1);
   RELEASE.SEGMENT (STATS.SEG2);
   MAP (TEMP.SEG, 1, 0);
   PW1 => OLD.MAPPED.SEG;
   SYS14.PAGE.SIZE / BYTES.PER.ITEM => NO.OF.ITEMS;
   MAKE (INTEGER32, NO.OF.ITEMS * 2, PW6 * SYS14.SEG.SIZE) => PTR;
   FOR I < SYS21.NO.OF.STATS DO
      PTR^ [I + NO.OF.ITEMS] -> PTR^ [I];
   OD
FI
@BOX 4.1
NEW.LINES (0);
OUT.FN (%"STATS");
NEWLINES (2);
FOR I < SYS21.NO.OF.STATS DO
   OUT.I (PTR^ [I], 12);
   OUT.CH (" ");
   CAPTION (STATS.MESSAGES [I]);
   NEW.LINES (1);
OD
MAP (OLD.MAPPED.SEG, 1, 0);
RELEASE.SEGMENT (TEMP.SEG);
@BOX 5.1
END
@END


@TITLE LIB08.3(1,11)
@COL 1S-2R-3T-4R-17R-15R-5R-6R-7T-8T-9T-10T-11T-16R-12R-13R-14F
@FLOW 1-2-3OK-4-17-15-5-6-7OK-8OK-9OK-10NO-11NO-16-12-13-14
@FLOW 3FAILED-13
@FLOW 7FAILED-13
@FLOW 8NONE-13
@FLOW 9FAILED-13
@FLOW 10YES-6
@FLOW 11YES-15
@BOX 1.0
INTERACTIVE JOB JOB (SUPERVISOR, LOG, NUMERIC DELIMITER)
@BOX 2.0
INITIALISE PARAMETERS
#LIB08.3.5
@BOX 3.0
LOOK UP SUPERVISOR?
@BOX 4.0
SET UP INITIAL MESSAGE
#LIB08.3.2
@BOX 5.0
RESET TERMINAL COUNT
@BOX 6.0
COMPLETE INITIAL MESSAGE
#LIB08.3.3
@BOX 7.0
SEND MESSAGE TO THE SUPERVISOR?
@BOX 8.0
WAIT FOR REPLY?
@BOX 9.0
TERMINAL PROCESS CREATED?
@BOX 10.0
MORE PROCESS TO BE CREATED?
@BOX 11.0
MORE ENTRIES LEFT?
@BOX 12.0
MONITOR PROCESSES
#LIB08.3.4
@BOX 13.0
KILL PROCESSES STILL RUNNING
SELECT ORIGINAL STREAMS
@BOX 14.0
END
@BOX 15.0
READ NEXT SCRIPT LINE
@BOX 16.0
SEND INITIAL MESSAGE
@BOX 17.0
READ MONITORING LEVEL
@BOX 1.1
PROC INT.JOB.JOB (SUPVSR, LOG, N.DLMTR);
::VARIABLES AND LITERALS
#LIB08.3.1
@BOX 2.1
::INITIALISE PARAMETERS
#LIB08.3.5
@BOX 3.1
PROCESS.NAME (SUPVSR);
LOOK.UP.PROCESS (PWW1, PWW2 => MACH.NAME);
IF PW0 < 0
@BOX 4.1
::SET UP INITIAL NESSAGE
#LIB08.3.2
@BOX 5.1
0 => I;
@BOX 6.1
::COMPLETE INITIAL MESSAGE
#LIB08.3.3
@BOX 7.1
SEND.MESSAGE (^MESS, ^DESTN, %F, 0, 0, 0);
IF PW0 /= 0
@BOX 8.1
WAIT (%80, 10);
IF PW1 & %80 /= %80
@BOX 9.1
READ.MESSAGE (^DUMMY.MESS, ^DUMMY.DEST, 7, -1);
LOOK.UP.PROCESS (PROC.NAME [PROC.NO], MACH.NAME);
IF PW0 /= 0
@BOX 10.1
PW1 => SPN [PROC.NO];
PW2 => PID [PROC.NO];
IF 1 +> I < TERMS
@BOX 11.1
SELECT.INPUT (CI.STR);
WHILE NEXT.CH () => I /= "@" /= "$L" DO
   IN.CH ();
OD
IF I = "$L" THEN
   IN.CH ();
FI
IF NEXT.CH () /= "@" AND S.NO < NO.OF.SCRIPTS - 1
@BOX 12.1
::MONITOR PROCESSES
#LIB08.3.4
@BOX 13.1
PW0 => SAVE.PW0;
FOR I < PROC.NO + 1 DO
   KILL (PROC.NAME [I], MACH.NAME);
OD
SELECT.OUTPUT (CO.STR);
MAP (OLD.MAPPED.SEG, 2, 0);
RELEASE.SEGMENT (PW1);
SAVE.PW0 => PW0;
@BOX 14.1
END
@BOX 15.1
::READ NEXT SCRIPT ENTRY
#LIB08.3.6
@BOX 16.1
::SEND INITIAL MESSAGE
#LIB08.3.7
@BOX 17.1
PROMPT (%"FULL MONITORING (Y/N):");
(IF IN.CH () = "Y" THEN 1 ELSE 0) => FULL.MONITORING;
WHILE NEXT.CH () /= "$L" DO
   IN.CH ();
OD
IN.CH ();
PROMPT (%"$LSCRIPT NAME:");
@END

@TITLE LIB08.3.1(1,11)
@COL 1S-2R
@FLOW 1-2
@BOX 1.0
VARIABLES AND LITERALS
@BOX 1.1
::VARIABLES AND LITERALS
@BOX 2.1
LITERAL / INTEGER PRMPT.CH = %1F;
LITERAL / ADDR [LOGICAL8] NIL =;
ADDR SAVE.PW0;
INTEGER32 RAND;
INTEGER CI.STR, CO.STR, LOG.STR, PROC.STR, I, JOB.NUM, RUNS,
   TERMS, S.NO, PROC.NO, TERM.PROCS, START, DLMTR,
   OLD.MAPPED.SEG, MASTER.PTR, FULL.MONITORING;
LOGICAL8 [33] SN;
LOGICAL64 JOB.NAME, MACH.NAME;
INTEGER [4] DESTN, DUMMY.DEST, SOURCE;
LOGICAL8 [80] MESS, DUMMY.MESS;
ADDR [LOGICAL8] SCRIPT, MASTER;
LOGICAL64 [NO.OF.SCRIPTS] SCRIPT.NAME;
INTEGER16 [SYS13.NO.OF.PROCS] PROC.TIMER, SCRIPT.NO, RUN,
   SPN, PID, TOTAL.CMDS;
INTEGER32 [SYS13.NO.OF.PROCS] SI.POS, CI.POS, EI.POS,
   OLD.MILLI.SEC, RESPONSE.SUM;
LOGICAL64 [SYS13.NO.OF.PROCS] PROC.NAME;
PSPEC COPY (ADDR [LOGICAL8], LOGICAL64);
PROC COPY (TO, FRM);
INTEGER I;
FOR I < 8 DO
   IF FRM & %FF => TO^ [7 - I] = 0 THEN
      " " => TO^ [7 - I];
   FI
   FRM ->> 8 => FRM;
OD
END
PSPEC OUT.HDNG (INTEGER, LOGICAL8);
PROC OUT.HDNG (PROC.NO, L.TYPE);
   NEW.LINES (0);
   OUT.TIME ();
   SPACES (1);
   OUT.NAME (PROC.NAME [PROC.NO]);
   OUT.CH ("|");
   OUT.NAME (SCRIPT.NAME [SCRIPT.NO [PROC.NO]]);
   OUT.CH ("|");
   OUT.I (RUN [PROC.NO], 0);
   OUT.CH ("|");
   OUT.CH (L.TYPE);
   CAPTION (%":");
END
@END

@TITLE LIB08.3.2(1,11)

@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
SET UP INITIAL MESSAGE
@BOX 2.0
SET UP LOGIN MESSAGE FOR SUPERVISOR
@BOX 3.0
END
@BOX 1.1
::SET UP INITIAL MESSAGE
BEGIN
@BOX 2.1
FOR I < 4 DO
   0 => MESS [I];
OD
FOR I < 76 DO
   " " => MESS [I + 4];
OD
PW1 => DESTN [0];
PW2 => DESTN [1];
PW3 => DESTN [2];
0 => DESTN [3];
NAMES ();
COPY (PART (^MESS, 6, 13), PWW1);
COPY (PART (^MESS, 15, 22), PWW2);
PWW3 <<- 16 ! "00" => JOB.NAME;
COPY (PART (^MESS, 33, 40), "C10000");
"P" => MESS[40];
"1" => MESS[41];
"0" => MESS[42];
"$L" => MESS [43];
40 => MESS [0];
0 => JOB.NUM;
@BOX 3.1
END
@END
@TITLE LIB08.3.3(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
COMPLETE INITIAL MESSAGE
@BOX 2.0
FIND A JOB NAME AND COMPLETE
INITIAL MESSAGE FOR LOGIN
@BOX 3.0
END
@BOX 1.1
::COMPLETE INITIAL MESSAGE
BEGIN
@BOX 2.1
0 => TOTAL.CMDS [1 +> PROC.NO] => OLD.MILLI.SEC [PROC.NO]
   => RESPONSE.SUM [PROC.NO];
START => SI.POS [PROC.NO] => CI.POS [PROC.NO];
MASTER.PTR => EI.POS [PROC.NO];
S.NO => SCRIPT.NO [PROC.NO];
RUNS => RUN [PROC.NO];
WHILE PW0 = 0 DO
   IF 1 +> JOB.NUM & %F = 10 THEN
      JOB.NUM + %100 & %F00 => JOB.NUM;
   FI
   LOOK.UP.PROCESS (JOB.NUM ! JOB.NAME, MACH.NAME);
OD
COPY (PART (^MESS, 24, 31), JOB.NUM ! JOB.NAME => PROC.NAME [PROC.NO]);
@BOX 3.1
END
@END
@TITLE LIB08.3.4(1,11)
@COL 1S-14N-18T-20R-21T-3R-22T-23R-4T-5T-6R-7R-2T-8T-9R
@COL 15N-17R-10R-13T-11R-12R-16F
@ROW 14-15
@ROW 3-17
@ROW 7-10
@ROW 9-12
@FLOW 1-14-18NO-20-21YES-3-22YES-21
@FLOW 2YES-14
@FLOW 4YES-7
@FLOW 5YES-10-13NO-11-12-16
@FLOW 8FAILED-12
@FLOW 13YES-15-14
@FLOW 18YES-17-4
@FLOW 21NO-14
@FLOW 22NO-23-4NO-5NO-6-7-2NO-8OK-9-14
@BOX 1.0
MONITOR PROCESSES
@BOX 2.0
WAIT BEFORE SEND MESSAGE?
@BOX 3.0
DETERMINE WHICH TERMINAL SENT THE
MESSAGE, PREPARE DESTINATION FOR
NEXT MESSAGE
#LIB08.3.4.2
@BOX 4.0
MORE LINES TO BE SENT?
@BOX 5.0
END OF TERMINAL RUN?
@BOX 6.0
RESET POINTERS
@BOX 7.0
READ FROM SCRIPT
#LIB08.3.4.1
@BOX 8.0
SEND MESSAGE TO TERMINAL?
@BOX 9.0
COPY MESSAGE TO LOG DOCUMENT
@BOX 10.0
SEND STOP MESSAGE IF NECESSARY
@BOX 11.0
OUTPUT STATS, OUTPUT MESSAGE
MONITORS TO THE LOG
@BOX 12.0
RESET PROCESS NUMBER
@BOX 13.0
ANY TERMINALS RUNNING?
@BOX 16.0
END
@BOX 17.0
SET UP MESSAGE PARAMETERS
@BOX 18.0
DELAYED MESSAGE?
@BOX 20.0
WAIT UNTIL SERVICE IS REQUIRED
@BOX 21.0
MESSAGES AVAILABLE?
@BOX 22.0
NO PROMPT SEEN?
@BOX 23.0
CHECK MESSAGE QUEUEING
@BOX 1.1
::MONITOR PROCESSES
BEGIN
INTEGER32 TEMP1, TEMP2, START.TIME, MILLI.TIME;
INTEGER32 [SYS13.NO.OF.PROCS] ARRIVAL.TIME;
INTEGER PROMPT, CH, Q, BUF.FULL, PROCS.CREATED;
INTEGER16 MIN, NOW, PT, MESSAGE.COUNTER, RD.PTR, WT.PTR;
DATAVEC NULL.MESS (LOGICAL8)
   0 0 0 0
END
0 => MESSAGE.COUNTER => RD.PTR => WT.PTR;
TERM.PROCS => PROCS.CREATED;
SELECT.OUTPUT (LOG.STR);
OUTFN (%"STARTED");
READ.TIMER ();
PW3 => START.TIME;
READ.STATS ();
@BOX 2.1
MASTER.PTR => CI.POS [PROC.NO];
IF BUF.FULL = 2
@BOX 3.1
:: DETERMINE WHICH TERMINAL SENT THE
:: MESSAGE, PREPARE DESTINATION FOR
:: NEXT MESSAGE
#LIB08.3.4.2
@BOX 4.1
IF CI.POS [PROC.NO] => MASTER.PTR
   < EI.POS [PROC.NO]
@BOX 5.1
IF 1 -> RUN [PROC.NO] =< 0
@BOX 6.1
SI.POS [PROC.NO] => CI.POS [PROC.NO]
   => MASTER.PTR;
@BOX 7.1
::READ FROM SCRIPT
#LIB08.3.4.1
@BOX 8.1
SEND.MESSAGE (^MESS, ^SOURCE, %F, 0, 0, 0);
IF PW0 /= 0
@BOX 9.1
TIME.AND.DATE ();
PWW2 => OLD.MILLI.SEC [PROC.NO];
1 +> TOTAL.CMDS [PROC.NO];
IF FULL.MONITORING = 1 THEN
   OUT.HDNG (PROC.NO, "C");
   FOR I < MESS [0] DO
      IF MESS [I + 4] => CH < %20 /= "$L" THEN
         CAPTION (%"<CTRL>-");
         %40 +> CH;
      FI
      OUT.CH (CH);
   OD
FI
@BOX 10.1
0 => OLD.MILLI.SEC [PROC.NO];
IF RUN [PROC.NO] = 0 THEN
   DATAVEC STOP.MESS (LOGICAL8)
      5 0 [3] "STOP$L"
   END
   SEND.MESSAGE (^STOP.MESS, ^SOURCE, %F, 0, 0, 0);
ELSE
   IF RUN [PROC.NO] = -1 THEN
      1 -> TERM.PROCS;
   FI
FI
@BOX 11.1
OUT.STATS (0);
CAPTION (%"$LUSER TIME CONSUMED BY IJJ : ");
READ.TIMER ();
OUT.I (PW3 - START.TIME, 10);
CAPTION (%"$L$L$LPROCESS    TOTAL.CMD.TIME   TOTAL.CMDS");
CAPTION (%"   RESPONSE.TIME$L$L");
FOR PROC.NO < PROCS.CREATED DO
   OUT.NAME (PROC.NAME [PROC.NO]);
   OUT.I (RESPONSE.SUM [PROC.NO], 11);
   OUT.I (TOTAL.CMDS [PROC.NO], 14);
   OUT.I (RESPONSE.SUM [PROC.NO] / TOTAL.CMDS [PROC.NO], 13);
   NEW.LINES (0);
OD
IF LOG.STR /= CO.STR THEN
   END.OUTPUT (LOG.STR, 0);
ELSE
   BREAK.OUTPUT (LOG.STR);
FI
@BOX 12.1
PROCS.CREATED - 1 => PROC.NO;
@BOX 13.1
IF TERM.PROCS > 0
@BOX 16.1
END
@BOX 17.1
%7FFF => PROC.TIMER [PROC.NO];
SPN [PROC.NO] => SOURCE [0];
PID [PROC.NO] => SOURCE [1];
8 => SOURCE [2];
@BOX 18.1
TIME.AND.DATE ();
PWW1 & %7FFF => NOW;
PWW2 => MILLI.TIME;
%7FFF => MIN;
-1 => PROC.NO;
WHILE 1 +> PROC.NO < PROCS.CREATED AND
   PROC.TIMER [PROC.NO] => PT > NOW DO
   IF PT < MIN THEN
      PT => MIN;
   FI
OD
IF PROC.NO < PROCS.CREATED
@BOX 20.1
WAIT (%80, MIN - NOW);
@BOX 21.1
READ.CH.STATUS (7);
IF PW4 = 0
@BOX 22.1
IF PROMPT = 0
@BOX 23.1
READ.CH.STATUS (7);
FOR PW4 - MESSAGE.COUNTER DO
   MILLI.TIME => ARRIVAL.TIME [WT.PTR];
   IF 1 +> WT.PTR >= SYS13.NO.OF.PROCS THEN 0 => WT.PTR FI
   1 +> MESSAGE.COUNTER;
OD
@END
@TITLE LIB08.3.4.1(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
READ FROM SCRIPT
@BOX 2.0
READ FROM SCRIPT , CHECK FOR
ESCAPE AND WAITS
@BOX 3.0
END
@BOX 1.1
::READ FROM SCRIPT
BEGIN
@BOX 2.1
3 => I;
0 => BUF.FULL;
IF MASTER^ [MASTER.PTR + 1] /= "~" THEN
   WHILE MASTER.PTR < EI.POS [PROC.NO] AND
      BUF.FULL = 0 AND 1 +> I < 80 AND
      MASTER^ [1 +> MASTER.PTR] => CH => MESS [I] /= "$L" DO
      IF CH = DLMTR THEN
         IF I < 78 THEN
            PROC.NO / 10 => Q + "0" => MESS [I];
            PROC.NO - (Q * 10) + "0" => MESS [1 +> I];
         ELSE
            1 => BUF.FULL -> I;
         FI
      FI
   OD
   I - (IF I < 80 THEN 3 ELSE 4) => MESS [0];
ELSE
   1 +> MASTER.PTR;
   0 => PT;
   WHILE MASTER^ [1 +> MASTER.PTR] => CH /= "$L" DO
      IF CH /= DLMTR THEN
         PT * 10 + (CH - "0") => PT;
      ELSE
         65539 *> RAND;
         IF RAND < 0 THEN
            2147483647 + RAND + 1 => RAND;
         FI
         RAND & %F10 ->> 8 => PT;
         WHILE MASTER^ [1 +> MASTER.PTR] /= "$L" DO OD
         1 -> MASTER.PTR;
      FI
   OD
   IF FULL.MONITORING = 1 THEN
      CAPTION (%"<<WAIT>>");
      OUT.I (PT, 3);
      NEW.LINES (1);
   FI
   TIME.AND.DATE ();
   PWW1 & %7FFF => NOW + PT & %7FFF => PROC.TIMER [PROC.NO];
   2 => BUF.FULL;
FI
@BOX 3.1
END
@END

@TITLE LIB08.3.4.2(1,11)
@COL 1S-2R-3T-4R-5R-6F
@FLOW 1-2-3-4-5-6
@FLOW 3UNKNOWN-6
@BOX 1.0
DETERMINE WHICH TERMINAL
SENT THE MESSAGE
@BOX 2.0
NOTE ARRIVAL TIME
@BOX 3.0
FIND IDENTIFICATION
OF SENDER
@BOX 4.0
EVALUATE RESPONSE TIME
@BOX 5.0
COPY MESSAGE TO LOG DOCUMENT
@BOX 6.0
END

@BOX 1.1
BEGIN
DATAVEC ERROR.MESS (LOGICAL8)
   ">*>"
END
@BOX 2.1
TIME.AND.DATE ();
PWW2 => MILLI.TIME;
IF MESSAGE.COUNTER = 0 THEN
   MILLI.TIME => TEMP1;
ELSE
   ARRIVAL.TIME [RD.PTR] => TEMP1;
   IF 1 +> RD.PTR >= SYS13.NO.OF.PROCS THEN 0 => RD.PTR FI
   1 -> MESSAGE.COUNTER;
FI
@BOX 3.1
0 => PROMPT => SOURCE [1] => SOURCE [2];
READ.MESSAGE (^MESS, ^SOURCE, 7, -1);
IF SOURCE [2] /= 0 THEN
   SEND.MESSAGE (^NULL.MESS, ^SOURCE, 0, 0, 0, 0);
FI
8 => SOURCE [2];
-1 => PROC.NO;
WHILE 1 +> PROC.NO < PROCS.CREATED AND
   SOURCE [1] /= PID [PROC.NO] DO OD
IF PROC.NO = PROCS.CREATED
@BOX 4.1
IF OLD.MILLI.SEC [PROC.NO] => TEMP2 /= 0 THEN
   TEMP1 - TEMP2 +> RESPONSE.SUM [PROC.NO];
   0 => OLD.MILLI.SEC [PROC.NO];
FI
@BOX 5.1
IF MESS [0] > 80 THEN 80 => MESS [0] FI
FOR I < MESS [0] DO
   IF MESS [I + 4] = PRMPT.CH THEN
      1 => PROMPT;
   FI
OD
IF FULL.MONITORING = 1 OR
   PART (^MESS, 4, 3) = ^ERROR.MESS THEN
   OUT.HDNG (PROC.NO, "R");
   FOR I < MESS [0] DO
      IF MESS [I + 4] => CH /= PRMPT.CH THEN
         IF CH < %20 /= "$L" THEN
            CAPTION (%"<CTRL>-");
            %40 +> CH;
         FI
         OUT.CH (CH);
      FI
   OD
FI
IF RUN [PROC.NO] =< 0 THEN
   1 => PROMPT;
FI
@BOX 6.1
END
@END

@TITLE LIB08.3.5(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
INITIALISE PARAMETERS
@BOX 2.0
SET UP PARAMTERS AND STREAMS
@BOX 3.0
END
@BOX 1.1
::INITIALISE PARAMETERS
BEGIN
@BOX 2.1
100 => RAND;
CREATE.SEGMENT (-1, SYS14.SEG.SIZE);
MAP (PW1, 2, 0);
PW1 => OLD.MAPPED.SEG;
MAKE (LOGICAL8, SYS14.SEG.SIZE, PW6 * SYS14.SEG.SIZE)
   => MASTER;
-1 => MASTER.PTR;
-1 => S.NO => PROC.NO;
CURRENT.INPUT () => CI.STR;
CURRENT.OUTPUT () => CO.STR;
DATAVEC JOB.SUP (LOGICAL8)
   "JOB*"
END
IF SUPVSR = NIL THEN
   ^JOB.SUP => SUPVSR;
FI
IF N.DLMTR => DLMTR = 0 OR DLMTR = "~" THEN
   %100 => DLMTR;
FI
IF LOG /= NIL THEN
   DEFINE.OUTPUT (-1, LOG, %200, 0) => LOG.STR;
ELSE
   CO.STR => LOG.STR;
FI
SET.CH.STATUS (7, 1, 0, 0);
WHILE PW0 = 0 DO
   READ.MESSAGE (^DUMMY.MESS, ^DUMMY.DEST, 7, -1);
OD
@BOX 3.1
END
@END
@TITLE LIB08.3.6(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
READ NEXT SCRIPT ENTRY
@BOX 2.0
READ ENTRY AND COPY SCRIPT TO BUFFER
@BOX 3.0
END
@BOX 1.1
::READ NEXT SCRIPT ENTRY
BEGIN
INTEGER STREAM, PRIORITY;
INTEGER8 TEMP;
LOGICAL64 TEMP64;
@BOX 2.1
PROCESS.NAME (PART (^SN, 0, IN.STR (^SN) - 1)) => SCRIPT;
0 => TEMP64;
-1 => I;
WHILE 1 +> I < SIZE (SCRIPT) DO
   TEMP64 <<- 8 ! SCRIPT^ [I] => TEMP64;
OD
TEMP64 => SCRIPT.NAME [1 +> S.NO];
PROMPT (%"TERMINALS  :");
IF IN.I () => TERMS =< 0 THEN
   1 => TERMS;
FI
PROMPT (%"RUNS       :");
IF IN.I () => RUNS =< 0 THEN
   1 => RUNS;
FI
PROMPT (%"PRIORITY   :");
IF IN.I() => PRIORITY >= 8 =< 11 THEN
   PRIORITY / 10 => TEMP + "0" => MESS[41];
   10 * TEMP -: PRIORITY + "0" => MESS[42]
FI
PROMPT (%"$LSCRIPT NAME:");
DEFINE.INPUT (-1, SCRIPT, 0) => STREAM;
SELECT.INPUT (STREAM);
MASTER.PTR => START;
WHILE I.ENQ () & 8 = 0 AND
   MASTER.PTR < SYS14.SEG.SIZE - 1 DO
   IN.CH () => MASTER^ [1 +> MASTER.PTR];
OD
END.INPUT (STREAM, 0);
@BOX 3.1
END
@END

@TITLE LIB08.3.7(1,9)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
SEND INITIAL MESSAGE
@BOX 2.0
SEND MESSAGE
@BOX 3.0
END
@BOX 1.1
::SEND INITIAL MESSAGE
BEGIN
DATAVEC INIT.MESS (LOGICAL8)
   14 0 [3] "PROMPT.CH %1F$L"
END
@BOX 2.1
IN.CH ();
PROC.NO + 1 => TERM.PROCS;
FOR PROC.NO < TERM.PROCS DO
   SPN [PROC.NO] => SOURCE [0];
   PID [PROC.NO] => SOURCE [1];
   8 => SOURCE [2];
   %7FFF => PROC.TIMER [PROC.NO];
   -1 => PW0;
   WHILE PW0 /= 0 DO
      SEND.MESSAGE (^INIT.MESS, ^SOURCE, %F, 0, 0, 0);
   OD
OD
@BOX 3.1
END
@END

