Trailing-Edge
-
PDP-10 Archives
-
AP-D471B-SB_1978
-
sendm.bli
There are no other files named sendm.bli in the archive.
!***COPYRIGHT (C) 1974, 1975, 1976, 1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
MODULE SENDM(RESERVE(#11,#12,#13,#14),SREG=#17,FREG=#16,
DREGS=4,VREG=#15,MLIST,TIMER=EXTERNAL(SIX12),FSAVE)=
BEGIN
REQUIRE DATA.BLI; !EVERYONE NEEDS THIS...COMMON
EXTERNAL CHKGH,
CHKMSG,
INLOGMSG,
OUTLOGMSG,
ROLGH,
ROLMSG,
GPURGE,
COMPARE;
COMMENT;
! CHKMCL.BLI
! ====== ===
! ROUTINE CHKMCLASS
! ======= =========
! THIS ROUTINE TAKES THE ADDRESS OF A PAGE, PICKS UP THE MESSAGE CLASS
! CONTAINED IN THAT PAGE, AND COMPARES IT WITH THE ENTRIES IN THE
! MESSAGE CLASS TABLE. IF THE MESSAGE CLASS MATCHES ONE OF THE TABLE
! ENTRIES, THE INDEX TO THAT ENTRY IS RETURNED, OTHERWISE THE DEFAULT
! VALUE IS RETURNED, AND AN ERROR STATUS IS SET IN THE PAGE
! SIDE EFFECT:
! THE ERROR STATUS IS SET IN THE COMMAND PAGE IF THE MESSAGE
! CLASS IS UNKNOWN
ROUTINE CHKMCLASS(PAGEADDR) =
BEGIN
REGISTER
MCLASSPTR;
BIND BLNKS = PLIT( #201004020100,
#201004000000);
MCLASSPTR _ (.PAGEADDR)[P0MCLS]; ! SET UP A POINTER BECAUSE WE'LL USE IT SEVERAL TIMES
IF NOT COMPARE(.MCLASSPTR,BLNKS,MCLASSSIZE) THEN !IF NON BLANK CLASS
BEGIN
INCR I FROM 0 TO .MCOUNT BY MCLASSSIZE DO ! FOR EACH ENTRY IN THE MESSAGE CLASS TABLE
IF COMPARE(.MCLASSPTR, MCLASS[.I], MCLASSSIZE) THEN RETURN (.I ^ (-1));
! IF WE FIND ONE, ADJUST THE INDEX AND RETURN
(.PAGEADDR)[P0STATUS] _ STSMCLUNK ! WE DIDN'T FIND ONE SO SET THE ERROR STATUS IN THE PAGE
END;
.MDEFAULT ! IF UNKNOWN MESSAGE CLASS OR MESSAGE CLASS BLANK THEN
! RETURN THE DEFAULT VALUE IF NO MATCH
END;
EXTERNAL LINK;
COMMENT;
! ATTACH.BLI
! ====== ===
! ROUTINE ATTACH
! ======= ======
! THIS ROUTINE IS USED TO LINK A MESSAGE TO AN OUTPUT (TERMINAL TYPE)
! DESTINATION. IT UPDATES ALL GROUP HEADERS (ONE FOR EACH DEST)
ROUTINE ATTACH(IMAHPTR,ENDI,GROUP,MHPTR) =
BEGIN
REGISTER
GHPTR,
DTAB,
NTRMS;
LOCAL IND;
EXTERNAL RUNMSW;
MAP FORMAT IMAHPTR;
MAP FORMAT GHPTR;
MAP FORMAT MHPTR;
IF (NTRMS _ .IMAHPTR[I0TRMCNT]) EQL 0 THEN RETURN; !QUIT IF NO TERMINALS
GHPTR _ .GROUP;
LINK( GHPTR[G0MHS], .MHPTR); ! LINK THE FIRST NORMALLY
GHPTR[G0ENDI] _ IND _ IF .ENDI GEQ EGI THEN TRUE ELSE FALSE;
IF .GHPTR[G0OUTMH] EQL 0 THEN GHPTR[G0OUTMH] _ .MHPTR; ! RESET THE OUTMH IF NEEDED
RUNMSW _ -1; ! START MSGOUT RUNNING
DTAB _ .IMAHPTR[I0DESTAB]; ! GET THE DESTINATION TABLE
INCR I FROM 1 TO .NTRMS - 1 DO ! FOR EACH TERMINAL TYPE DESTINATION
BEGIN
GHPTR _ .(.DTAB)[.I]<RH>; ! GET IT'S GH
GHPTR[G0LMHPTR] _ .MHPTR; ! SET THE LAST MH POINTER
IF .GHPTR[G0OUTMH] EQL 0 THEN GHPTR[G0OUTMH] _ .MHPTR; ! RESET THE OUTMH IF NEEDED
GHPTR[G0ENDI] _ .IND ! SET THE END INDICATOR
END;
END;
EXTERNAL MOVE,
CHKSRCTAB,
CHKLFTAB,
BUILD;
COMMENT;
! SUBROUTINE SEND4
! ========== =====
! LAST MODIFIED: 15 JUN 76 BY CDO
! THIS MODULE IS CALLED BY SEND MODULE TO PROCESS THE INITIAL "SEND" COMMAND,
! I.E. FUNCTION CODE = SENDRR IN THE PAGE SENT BY A MPP.
! SEND4 PERFORMS THE FOLLOWING FUNCTIONS:
! 1) CHECK THE VALIDITY OF THE MESSAGE CLASS IN THE PAGE.
! 2) IF DESTINATION COUNT IS GREATER THAN 1, A DESTINATION (DTAB) IS CREATED.
! SIZE OF DTAB IS DETERMINED BY THE MESSAGE-CLASS AND THE DESTINATION COUNT, I.E.
! IF MESSAGE-CLASS IS NOT "ALL", SIZE OF DTAB = "DESTINATION COUNT" WORDS
! IF MESSAGE-CLASS IS "ALL", SIZE OF DTAB = "S0CNT" WORDS.
! 3) CHECK THE VALIDITY OF EVERY DESTINATION SPECIFIED IN THE PAGE.
! 4) FILL DTAB, SOURCE TYPE DESTINATIONS ARE STORED STARTING FROM THE LEFT
! (TOP/LOW ADDRESS) OF DTAB,
! LEAF TYPE DESTINATIONS ARE STORED STARTING FROM THE RIGHT (BOTTOM/
! HIGH ADDRESS) OF THE DTAB.
! THERE IS ONE WORD PER DESTINATION IN THE DTAB, THE CONTENTS OF THE WORD ARE:
! LH = 0 IF DEST IS LEAF TYPE,
! 1 IF DEST IS SOURCE TYPE.
! **** IT MIGHT BE A LITTLE FASTER TO REVERSE THE ABOVE
! 0 FOR TERMINAL, 1 FOR LEAF
! RH = PTR TO THE SOURCE IN SRCTAB, OR
! ENTRY IN THE LFTAB.
! 5) CREATE A NEW RHTSN
! 6) CREATE A NEW IMAH ENTRY IN SENDQ
! 7) CREATE A MH
! 8) SET UP RESPONSES TO MPP IN THE PAGE
! 9) IF FATAL ERROR OCCURS, RETURNS CALLER THE VALUE -1, OTHERWISE RETURNS CALLER
! THE ADDRESS OF THE IMAH ENTRY JUST CREATED.
GLOBAL ROUTINE SEND4(JOBSLOT,PAGEADDR) =
BEGIN
REGISTER
J,
K,
M;
MAP FORMAT LFTAB:SENDQ;
LABEL LOOP;
BIND
MCLASSALL = 2,
MCLASSIMMED = 0;
LOCAL
DCNT,
CLASS,
DTAB,
LEAF,
UNKNOWN,
SOURCE,
ATLEASTONEDISABLED,
DEST,
FORMAT IMAHPTR
:MHPTR
:SRCPTR;
(.PAGEADDR)[P0STATUS] _ STSGOOD; ! ASSUME GOOD THINGS WILL HAPPEN
CLASS _ CHKMCLASS(.PAGEADDR); ! OBTAIN A NUMERICAL VALUE FOR THE MESSAGE CLASS
SOURCE _ LEAF _ UNKNOWN _ J _ 0; ! CLEAR LOTS OF COUNTS AND POINTERS
IF .CLASS EQL MCLASSALL THEN ! IF THE MESSAGE CLASS IS ALL THEN
BEGIN
CLASS _ -1; ! SET CLASS TO -1
SOURCE _ .SRCTAB + 1; ! IN CASE ONLY 1 TERMINAL IN CONFIG
J _ DCNT _ .S0CNT ! DESTINATION COUNT TO THE NUMBER OF TERMINAL ON THE SYSTEM
END
ELSE DCNT _ .(.PAGEADDR)[P0DSCNT]; ! OTHERWISE SET THE DESTINATION COUNT TO THE VALUE GIVEN
! IN THE PAGE
IF .DCNT GTR 1 THEN ! IF THE DESTINATION COUNT > 1 THEN
BEGIN
DTAB _ GETMEM(.DCNT); ! GET ROOM FOR A DESTINATION TABLE (DTAB)
MOVE(0,.DTAB,.DCNT); ! AND CLEAR THE DESTINATION TABLE
IF .CLASS LSS 0 THEN ! IF THE CLASS IS ALL
BEGIN
SOURCE _ SRCPTR _ .SRCTAB + 1;
J _ 0;
UNTIL @@SRCPTR EQL 0 DO ! PUT THE ADDRESS OF EACH SOURCE TABLE ENTRY IN THE DTAB
BEGIN
(.DTAB)[.J]<RH> _ .SRCPTR;
(.DTAB)[.J]<LH> _ 1;
J _ .J + 1;
SRCPTR _ .SRCPTR + .S0SIZE
END
END
END;
K _ 1;
ATLEASTONEDISABLED _ FALSE;
IF .CLASS GEQ MCLASSIMMED THEN ! IF THE MESSAGE CLASS IS NOT ALL THEN
BEGIN
J _ 0; ! START COUNTING AGAIN
INCR I FROM 0 TO .DCNT-1 DO ! FOR EACH DESTINATION IN THE PAGE
LOOP: BEGIN
DEST _ (.PAGEADDR)[P0DTAB+.I*3]; ! GET IT'S ADDRESS
SRCPTR _ CHKSRCTAB(.DEST); ! AND SEE IF IT IS A GOOD TERMINAL
IF .SRCPTR NEQ 0 THEN ! IF YES THEN
BEGIN
(.DEST+2)<RH> _ STSGOODDST; ! MARK IT AS GOOD IN THE PAGE
IF .SOURCE EQL 0 THEN SOURCE _ .SRCPTR; ! SAVE THE ADDRESS OF THE FIRST SOURCE
IF .DCNT GTR 1 THEN ! IF THERE ARE MORE THAN ONE DESTINATIONS
BEGIN
(.DTAB)[.J]<RH> _ .SRCPTR; ! STORE THEM IN THE DTAB
(.DTAB)[.J]<LH> _ 1; ! AND FLAG IT AS A TERMINAL
J _ .J + 1
END
ELSE J _ 1; !COUNT ONLY TERMINAL
IF .SRCPTR[S0ED] THEN ATLEASTONEDISABLED _ TRUE; !IF DISABLED THEN REMEMBER IT
LEAVE LOOP ! SKIP THE REST OF THE LOOP
END;
IF .LFTAB NEQ 0 THEN ! IS A LEAF TYPE DESTINATION POSSIBLE
BEGIN
M _ CHKLFTAB(.DEST); ! YES THEN SEE IF THIS IS ONE
IF .M NEQ 0 THEN ! IF IT IS THEN
BEGIN
(.DEST+2)<RH> _ STSGOODDST; ! MARK IT AS GOOD IN THE PAGE
LEAF _ .LEAF + 1; ! COUNT THE NUMBER OF LEAF TYPE DESTINATIONS
IF .DCNT GTR 1 THEN ! IF THERE ARE MORE THAN DESTINATIONS
BEGIN
(.DTAB)[.DCNT-.K]<RH> _ .M; ! THEN STORE IT IN DTAB
K _ .K + 1
END;
IF .LFTAB[L0ED(.M)] THEN ATLEASTONEDISABLED _ TRUE;
!IF DISABLED THEN REMEMBER IT
LEAVE LOOP
END
END;
UNKNOWN _ .UNKNOWN + 1; ! NOT LEAF OR TERMINAL, TOO BAD & COUNT BAD ONES
(.DEST+2)<RH> _ STSBADDST; ! MARK AS BAD IN THE PAGE
LEAVE LOOP
END
END
ELSE
BEGIN
CLASS _ MCLASSIMMED ! IF THE MESSAGE CLASS IS ALL, MAKE IT IMMEDIATE
END;
! NOTE: IF NO DESTINATIONS IN DESTINATION TABLE AND THE MESSAGE
! CLASS IS NOT ALL THEN THE "ALL DESTINATIONS UNKNOWN"
! ERROR RESULTS.
IF .UNKNOWN EQL .DCNT THEN ! IF ALL DESTINATIONS UNKNOWN
BEGIN
(.PAGEADDR)[P0STATUS] _ STSALLDSTUNK; ! SET STATUS IN PAGE
IF .DCNT GTR 1 THEN RETMEM(.DTAB,.DCNT); !CLEAN UP MEMORY
RETURN -1 ! AND LEAVE
END;
! STORE THE STATUS IN THE PAGE
IF .UNKNOWN NEQ 0 THEN (.PAGEADDR)[P0STATUS] _ STSUNKDST ! IF ANY UNKNOWN THEN SET UNKNOWN
! DESTINATION(S) STATUS
ELSE IF .ATLEASTONEDISABLED THEN (.PAGEADDR)[P0STATUS] _ STSDISDST;
! ELSE IF ANY DISABLED THEN SET THE
! DISABLED DESTINATION(S) STATUS
IF (RHTSN _ .RHTSN + 1) EQL 0 THEN RHTSN _ 1; ! GET AN OUTPUT TSN (RIGHT HALF)
! AND INSURE IT IS NEVER 0
(.PAGEADDR)[P0TSN]<RH> _ .RHTSN; ! AND STORE IT
IMAHPTR _ CREATEIMAH(SENDQ[SQ0IMAHS(.JOBSLOT)]); ! MAKE AN IMAH AND ATTACH IT TO THE SENDQ
MHPTR _ CREATEMH(0); ! MAKE AN MH
IMAHPTR[I0TSN] _ .(.PAGEADDR)[P0TSN]; ! STORE THE TSN IN THE IMAH
IMAHPTR[I0MHPTR] _ .MHPTR; ! AND THE MHPTR IN THE IMAH
IMAHPTR[I0LFCNT] _ .LEAF; ! SAVE THE NUMBER OF LEAVES
IMAHPTR[I0MCLSS] _ .CLASS; ! SAVE THE MESSAGE CLASS
IMAHPTR[I0TRMCNT] _ MHPTR[M0DSCNT] _ .J; ! PROPOGATE TERMINAL COUNT
IF .DCNT GTR 1 THEN ! IF THE DESTINATION COUNT > 1 THEN
BEGIN
IMAHPTR[I0DESTAB] _ .DTAB; ! SAVE THE DTAB POINTER IN THE IMAH
IMAHPTR[I0DSTSIZE] _ .DCNT; ! SET DSTSIZE TO THE SIZE OF THE DESTINATION TABLE
END
ELSE
BEGIN
IMAHPTR[I0DSTSIZE] _ 0; ! OTHERWISE ZERO THE DESTINATION SIZE
IMAHPTR[I0DESTAB] _ IF.SOURCE EQL 0 THEN .M ! IF NO TERMINAL TYPES SAVE THE LEAF TABLE POINTER
ELSE .SOURCE; ! OTHERWISE SAVE THE FIRST SOURCE
END;
.IMAHPTR
END;
COMMENT;
! ROUTINE: FINDS
! =====
ROUTINE FINDS(TSN,JSLOT)=
! TSN = TRANSACTION SEQUENCE NUMBER TO BE FOUND
! JSLOT = JOB SLOT NUMBER TO USE AS THE INDEX INTO THE SENDQ
! RETURNS:
! IMAH POINTER IF ONE AVAILABLE
! 0 IF NO IMAH'S AVAILABLE IN THE TREE SPECIFIED
! SIDE EFFECTS:
! NONE
BEGIN
REGISTER IMAHPTR,TSNREG;
BIND NOTFOUND=0;
MAP FORMAT IMAHPTR;
MAP FORMAT SENDQ;
! IF SENDQ FOR THIS JSN IS EMPTY THEN WE CAN'T FIND A MATCHING TSN
IF (IMAHPTR _ .SENDQ[SQ0FIMAH(.JSLOT)]) EQL 0 THEN RETURN NOTFOUND;
TSNREG _ .TSN;
! LOOP WHILE THE TSN WE WANT AND THE TSN OF THE SENDQ ENTRY DON'T MATCH
WHILE .TSNREG NEQ .IMAHPTR[I0TSN] DO
! IF THERE ARE NO MORE ENTRIES TO LOOK AT THEN EXIT NOTFOUND
IF (IMAHPTR_.IMAHPTR[I0FORE]) EQL 0 THEN RETURN NOTFOUND;
.IMAHPTR
END;
EXTERNAL MOVE;
COMMENT;
!ROUTINE UNPACK
!====== =======
!LAST MODIFIED: 6 MAY 76 BY CDO
!SUBROUTINE CHAIN
!========== =====
! THIS ROUTINE LINKS A CHUNK TO THE CHUNK-CHAIN IN THE MH.
GLOBAL ROUTINE CHAIN(MHPTR,CHUNK) =
BEGIN
REGISTER FORMAT OLDOUTCHUNK;
MAP FORMAT MHPTR:CHUNK;
OLDOUTCHUNK _ .MHPTR[M0OUTCHNK]; ! SAVE THE OLD LAST OUTPUT CHUNK
MHPTR[M0OUTCHNK] _ .CHUNK; ! MAKE THE NEW CHUNK THE LAST OUTPUT CHUNK
IF .OLDOUTCHUNK EQL 0 THEN MHPTR[M0INCHNK] _ .CHUNK ! IF THERE WAS NO OLD LAST OUTPUT CHUNK THEN
! MAKE THE NEW LAST THE FIRST ALSO
ELSE OLDOUTCHUNK[C0LINK] _ .CHUNK; ! OTHERWISE LINK THE NEW LAST TO THE OLD LAST
END;
COMMENT;
!SUBROUTINE UNPACK
!========== ======
! THIS ROUTINE UNPACKS TEXT UNITS AND TEXT UNIT DESCRIPTORS IN THE PAGE INTO CHUNKS.
! EACH TEXT UNIT DESCRIPTOR IS STORED IN THE FIRST TWO WORDS OF A CHUNK,
! THE ASSOCIATED TEXT UNIT IS STORED INTO THE DATA AREA OF THE CHUNK.
GLOBAL ROUTINE UNPACK(MHPTR,PAGEADDR,JOBSLOT,IMAHPTR) =
BEGIN
REGISTER
TEXTUNIT,
CHUNK;
MAP FORMAT TEXTUNIT;
MAP FORMAT CHUNK;
MAP FORMAT MHPTR;
MAP FORMAT IMAHPTR;
LABEL COPYUNITS;
LOCAL LASTENDI;
LASTENDI _ 0; !ASSUME NO ENDI
INCR I FROM 0 TO .(.PAGEADDR)[P0TUC]-1 DO ! FOR ALL THE TEXT UNIT DESCRIPTORS
COPYUNITS: BEGIN
TEXTUNIT _ (.PAGEADDR)[P0TUD(.I)];
! GET A TEXT UNIT DESCRIPTOR IN THE PAGE.
LASTENDI _ .TEXTUNIT[ C0ENDI ]; !EXTRACT ITS ENDI
IF .TEXTUNIT[ C0WORDS ] EQL 0 THEN LEAVE COPYUNITS; !SKIP THIS CHUNK OF EMPTY
WHILE .TEXTUNIT[ C0BCNT ] GTR ( PTLSIZE - C0HEADSIZE ) * ASCIIBYTESPERWORD DO
! WHILE WE HAVE MORE THAN A PARTICLE WILL HOLD DO
BEGIN
CHUNK _ GETMEM( PTLSIZE ); ! GET THE MAXIMUM A PARTICLE WILL HOLD
CHUNK[ C0BPOS ] _ .TEXTUNIT[ C0BPOS ];
! SAVE THE BYTE POSITION
CHUNK[ C0BSIZ ] _ .TEXTUNIT[ C0BSIZ ];
! AND SIZE INFO
CHUNK[ C0ENDI ] _ 0; ! MAKE THE CHUNK AS INCOMPLETE
CHUNK[ C0LINK ] _ 0; ! AND NOT LINKED TO ANYTHING
CHUNK[ C0BCNT ] _ ( PTLSIZE - C0HEADSIZE - 1 ) * ASCIIBYTESPERWORD +
( .TEXTUNIT[ C0BPOS ] / ASCIISIZE );
! BYTE COUNT IS DEPENDENT UPON HOW MANY BYTES
! ARE IN THE FIRST WORD
CHUNK[ C0WORDS ] _ PTLSIZE - C0HEADSIZE;
! WORD COUNT = MAXIMUM
TEXTUNIT[ C0BCNT ] _ .TEXTUNIT[ C0BCNT ] - .CHUNK[ C0BCNT ];
! FIX TEXTUNIT DESCRIPTOR FOR THE NEXT TIME
TEXTUNIT[ C0WORDS ] _ .TEXTUNIT[ C0WORDS ] - .CHUNK[ C0WORDS ];
! ...
TEXTUNIT[ C0BPOS ] _ #44; ! THE NEW FIRST BYTE IS IN THE FIRST POSITION
MOVE( .TEXTUNIT[ C0LINK ] + .PAGEADDR, CHUNK[ C0DATA ], PTLSIZE - C0HEADSIZE );
! MOVE THE DATA TO THE CHUNK
TEXTUNIT[ C0LINK ] _ .TEXTUNIT[ C0LINK ] + .CHUNK[ C0WORDS ];
! MODIFY THE TUD'S POINTER TO THE TEXT
CHAIN( .MHPTR, .CHUNK ) ! ATTACH THE CHUNK TO THE MH
END;
CHUNK _ GETMEM(.TEXTUNIT[C0WORDS] + C0HEADSIZE);
! GET MEMORY TO STORE THE TEXT UNIT,
! WHERE C0WORDS IS THE NUMBER OF WORDS THE TEXT AREA REQUIRES,
! AND THE HEADER OF THE CHUNK NEEDS C0HEADSIZE WORDS.
MOVE(.TEXTUNIT,.CHUNK,C0HEADSIZE);
! FORM A CHUNK HEADER BY COPYING THE TUD
CHUNK[C0LINK] _ 0; ! AND ZEROING THE LINK POINTER
MOVE(.PAGEADDR+.TEXTUNIT[C0LINK],CHUNK[C0DATA],.TEXTUNIT[C0WORDS]);
!SET UP THE DATA AREA IN THE CHUNK
CHAIN(.MHPTR,.CHUNK) !LINK THE NEW CHUNK TO THE CHUNK-CHAIN
END;
.LASTENDI !RETURN LAST END INDICTOR SEEN
END;
EXTERNAL LINK,
CHKRUN,
NEXTINTSN,
BUILD;
COMMENT;
! SUBROUTINE LFOUT
! ================
! THIS ROUTINE CREATES A GROUP HEADER AND LINKS IT TO A LEAF, IF THE
! LEAF IS ENABLED FOR OUTPUT. IF THE LEAF IS DISABLED FOR OUTPUT, IT IS
! LINKED TO THE LFTAB
! LAST MODIFIED: 28 JUN 76 BY ILG
! .DEST CONTAINS THE LOCATION OF AN ENTRY IN DESTAB
ROUTINE LFOUT(DEST,MHPTR,TSN,ENDI) =
BEGIN
REGISTER
I,
LEAFSTATUS,
GHPTR,
LEAFPTR;
MAP FORMAT MHPTR;
MAP FORMAT LFTAB;
MAP FORMAT GHPTR;
MAP FORMAT LEAFPTR;
I _ .DEST;
LEAFPTR _ .LFTAB[L0LFPTR(.I)];
IF (LEAFSTATUS_.LFTAB[L0ED(.I)]) THEN GHPTR _ CREATEGH(LFTAB[L0GHS(.I)]) ! IF DISABLED MAKE A GROUP HEADER
! AND ATTACH TO THE LFTAB
ELSE GHPTR _ CREATEGH(LEAFPTR[N0GHS]); ! IF ENABLED MAKE A GROUP HEADER
! AND ATTACH TO THE LEAF
LINK(GHPTR[G0MHS],.MHPTR); ! LINK THE MESSAGE TO THE GROUP
GHPTR[G0LHTSN] _ NEXTINTSN(); ! LOAD GH WITH GOODIES
GHPTR[G0RHTSN] _ 0;
GHPTR[G0LFPTR] _ .LEAFPTR;
GHPTR[G0OUTMH] _ .MHPTR;
GHPTR[G0SENDER] _ LFTAB[L0DST(.I)]; ! STORE POINTER TO THE OP LEAF NAME
! =======
GHPTR[G0TYPEOFSENDER] _ LEAFTYPE; ! LET EVERYONE AN MPP SENT THIS
IF .ENDI GTR EMI THEN GHPTR[G0ENDI] _ TRUE; ! IF IT'S END INDICATOR >= EGI THEN
! SET GROUP DONE BIT
IF .CHECKPOINTING AND .LEAFPTR[N0CHKPNT] THEN !IF CHECKPOINTING AND
!CHECKPOINTING THIS LEAF
BEGIN
GHPTR[G0DSKGHADDR] _ CHKGH( .LEAFPTR[N0LLFNO], ! CHECKPOINT THE GROUP
.GHPTR[G0TSN],
.GHPTR[G0SENDER],
.MHPTR);
! AND STORE THE DISK GROUP HEADER ADDRESS
GHPTR[G0CHKPNT] _ TRUE ! THIS GROUP IS BEING CHECKPOINTED
END;
IF .INLOGGING THEN
INLOGMSG( .GHPTR[G0TSN],
.MHPTR[M0DATE],
.MHPTR[M0TIME],
.GHPTR[G0SENDER],
0,
.MHPTR[M0INCHNK]);
IF .LEAFSTATUS EQL 0 THEN CHKRUN(.LEAFPTR,1,.GHPTR); ! IF WE ATTACHED THE GROUP TO A LEAF THEN
! INCREMENT STUFF AND SEE IF WE NEED TO RUN SOMEONE
.GHPTR ! RETURN THE GROUP HEADER POINTER
END;
EXTERNAL MOVE;
COMMENT;
! SUBROUTINE COPYMSG
! ==================
! LAST MODIFIED: 9 JUN 76 BY CDO
! THIS ROUTINE MAKES A COPY OF THE MESSAGE AND MESSAGE HEADER OF
! THE MESSAGE POINTED TO BY THE MHPTR SUPPLIED IN THE CALL
ROUTINE COPYMSG(MHPTR,DATE,TIME) =
BEGIN
REGISTER
SIZE,
NEWMHPTR,
CHUNK,
CHKPTR;
MAP FORMAT MHPTR;
MAP FORMAT NEWMHPTR;
MAP FORMAT CHUNK;
MAP FORMAT CHKPTR;
NEWMHPTR _ CREATEMH(0); ! MAKE A NEW MESSAGE HEADER
NEWMHPTR[M0DATE] _ .DATE; ! AND STORE THE DATE IN IT
NEWMHPTR[M0TIME] _ .TIME; ! AND TIME TOO
CHUNK _ .MHPTR[M0INCHNK]; ! THEN STARTING WITH THE FIRST CHUNK
WHILE .CHUNK NEQ 0 DO ! AND FOR EACH CHUNK OF THE MESSAGE
BEGIN
SIZE _ .CHUNK[C0WORDS] + C0HEADSIZE;
CHKPTR _ GETMEM(.SIZE); ! REQUEST ENOUGH MEMORY FOR THIS CHUNK
MOVE(.CHUNK,.CHKPTR,.SIZE); ! COPY OLD INTO NEW
CHKPTR[C0LINK] _ 0; ! CLEAR THE LINK POINTER IN THE CHUNK HEADER
CHAIN(.NEWMHPTR,.CHKPTR); ! AND ATTACH THE CHUNK TO THE NEW MESSAGE HEADER
CHUNK _ .CHUNK[C0LINK]; ! STEP TO THE NEXT CHUNK TO COPY
END;
NEWMHPTR[ M0OUTCHNK ] _ .NEWMHPTR[ M0INCHNK ];
.NEWMHPTR ! RETURN A POINTER TO THE NEW MESSAGE HEADER TO THE CALLER
END;
COMMENT;
! SUBROUTINE SENDLF
! ========== ======
! LAST MODIFIED: 1 JUN 76 BY CDO
ROUTINE SENDLF(IMAHPTR,DATE,TIME,ENDI) =
BEGIN
REGISTER
DTAB,
DEST,
DCNT;
MAP FORMAT IMAHPTR;
LOCAL START,
FORMAT GHPTR:MHPTR;
DCNT _ .IMAHPTR[I0DSTSIZE]; ! PICKUP THE TOTAL NUMBER OF DESTINATIONS
MHPTR _ .IMAHPTR[I0MHPTR]; ! PICKUP THE CURRENT MESSAGE HEADER
DTAB _ .IMAHPTR[I0DESTAB]; ! PICKUP THE CURRENT DESTINATION TABLE
INCR I FROM IF .IMAHPTR[I0TRMCNT] EQL 0 THEN 2 ELSE 1 TO .IMAHPTR[I0LFCNT] DO
(.DTAB)[.DCNT-.I] _ LFOUT(.(.DTAB)[.DCNT-.I],COPYMSG(.MHPTR,.DATE,.TIME),.IMAHPTR[I0TSN],.ENDI);
IF .IMAHPTR[I0TRMCNT] EQL 0 THEN ! IF THERE ARE NO SOURCE TYPE DESTINATIONS THEN
BEGIN
MHPTR[M0DATE] _ .DATE; ! DATE AND TIME STAMP THE MESSAGE HEADER
MHPTR[M0TIME] _ .TIME;
IF .DCNT EQL 0 THEN DEST _ .DTAB
ELSE DEST _ .(.DTAB)[.DCNT-1]; ! OTHERWISE GET THE LAST ENTRY OF THE DTAB
IMAHPTR[I0GHPTR] _ GHPTR _ LFOUT(.DEST,.MHPTR,.IMAHPTR[I0TSN],.ENDI);
IF .DCNT EQL 0 THEN IMAHPTR[I0DESTAB] _ .GHPTR ! THEN SAVE THE GH IN THE IMAH
ELSE (.DTAB)[.DCNT-1] _ .GHPTR; ! SAVE THE GH IN THE DTAB
END
END;
EXTERNAL LINK,
UNLINK,
DELMH,
DELGH,
DMHS;
COMMENT;
!ROUTINE PURGE
! ====== =====
! LAST MODIFIED: 15 DEC 76 BY CDO
! SUBROUTINE KILGROUP
! ========== ========
! THIS SUBROUTINE IS USED TO DELETE A GROUP FROM CORE AND DISK, AND
! IF UNFINISHED, THEN THE SENDER IS MARKED AS PURGING
GLOBAL ROUTINE KILGROUP(GHPTR, JOBSLOT) =
BEGIN
REGISTER
SRCPTR,
NEXT,
CHUNK;
MAP FORMAT GHPTR;
MAP FORMAT SRCPTR;
MAP FORMAT CHUNK;
MAP FORMAT RECVQ;
IF .GHPTR[G0ENDI] EQL 0 THEN
!IF THE GROUP HAS NOT ENCOUNTERED AN EGI OR EPI,
BEGIN
IF .GHPTR[G0TYPEOFSENDER] EQL TERMINAL THEN ! IF SENDER IS A TERMINAL THEN
BEGIN
SRCPTR _ .GHPTR[G0SENDER]; !THEN GET THE SENDER OF THE GROUP.
SRCPTR[S0PURGE] _ TRUE; !MARK PURGING
CHUNK _ .SRCPTR[S0FCHNK];
!GET THE FIRST CHUNK IN SRCTAB.
!(NOTE: THE INPUT CHUNKS STORED IN SRCTAB ARE CHUNKS
!THAT BELONG TO AN INCOMPLETE MESSAGE.)
UNTIL .CHUNK EQL 0 DO
!DELETE ALL THE INPUT CHUNKS IN THIS SENDER.
BEGIN
NEXT _ .CHUNK[C0LINK];
DELCHNK(.CHUNK);
CHUNK _ .NEXT;
END;
SRCPTR[S0CHUNKS] _ 0
END
ELSE ! ELSE IF SENDER IS AN MPP
BEGIN
GHPTR[G0PURGING] _ TRUE; ! MARK AS PURGING
DMHS(.GHPTR); ! ZAP ALL THE MESSAGE HEADERS OF THE GROUP
! BUT NOT THE GH
IF .JOBSLOT GEQ 0 THEN ! AND IF A JOB SLOT NUMBER WAS GIVEN THEN
UNLINK(RECVQ[R0GHS(.JOBSLOT)],.GHPTR); ! UNLINK THE GH FROM THE RECVQ
END
END;
! IF CHECKPOINTING OR ROLLING THEN ZAP ANYTHING ON THE DISK
IF .GHPTR[G0DSKGHADDR] NEQ 0 THEN GPURGE(.GHPTR[G0DSKGHADDR]);
IF .GHPTR[G0TYPEOFSENDER] EQL TERMINAL OR .GHPTR[G0ENDI] NEQ 0 THEN ! IF TERMINAL OR GROUP COMPLETE THEN
IF .JOBSLOT GEQ 0 THEN ! IF A JOB SLOT NUMBER WAS SPECIFIED THEN
DELGH(RECVQ[R0GHS(.JOBSLOT)],.GHPTR) !DELETE THE CURRENT GH
ELSE DELGH(0, .GHPTR); ! DELETE WITH NO UNLINKING
! OTHERWISE DON'T
END;
COMMENT;
! SUBROUTINE PURGEI
! ========== ======
! THIS SUBROUTINE IS CALLED AFTER A EPI HAS BEEN SENT BY AN MPP,
! IS TO STOP ALL THE UNFINISHED INPUT TRANSACTIONS IN THE RECVQ
! THAT BELONG TO THIS MPP.
! IN ORDER TO STOP THE UNFINISHED INPUT TRANSACTIONS, THE PURGE BIT
! IN THE SRCTAB FOR EACH SENDER SHOULD BE SET.
! THE ASSOCIATED GH'S, MH'S, CHUNKS ARE ALL PURGED.
GLOBAL ROUTINE PURGEI(JOBSLOT) =
BEGIN
REGISTER
SRCPTR,
GHPTR,
JSN,
NEXT;
MAP FORMAT RECVQ;
MAP FORMAT SRCPTR;
MAP FORMAT GHPTR;
JSN _ .JOBSLOT; ! PUT THE JOB SLOT NUMBER IN A REGISTER BECAUSE
! I DON'T TRUST BLISS' OPTIMIZER
IF .RECVQ[R0FGH(.JSN)] EQL 0 THEN RETURN; ! IF NOTHING WAS RECEIVED BY THIS JOB THEN LEAVE NOW
GHPTR _ .RECVQ[R0FGH(.JSN)]; !GET THE FIRST GH IN RECVQ
UNTIL .GHPTR EQL 0 DO
BEGIN
NEXT _ .GHPTR[G0FORE];
KILGROUP( .GHPTR, .JSN); ! DELETE THE GROUP
GHPTR _ .NEXT
!GET THE NEXT GH IN RECVQ.
END
END;
COMMENT;
! SUBROUTINE PURGEO
! ========== ======
! THIS ROUTINE IS CALLED AFTER A EPI HAS BEEN SENT BY AN MPP,
! IS TO FORCE AN EGI TO ALL THE OUTPUT MESSAGES IN THE SENDQ.
GLOBAL ROUTINE PURGEO(JOBSLOT) =
BEGIN
REGISTER
IMAHPTR,
MHPTR,
GHPTR,
CHUNK;
MAP FORMAT SENDQ;
MAP FORMAT IMAHPTR;
MAP FORMAT MHPTR;
MAP FORMAT GHPTR;
MAP FORMAT CHUNK;
LOCAL NEXT, SIZE;
IMAHPTR _ .SENDQ[SQ0FIMAH(.JOBSLOT)]; !GET THE FIRST IMAH IN SENDQ.
UNTIL .IMAHPTR EQL 0 DO
!CHANGE THE LAST CHUNK'S END INCATOR TO EGI,
!SET THE G0ENDI BIT IN THE ASSOCIATED GH.
!GET THE NEXT IMAH IN SENDQ.
BEGIN
IF ( GHPTR _ .IMAHPTR[I0GHPTR] ) NEQ 0 THEN ! IF OUTPUT AT LEAST EMI'ED
BEGIN
GHPTR[G0ENDI] _ TRUE;
IF (MHPTR _ .IMAHPTR[I0MHPTR]) EQL 0 THEN ! IF AN MH DOESN'T EXIST THEN
BEGIN
MHPTR _ CREATEMH(0); ! MAKE ONE
IMAHPTR[I0MHPTR] _ .MHPTR;
MHPTR[M0DSCNT] _ .GHPTR[G0DSTCNT];
CHUNK _ GETMEM(C0HEADSIZE);
! NOTE; ASSUMES 7 BIT BYTES
CHUNK[C0BPOS] _ 36;
CHUNK[C0BSIZ] _ 7;
CHUNK[C0LINK] _ 0;
CHUNK[C0WORDS] _ 0;
CHUNK[C0BCNT] _ 0;
MHPTR[M0INCHNK] _ MHPTR[M0OUTCHNK] _ .CHUNK;
END
ELSE CHUNK _ .MHPTR[M0OUTCHNK];
CHUNK[C0ENDI] _ EGI;
MHPTR[M0OUTCHNK] _ .MHPTR[M0INCHNK];
ATTACH( .IMAHPTR, EGI, .GHPTR, .MHPTR)
END ELSE BEGIN
MHPTR _ .IMAHPTR[I0MHPTR];
WHILE .MHPTR NEQ 0 DO
BEGIN
NEXT _ .MHPTR[M0FORE];
MHPTR[M0LINK] _ 0;
DELMH(0,.MHPTR);
MHPTR _ .NEXT
END;
END;
IF (SIZE _ .IMAHPTR[I0DSTSIZE]) NEQ 0 THEN ! PICK UP THE SIZE OF THE DESTTAB FROM THE IMAH
RETMEM(.IMAHPTR[I0DESTAB],.SIZE); ! IF ANY THEN DELETE THE DESTTAB
NEXT _ .IMAHPTR[I0FORE];
DELIMAH(SENDQ[SQ0IMAHS(.JOBSLOT)],.IMAHPTR); ! DELETE THE IMAH
IMAHPTR _ .NEXT; ! GOTO THE NEXT IMAH
END
END;
COMMENT;
! SUBROUTINE SENDEXIT
! ========== ========
! LAST MODIFIED: 15 JUN 76 BY CDO
! THIS ROUTINE DOES COMMON CLEAN UP
! CALLED BEFORE LEAVING SEND
ROUTINE SENDEXIT(JOBSLOT,IMAHPTR,ENDI) =
BEGIN
REGISTER
SIZE,
DTAB,
GHPTR;
MAP FORMAT GHPTR;
MAP FORMAT SENDQ;
MAP FORMAT IMAHPTR;
EXTERNAL RUNMSW;
IMAHPTR[I0MHPTR] _ 0; ! CLEAR MESSAGE HEADER IN IMAH
RUNMSW _ -1; ! START THE OUTPUT PROCESS
IF .ENDI LSS EGI THEN RETURN; ! IF NOT EGI OR EPI THEN DONE FOR NOW
IF (SIZE _ .IMAHPTR[I0DSTSIZE]) NEQ 0 THEN ! PICK UP THE SIZE OF THE DESTAB FROM THE IMAH
RETMEM(.IMAHPTR[I0DESTAB],.SIZE); ! AND IF NON-ZERO THEN DELETE THE DESTAB
DELIMAH(SENDQ[SQ0IMAHS(.JOBSLOT)], .IMAHPTR); ! REMOVE IMAH FROM SENDQ
IF .ENDI EQL EPI THEN ! IF EPI THEN
BEGIN
PURGEI(.JOBSLOT); ! CLEAR THIS MPP'S RECVQ
PURGEO(.JOBSLOT); ! AND SENDQ
SETMPPSTATUS(.JOBSLOT,EPIBIT) ! AND TELL THE KERNEL IT IS KILLABLE
END
END;
EXTERNAL LINK,
MSGCHN,
BUILD,
OUTLOGMSG,
DCHNKS,
INSERT,
DROLGH,
DROLMSG;
COMMENT;
! SUBROUTINE SEND
! ===============
! LAST MODIFIED: 29 MAR 77 BY CDO
GLOBAL ROUTINE SEND(JOBSLOT,PAGEADDR) =
BEGIN
LOCAL DATE,
TIME,
GHPTR,
ENDI,
VALUE,
DTAB,
TRMCNT,
LTTYNO,
MHS;
REGISTER
IMAHPTR,
MHPTR,
DEST;
MAP FORMAT IMAHPTR;
MAP FORMAT MHPTR;
MAP FORMAT GHPTR;
MAP FORMAT DEST;
BIND MCLASSDEF = 1;
MACRO LOGANDCHKORROLL =
IF .INLOGGING THEN INLOGMSG(.DEST[G0TSN],.DATE,.TIME,.DEST[G0SENDER],0,.MHPTR[M0INCHNK]);
IF .DEST[G0CHKPNT] THEN
BEGIN
MHPTR[M0DSKADDR]_CHKMSG(.DEST[G0DSKGHADDR],.DATE,.TIME,.MHPTR[M0INCHNK],.MHPTR[M0SOT]);
IF .DEST[G0ONDSK] THEN ! IF ROLLING OTHERS
BEGIN
DCHNKS(.MHPTR); ! ZAP THE CHUNKS
MHPTR[M0CHNKS] _ 0 ! AND MARK IT OUT
END
END
ELSE
IF .DEST[G0ONDSK] THEN !IF ROLLING FOR THIS GROUP
BEGIN
MHPTR[M0DSKADDR]_ROLMSG(.DEST[G0DSKGHADDR],.MHPTR[M0INCHNK],.MHPTR[M0SOT]);
MHPTR[M0CHNKS] _ 0
END;
$; !!!!!!! END OR LOGANDCHKORROLL
! BEGIN !
VALUE _ DELETEPAGE; ! ASSUME THIS IS A SEND WITH NO RESPONSE
IF .(.PAGEADDR)[P0FCN] EQL SENDRR THEN ! IF IT IS A SEND WITH RESPONSE (INITIAL SEND)
BEGIN
VALUE _ SENDPAGE; ! THEN WE WILL SEND THIS PAGE BACK
IMAHPTR _ SEND4(.JOBSLOT,.PAGEADDR); ! TAKE CARE OF THE INITIAL SET UP
IF .IMAHPTR LSS 0 THEN RETURN .VALUE; ! IF ERROR LEAVE NOW
MHPTR _ .IMAHPTR[I0MHPTR] ! PICK UP THE MHPTR MADE BY SEND4
END
ELSE
BEGIN
IF ( IMAHPTR _ FINDS(.(.PAGEADDR)[P0TSN],.JOBSLOT) ) EQL 0 THEN
! IF NOT INITIAL SEND, FIND THE OLD DESTINATIONS
BEGIN
(.PAGEADDR)[P0STATUS] _ STSNOTINSEND;
RETURN .VALUE
END;
IF (MHPTR _ .IMAHPTR[I0MHPTR]) EQL 0 THEN ! ANY MH LEFT FROM A PREVIOUS SEND?
BEGIN
MHPTR _ CREATEMH(0); ! NO THEN MAKE ONE
IMAHPTR[I0MHPTR] _ .MHPTR; ! AND TELL THE IMAH WE DID
GHPTR _ .IMAHPTR[I0GHPTR]; ! GET THE GROUP HEADER
MHPTR[M0DSCNT] _ .GHPTR[G0DSTCNT]; ! AND COPY THE COUNT FROM IT TO THE NEW MH
! SEND4 CREATES AN MH, SO THIS CODE ISN'T USED
! THE FIRST TIME THRU ( WITH SEND4)
END
END;
ENDI _ UNPACK(.MHPTR,.PAGEADDR,.JOBSLOT,.IMAHPTR); ! UNPACK
IF .ENDI LSS EMI THEN RETURN .VALUE; ! IF NOT A FULL MESSAGE THEN LEAVE NOW
IF (MHPTR[M0OUTCHNK] _ .MHPTR[M0INCHNK]) EQL 0 THEN BEGIN
DELETE(0,.MHPTR,M0SIZE,-1); ! REMOVE EMPTY HEADER
SENDEXIT(.JOBSLOT,.IMAHPTR,.ENDI); ! CLEAN UP AFTER CALLER
RETURN .VALUE ! AND EXIT NOW
END;
TRMCNT _ .IMAHPTR[ I0TRMCNT ]; !REMEMBER TERMINAL COUNTS
STAMP(DATE,TIME); ! DATE AND TIME STAMP A COMPLETE MESSAGE
IF .OUTLOGGING THEN ! LOG THE OUTPUT MESSAGE
OUTLOGMSG(.IMAHPTR[I0TSN],
.DATE,
.TIME,
(.PAGEADDR)[P0MCLS],
.JOBSLOT,
.(.PAGEADDR)[P0DSCNT],
(.PAGEADDR)[P0DTAB],
.MHPTR[M0INCHNK]);
DTAB _ .IMAHPTR[I0DESTAB]; ! GET THE DESTINATION TABLE FROM THE IMAH
IF ( GHPTR _ .IMAHPTR[I0GHPTR]) EQL 0 THEN ! IF WE DON'T HAVE A GROUP HEADER
BEGIN
IF .IMAHPTR[I0LFCNT] NEQ 0 THEN ! IF THE LEAF COUNT IS NON-ZERO OUTPUT THE LEAVES
SENDLF(.IMAHPTR,.DATE,.TIME,.ENDI);
IF .IMAHPTR[I0MCLSS] EQL MCLASSDEF AND .TRMCNT NEQ 0 THEN
! IF DEFERRED AND AT LEAST ONE SOURCE TYPE
BEGIN
IMAHPTR[I0DSKMH] _ MHPTR[M0DSKADDR] _ DROLMSG( .MHPTR[M0INCHNK], 0 ); ! ROLL OUT 1ST MSG
MHPTR[M0CHNKS] _ 0
END;
INCR I FROM 0 TO .TRMCNT - 1 DO ! FOR ALL TERMINALS
BEGIN
IF .IMAHPTR[I0DSTSIZE] EQL 0 THEN
DEST _ .DTAB ! IF ONLY ONE DESTINATION THEN DTAB IS THE DEST
ELSE DEST _ .(.DTAB)[.I]<RH>; ! ELSE DTAB IS A POINTER TO THE DEST TABLE
IF .IMAHPTR[I0MCLSS] EQL MCLASSDEF THEN ! IF DEFERRED
BEGIN
GHPTR _ CREATEGH(DEST[S0DGHS]); ! CREATE A GROUP HEADER
! AND LINK TO DEFERRED MESSAGES
DEST[S0DFGCNT] _ .DEST[S0DFGCNT] + 1; ! INCREMENT THE DEFERRED MESSAGE COUNT
LTTYNO _ (.DEST<RH>-(.SRCTAB+1))/.S0SIZE; ! FIGURE TTY NUMBER
GHPTR[G0DSKGHADDR] _ DROLGH( .LTTYNO, .MHPTR[M0DSKADDR],
.IMAHPTR[I0TSN],.DEST);
! SAVING THE DISK ADDRESS IN THE GH
GHPTR[G0ONDSK] _ TRUE ! MARK IT AS ON DSK
END
ELSE ! IF IMMEDIATE
BEGIN
MSGCHN(.DEST); ! INSERT INTO OUTPUT CHAIN
GHPTR _ CREATEGH(DEST[S0IGHS]); ! THEN CREATE A GROUP HEADER AND LINK IT
! TO THE IMMEDIATE MESSAGES
DEST[S0DEFSENDING] _ FALSE ! SET THINGS SO WE CAN SEND
! PIGGYBACK DEFERRED'S AGAIN
END;
GHPTR[G0OUTMH] _ .MHPTR; ! MHPTR,
GHPTR[G0SENDER] _ .DEST; ! SENDER,
GHPTR[G0DSTCNT] _ .TRMCNT; ! DESTINATION COUNT IN THE GH
GHPTR[G0TSN] _ .IMAHPTR[I0TSN]; ! AND THE TRANSACTION SEQUENCE NUMBER
IF .I EQL 0 THEN
BEGIN
IMAHPTR[I0GHPTR] _ .GHPTR; ! FOR THE FIRST DESTINATION SAVE THE GHPTR
LINK( GHPTR[G0MHS], .MHPTR); ! LINK THE MESSAGES TOGETHER
MHS _ .GHPTR[G0MHS]; ! AND REMEMBER THE LINKAGE
END
ELSE GHPTR[G0MHS] _ .MHS; ! ELSE STORE THE REMEMBERED LINKAGE
IF .ENDI GTR EMI THEN GHPTR[G0ENDI] _ TRUE; ! IF EGI OR EPI, MARK THE GROUP COMPLETE
IF .IMAHPTR[I0DSTSIZE] NEQ 0 THEN ! IF MORE THAN ONE DEST THEN
(.DTAB)[.I] _ .GHPTR ! STORE THE GH IN THE DESTINATION TABLE
ELSE IMAHPTR[ I0DESTAB ] _ .GHPTR ! STORE THE GH IN THE IMAH FOR A SINGLE DEST
END;
SENDEXIT(.JOBSLOT,.IMAHPTR,.ENDI); ! ALL DONE WITH "IF NO GH" SO FINISH UP
RETURN .VALUE ! AND RETURN
END;
IF .TRMCNT NEQ 0 THEN ATTACH(.IMAHPTR,.ENDI,.GHPTR,.MHPTR); ! LINK THE MESSAGE
IF .IMAHPTR[I0LFCNT] NEQ 0 THEN ! IF LEAF DESTINATION(S) THEN
BEGIN
INCR I FROM IF .TRMCNT EQL 0 THEN 2 ELSE 1 TO .IMAHPTR[I0LFCNT] DO
BEGIN
DEST _ .(.DTAB)[.IMAHPTR[I0DSTSIZE] - .I];
IF .ENDI GTR EMI THEN DEST[G0ENDI] _ TRUE;
IF .DEST[G0PURGING] THEN BEGIN
IF .ENDI GTR EMI THEN DELGH(0,.DEST)
END ELSE BEGIN
MHPTR _ COPYMSG(.IMAHPTR[I0MHPTR],.DATE,.TIME);
LOGANDCHKORROLL;
INSERT(.MHPTR,.DEST)
END
END;
IF .TRMCNT EQL 0 THEN
BEGIN
MHPTR _ .IMAHPTR[I0MHPTR]; !GET THE MH BACK AFTER COPIES
MHPTR[M0DATE] _ .DATE; ! DATE AND TIME STAMP THE MESSAGE
MHPTR[M0TIME] _ .TIME;
DEST _ .IMAHPTR[I0GHPTR]; ! SET UP FOR LOGANDCHKORROLL
IF .ENDI GTR EMI THEN DEST[G0ENDI] _ TRUE;
IF .DEST[G0PURGING] THEN BEGIN
IF .ENDI GTR EMI THEN DELGH(0,.DEST);
DELMH(0,.MHPTR)
END ELSE BEGIN
LOGANDCHKORROLL;
INSERT(.MHPTR,.DEST) ! ATTACH IT TO A GROUP
END
END
END;
IF .IMAHPTR[I0MCLSS] EQL MCLASSDEF AND .TRMCNT NEQ 0 THEN
! IF DEFERRED AND AT LEAST ONE SOURCE TYPE
BEGIN
MHPTR _ .IMAHPTR[I0MHPTR]; ! MAKE SURE WE HAVE THE RIGHT MHPTR
MHPTR[M0DSKADDR] _ DROLMSG( .MHPTR[M0INCHNK], .IMAHPTR[I0DSKMH]); ! ROLL THE MSG OUT
MHPTR[M0CHNKS] _ 0
END;
SENDEXIT(.JOBSLOT,.IMAHPTR,.ENDI); ! FINISH UP
.VALUE ! RETURN WHAT TO DO WITH THE PAGE
END;
END;