Google
 

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;