Trailing-Edge
-
PDP-10 Archives
-
AP-D471B-SB_1978
-
recvm.bli
There are no other files named recvm.bli in the archive.
!***COPYRIGHT (C) 1974, 1975, 1976, 1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
MODULE RECVM(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
EXTERNAL ROLIN;
COMMENT;
! ROUTINE: FINDR
! =====
ROUTINE FINDR(TSN,JSLOT)=
! TSN = TRANSACTION SEQUENCE NUMBER TO BE FOUND
! JSLOT = JOB SLOT NUMBER TO USE AS THE INDEX INTO THE RECVQ
! RETURNS:
! GROUP POINTER IF ONE AVAILABLE
! 0 IF NO GROUPS AVAILABLE IN THE TREE SPECIFIED
! SIDE EFFECTS:
! NONE
BEGIN
REGISTER GHPTR,TSNREG;
BIND NOTFOUND=0;
MAP FORMAT GHPTR;
MAP FORMAT RECVQ;
! IF RECVQ FOR THIS JSN IS EMPTY THEN WE CAN'T FIND A MATCHING TSN
IF (GHPTR _ .RECVQ[R0FGH(.JSLOT)]) EQL 0 THEN RETURN NOTFOUND;
TSNREG _ .TSN;
! LOOP WHILE THE TSN WE WANT AND THE TSN OF THE RECVQ ENTRY DON'T MATCH
WHILE .TSNREG NEQ .GHPTR[G0TSN] DO
! IF WE REACH THE END OF THE RECVQ WITH NO MATCH THEN RETURN NOTFOUND
IF (GHPTR_.GHPTR[G0FORE]) EQL 0 THEN RETURN NOTFOUND;
.GHPTR ! OTHERWISE RETURN A POINTER TO THE GROUP HEADER
END;
EXTERNAL QHASH,
MOVE;
COMMENT;
! LAST MODIFIED: 23 JUN 76 BY CDO
! ROUTINE: GETGROUP
! ========
ROUTINE GETGROUP(PAGEADDR,NPTR)=
! PAGEADDR = LOC(PAGE) CONTAINING THE COMMAND
! RETURNS:
! GROUP POINTER IF ONE AVAILABLE
! 0 IF NO GROUPS AVAILABLE IN THE TREE SPECIFIED
! SIDE EFFECT:
! FILLS IN QUEUE NAMES IN THE PAGE
BEGIN
MACRO
LEAF = (.NODEPTR[N0NXTND] EQL 0)$, ! THIS MACRO PRODUCES A
! TRUE VALUE IF THE CURRENT NODE IS A LEAF
TCOUNT = .NODEPTR[N0TSCNT]$, ! GIVES NUMBER OF
! TRANSACTIONS IN THIS
! NODE
DROP = NODEPTR _ .NODEPTR[N0NXTND]$, ! TAKES THE NODE POINTER
! DOWN TO THE NEXT LEVEL
SHIFT = IF(NODEPTR _ .NODEPTR[N0SAMND]) EQL 0 THEN
INFORM(PLIT ASCIZ 'FERROR IN GETGROUP',0,0,0,0,0)$,
! TAKES THE NODE POINTER
! TO THE NEXT NODE ON
! THIS LEVEL
FILL = PAGENAME _ (.PAGEADDR)[P0PRIM + .NODEPTR[N0LEVEL] * LEAFNAMLEN]; ! GET A NAME FIELD PTR
ZERO(.PAGENAME, .PAGENAME + LEAFNAMLEN); ! ZERO THE WHOLE FIELD
MOVE(NODEPTR[N0NAME], .PAGENAME, LEAFNAMLEN)$; ! FILL IN THE NAME
REGISTER
NODEPTR,
PAGENAME;
MAP FORMAT NODEPTR;
NODEPTR _ .NPTR; ! STORE THE NODEPTR IN A REGISTER
IF TCOUNT LEQ 0 THEN RETURN 0; ! DONE IF THE NODE IS EMPTY
WHILE NOT LEAF DO ! IF THERE ARE TRANSACTIONS UNDER THIS NODE
! FIND A LEAF
BEGIN
DROP;
WHILE TCOUNT EQL 0 DO SHIFT;
FILL
END;
RETURN .NODEPTR[N0FGH] ! RETURN A GROUP POINTER TO THE FIRST GROUP OF THE LEAF
END;
EXTERNAL MOVE,
UNLINK,
MAKEBP,
SKIPCHUNKS;
COMMENT;
! LAST MODIFIED: 8 APR 74 BY AG
! SUBROUTINE PACK
! ===============
! THIS ROUTINE PACKS INPUT CHUNKS INTO THE PAGE.
! EACH CHUNK IS TRANSFORMED INTO A TEXT UNIT DESCRIPTOR AND
! THE TEXT AREA.
! THE RIGHT HALF OF WORD0 OF THE TEXT UNIT DESCRIPTOR IS THE OFFSET
! FROM THE BEGINNING OF THE PAGE WHERE THE TEXT IS STORED, THE LEFT
! HALF AND THE WORD1 ARE THE SAME AS THE STRUCTURE IN THE CHUNK HEADER.
! THE CHUNKS OF THE MESSAGE ARE DELETED AS THEY ARE PACKED ON THE PAGE
! BUT THE MESSAGE HEADERS AND GROUP HEADERS ARE NOT.
! KNOWN RESTRICTION
! ===== ===========
! THIS ROUTINE WILL NOT WORK WHEN THE CHUNKSIZE IS GREATER THAN THE
! TEXT AREA SIZE
GLOBAL ROUTINE PACK(MHPTR,PAGEADDR) =
BEGIN
REGISTER
AREA,
INDEX,
OFFSETT,
FORMAT CHUNK;
LOCAL WORDS,
WORD2,
ENDI,
TEMP,
FIRST,
COUNT,
FFROM,
BP;
MAP FORMAT MHPTR;
LABEL LOOP;
AREA _ PAGETEXTAREA;
OFFSETT _ PAGESIZE - PAGETEXTAREA;
!START OFFSETT AT THE BEGINNING OF THE TEXT
!AREA IN THE PAGE
INDEX _ -1; !INDEX IS THE KEY USED TO INDEX THE
!TUD'S AND THE TEXTS IN THE PAGE.
CHUNK _ .MHPTR[M0OUTCHNK];
IF .MHPTR[M0INCHNK] EQL .CHUNK THEN ! IF THE FIRST CHUNK OF THE MESSAGE THEN
BEGIN
CHUNK _ SKIPCHUNKS( .CHUNK, .MHPTR[M0SOT], TRUE);
FIRST _ TRUE;
COUNT _ .CHUNK<LH>
END
ELSE FIRST _ FALSE;
ENDI _ 0; !SET ENDI TO 0, IF NO CHUNK IS PACKED, 0 WILL BE THEN RETURNED.
LOOP: WHILE .CHUNK NEQ 0 DO
BEGIN
IF .FIRST THEN
BEGIN
FIRST _ FALSE;
BP _ FFROM _ MAKEBP( .CHUNK, .COUNT);
FFROM<LH> _ 0;
BP<C00ENDI> _ .CHUNK[C0ENDI];
WORD2<C00BCNT> _ .CHUNK[C0BCNT] - .COUNT;
WORDS _ WORD2<C00WORDS> _ .CHUNK[C0WORDS] - ( IF .COUNT EQL 0 THEN 0 ELSE (.COUNT - 1) / 5 )
END
ELSE
BEGIN
WORDS _ WORD2<C00WORDS> _ .CHUNK[C0WORDS];
WORD2<C00BCNT> _ .CHUNK[C0BCNT];
FFROM _ CHUNK[C0DATA];
BP<LH> _ .(.CHUNK)<LH>
END;
BP<RH> _ .OFFSETT;
IF .WORDS+2 GTR .AREA THEN LEAVE LOOP;
!WORDS CONTAINS THE TOTAL NUMBER OF WORDS STORED IN
!THE TEXT AAREA OF THE CHUNK, WHERE 2 IS THE NUMBER OF
!WORDS THE TUD REQUIRES.
INDEX _ .INDEX + 1;
!SET UP THE INDEX'TH TUD IN PAGE
(.PAGEADDR)[P0TUD(.INDEX)] _ .BP;
(.PAGEADDR)[P0TUD(.INDEX)]+1 _ .WORD2;
!SET UP THE TEXT AREA FOR THE INDEX'TH CHUNK IN THE PAGE.
MOVE( .FFROM, .PAGEADDR+.OFFSETT, .WORDS);
AREA _ .AREA - .WORDS - 2;
OFFSETT _ .OFFSETT + .WORDS;
ENDI _ .CHUNK[C0ENDI]; !UPDATE THE ENDI TO REFLECT THE LAST CHUNK JUST PACKED.
!NOTE
! THIS COULD BE MADE MORE EFFICIENT BY MODIFYING DELCHNK
TEMP _ .CHUNK[C0LINK];
DELCHNK(.CHUNK); ! ZAP THE CHUNK
CHUNK _ .TEMP
END;
(.PAGEADDR)[P0TUC] _ .INDEX + 1;
!SET UP THE TEXT UNIT COUNT FIELD IN PAGE.
IF .CHUNK NEQ 0 THEN MHPTR[M0OUTCHNK] _ .CHUNK
!IF THE LAST CHUNK PACKED IS NOT THE END OF A
!MESSAGE OR THE END OF A GROUP, UPDATE THE NEXT OUTPUT
!CHUNK POINTER IN THE MH.
ELSE MHPTR[M0INCHNK] _ MHPTR[M0OUTCHNK] _ 0;
! CLEAR POINTERS TO CHUNKS IF THE MESSAGE IS EMPTY
(.PAGEADDR)[P0DATE] _ .MHPTR[M0DATE];
(.PAGEADDR)[P0TIME] _ .MHPTR[M0TIME];
!STORE THE DATE AND TIME INTO THE PAGE.
.ENDI !RETURN THE VALUE OF THE END INDICATOR OF THE
!LAST CHUNK PACKED INTO THE PAGE.
END;
EXTERNAL WAITSET,
QHASH,
UNLINK,
DECREMENT,
LINK;
COMMENT;
! ROUTINE RECV
! ======= ====
!LAST MODIFIED: 4 NOV 76 BY CDO
! EXECUTES RECEIVE FUNCTION FROM COBOL
! THIS FUNCTION CONSISTS OF GETTING THE NEXT AVAILABLE MESSAGE
! (IF ANY) FROM THE QUEUE STRUCTURES
GLOBAL ROUTINE RECV(JSN,PAGEADDR)=
BEGIN
REGISTER
GHPTR,
PADDR,
ENDI,
LEAFPTR;
LOCAL
MHPTR,
NODEPTR;
MAP FORMAT GHPTR;
MAP FORMAT RECVQ;
MAP FORMAT MHPTR;
MAP FORMAT LEAFPTR;
MAP FORMAT NODEPTR;
MACRO
! NOTNEWTRANSACTION HAS A VALUE OF TRUE IF NOT NEW TRANSACTION
NOTNEWTRANSACTION = (.(.PADDR)[P0TSN] NEQ 0)$,
! RECVNOWAIT HAS A VALUE OF TRUE IF THE CURRENT FUNCTION IS RECV NO WAIT
RECVNOWAIT = (.(.PADDR)[P0FCN] EQL RNW)$;
!BEGIN!
!PUT THE PAGEADDRESS IN A REGISTER
PADDR _ .PAGEADDR;
(.PADDR)[P0STATUS] _ STSGOOD; ! ASSUME THINGS WILL BE GOOD
IF NOTNEWTRANSACTION THEN
! IF THIS A REQUEST FOR AN OLD TRANSACTION THEN TRY TO FIND IT IN THE RECVQ
BEGIN
IF (GHPTR _ FINDR(.(.PADDR)[P0TSN],.JSN)) EQL 0 THEN
! IF NOT IN THE RECVQ THEN ERROR
BEGIN
(.PADDR)[P0STATUS] _ STSNOTINRECV;
RETURN SENDPAGE
END;
IF .GHPTR[G0LOSTTERM] THEN
!IF ABORTING DUE TO LOST TERMINAL
BEGIN
(.PADDR)[P0STATUS] _ STSLOSTTERM;
RETURN SENDPAGE
END;
IF .GHPTR[G0FINISHED] THEN
! IF TRYING TO READ MORE FROM AN EMPTY GROUP
BEGIN
(.PADDR)[P0STATUS] _ STSPASTEGI;
RETURN SENDPAGE
END;
! OTHERWISE SEE IF THERE IS ANYTHING IN THE GROUP TO RECV
IF .GHPTR[G0EMPTY] THEN
BEGIN
! IF THERE ISN'T THEN
IF RECVNOWAIT THEN
! IF RECV NO WAIT THEN ZERO THE TEXT UNIT COUNT,
! SET STATUS TO NODATA,
! AND RETURN WITH SENDPAGE
BEGIN
(.PADDR)[P0STATUS] _ STSNODATA;
(.PADDR)[P0TUC] _ 0;
RETURN SENDPAGE
END
! IF RECV WAIT THEN SAVE PADDR AND JSN IN THE GH
! AND RETURN WITH KEEPPAGE
ELSE
BEGIN
GHPTR[G0PADDR] _ .PADDR ^ (-9); %SHIFT IS BECAUSE G0PADDR IS ONLY 9 BITS WIDE%
GHPTR[G0JSN] _ .JSN;
RETURN KEEPPAGE
END
END;
! IF ILLEGAL QUEUE SPECIFICATION IN PAGE RETURN SEND PAGE
IF (NODEPTR _ QHASH( (.PADDR)[ P0PRIM ] )) EQL 0 THEN ! PICK UP THE NODEPTR
BEGIN
(.PADDR)[P0STATUS] _ STSILLQNAME; ! AND IF IT IS BAD
! SET ILLEGAL QUEUENAME STATUS CODE
RETURN SENDPAGE ! AND RETURN WITH ERROR
END
END
ELSE
! IF THIS ISN'T A REQUEST FOR AN OLD TRANSACTION THEN
BEGIN
IF FALSE THEN ! ** REMOVE FOR AN EXTRA ERROR CHECK ** !
IF .RECVQ[R0GHS(.JSN)] NEQ 0 THEN ! WANT'S NEW BUT STILL OLD AROUND
BEGIN
(.PADDR)[P0STATUS] _ STSNEVEREPI; ! SET NEVER EPI'ED THE OLD ONE
! USUALLY, USER DIDN'T CHECK STATUS ON
! SEND AND IT INDICATED FAILURE
RETURN SENDPAGE ! RETURN ERROR TO LIBOL
END;
! DETERMINE WHERE TO PICK UP A GROUP IN THE QUEUE STRUCTURE
! IF ILLEGAL QUEUE SPECIFICATION IN PAGE RETURN SEND PAGE
IF (NODEPTR _ QHASH( (.PADDR)[ P0PRIM ] )) EQL 0 THEN ! PICK UP THE NODEPTR
BEGIN
(.PADDR)[P0STATUS] _ STSILLQNAME; ! AND IF IT IS BAD
! SET ILLEGAL QUEUENAME STATUS CODE
RETURN SENDPAGE ! AND RETURN WITH ERROR
END;
! IF NOTHING TO RECV THEN
IF (GHPTR _ GETGROUP(.PADDR,.NODEPTR)) EQL 0 THEN
BEGIN
! IF RECV NO WAIT THEN ZERO TEXT UNIT COUNT,
! SET STATUS TO NO DATA AND
! RETURN WITH SENDPAGE
IF RECVNOWAIT THEN
BEGIN
(.PADDR)[P0STATUS] _ STSNODATA;
(.PADDR)[P0TUC] _ 0;
RETURN SENDPAGE
END
ELSE
! IF RECV WAIT THEN PUT JOB IN WAITLIST AND
! RETURN WITH KEEPPAGE
BEGIN
WAITSET(.JSN,.PADDR,.NODEPTR);
RETURN KEEPPAGE
END
END;
! IF THE OPERATOR HAS MARKED THIS MPP FOR DELETION
IF (GETMPPSTATUS( .JSN ) AND OPRKILLBIT) NEQ 0 THEN
BEGIN
WAITSET(.JSN,.PADDR,.NODEPTR);
RETURN KEEPPAGE
END;
! CLEAR THE EPI BIT IN THE JOB STATUS TABLE
CLRMPPSTATUS( .JSN, EPIBIT );
! UNLINK THE GROUP FROM THE LEAF
LEAFPTR _ .GHPTR[G0LFPTR];
UNLINK( LEAFPTR[N0GHS],.GHPTR);
GHPTR[G0LINK] _ 0; ! ZAP ANY LINKAGES
! DECREMENT THE COUNTS IN THE LEAF
DECREMENT(.LEAFPTR, IF .GHPTR[ G0ONDSK ] THEN FALSE ELSE TRUE);
! LINK THE GROUP TO THE APPROPRIATE SLOT INT THE RECVQ
LINK(RECVQ[R0GHS(.JSN)],.GHPTR);
! SET THE BEING RECEIVED BIT SO SOME FOOL DOESN'T ROLL A MESSAGE OUT FROM UNDER US.
GHPTR[G0RECEIVING] _ TRUE;
END;
MHPTR _ .GHPTR[G0OUTMH]; ! GET THE MH TO OUTPUT
! IF WE ARE CHECKPOINTING OR ROLLING AND THE NEXT MESSAGE OF THIS GROUP IS ON DISK
IF .MHPTR[ M0CHNKS ] EQL 0 THEN IF .GHPTR[G0ONDSK] THEN
! IF THE MESSAGE IS ON DISK ROLL IT IN OTHERWISE THERE IS AN ERROR
IF .MHPTR[M0DSKADDR] NEQ 0 THEN
! THEN ROLL IT IN AND WAIT TIL IT GETS IN
MHPTR[M0INCHNK] _ MHPTR[M0OUTCHNK] _ ROLLIN(.MHPTR[M0DSKADDR],.GHPTR[G0DSKGHADDR])
ELSE
INFORM(PLIT ASCIZ 'FMESSAGE MARKED ON DISK BUT NO DISK ADDRESS FOR JOB SLOT: %0D%,
MPP: %0J%, TSN: %1H%@',.JSN,.(.PADDR)[P0TSN],0,0,0);
! STORE TSN, STATUS, MESSAGE COUNT, AND SENDER IN PAGE
(.PADDR)[P0STATUS] _ IF .GHPTR[G0LOSTTERM] THEN STSLOSTTERM ELSE STSGOOD;
(.PADDR)[P0TSN] _ .GHPTR[G0TSN];
MOVE(.GHPTR[G0SENDER],(.PADDR)[P0SRCE],SRCNAMLEN);
! NOTE: THE COUNT IS THE COUNT FROM THE NODE REQUESTED, NOT
! ===
! NECESSARILY THE COUNT OF THE LEAF READ
(.PADDR)[P0MGC] _ .NODEPTR[N0TSCNT];
! PACK A PAGE
! AND ZAP THE CHUNKS OF THE MESSAGE
ENDI _ PACK(.MHPTR,.PADDR);
IF .ENDI GEQ EMI THEN
BEGIN
!FIX POINTERS IN GH
!IF EMPTY THEN SET G0EMPTY
IF .ENDI EQL EMI THEN
BEGIN
MHPTR _ .GHPTR[G0OUTMH];
IF (GHPTR[G0OUTMH] _ .MHPTR[M0FORE]) EQL 0 THEN
GHPTR[G0EMPTY] _ TRUE
END
ELSE
BEGIN
! MAKE THE GROUP FINISHED SO A USER CAN'T FOUL US UP
GHPTR[G0FINISHED] _ TRUE;
END
END;
SENDPAGE
END;
END;