!***COPYRIGHT (C) 1974, 1975, 1976, 1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.*** MODULE DEVSER(RESERVE(#11,#12,#13,#14),SREG=#17,FREG=#16,DREGS=4, VREG=#15,MLIST,TIMER=EXTERNAL(SIX12),FSAVE)= BEGIN REQUIRE DATA.BLI; EXTERNAL MOVE, UNLINK; COMMENT; ! THIS FILE CONTAINS THE DISK SERVICE ROUTINES FOR ROLLING AND/OR ! FAILSOFTING INCOMING MESSAGES, AND "FAILSOFTING" OUTGOING ! DEFERRED MESSAGES. ! THE FAILSOFT/ROLLOUT FILE FOR INCOMING MESSAGES IS TREE STRUCTURED ! IN THE FOLLOWING MANNER: ! ( GROUP ON DISK ) ! ----------- --------- ----------- ----------- ! ! LEAF !====>! DSKGH !====>! DSK !====>! DSK !... ! ! POINTER ! ! TABLE ! ! MESSAGE !==V ! MESSAGE ! ! ! TABLE ! --------- ! HEADER ! : ! HEADER ! ! ----------- . ----------- : ----------- ! . : ! . V ! ---------- ! ! CHUNKS ! ! ---------- ! ! ( GROUP IN CORE ) ! ----------- --------- ---------- ----------- ! ! LEAF !====>! GROUP !====>! MESSAGE !====>! MESSAGE ! ... ! ! OF THE ! ! HEADER! ! HEADER !==V ! HEADER ! ! ! TREE ! --------- ----------- : ----------- ! ----------- . : ! . : ! . V ! ---------- ! ! CHUNKS ! ! ---------- ! LEAF POINTER TABLE ! ! ----------- ! ! T1 ! T2 ! ! ----------- ! ! . ! ! ---- . ---- ! ! . ! ! ---- . ---- ! ! . ! ! ----------- ! ! ! TN ! ! ----------- ! ! THE GROUP POINTER TABLE CONSISTS OF ONE HALF-WORD PER LEAF AND ! THE CONTENTS OF THESE HALFWORDS ARE POINTERS TO THE BEGINNING ! OF THE DSKGHTAB ASSOCIATED WITH EACH LEAF. THE GROUP POINTER ! TABLE RESIDES AT A FIXED LOCATION IN THE ROLLOUT FILE. AS OF ! THIS WRITING, THAT LOCATION IS PTL .IBASE AND UP AS REQUIRED. ! CHECK DATBAS FOR THE CURRENT ADDRESS. ! DISK GROUP HEADER TABLE (DSKGHTAB): ! ! ------------------------------------------------- ! WORD 0: ! POINTER TO PREV DSKGH ! POINTER TO NEXT DSKGH ! ====V ! ------------------------------------------------- : ! ! UNUSED ! (2): ! ------------------------------------------------- : ! ! UNUSED ! (3): ! ------------------------------------------------- : ! ! UNUSED ! (4): ! ------------------------------------------------- : ! ENTRY 1: ! UNUSED ! POINTER TO FIRST DSKMH! (5): ! ------------------------------------------------- : ! ! TRANSACTION SEQUENCE NUMBER ! (6): ! ------------------------------------------------- : ! ! SENDER ID ! : ! ------------------------------------------------- : ! ! UNUSED ! : ! ------------------------------------------------- : ! ENTRY 2: ! . ! : ! ------------------------------------------------- : ! ! . ! : ! ------------------------------------------------- : ! ! . ! : ! ------------------------------------------------- : ! : ! V=============================================================< ! : ! : ------------------------------------------------- ! >====> ! POINTER TO PREV DSKGH ! POINTER TO NEXT DSKGH ! ! ------------------------------------------------- ! ! 0 ! ! ------------------------------------------------- ! ! 0 ! ! ------------------------------------------------- ! ! 0 ! ! ------------------------------------------------- ! ENTRY N: ! ! ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- ! DISK MESSAGE HEADER (DSKMH): ! ! ------------------------------------------------- ! WORD 0: ! POINTER TO PREV DSKMH ! POINTER TO NEXT DSKMH ! (1) ! ------------------------------------------------- ! ! DATE ! (2) ! ------------------------------------------------- ! ! TIME ! (3) ! ------------------------------------------------- ! ! POINTER TO DSKGHTAB ! (4) ! ------------------------------------------------- ! ! TRANSACTION SEQUENCE NUMBER ! (?) ! ------------------------------------------------- ! ! SOT ! ENDI ! (?) ! ------------------------------------------------- ! FIRST RI: ! RETRIEVAL INFORMATION ! (5) ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- ! LAST RI: ! -1 (6) ! NEXT BLOCK OF RI'S ! ====V ! ------------------------------------------------- : ! : ! V=============================================================< ! : ! : ------------------------------------------------- ! >====> ! COPY FROM FIRST MH ! (7) ! ------------------------------------------------- ! ! 0 ! ! ------------------------------------------------- ! ! 0 ! ! ------------------------------------------------- ! ! 0 ! ! ------------------------------------------------- ! FIRST RI: ! RETRIEVAL INFORMATION ! ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- ! LAST RI: ! -1 ! NEXT BLOCK OF RI'S ! ====: ! ------------------------------------------------- : ! ETC. ! ! (1) POINTER TO NEXT MH IS THE PARTICLE NUMBER OF THE NEXT ! DSKMH PARTICLE ( OR ZERO IF NONE OR IF EXTENDED MH) ! IF EXTENDED MH, ONLY THE LAST EXTENSION HAS A POINTER ! TO THE NEXT ! (2) IF FAILSOFTING THEN THE DATE OF THE MESSAGE IS STORED, ! OTHERWISE 0. ! (3) TIME IS TREATED THE SAME AS DATE ! (4) XWD OFFSET_IN_THE_PARTICLE, PARTICLE_NUMBER ! (5) RI ( RETREIVAL INFORMATION ) CONSISTS OF XWD NUMBER_OF_ ! CONTIGIOUS_PARTICLES, PARTICLE_NUMBER_OF_THE_FIRST_PARTICLE ! (6) IF THE NUMBER_OF_PARTICLES IS -1 THEN THE PARTICLE_ ! NUMBER_OF_THE_FIRST_PARTICLE IS THE POINTER TO THE NEXT ! EXTENSION. ! (7) THE HEADER INFORMATION IN THE EXTENSIONS IS JUST A COPY ! OF THAT IN THE FIRST ! ! ! ! CHUNK_PARTICLE FORMAT: ! ! SAME AS IN-CORE: ! ! ------------------------------------------------- ! ! POS ! SIZE ! ENDI ! GARBAGE ! ! ------------------------------------------------- ! ! WORD COUNT ! BYTE COUNT ! ! ------------------------------------------------- ! ! DATA ! ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- ! ! . ! ! ------------------------------------------------- FORWARD DSKMSG(4), STOREDSKGH(6), STORENEXTMH(1), DELDSKGH(2), FINDNEXTMH(1), ZAPDSKMHS(1); EXTERNAL TRMDSKTAB, LEAFDSKTAB; COMMENT; ! 1. FAILSOFT GROUP HEADER ! == ========== ===== ====== ! CALLING ARGUEMENTS: ! 1) LEAF NUMBER THIS TRANSACTION BELONGS TO ! 2) TRANSACTION SEQUENCE NUMBER ! 3) THE SENDER ! 4) POINTER TO MESSAGE HEADER ! RETURNS: DISK GH ADDR ! SIDE EFFECTS: DISK ADDRESS SET IN MH ! BLISS CALLING SEQUENCE: IF .FAILSOFTING THEN ! CHKGH( .LEAFNO, .TSN, .SENDERID, .MHPTR ) ! FUNCTION: WRITE THE MESSAGE ON A FAILSOFT FILE ! AND MODIFY THE LEAF DISK ADDR TABLE GLOBAL ROUTINE CHKGH( LEAFNO, TSN, SENDERID, MHPTR)= BEGIN REGISTER FIRSTMH, DSKGH; MAP FORMAT MHPTR; MHPTR[ M0DSKADDR ] _ FIRSTMH _ DSKALL( 1 ); ! ALLOCATE THE FIRST MH OF THE GROUP DSKGH _ STOREDSKGH(.LEAFNO,.FIRSTMH,.TSN,.SENDERID,LEAFDSKTAB,.IBASE); !ADD ENTRY TO FAILSOFT FILE STORENEXTMH( .DSKGH, .FIRSTMH); ! ADD AN ENTRY TO THE NEXTMH TABLE DSKMSG( .MHPTR[ M0INCHNK ], ! FAILSOFT .MHPTR[ M0DATE ], ! THE CHUNK .MHPTR[ M0TIME], .DSKGH, .MHPTR[ M0SOT ]); ! RETURN XWD .DSKGH ! OFFSETT,,DSKGHADDR END; COMMENT; ! 2. FAILSOFT MESSAGE ! == ========== ======= ! CALLING ARGUEMENTS: ! 1) DISK ADDR OF DSKGH ! 2) THE DATE THIS MESSAGE WAS RECEIVED ! 3) THE TIME THIS MESSAGE WAS RECEIVED ! 4) POINTER TO THE CHUNKS OF THE MESSAGE ! 5) START OF TEXT ! RETURNS: LH) 0 ! RH) DISK ADDRESS OF THE MESSAGE ! BLISS CALLING SEQUENCE: IF .FAILSOFTING THEN ! CHKMSG(.DSKADDR,.DATE,.TIME, ! .CHUNKPTR,.SOT) ! FUNCTION: WRITE THE MESSAGE ON A FAILSOFT FILE GLOBAL ROUTINE CHKMSG(DSKGHADDR,DATE,TIME,CHUNKPTR,SOT)= BEGIN DSKMSG( .CHUNKPTR, .DATE, .TIME, .DSKGHADDR, .SOT) END; COMMENT; ! 3. GPURGE ! == ====== ! CALLING ARGUEMENTS: DISK ADDRESS OF THE DSKGH ! RETURNS: 0 ALWAYS ! BLISS CALLING SEQUENCE: GPURGE(.DSKADDR) ! FUNCTION: PURGE THE GROUP FROM THE FAILSOFT/ROLLOUT FILE ON DISK GLOBAL ROUTINE GPURGE(DSKGHADDR)= BEGIN REGISTER DSKMH; DSKMH _ DELDSKGH( .DSKGHADDR, LEAFTYPE); ! DELETE THE DISK GROUP HEADER DPAT(); ! FORCE THE PARTICLE ALLOCATION TABLES TO BE WRITTEN ! NOTE: IF THE SYSTEM CRASHES BEFORE THIS ROUTINE IS ! COMPLETED, THERE WILL BE LOST PARTICLES, BUT ! THE GROUP WILL BE DELETED AS FAR AS DSKGHTAB ! IS CONCERNED. ZAPDSKMHS( .DSKMH); ! KILL ALL THE MESSAGES IN THIS GROUP DPAT(); ! FORCE THE PARTICLE ALLOCATION TABLES TO BE WRITTEN END; COMMENT; ! 4. ROLLIN ! == ====== ! CALLING ARGUEMENTS: 1) DISK ADDRESS OF MESSAGE TO ROLLIN ! 2) THE DISK ADDRESS OF THE GROUP HEADER ! FOR THIS MESSAGE ! RETURNS: POINTER TO FIRST CHUNK OF THE MESSAGE ! BLISS CALLING SEQUENCE: POINTER _ ROLIN(.DSKADDR,.DSKGHADDR) ! FUNCTION: ROLL IN A MESSAGE FROM THE ROLLOUT OR FAILSOFT FILE ! MAKES CHUNKS IN CORE. GLOBAL ROUTINE ROLIN(DSKADDR, DSKGHADDR)= BEGIN OWN DSKMH[PTLSIZE]; STRUCTURE STR[I,J,K] = .STR[.I]<.J,.K>; MAP STR DSKMH; LABEL LOOP; REGISTER J, PTLTOREAD, CHUNKPTR, PTLLEFT; LOCAL FIRST, LAST, AMT, BUFFADDR; MAP FORMAT CHUNKPTR; MAP FORMAT BUFFADDR; MAP FORMAT LAST; MOVE( DREAD( .DSKADDR), DSKMH, PTLSIZE); ! GET THE FIRST DSKMH OF THE MSG TO ROLL IN J _ FIRST _ 0; ! INITALIZE PTLTOREAD _ .DSKMH[DM0RIPTL(.J)]; ! GET RETRIEVAL INFORMATION (RI) PTLLEFT _ .DSKMH[DM0RICOUNT(.J)]; LOOP: REPEAT BEGIN BUFFADDR _ DREAD( .PTLTOREAD); ! READ IN A BUFFER CHUNKPTR _ GETMEM( AMT _ .BUFFADDR[C0WORDS] + C0HEADSIZE); ! GET ROOM FOR THE CHUNK IN CORE MOVE( .BUFFADDR, .CHUNKPTR, .AMT); ! AND MOVE IT INTO CORE IF .FIRST EQL 0 THEN ! IF FIRST CHUNK LAST _ FIRST _ .CHUNKPTR ! SAVE ADDR OF FIRST CHUNK ! AND POINTER TO PREVIOUS ELSE LAST _ LAST[C0LINK] _ .CHUNKPTR; ! ELSE LINK PREVIOUS CHUNK TO THIS ONE IF .CHUNKPTR[C0LINK] EQL 0 THEN LEAVE LOOP; ! IF LAST CHUNK THEN GET OUT OF THIS LOOP ! OTHERWISE GET NEXT PARTICLE TO READ IF (PTLLEFT _ .PTLLEFT - 1) GTR 0 THEN PTLTOREAD _ .PTLTOREAD + 1 ELSE BEGIN J _ .J + 1; SELECT (PTLLEFT _ .DSKMH[DM0RICOUNT(.J)]) OF NSET #777777: BEGIN MOVE( DREAD( .DSKMH[DM0RIPTL(.J)]), DSKMH, PTLSIZE); J _ 0; PTLLEFT _ .DSKMH[DM0RICOUNT(.J)]; PTLTOREAD _ .DSKMH[DM0RIPTL(.J)] END; 0: INFORM ( PAZ 'FRI NOT FOUND@', 0, 0, 0, 0, 0); OTHERWISE: PTLTOREAD _ .DSKMH[DM0RIPTL(.J)]; TESN END END; .FIRST ! RETURN POINTER TO THE FIRST CHUNK END; COMMENT; ! 5. ROLLOUT GROUP HEADER ! == ======= ===== ====== ! FUNCTION: FAILSOFT THE GROUP HEADER, MESSAGE HEADER, RETURN ! DISK ADDRESS. DEALLOCATE THE CORE BELONGING TO THE ! CHUNKS OF THE MESSAGE. GLOBAL ROUTINE ROLGH(LEAFNO, TSN, SENDERID, MHPTR)= BEGIN EXTERNAL DCHNKS; REGISTER FIRSTMH, DSKGH; MAP FORMAT MHPTR; MHPTR[ M0DSKADDR ] _ FIRSTMH _ DSKALL( 1 ); ! ALLOCATE THE FIRST MH OF THE GROUP DSKGH _ STOREDSKGH(.LEAFNO,.FIRSTMH,.TSN,.SENDERID,LEAFDSKTAB,.IBASE); STORENEXTMH( .DSKGH, .FIRSTMH); ! ADD AN ENTRY TO THE NEXTMH TABLE DSKMSG( .MHPTR[ M0INCHNK ],0,0,.DSKGH,.MHPTR[ M0SOT ]); DCHNKS(.MHPTR); ! RETURN THE CHUNKS .DSKGH ! OFFSETT,,DSKGHADDR END; COMMENT; ! 6. ROLLOUT MESSAGE ! == ======= ======= ! CALLING ARGUEMENTS: 1) THE DISK GH ADDRESS ! 2) POINTER TO FIRST CHUNK OF THE MESSAGE ! 3) START OF TEXT ! RETURNS: LH) 0 ! RH) DISK ADDRESS OF THE MESSAGE ! BLISS CALLING SEQUENCE: IF NOT .FAILSOFTING THEN ! DSKADDR _ ROLMSG(.DSKGHADDR,.CHUNKPTR,.SOT) ! FUNCTION: ALLOCATE DISK SPACE, INITIATE DISK WRITE, AND RETURN ! DISK ADDRESS. DEALLOCATE THE CORE BELONGING TO THE ! CHUNKS OF THE MESSAGE. GLOBAL ROUTINE ROLMSG(DSKGHADDR,CHUNKPTR,SOT)= BEGIN REGISTER VALUE, CHNK; MAP FORMAT CHNK; VALUE _ DSKMSG( .CHUNKPTR, 0, 0, .DSKGHADDR, .SOT); CHNK _ .CHUNKPTR; DO DELCHNK(.CHNK) WHILE (CHNK _ .CHNK[ C0LINK ]) NEQ 0; .VALUE END; COMMENT; ! 7. DEFERRED GROUP ROLLOUT ! == ======== ===== ======= ! CALLING ARGUEMENTS: 1) THE LOGICAL TERMINAL NUMBER ! 2) THE DISK ADDRESS OF THE DSKMH ! 3) THE TSN ASSIGNED ! 4) THE SENDER ! RETURNS: DISK GROUP ADDRESS ! BLISS CALLING SEQUENCE: DSKADDR _ DROLGH(.SRCPTR[S0LTTYNO], ! .DSKMHADDR, ! .MHPTR[M0TSN], ! .MHPTR[M0SOT); ! FUNCTION: TO WRITE A DISK GROUP HEADER AND LINK IT TO THE ! DSK DESTINATION POINTER TABLE GLOBAL ROUTINE DROLGH( LTTYNO, DSKMH, TSN, SENDERID)= BEGIN STOREDSKGH( .LTTYNO, .DSKMH, .TSN, .SENDERID, TRMDSKTAB, .OBASE ) ! ENTER INTO FAILSOFT END; COMMENT; ! 8. DEFERRED MESSAGE ROLLOUT ! == ======== ======= ======= ! CALLING ARGUEMENTS: 1) POINTER TO THE FIRST CHUNK OF THE ! MESSAGE ! 2) THE DISK ADDRESS OF THE MESSAGE HEADER ! OF THE LAST MESSAGE ! RETURNS: LH) 0 ! RH) DISK ADDRESS OF THE MESSAGE ! BLISS CALLING SEQUENCE: DSKADDR _ DROLMSG(.CHUNKPTR, ! .DSKMHADDR) ! FUNCTION: ALLOCATE DISK SPACE, INITIATE DISK WRITE, DELETES CHUNKS, ! AND RETURN DISK ADDRESS. GLOBAL ROUTINE DROLMSG(CHUNKPTR, DSKMHADDR)= BEGIN REGISTER NEXT, FIRSTMH, RET; MAP FORMAT CHUNKPTR; RET _ IF .DSKMHADDR EQL 0 THEN BEGIN FIRSTMH _ DSKALL( 1 ); ! ALLOCATE THE FIRST MH OF THE GROUP FIRSTMH _ .FIRSTMH; !WANT ONLY PARTICLE NUMBER STORENEXTMH( .FIRSTMH, .FIRSTMH); ! ADD AN ENTRY TO THE NEXTMH TABLE DSKMSG( .CHUNKPTR, ! FAILSOFT 0, ! THE CHUNK 0, .FIRSTMH, 0 ) END ELSE DSKMSG( .CHUNKPTR, 0, 0, .DSKMHADDR, 0); WHILE .CHUNKPTR NEQ 0 DO BEGIN NEXT _ .CHUNKPTR[C0LINK]; DELCHNK( .CHUNKPTR ); CHUNKPTR _ .NEXT END; .RET END; COMMENT; ! 9. DEFERRED GROUP DELETION ! == ======== ===== ======== ! CALLING ARGUEMENTS: 1) DISK ADDRESS OF GROUP TO DELETE ! 2) SAVE FLAG - IF TRUE THEN DON'T DELETE ! THE MESSAGES OF THIS GROUP ! BECAUSE THEY BELONG TO SOMEONE ELSE ! ALSO ! RETURNS: 0 ALWAYS ! BLISS CALLING SEQUENCE: POINTER _ DGPURGE(.DSKGHADDR,.SAVEFLAG) ! FUNCTION: GLOBAL ROUTINE DGPURGE(DSKGHADDR,SAVEFLAG)= BEGIN REGISTER DSKMH; DSKMH _ DELDSKGH( .DSKGHADDR, TERMINAL ); ! DELETE THE GROUP HEADER DPAT(); ! FORCE THE PARTICLE ALLOCATION TABLES TO BE WRITTEN IF .SAVEFLAG THEN RETURN; ZAPDSKMHS( .DSKMH ); ! THEN DELETE THE MESSAGES DPAT(); ! FORCE THE PARTICLE ALLOCATION TABLES TO BE WRITTEN END; COMMENT; ! AUX ROUTINES ! ROUTINE DSKMSG ! ======= ====== ! THIS ROUTINE WRITES A MESSAGE TO THE DISK. ! IT CREATES A DSKMH, AND WRITES EACH PARTICLE OUT, STORING ! THE PARTICLE'S ADDRESS IN THE DSKMH. WHEN ALL THE PARTICLES ! ARE WRITTEN, THE DSKMH IS ITSELF WRITTEN TO DISK ROUTINE DSKMSG( CHUNKPTR, DATE, TIME, DSKGHADDR, SOT) = BEGIN OWN DSKMH[PTLSIZE]; STRUCTURE STR[I,J,K] = .STR[.I]<.J,.K>; MAP STR DSKMH; LABEL LOOP; REGISTER BUFFADDR, PTLLEFT, J, PTLTOFILL; LOCAL NEXTMH, DSKMHPTL, INDEX, PTLREQ, CHUNK, ENDI, PTLGOTTEN; MAP FORMAT INDEX; MAP FORMAT CHUNK; MAP FORMAT BUFFADDR; MAP FORMAT CHUNKPTR; IF (INDEX _ FINDNEXTMH( .DSKGHADDR)) EQL -1 THEN INFORM( PAZ 'FDSKMSG CALLED BUT NO NEXT GH@',0,0,0,0,0); DSKMHPTL _ .INDEX[ NM0NEXTMH ]; ZERO( DSKMH, DSKMH + PTLSIZE - 1); DSKMH[DM0DATE] _ .DATE; DSKMH[DM0TIME] _ .TIME; DSKMH[DM0DSKGHADDR] _ .DSKGHADDR; DSKMH[DM0SOT] _ .SOT; PTLREQ _ 0; CHUNK _ .CHUNKPTR; WHILE .CHUNK NEQ 0 DO BEGIN PTLREQ _ .PTLREQ + 1; ENDI _ .CHUNK[ C0ENDI]; CHUNK _ .CHUNK[C0LINK] END; DSKMH[DM0ENDI] _ .ENDI; IF .ENDI GEQ EGI THEN BEGIN INDEX[ NM0GHADDR ] _ INDEX[ NM0NEXTMH ] _ NEXTMH _ 0 END ELSE BEGIN NEXTMH _ INDEX[ NM0NEXTMH ] _ DSKALL( 1 ); END; J _ PTLLEFT _ BUFFADDR _ 0; WHILE .CHUNKPTR NEQ 0 DO BEGIN ! GET PTL TO FILL IF (PTLLEFT _ .PTLLEFT - 1) GTR 0 THEN PTLTOFILL _ .PTLTOFILL + 1 ELSE BEGIN LOOP: REPEAT BEGIN PTLGOTTEN _ DSKALL( .PTLREQ); PTLLEFT _ .PTLGOTTEN; PTLTOFILL _ .PTLGOTTEN; PTLREQ _ .PTLREQ - .PTLLEFT; IF .J EQL LASTRI AND .PTLREQ NEQ 0 THEN BEGIN DSKMH[DM0RICOUNT(.J)] _ -1; DSKMH[DM0RIPTL(.J)] _ .PTLTOFILL; PTLREQ _ .PTLREQ + .PTLLEFT; BUFFADDR _ DGET( .DSKMHPTL); MOVE( DSKMH, .BUFFADDR, PTLSIZE); DWRITE( .BUFFADDR, .DSKMHPTL); ZERO( DSKMH + FIRSTRI, DSKMH + PTLSIZE - 1); !ZAP RI'S IN NEW DSKMH DSKMHPTL _ PTLTOFILL; IF .PTLLEFT GTR 1 THEN DSKDEA(.PTLLEFT-1,.PTLTOFILL+1); J _ 0 END ELSE BEGIN DSKMH[DM0RI(.J)] _ .PTLGOTTEN; J _ .J + 1; LEAVE LOOP END END END; ! GOT PTL TO FILL BUFFADDR _ DGET( .PTLTOFILL); ! GET THE BUFFER TO STUFF MOVE( .CHUNKPTR, .BUFFADDR, .CHUNKPTR[C0WORDS] + C0HEADSIZE); ! AND STUFF AWAY DWRITE( .BUFFADDR, .PTLTOFILL); ! THEN SEND IT OUT CHUNKPTR _ .CHUNKPTR[C0LINK] END; DSKMH[DM0NEXTMH] _ .NEXTMH; BUFFADDR _ DGET( .DSKMHPTL); MOVE( DSKMH, .BUFFADDR, PTLSIZE); DWRITE( .BUFFADDR, .DSKMHPTL); IF .NEXTMH NEQ 0 THEN !IF AWAITING MORE INPUT BEGIN BUFFADDR _ DGET(.NEXTMH); !GET THE NEXT MH PARTICLE ZERO(.BUFFADDR, .BUFFADDR + PTLSIZE -1); !AND CLEAR IT DWRITE(.BUFFADDR, .NEXTMH) !CAUSE IT'S REALLY EMPTY END; DPAT(); !FORCE OUT FAILSOFT FILE .DSKMHPTL END; COMMENT; ! ROUTINE ZAPDSKMHS ! ======= ========= ! THIS ROUTINE DELETES ALL THE MESSAGES OF A GIVEN HEAD MH ROUTINE ZAPDSKMHS( DSKMH) = BEGIN REGISTER BUFFADDR, NEXTMH, PREVMH; LOCAL COUNT; MAP FORMAT BUFFADDR; LABEL LOOP, BIGLOOP; BUFFADDR _ DREAD(.DSKMH); ! MAKE SURE THE BUFFER IS STILL AVAILABLE NEXTMH _ .BUFFADDR[DM0NEXTMH]; ! SAVE THE NEXT ONE TO GET BIGLOOP: REPEAT ! FOR EACH DSKMH IN THIS GROUP BEGIN LOOP: INCR RI FROM 0 TO LASTRI DO ! ZAP ALL THE CHUNKS IN EACH BEGIN SELECT (COUNT _ .BUFFADDR[DM0RICOUNT( .RI)] ) OF NSET #777777: BEGIN ! IF EXTENDED DSKMH, PICK UP THE EXTENSION PREVMH _ .DSKMH; DSKMH _ .BUFFADDR[DM0RIPTL(.RI)]; BUFFADDR _ DREAD( .DSKMH); DSKDEA( 1, .PREVMH); RI _ -1 ! RESTART THE INCR LOOP END; 0: LEAVE LOOP; ! IF NONE LEFT THEN DONE ! ALSO DONE IF INCR LOOP FINISHES OTHERWISE: DSKDEA( .COUNT, .BUFFADDR[DM0RIPTL(.RI)]); ! IF NORMAL RI THEN ZAP THE CHUNKS/PARTICLES TESN END; DSKDEA( 1, .DSKMH); ! ZAP THE DSKMH IF (DSKMH _ .NEXTMH) EQL 0 THEN LEAVE BIGLOOP; ! IF OUT OF DSKMH'S THEN DONE BUFFADDR _ DREAD( .DSKMH); ! OTHERWISE TRY ANOTHER NEXTMH _ .BUFFADDR[DM0NEXTMH] END END; COMMENT; ! ROUTINE STOREDSKGH ! ======= ========== ! THIS ROUTINE PUTS AN ENTRY INTO THE DSKGHTAB OF THE TABLE. ROUTINE STOREDSKGH( LOFFSET, MHPTR, TSN, SENDERID, GHTABLE, BASEPTL ) = BEGIN MACRO STOREARGS(X) = BUFFADDR[DG0MH( X)] _ .MHPTR; BUFFADDR[DG0TSN( X)] _ .TSN; BUFFADDR[DG0SENDER( X)] _ .SENDERID$; MACRO MAKENEW( LINKS, LOFFSET ) = BEGIN BUFFADDR _ DGET(DSKALL(1)); ! GET A PARTICLE FOR A DSKGH ZERO( .BUFFADDR, .BUFFADDR + PTLSIZE - 1); ! ZERO IT BUFFADDR[DG0LINKS] _ LINKS; ! STORE THE FORWARD AND REVERSE LINKS BUFFADDR[DG0LEAF] _ LOFFSET; ! STORE A POINTER TO THE OWNER STOREARGS(1); ! STORE THE INFO ABOUT THE CORE GH DWRITE( .BUFFADDR, .BUFFADDR); ! WRITE IT OUT (.GHTABLE + LOFFSET) _ .BUFFADDR; ! SAVE THE PTL NUMBER J _ 1; ! AND MARK THE OFFSET IN THE PTL AS ONE .BUFFADDR ! RETURN THE PARTICLE NUMBER END$; REGISTER BUFFADDR, J, PTL, LAST; LOCAL LINKS, RET; MAP FORMAT BUFFADDR; ! BEGIN ! IF .(.GHTABLE + .LOFFSET) EQL 0 THEN ! IS THERE ALREADY A DSKGH BEGIN ! *NO* THEN PTL _ MAKENEW( 0, .LOFFSET); ! MAKE A DSKGH BUFFADDR _ DREAD( .BASEPTL + .LOFFSET / LEAFPERPTL); !PUT IT IN THE DISK LEAF POINTER TABLE BUFFADDR[DD0LEAF((.LOFFSET MOD LEAFPERPTL))] _ .PTL; ! ... DWRITE( .BUFFADDR, .BUFFADDR) ! ... END ELSE BEGIN ! *YES* ALREADY A DSKGH IF ( J _ .(.GHTABLE + .LOFFSET)) EQL 0 THEN ! ANY ROOM LEFT IN IT BEGIN ! *NO* LINKS _ 0; ! MAKE NEW LINKAGE LAST _ LINKS _ .(.GHTABLE + .LOFFSET); ! GET PTL NUMBER OF LAST DSKGH PTL _ MAKENEW( .LINKS, .LOFFSET); ! MAKE A NEW DSKGH BUFFADDR _ DREAD( .LAST); ! READ THE OLD ONE BUFFADDR[ DG0NEXT] _ .PTL; ! LINK THE OLD TO THE NEW DWRITE( .BUFFADDR, .LAST) ! WRITE THE OLD END ELSE BEGIN ! *YES* ROOM LEFT IN THE DSKGH BUFFADDR _ DREAD( PTL _ .(.GHTABLE + .LOFFSET)); ! READ THE OLD DSKGH STOREARGS(.J); ! STORE WHAT WE'RE HERE TO SAVE DWRITE( .BUFFADDR, .BUFFADDR) ! WRITE THE OLD DSKGH END END; RET _ .J; RET _ .PTL; (.GHTABLE + .LOFFSET) _ IF (J _ .J + 1) GTR DG0MAX THEN 0 ELSE .J; ! STORE THE NEXT AVAILABLE SLOT ( IF ANY ) ! IN THE DSKGH DPAT(); !FORCE OUT DSKGHTABLE .RET END; COMMENT; ! ROUTINE DELDSKGH ! ======= ========= ! THIS ROUTINE REMOVES AN ENTRY FROM THE LEAFGHTAB OR TRMGHTAB AND CLEANS ! UP AS REQUIRED GLOBAL ROUTINE DELDSKGH( PAIR, WHICHTAB ) = BEGIN REGISTER BUFFADDR, PREV, NEXT; MAP FORMAT BUFFADDR; LABEL LOOP; LOCAL OFFSETT, GH, PTL, DSKMH, LEAFNO; ! SPLIT PAIR INTO PTL AND INDEX INTO PTL PTL _ .PAIR; OFFSETT _ .PAIR; BUFFADDR _ DREAD( .PTL); ! READ THE DSKGHTAB PARTICLE DSKMH _ .BUFFADDR[DG0MH( .OFFSETT)]; ! GET THE POINTER TO THE DSKMH GH _ BUFFADDR[DG0ENTRY( .OFFSETT)]; ! GET A POINTER TO THE ENTRY WE ARE INTERESTED IN ZERO( .GH, .GH + DG0SIZE - 1); ! AND ZAP IT IF ! SEE IF THE WHOLE PARTICLE IS ZERO LOOP: BEGIN INCR I FROM BUFFADDR[DG0ENTRY(1)] TO BUFFADDR[DG0ENTRY(DG0MAX)] DO IF @@I NEQ 0 THEN LEAVE LOOP WITH TRUE; FALSE END THEN RETURN( DWRITE( .BUFFADDR, .PTL); .DSKMH ); ! IF NOT ALL ZERO REWRITE IT AND EXIT NEXT _ .BUFFADDR[DG0NEXT]; PREV _ .BUFFADDR[DG0PREV]; IF .NEXT EQL 0 THEN ! NEVER REMOVE THE LAST TABLE BEGIN IF .WHICHTAB EQL TERMINAL THEN TRMDSKTAB[ .BUFFADDR[DG0LEAF]] _ 1 ^ 18 + .PTL ELSE LEAFDSKTAB[ .BUFFADDR[DG0LEAF]] _ 1 ^ 18 + .PTL; RETURN( DWRITE( .BUFFADDR, .PTL); .DSKMH ) END; IF .PREV NEQ 0 THEN BEGIN BUFFADDR _ DREAD( .PREV); BUFFADDR[ DG0NEXT] _ .NEXT; DWRITE( .BUFFADDR, .PREV) END ELSE BEGIN LEAFNO _ .BUFFADDR[ DG0LEAF ]; IF .WHICHTAB EQL TERMINAL THEN BEGIN BUFFADDR _ DREAD( .OBASE + .LEAFNO / LEAFPERPTL); BUFFADDR[DD0LEAF((.LEAFNO MOD LEAFPERPTL))] _ .NEXT; DWRITE( .BUFFADDR, .BUFFADDR) END ELSE BEGIN BUFFADDR _ DREAD( .IBASE + .LEAFNO / LEAFPERPTL); BUFFADDR[DD0LEAF((.LEAFNO MOD LEAFPERPTL))] _ .NEXT; DWRITE( .BUFFADDR, .BUFFADDR) END END; IF .NEXT NEQ 0 THEN BEGIN BUFFADDR _ DREAD( .NEXT); BUFFADDR[DG0PREV] _ .PREV; DWRITE( .BUFFADDR, .NEXT) END; DSKDEA( 1, .PTL); ! AND DEALLOCATE IT .DSKMH END; COMMENT; OWN NEXTMHTAB; ! ROUTINE STORENEXTMH ! ======= =========== ! THIS ROUTINE FINDS AN AVAILABLE LOCATION IN THE NEXTMHTABLE ! AND STORE THE VALUE GIVEN THERE ROUTINE STORENEXTMH( DSKGHADDR, MHPTR ) = BEGIN REGISTER ADDR; MAP FORMAT ADDR; IF (ADDR _ FINDNEXTMH(.DSKGHADDR)) NEQ -1 THEN BEGIN ADDR[NM0NEXTMH] _ .MHPTR; RETURN END; IF (ADDR _ .NEXTMHTAB) EQL 0 THEN ! IF NO TABLE YET THEN BEGIN ADDR _ NEXTMHTAB _ GETMEM( NM0SIZE); ! MAKE SOME ROOM ZERO( .ADDR, .ADDR + NM0SIZE - 1); ! AND ZAP IT ADDR[NM0END0] _ -1; ! MARK THE END ADDR[NM0END1] _ -1; ! MARK THE END ADDR[NM0GHADDR] _ .DSKGHADDR; ! STORE WHAT WE WANTED ADDR[NM0NEXTMH] _ .MHPTR; ! SAVE MH'S RETURN ! ALL DONE FOR NOW END; REPEAT ! IF WE HAVE A TABLE ALREADY THEN BEGIN ! UNTIL WE FIND A PLACE TO PUT THE DSKGHADDR GO SELECT .ADDR[NM0GHADDR] OF NSET -1: IF .ADDR[NM0NEXTMH] EQL #777777 THEN ! IF END OF TABLE THEN BEGIN ADDR _ ADDR[NM0NEXTMH] _ GETMEM( NM0SIZE); ! MAKE SOME ROOM ZERO( .ADDR, .ADDR + NM0SIZE - 1); ! AND ZAP IT ADDR[NM0END0] _ -1; ! MARK THE END ADDR[NM0END1] _ -1; ! MARK THE END ADDR[NM0GHADDR] _ .DSKGHADDR; ! STORE WHAT WE WANTED ADDR[NM0NEXTMH] _ .MHPTR; ! SAVE MH'S RETURN ! ALL DONE FOR NOW END ELSE ADDR _ .ADDR[NM0NEXTMH]; !STEP TO NEXT TABLE 0: ( ADDR[NM0GHADDR] _ .DSKGHADDR; ADDR[NM0NEXTMH] _ .MHPTR; ! SAVE MH'S RETURN); ! FOUND A PLACE SO STORE WHAT WE WANTED OTHERWISE: ADDR _ .ADDR + NM0ENTRYSIZE; ! OTHERWISE TRY THE NEXT LOCATION TESN END END; COMMENT; ! ROUTINE FINDNEXTMH ! ======= ========== ! THIS ROUTINE IS USED TO SEARCH THE NEXTMHTAB TO FIND THE NEXT ! DSKMH TO USE FOR THE GROUP WHOSE DSKMH IS PROVIDED. ! RETURNS: INDEX INTO THE NEXTMH TABLE ROUTINE FINDNEXTMH( DSKGHADDR) = BEGIN REGISTER ADDR, GHADDR; MAP FORMAT ADDR; GHADDR _ .DSKGHADDR; ! PUT THE DSKGHADDR IN A REGISTER FOR SPEED IF (ADDR _ .NEXTMHTAB) EQL 0 THEN RETURN -1; ! ERROR RETURN (NO TABLE) REPEAT ! UNTIL MATCH OR END OF TABLE DO BEGIN SELECT .ADDR[NM0GHADDR] OF NSET -1: IF (ADDR _ .ADDR[NM0NEXTMH]) EQL #777777 THEN RETURN -1; ! OOPS END OF TABLE .GHADDR: RETURN .ADDR; ! JUST WHAT WE WANTED OTHERWISE: ADDR _ .ADDR + NM0ENTRYSIZE; ! TRY ANOTHER TESN END END; COMMENT; ! THIS FILE CONTAINS THE ROUTINES USED TO WRITE THE LOG OR AUDIT ! FILES. THESE ROUTINES TAKE RELATIVELY COMPLEX CALLS AND ! BREAK THEM DOWN INTO PRIMATIVE WRITE WORD AND WRITE VECTOR FOR KERNEL ! CALLS COMMENT; ! 1. INLOGMSG ! == ======== ! CALLING ARGUEMENTS: 1) THE TRANSACTION SEQUENCE NUMBER OF ! THE MESSAGE (ONE WORD) ! 2) THE DATE THIS MESSAGE WAS RECEIVED ! (ONE WORD, EQUIVALENT OF RESULT OF ! DATE UUO) ! 3) THE TIME THIS MESSAGE WAS RECEIVED ! (ONE WORD, EQUIVALENT OF RESULT OF ! MSTIME UUO) ! 4) POINTER TO THE LOGICAL NAME OF THE ! TERMINAL WHO SENT THIS MESSAGE ! (THE LEFT HALF OF THE GLOBAL SYMBOL ! SRCTAB CONTAINS THE MAXIMUM NUMBER OF ! CHARACTERS IN A LOGICAL SOURCE NAME) ! 5) POINTER TO THE TRANSACTION CODE OF ! THE MESSAGE (TRCODELENGTH WILL BE ! A GLOBAL SYMBOL WHICH CONTAINS THE ! MAXIMUM LENGTH OF A TRANSACTION CODE) ! 6) A POINTER TO THE FIRST CHUNK OF THE ! MESSAGE ! RETURNS: 0 ALWAYS ! BLISS CALLING SEQUENCE: IF .INLOGGING THEN INLOGMSG(.TSN,.DATE, ! .TIME,.SENDERID,.TRCODEPTR,.CHUNKPTR) ! FUNCTION: WRITE THE LOG FILE (IF THE USER HAS REQUESTED IT AND ! THE LOGGING DEVICE IS AVAILABLE) ! THE FORMAT OF A LOG FILE RECORD: ! WORD 1: -1 ! WORD 2: WORD COUNT OF THE WORDS IN THIS RECORD (M+1) ! WORD 2: CHECKSUM OF THE WORDS IN THIS RECORDS (EXCLUDING THE CHECKSUM WORDS) ! WORD 3: TRANSACTION SEQUENCE NUMBER OF THIS MESSAGE ! WORD 4: DATE OF THIS MESSAGE ! WORD 5: TIME THIS MESSAGE WAS RECEIVED ! WORDS 6 THRU 8: ! SOURCE TERMINAL NAME ! WORD 9: SIZE OF THE TRANSACTION CODE FIELD ! WORD 10 THRU WORD (10 + CONTENTS OF WORD 9): ! THE TRANSACTION CODE OF THIS MESSAGE ! WORD (11 + CONTENTS OF WORD 9): ! THE NUMBER OF CHUNKS TO FOLLOW ! WORD (12+CONTENTS OF WORD 9) THRU WORD M ! THE CHUNKS OF THIS MESSAGE ! (M DEPENDS ON THE LENGTH AND NUMBER OF THE CHUNKS) ! WORD M+1: -1 GLOBAL ROUTINE INLOGMSG(TSN,DATE,TIME,SENDERPTR,TRCODEPTR,CHUNKPTR)= BEGIN REGISTER CHUNK, COUNT, CHUNKCOUNT; MAP FORMAT CHUNKPTR; MAP FORMAT CHUNK; COUNT _ 11 + .TRCW; ! LENGTH OF RECORD IS 11 + TRANSACTION CODE LENGTH + MSG LENGTHS CHUNKCOUNT _ 0; CHUNK _ .CHUNKPTR; DO BEGIN CHUNKCOUNT _ .CHUNKCOUNT + 1; COUNT _ .COUNT + ( .CHUNK[C0WORDS] + C0HEADSIZE ) END WHILE (CHUNK _ .CHUNK[C0LINK]) NEQ 0; INAUDW( -1 ); INAUDW(.COUNT); INAUDW(.TSN); INAUDW(.DATE); INAUDW(.TIME); INAUDVECTOR( .SENDERPTR, SRCNAMLEN); ! OUTPUT THE SENDER ID. INAUDW( .TRCLEN ); ! WRITE THE TRANSACTION CODE LENGTH SELECT .TRCODEPTR OF NSET 0: DECR I FROM .TRCW - 1 TO 0 DO INAUDW(0); #777777: DECR I FROM .TRCW - 1 TO 0 DO INAUDW(.(PAZ '??????????')); OTHERWISE: INAUDVECTOR(.TRCODEPTR,.TRCW); TESN; INAUDW( .CHUNKCOUNT ); DO BEGIN INAUDVECTOR(.CHUNKPTR, .CHUNKPTR[C0WORDS] + C0HEADSIZE) END WHILE (CHUNKPTR _ .CHUNKPTR[C0LINK]) NEQ 0; INAUDW( -1 ); ! OUTPUT THE FINAL -1 END; ! END OF INLOGMSG COMMENT; ! 2. OUTLOGMSG ! == ========= ! CALLING ARGUEMENTS: 1) THE TRANSACTION SEQUENCE NUMBER OF ! THE MESSAGE ! 2) THE DATE THIS MESSAGE WAS SENT ! 3) THE TIME THIS MESSAGE WAS SENT ! 4) POINTER TO THE MESSAGE CLASS OF THIS ! MESSAGE IN THE LIBOL-MCS PAGE (THE ! MESSAGE CLASS IS ALWAYS EIGHT ! CHARACTERS LONG) ! 5) THE JSN OF THE JOB WHICH SENT ! THIS MSG ! 6) THE DESTINATION COUNT ! 7) POINTER TO THE DESTINATION TABLE IN ! THE LIBOL-MCS COMMUNICATIONS PAGE ! (SEE THE LIBOL SPEC FOR THE FORMAT) ! THIS PAGE CONTAINS THE LOGICAL ! DESTINATION NAMES. ! 8) A POINTER TO THE FIRST CHUNK OF THE ! MESSAGE ! RETURNS: 0 ALWAYS ! BLISS CALLING SEQUENCE: IF .OUTLOGGING THEN OUTLOGMSG(.TSN, ! .DATE,.TIME,.MSGCLASS,.JSN, ! .DESTCNT,.DESTTAB,.CHUNKPTR) ! FUNCTION: WRITE THE LOG FILE (IF THE USER HAS REQUESTED IT AND ! THE LOGGING DEVICE IS AVAILABLE) ! THE FORMAT OF A LOG FILE RECORD: ! WORD 1: -1 ! WORD 2: WORD COUNT OF THE WORDS IN THIS RECORD ! WORD 3: TRANSACTION SEQUENCE NUMBER OF THIS MESSAGE ! WORD 4: DATE OF THIS MESSAGE ! WORD 5: TIME THIS MESSAGE WAS RECEIVED ! WORD 6 THRU WORD 7: ! MESSAGE CLASS ! WORD 8 AND 9: DEVICE NAME (ASCIZ) ! WORD 10 AND 11: FILE NAME (ASCIZ) ! WORD 12: PPN (HALF WORD PAIR) ! WORD 13: A COUNT OF THE NUMBER OF DESTINATIONS ( CALL THE ! CONTENTS OF THIS WORD N) ! WORD 14 THRU WORD 14+N*3: ! DESTINATION NAMES ! WORD 15+N*3: ! THE NUMBER OF CHUNKS TO FOLLOW ! WORD 16+N*3 THRU WORD M: ! THE CHUNKS OF THIS MESSAGE ! (M DEPENDS ON THE LENGTH AND NUMBER OF THE CHUNKS) ! WORD M+1: -1 ! NOTE: THE TWO TYPES OF LOGS ARE DISTINGUISHABLE BECAUSE THE ! TRANSACTION SEQUENCE NUMBER OF AN INPUT MESSAGE HAS A ! ZERO RIGHT HALF, AND AN OUTPUT MESSAGE HAS A NON-ZERO ! RIGHT HALF GLOBAL ROUTINE OUTLOGMSG(TSN,DATE,TIME,MSGCLASSPTR,JSN,DESTCOUNT,DESTTABPTR,CHUNKPTR)= BEGIN EXTERNAL ?JB$MPP; ! CONTAINS A POINTER TO THE MPP PROTOTYPE ! INDEXED BY THE JSN BIND DEV = 1, NAME = 3, PPN = 5, DEBUGMPP = PLIT( 0, ! DEBUGGING MPP'S JUST GET THIS IN THE JOURNAL NOW 0, 0, 'DEBUG', 0, 0 ); REGISTER COUNT, CHUNKCOUNT, PROTOBLOCK, CHUNK; MAP FORMAT CHUNKPTR; MAP FORMAT CHUNK; IF (PROTOBLOCK _ .?JB$MPP[.JSN] ) EQL 0 THEN PROTOBLOCK _ DEBUGMPP; COUNT _ 15 + ( .DESTCOUNT * 3 ); ! RECORD LENGTH IS 15 + DESTINATION TABLE SIZE + MSG LENGTHS CHUNKCOUNT _ 0; IF ( CHUNK _ .CHUNKPTR ) NEQ 0 THEN DO BEGIN CHUNKCOUNT _ .CHUNKCOUNT + 1; COUNT _ .COUNT + ( .CHUNK[C0WORDS] + C0HEADSIZE ) END WHILE (CHUNK _ .CHUNK[C0LINK]) NEQ 0; OTAUDW( -1 ); OTAUDW(.COUNT); OTAUDW(.TSN); OTAUDW(.DATE); OTAUDW(.TIME); OTAUDVECTOR( .MSGCLASSPTR, 2); ! OUTPUT MESSAGE CLASS OTAUDVECTOR( (.PROTOBLOCK)[DEV], 2); ! OUTPUT THE MPPSPEC OTAUDVECTOR( (.PROTOBLOCK)[NAME], 2); OTAUDW( .(.PROTOBLOCK)[PPN]); OTAUDW( .DESTCOUNT ); OTAUDVECTOR( .DESTTABPTR, .DESTCOUNT * 3); ! OUTPUT THE DESTTAB OTAUDW( .CHUNKCOUNT ); IF .CHUNKPTR NEQ 0 THEN DO BEGIN OTAUDVECTOR( .CHUNKPTR, .CHUNKPTR[C0WORDS] + C0HEADSIZE ) END WHILE (CHUNKPTR _ .CHUNKPTR[C0LINK]) NEQ 0; OTAUDW( -1 ) END; ! END OF OUTLOGMSG END;