!***COPYRIGHT (C) 1974, 1975, 1976, 1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.*** MODULE MSGOUT(RESERVE(#11,#12,#13,#14),SREG=#17,FREG=#16,DREGS=4, VREG=#15,MLIST,TIMER=EXTERNAL(SIX12),FSAVE)= BEGIN REQUIRE DATA.BLI; EXTERNAL ROLIN, MOVE, UNDEFER; OWN OPCHAIN; MACRO FIRST = OPCHAIN$, LAST = OPCHAIN$; COMMENT; !ROUTINE GETALTERNATE !======= ============ ! THIS ROUTINE GETS THE ALTERNATE OF A TERMINAL ROUTINE GETALTERNATE(SRCPTR)= BEGIN MAP FORMAT SRCPTR; MACRO CURALT=(.SRCPTR[S0ALTPTR])$; IF .SRCPTR[S0SELF] THEN RETURN .SRCPTR; .CURALT END; EXTERNAL DELGH, DELMH, DGPURGE, UNLINK, BUFAVAIL; COMMENT; ! SUBROUTINE MSWRITE ! ========== ======= ! LAST MODIFIED: 15 SEPT 76 BY CDO ROUTINE MSWRITE(DEST) = BEGIN REGISTER MHPTR, GHPTR, SRCPTR; LOCAL SENDTO, SAVEREST, SAVECHNK, UDX; MAP FORMAT MHPTR; MAP FORMAT GHPTR; MAP FORMAT SRCPTR; MAP FORMAT SENDTO; SRCPTR _ .DEST; ! PICKUP THE SOURCE POINTER IF ( GHPTR _ .SRCPTR[S0FIGHPTR] ) EQL 0 THEN RETURN; ! IF NO MESSAGES, RETURN IF .GHPTR[G0SENDING] EQL 0 THEN ! IF OUTPUT NOT GOING ALREADY BEGIN IF .SRCPTR[S0ED] EQL DISABLED THEN RETURN; ! CHECK FOR DISABLED NOW GHPTR[G0SENDING] _ 1 ! NOT, MARK OUTPUT IN PROGRESS END; IF ( SENDTO _ GETALTERNATE( .SRCPTR ) ) EQL 0 THEN RETURN; ! IF NO ONE TO SEND TO, RETURN IF .SENDTO NEQ .SRCPTR THEN IF .SENDTO[ S0IGHS ] NEQ 0 THEN RETURN; ! IF ALTERNATE IS OUTPUTTING, RETURN IF (UDX_.SENDTO[S0PORTPTR]) EQL 0 THEN RETURN; ! IF NO PORT CONNECTED, RETURN IF NOT BUFAVAIL(.UDX) THEN RETURN; ! IF NO OUTPUT BUFFERS AROUND, RETURN IF (MHPTR _ .GHPTR[G0OUTMH]) EQL 0 THEN RETURN; ! IF NO MESSAGES AVB YET, RETURN GHPTR[G0OUTMH] _ .MHPTR[M0FORE]; ! SET UP FOR NEXT TIME IF .MHPTR[M0CHNKS] EQL 0 THEN ! IF NOT IN CORE IF .MHPTR[M0DSKADDR] NEQ 0 THEN ! IF ON DISK MHPTR[M0INCHNK]_MHPTR[M0OUTCHNK]_ROLIN(.MHPTR[M0DSKADDR],.GHPTR[G0DSKGHADDR]) ELSE INFORM(PLIT ASCIZ 'FMESSAGE MARKED ON DISK BUT NO DISK ADDRESS@', 0,0,0,0,0); ! DECREMENT COUNT OF RECEIVERS AND IF = 0, CAN RELEASE THE MESSAGE SAVEREST _ IF (MHPTR[M0DSCNT] _ .MHPTR[M0DSCNT] - 1) LEQ 0 THEN FALSE ELSE TRUE; SAVECHNK _ IF .SAVEREST AND .MHPTR[M0DSKADDR] EQL 0 THEN TRUE ELSE FALSE; OUTMSG(.MHPTR[M0OUTCHNK],.UDX,.SAVECHNK,FALSE); ! OUTPUT THE MESSAGE IF NOT .SAVECHNK THEN MHPTR[M0CHNKS] _ 0; ! DONE BY OUTMSG IF .GHPTR[G0ENDI] AND (.GHPTR[G0OUTMH] EQL 0) THEN ! IF THE GROUP IS DONE (I.E. EGI/EPI ! ENCOUNTERED AND COMPLETELY TRANSMITTED) BEGIN IF .GHPTR[G0ONDSK] THEN DGPURGE(.GHPTR[G0DSKGHADDR],.SAVEREST); ! CLEAR DISK IMAGE IF NOT .SAVEREST THEN DELGH(SRCPTR[S0IGHS],.GHPTR) ! DELETE THE GROUP IF NO MORE DESTINATIONS ELSE DELETE( SRCPTR[S0IGHS], .GHPTR, G0SIZE, NOTCHUNK); ! ELSE DELETE ONLY ! THE GROUP HEADER AND UNLINK IF .SRCPTR[S0IGHS] EQL 0 AND .PIGGYBACK NEQ 0 AND NOT .SRCPTR[S0DEFSENDING] THEN ! IF THERE ARE NO MORE IMMEDIATE GROUPS BEGIN ! AND THERE IS A PIGGY BACK QUOTA THEN SRCPTR[S0DEFSENDING] _ TRUE; ! SET A FLAG SO WE DON'T TRY TO UNDEFER UNDEFER( .SRCPTR, .PIGGYBACK) ! TRY TO UNDEFER SOME ! ANY MORE UNTIL THE USER DOES ANOTHER ! IMMEDIATE SEND END END; 0 END; COMMENT; ! MSGCHN INSERTS A TERMINAL INTO THE OUTPUT CHAIN. MSGOUT TAKES CARE OF THE REMOVAL GLOBAL ROUTINE MSGCHN(DEST)= BEGIN REGISTER SRCPTR, OLAST; MAP FORMAT SRCPTR; MAP FORMAT OLAST; SRCPTR _ .DEST; ! PICK IT UP IN A REGISTER IF .SRCPTR[S0OPCHAIN] NEQ 0 THEN RETURN; ! RETURN IF ALREADY IN THE CHAIN IF (OLAST _ .LAST) EQL .SRCPTR THEN RETURN; ! RETURN IF ONLY IN CHAIN LAST _ .SRCPTR; ! THIS IS NOW THE LAST SRCPTR[S0OPPREV] _ .OLAST; ! OLD LAST IS THIS ONES PREVIOUS SRCPTR[S0OPNEXT] _ 0; ! NEW LAST HAS NO NEXT IF .OLAST EQL 0 THEN FIRST _ .SRCPTR ! IF ONLY, THEN FIRST TOO ELSE OLAST[S0OPNEXT] _ .SRCPTR; ! ELSE THIS IS ITS NEXT 0 END; COMMENT; ! MSGOUT SCHEDULES 1 OUTPUT FOR EACH TERMINAL DURING THE SCHEDULER LOOP GLOBAL ROUTINE MSGOUT= BEGIN REGISTER SRCPTR,OPREV,ONEXT; MAP FORMAT SRCPTR; MAP FORMAT OPREV; MAP FORMAT ONEXT; SRCPTR _ .FIRST; ! GET FIRST TERMINAL IN OUTPUT CHAIN UNTIL .SRCPTR EQL 0 DO BEGIN MSWRITE(.SRCPTR); ! TRY TO OUTPUT SOME DATA IF .SRCPTR[S0IGHS] NEQ 0 THEN SRCPTR _ .SRCPTR[S0OPNEXT] ELSE ! IF OUTPUT LAST GROUP, REMOVE FROM CHAIN BEGIN OPREV _ .SRCPTR[S0OPPREV]; ! GET OLD PREVIOUS ONEXT _ .SRCPTR[S0OPNEXT]; ! AND NEXT SRCPTR[S0OPCHAIN] _ 0; ! DISSOLVE LINKS SRCPTR _ .ONEXT; ! SET UP FOR REST IF .OPREV EQL 0 THEN ! REMOVING THE FIRST IF .ONEXT EQL 0 THEN OPCHAIN _ 0 ! REMOVING THE ONLY ELSE BEGIN FIRST _ .ONEXT; ! RESET FIRST ONEXT[S0OPPREV] _ 0 ! IT HAS NO PREVIOUS END ELSE IF .ONEXT EQL 0 THEN ! REMOVING THE LAST BEGIN LAST _ .OPREV; ! RESET THE NEW LAST OPREV[S0OPNEXT] _ 0 ! IS HAS NO NEXT END ELSE BEGIN ONEXT[S0OPPREV] _ .OPREV; ! LINK REMAINING TOGETHER OPREV[S0OPNEXT] _ .ONEXT ! TO COMPLETE THE CHAIN END END END END; END;