!***COPYRIGHT (C) 1974, 1975, 1976, 1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.*** MODULE MSGIN(RESERVE(#11,#12,#13,#14),SREG=#17,FREG=#16,DREGS=4, VREG=#15,MLIST,TIMER=EXTERNAL(SIX12),FSAVE)= BEGIN GLOBAL WHYERROR; !ERROR CODES FOR ENTRY INTO THE ERROR LEAF REQUIRE DATA.BLI; !EVERYONE NEEDS THIS NEAT THING!! EXTERNAL COMPARE, UNLINK, MOVE; COMMENT; ! ROUTINE SKIPCHUNKS ! ======= ========== ! THIS ROUTINE SKIPS THE SPECIFIED NUMBER OF CHARACTERS GIVEN. IT ! WILL ADVANCE CHUNKS AS REQUIRED TO ACCOMPLISH THIS. ! CALLED WITH 1) POINTER TO FIRST CHUNK ! 2) NUMBER OF CHARACTERS TO SKIP ! 3) FLAG INDICATING WHETHER SKIPPED CHUNKS ARE TO BE DELETED ! RETURNS: LH) CHARACTERS UNSKIPPED IN THIS CHUNK (READY FOR INPUT TO MAKEBP) ! RH) CHUNKPTR ! BOTH 0 IF WE RUN OFF THE END GLOBAL ROUTINE SKIPCHUNKS( CHUNKPTR, COUNT, FLAG) = BEGIN REGISTER C, CHUNK; MAP FORMAT CHUNK; C _ .COUNT; ! PUT ARGS IN REGISTERS CHUNK _ .CHUNKPTR; WHILE .C GTR .CHUNK[C0BCNT] AND .CHUNK NEQ 0 DO BEGIN C _ .C - .CHUNK[C0BCNT]; IF .FLAG THEN DELCHNK(.CHUNK); CHUNK _ .CHUNK[C0LINK] END; IF .CHUNK NEQ 0 THEN ! IF WE DIDN'T GO OFF THE END BEGIN CHUNK _ .C; ! RETURN XWD COUNT, CHUNKPTR RETURN .CHUNK END; 0 ! ELSE RETURN BAD END END; COMMENT; ! ROUTINE MAKEBP ! ======= ====== ! THIS ROUTINE MAKES A BYTE POINTER GIVEN A CHUNKPTR AND THE NUMBER OF ! CHARACTERS TO SKIP ! CALLED WITH: 1) POINTER TO THE CHUNK ! 2) CHARACTERS TO SKIP ! RETURNS: A BYTE POINTER TO THE FIRST CHARACTER AFTER THE SKIP ! NOTE: THE CHARACTER MUST BE IN THE CHUNK GIVEN. GLOBAL ROUTINE MAKEBP( CHUNKPTR, COUNT) = BEGIN MAP FORMAT CHUNKPTR; REGISTER OUT; OUT _ 0; OUT _ ASCIISIZE; OUT _ 36 - (.COUNT MOD ASCIIBYTESPERWORD ) * ASCIISIZE; OUT _ CHUNKPTR[C0DATA] + .COUNT / ASCIIBYTESPERWORD; .OUT END; COMMENT; ! ROUTINE TC ! ======= == ! TC PICKS THE TRANSACTION CODE OUT OF THE MESSAGE ROUTINE TC( MHPTR, SRCPTR)= BEGIN REGISTER CHAR, COUNT, BPIN, BPOUT; LOCAL TRCODE, CHUNKPTR, CHARLEFT; MAP FORMAT MHPTR; MAP FORMAT CHUNKPTR; MAP FORMAT SRCPTR; MACRO NEXTCHAR = BEGIN WHILE ( CHARLEFT _ .CHARLEFT - 1 ) LSS 0 DO ! IF NO CHARACTERS LEFT ! IN THIS CHUNK GET ANOTHER BEGIN IF ( CHUNKPTR _ .CHUNKPTR[C0LINK]) EQL 0 THEN RETURN (RETMEM ( .TRCODE, .TRCW ); -1); BPIN _ CHUNKPTR[C0DATA]; BPIN _ 36; CHARLEFT _ .CHUNKPTR[C0BCNT] END; CHAR _ SCANI(BPIN); IF .CHAR GEQ #141 AND .CHAR LEQ #172 THEN CHAR _ .CHAR - #40 ELSE .CHAR END$, STORECHAR = (REPLACEI(BPOUT, .CHAR))$; CHUNKPTR _ .MHPTR[M0INCHNK]; TRCODE _ GETMEM(.TRCW); ! GET ROOM TO STORE A TRANSACTION CODE ZERO( .TRCODE, .TRCODE + .TRCW - 1); ! CLEAR THE TRANSACTION CODE FIELD IF ( CHUNKPTR _ SKIPCHUNKS( .CHUNKPTR, .FILLRB, FALSE)) EQL 0 THEN RETURN (RETMEM ( .TRCODE, .TRCW ); -1); COUNT _ .CHUNKPTR; BPIN _ MAKEBP( .CHUNKPTR, .COUNT); ! MAKE THE INPUT BYTE POINTER BPOUT _ (.TRCODE)<36,7>; ! AND THE OUTPUT BYTE POINTER CHARLEFT _ .CHUNKPTR[C0BCNT] - .COUNT; COUNT _ 0; IF .TRCDEL NEQ 0 THEN BEGIN WHILE (( COUNT _ .COUNT + 1) LEQ .TRCLEN) AND (NEXTCHAR NEQ .TRCDEL) DO STORECHAR; IF .COUNT LEQ .TRCLEN THEN COUNT _ .COUNT + 1; END ELSE BEGIN WHILE ( COUNT _ .COUNT + 1) LEQ .TRCLEN DO BEGIN NEXTCHAR; STORECHAR END END; SRCPTR[S0SOT] _ .FILLRB + .FILLRC + .COUNT - 1; .TRCODE END; COMMENT; ! ROUTINE DECODE ! ======= ====== ROUTINE DECODE(MHPTR,SRCPTR)= BEGIN REGISTER TCPTR, TCTAB, TCWORDS; LOCAL LEAFADDR, LEAF; MAP FORMAT LEAFADDR; MAP FORMAT MHPTR; MAP FORMAT SRCPTR; MACRO ERROR = RETURN -1 ^ 18 OR$; LABEL THIS; IF ( TCPTR _ TC(.MHPTR, .SRCPTR) ) EQL -1 THEN BEGIN WHYERROR _ 3; !ERROR = UNKNOWN TRCODE ERROR ERLEAF END; TCTAB _ TRCODE; TCWORDS _ .TRCW; LEAF _ BEGIN THIS: INCR COUNT FROM 0 TO .TRCODE[-1] - 1 DO BEGIN IF COMPARE(.TCPTR, .TCTAB, .TCWORDS) THEN LEAVE THIS WITH .COUNT; TCTAB _ .TCTAB + .TCWORDS END END; RETMEM( .TCPTR, .TCWORDS); ! GIVE BACK THE MEMORY TC GOT IF .LEAF LSS 0 THEN BEGIN WHYERROR _ 3; !ERROR = UNKNOWN TRCODE ERROR ERLEAF END ELSE BEGIN LEAFADDR _ .LFADDR[.LEAF]; IF .SRCPTR[S0LFSTS(.LEAFADDR[N0LLFNO],2)] NEQ 0 THEN BEGIN WHYERROR _ 4; !ERROR = DISABLED TERMINAL ERROR ERLEAF END ELSE IF .LEAFADDR[N0ED] THEN BEGIN WHYERROR _ 4; !ERROR = DISABLED AT LEAF ERROR ERLEAF END END; LEAFADDR _ .LEAF; .LEAFADDR END; EXTERNAL UNLINK, LINK, DECREMENT, INSERT, CHKRUN, NEXTINTSN, BUILD, DCHNKS, INLOGMSG, CHKGH, CHKMSG, ROLMSG, FINDPORT, SONLEAF, ERLEAF; COMMENT; !LAST MODIFIED: 30 JUL 76 BY CDO ! ROUTINE MSREAD ! ======= ====== ! CALLED WHEN THERE IS A BUFFER TO READ ! RETURNS TRUE IF EVERYTHING NORMAL ! FALSE IF SOMETHING WAS WRONG GLOBAL ROUTINE MSREAD = BEGIN REGISTER CHUNKPTR, SRCPTR, MHPTR, GHPTR; LOCAL COUNT, MPPPTR, LEAFPTR, PORT, TEMP, UDX, TRCODEINDEX, ENDI; MAP FORMAT CHUNKPTR; MAP FORMAT SRCPTR; MAP FORMAT PORT; MAP FORMAT TEMP; MAP FORMAT MHPTR; MAP FORMAT LEAFPTR; MAP FORMAT GHPTR; MAP FORMAT LFTAB; MACRO PURGEFLAG = SRCPTR[S0PURGE]$; !BEGIN! ! GET A CHUNK ! IF THERE ISN'T ONE TO GET THEN RETURN WITH A FALSE VALUE IF (CHUNKPTR _ INMSG()) EQL 0 THEN RETURN FALSE; ! BREAK UP THE VALUE RETURNED BY INMSG INTO ITS COMPONENTS UDX _ .CHUNKPTR; CHUNKPTR _ .CHUNKPTR; CHUNKPTR[C0LINK] _ 0; ! MAKE SURE THE LINK IS ZERO ! GET THE END INDICATOR ENDI _ .CHUNKPTR[C0ENDI]; ! FIND OUT WHO THE CHUNK COMES FROM SRCPTR _ 0; IF ( PORT _ FINDPORT( .UDX) ) NEQ 0 THEN IF ( SRCPTR _ .PORT[PT0SRCPTR] ) EQL 0 THEN SRCPTR _ .PORT[PT0TMPSRCPTR]; PORT[PT0CARRIER] _ TRUE; !DATA IMPLIES CARRIER IF .SRCPTR EQL 0 THEN BEGIN RETMEM(.CHUNKPTR,.CHUNKPTR[C0WORDS]+C0HEADSIZE); ! IF THE SENDER IS UNKNOWN ZAP THE CHUNK RETURN FALSE ! AND RETURN FALSE END; ! IF WE ARE PURGING MESSAGES FROM THIS SOURCE THEN SEE IF WE ! SHOULD STOP PURGING. BUT IN ANYCASE RETURN THE CHUNK TO FREE ! CORE IF .PURGEFLAG THEN BEGIN IF .ENDI GEQ EGI THEN PURGEFLAG _ FALSE; RETMEM(.CHUNKPTR,.CHUNKPTR[C0WORDS]+C0HEADSIZE); SRCPTR[S0TSN] _ SRCPTR[S0GHPTR] _ 0; RETURN TRUE END; ! IF TSN NOT ALREADY ASSIGNED THEN GET ONE IF .SRCPTR[S0TSN] EQL 0 THEN SRCPTR[S0TSN] _ NEXTINTSN(); ! LINK CHUNK TO SRCTAB IF (TEMP _ .SRCPTR[S0LCHNK]) EQL 0 THEN SRCPTR[S0LCHNK] _ SRCPTR[S0FCHNK] _ .CHUNKPTR ELSE SRCPTR[S0LCHNK] _ TEMP[C0LINK] _ .CHUNKPTR; ! IF NOT MESSAGE OR GROUP THEN EXIT MSREAD NOW IF .ENDI LEQ ESI THEN RETURN TRUE; ! OTHERWISE WE HAVE AT LEAST A MESSAGE, SO MAKE A MESSAGE HEADER MHPTR _ CREATEMH(0); ! FILL IN CHUNK POINTERS IN MESSAGE HEADER MHPTR[M0INCHNK] _ MHPTR[M0OUTCHNK] _ .SRCPTR[S0FCHNK]; ! CLEAR CHUNK POINTERS IN SRCTAB SRCPTR[S0CHUNKS] _ 0; ! DATE & TIME STAMP THE CREATED MESSAGE HEADER STAMP(MHPTR[M0DATE],MHPTR[M0TIME]); IF (GHPTR _ .SRCPTR[S0GHPTR]) NEQ 0 THEN ! IF GH ALREADY EXISTS BEGIN MHPTR[M0SOT] _ 0; IF .INLOGGING THEN INLOGMSG( .SRCPTR[S0TSN] ^ 18, .MHPTR[M0DATE], .MHPTR[M0TIME], SRCPTR[ S0ID ], ! NOTE POINTERPNOT VALUE 0, .MHPTR[M0INCHNK]); IF .GHPTR[G0CHKPNT] THEN BEGIN MHPTR[M0DSKADDR] _ CHKMSG( .GHPTR[G0DSKGHADDR], .MHPTR[M0DATE], .MHPTR[M0TIME], .MHPTR[M0INCHNK], .MHPTR[M0SOT]); IF .GHPTR[G0ONDSK] THEN ! IF GROUP IS NOT TO BE KEPT IN CORE BEGIN DCHNKS(.MHPTR); ! ZAP THE CHUNKS MHPTR[M0CHNKS] _ 0 ! AND MARK IT OUT END END ELSE IF .GHPTR[G0ONDSK] THEN !IF BEING ROLLED OUT BEGIN MHPTR[M0DSKADDR] _ ROLMSG( .GHPTR[G0DSKGHADDR], .MHPTR[M0INCHNK], .MHPTR[M0SOT]); MHPTR[M0CHNKS] _ 0 END; IF .ENDI EQL EGI THEN GHPTR[G0ENDI] _ 1; %EGI% ! SET END INDICATOR IN GH INSERT(.MHPTR,.GHPTR); !ATTACH MESSAGE END ELSE BEGIN ! IF GH DOESN'T EXIST THEN DECODE TRANSACTION TYPE LEAFPTR _ DECODE(.MHPTR,.SRCPTR); TRCODEINDEX _ .LEAFPTR; ! BREAK UP THE VALUE RETURNED FROM TRCODE LEAFPTR _ .LEAFPTR; IF .PORT[PT0SRCPTR] EQL 0 AND .LEAFPTR NEQ SONLEAF<0,0> THEN BEGIN ! IF NOT SIGNED ON AND NOT SIGNING ON LEAFPTR _ ERLEAF; WHYERROR _ 1; ! ERROR = NOT SIGNED ON TRCODEINDEX _ #777777 END; MHPTR[M0SOT] _ .SRCPTR[S0SOT]; !SAVE NUMBER OF CHARACTERS TO SKIP SRCPTR[S0SOT] _ 0; !CHECK FOR PROPER LENGTH MESSAGE HERE ALSO COUNT_0; CHUNKPTR_.MHPTR[ M0INCHNK ]; UNTIL .CHUNKPTR EQL 0 DO BEGIN COUNT_.COUNT+.CHUNKPTR[ C0BCNT ]; CHUNKPTR_.CHUNKPTR[ C0LINK ] END; IF .MHPTR[ M0SOT ] GTR .COUNT THEN BEGIN WHYERROR _ 2; !ERROR = NOT ENOUGH DATA TRCODEINDEX _ #777777; LEAFPTR _ ERLEAF END; IF .INLOGGING THEN INLOGMSG( .SRCPTR[S0TSN] ^ 18, .MHPTR[M0DATE], .MHPTR[M0TIME], SRCPTR[S0ID], ! NOTE POINTER NOT VALUE IF .TRCODEINDEX NEQ #777777 THEN TRCODE[.TRCODEINDEX*.TRCW] ELSE .TRCODEINDEX, .MHPTR[M0INCHNK]); ! MAKE A GROUP HEADER, ZERO IT, AND LINK IT TO A LEAF GHPTR _ CREATEGH(LEAFPTR[N0GHS]); SRCPTR[S0GHPTR] _ .GHPTR; ! TELL SRCPTR WHERE THE GH IS ! STORE POINTER TO SENDER IN THE GH GHPTR[G0SENDER] _ SRCPTR[S0ID]; !NOTE: ADDRESS NOT VALUE! ! STORE POINTERS TO THE MESSAGE IN THE GH GHPTR[G0FMHPTR] _ GHPTR[G0LMHPTR] _ GHPTR[G0OUTMH] _ .MHPTR; GHPTR[G0LFPTR] _ .LEAFPTR; ! SAVE GROUPS PARENT LEAF IN THE GH GHPTR[G0LHTSN] _ .SRCPTR[S0TSN]; ! SAVE TSN IN GH IF .ENDI EQL EGI THEN GHPTR[G0ENDI] _ 1; ! SET END INDICATOR IN GH IF (.LEAFPTR LSS ERLEAF<0,0>) AND .CHECKPOINTING AND .LEAFPTR[N0CHKPNT] THEN BEGIN !MUST FAILSOFT THIS REAL TRANSACTION GHPTR[G0DSKGHADDR] _ CHKGH( .LEAFPTR[N0LLFNO], ! CHECKPOINT THE GROUP .GHPTR[G0TSN], .GHPTR[G0SENDER], .MHPTR); ! AND STORE THE DISK GROUP HEADER ADDRESS GHPTR[G0CHKPNT] _ TRUE ! THIS IS BEING CHECKPOINTED END; CHKRUN(.LEAFPTR, 1, .GHPTR); ! INCREMENT THE GROUP COUNT OF THE LEAF, ! ROLL OUT IF QUOTA EXCEEDED, ! AND GET ANYONE OUT OF WAITING IF WE CAN END; ! IF END OF GROUP THEN CLEAN UP SRCTAB IF .ENDI EQL EGI THEN SRCPTR[S0TSN] _ SRCPTR[S0GHPTR] _ 0; TRUE END; END;