Trailing-Edge
-
PDP-10 Archives
-
BB-D868D-BM
-
language-sources/qsrsch.mac
There are 48 other files named qsrsch.mac in the archive. Click here to see a list.
TITLE QSRSCH - Scheduler and queue-dependent functions for QUASAR
;
;
; COPYRIGHT (c) 1975,1976,1977,1978,1979
; DIGITAL EQUIPMENT CORPORATION
;
; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
; AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE
; AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS
; SOFTWARE OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR
; OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. NO TITLE TO
; AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED.
;
; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE
; WITHOUT NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT
; BY DIGITAL EQUIPMENT CORPORATION.
;
; DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY
; OF ITS SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY
; DIGITAL.
SEARCH QSRMAC,GLXMAC,D60UNV ;PARAMETER FILE
PROLOG(QSRSCH) ;GENERATE NECESSARY SYMBOLS
SEARCH ORNMAC ;GET WTO PARAMETERS.
SUBTTL Macro definitions
;VDFALT macro is used to default a field with a particular value
DEFINE VDFALT(AC,LOCN,FIELD,DEFALT,%DUMMY),<
LOAD (AC,LOCN,FIELD)
XLIST
JUMPN AC,%DUMMY
MOVX (AC,DEFALT)
STORE (AC,LOCN,FIELD)
%DUMMY:
LIST
SALL
> ;END DEFINE VDFALT
;LDFALT macro is used to default a field with the contents of a specified location
DEFINE LDFALT(AC,LOCN,FIELD,LOC2,%DUMMY),<
LOAD (AC,LOCN,FIELD)
XLIST
JUMPN AC,%DUMMY
MOVE AC,LOC2
STORE (AC,LOCN,FIELD)
%DUMMY:
LIST
SALL
> ;END DEFINE LDFALT
;PDFALT macro is used to default a 'limit parameter' with a particular value
DEFINE PDFALT(AC,BLOCK,NAME,DEFALT,%DUMMY),<
GETLIM (AC,BLOCK,NAME)
XLIST
JUMPN AC,%DUMMY
MOVX AC,DEFALT
STOLIM (AC,BLOCK,NAME)
%DUMMY:
LIST
SALL
> ;END DEFINE PDFALT
SUBTTL Module Storage
MSGPDB: BLOCK IPCHSZ ;PLACE TO BUILD IPCF PDB
MSGMSG: BLOCK SUP.SZ ;PLACE TO BUILD NEEDED MESSAGES
SHUTYP: BLOCK 1 ;ENTRY POINT INDICATOR FOR SHUTDOWN
SUBTTL S$INIT -- Scheduler Initialization Point
;This routine is called at once-only to initialize the data base
; for the scheduler.
ENTRY S$INIT
S$INIT: DOSCHD ;FORCE INITIAL SCHEDULING PASS
$RETT
SUBTTL S$SCHD -- Scheduler Entry Point
;S$SCHD is called from the main program to execute a scheduling pass
; through the OBJ queue.
;
;The algorithm for scheduling is as follows:
;**************put a flowchart or something impressive here***************
S$SCHD:: PUSHJ P,CHKTIM ;CHECK OBJECT TIMERS
AOSE G$SCHD## ;COUNT DOWN THE SCHED FLAG
$RETT ;DON'T SCHEDULE NOW
$COUNT(SLCD) ;WE EXHAUSTED THE COUNTER
PUSHJ P,.SAVE4 ;SAVE P1-P4
PUSHJ P,I$SYSV## ;READ SYSTEM VARIABLES
SKIPGE G$KSYS## ;IS TIMESHARING OVER?
$RETT ;YES, RETURN
PUSHJ P,D$CLSV## ;CLEAR VALID STATUS BITS FOR ALL STRS
LOAD P1,HDROBJ##+.QHLNK,QH.PTF ;GET POINTER TO FIRST OBJECT
SCHD.1: JUMPE P1,SCH2.1 ;DONE WITH PASS1, DO PASS2
LOAD S2,OBJSCH(P1) ;GET SCHEDULER STATE INFO
TXC S2,OBSSTA!OBSSUP ;COMPLEMENTS BITS WE WANT ON
TXNE S2,OBSSTA!OBSSUP!OBSBUS ;MUST BE STARTED+SETUP+NOTBUSY
JRST SCHD.4 ;NO GOOD, TRY NEXT
LOAD S1,OBJSCH(P1) ;GET THE STATUS BITS.
TXNN S1,OBSSEJ ;DO WE WANT TO SHUT IT DOWN ??
JRST SCHD.2 ;NO,,KEEP ON GOING ...
LOAD P4,.QELNK(P1),QE.PTN ;GET NXT ENTRY NOW,CURRENT BEING DELETED
MOVE S1,P1 ;PUT THE OBJECT ADDRESS INTO S1.
PUSHJ P,S$SHUT ;SHUT IT DOWN
LOAD P1,P4 ;GET THE NEXT LINK (AFTER DELETE)
JRST SCHD.1 ;AND CONTINUE PROCESSING.
SCHD.2: MOVE S1,OBJNOD(P1) ;GET NODE NAME
PUSHJ P,N$NODE## ;SEE IF NODE IS ON-LINE
JUMPF SCHD.4 ;NOT, IGNORE THE OBJECT
LOAD P2,OBJSCH(P1),OBSQUH ;GET ADDRESS OF QUEUE HEADER
LOAD P2,.QHPAG(P2),QH.SCH ;GET ADDRESS OF SCHEDULING VECTOR
MOVE S1,P1 ;PUT THE OBJECT ADDRESS INTO S1.
PUSHJ P,SCHFJB(P2) ;FIND A JOB FOR THE OBJECT
JUMPF SCHD.3 ;NO JOBS,,SEE IF REMOTE AND GET NEXT OBJ
MOVE S2,OBJSCH(P1) ;GET SCHEDULER FLAGS
TXNE S2,OBSIGN+OBSSTP ;ARE WE IGNORING or STOPPED BY OPR ??
JRST SCHD.4 ;YES, DON'T SCHEDULE IT
TXO S2,OBSBUS ;NO, SET BUSY SO THAT KILPSB WILL
STORE S2,OBJSCH(P1) ; CLEAN UP ON A SEND FAILURE
MOVE S2,P1 ;PUT OBJECT IN S2
PUSHJ P,SCHSCH(P2) ;AND SCHEDULE THE JOB
MOVX S1,SPLMBC ;GET "MINUTES BETWEEN CHECKPOINTS"
PUSHJ P,I$AFT## ;GET TIME FOR FIRST CHECKPOINT
STORE S1,OBJTIM(P1) ;AND STORE IT
PUSHJ P,G$STIM## ;SET THE TIMER
SKIPA ;SKIP OVER EMPTY QUEUE OBJECT CHECK
SCHD.3: PUSHJ P,CHKOBJ ;Q IS EMPTY,,DO END-OF-QUEUE PROCESSING
SCHD.4: LOAD P1,.QELNK(P1),QE.PTN ;POINT TO NEXT OBJECT
JRST SCHD.1 ;AND LOOP
SUBTTL PASS 2 OF THE SCHEDULER
SCH2.1: LOAD P1,HDROBJ##+.QHLNK,QH.PTF ;POINT TO THE FIRST OBJECT
SCH2.2: JUMPE P1,.RETT ;RETURN WHEN DONE
LOAD S1,OBJSCH(P1) ;GET THE SCHEDULING BITS
TXC S1,OBSSTA ;COMPLIMENT 'STARTED'
TXNE S1,OBSSTA!OBSSUP!OBSSIP ;MUST BE STARTED+NOTSETUP+NOTSIP
JRST SCH2.5 ;NO, TRY NEXT OBJECT
MOVE S1,OBJNOD(P1) ;GET THE OBJECTS NODE NAME
PUSHJ P,N$NODE## ;CHECK ONLINE'NESS !!!
MOVE P3,NETSTS(S2) ;SAVE THE NODE STATUS BITS IN P3
JUMPT SCH2.0 ;NODE ONLINE,,CONTINUE
;Here is Node is Offline
TXNN P3,NETIBM ;IS THIS AN IBM REMOTE STATION ???
JRST SCH2.5 ;NO,,JUST PROCESS NEXT OBJECT
LOAD S1,OBJTYP(P1) ;YES,,GET THE OBJECT TYPE
CAXE S1,.OTBAT ;IF ITS A BATCH OBJECT OR
CAXN S1,.OTRDR ; CARD READER THEN OK
JRST SCH.2A ;YES TO EITHER,,LETERRIP !!!
JRST SCH2.5 ;NO,,JUST PROCESS NEXT OBJECT
;Here if Node Is Online - Check for any Requests to be Processed
SCH2.0: TXNE P3,NETIBM ;IS THIS AN IBM REMOTE STATION ???
JRST SCH.2A ;YES,,DONT CARE IF THERE ARE ANY JOBS !
LOAD S2,OBJSCH(P1),OBSQUH ;GET ADDRESS OF QUEUE HEADER
LOAD S2,.QHPAG(S2),QH.SCH ;GET ADDRESS OF SCHEDULING VECTOR
MOVE S1,P1 ;COPY OBJ ADDRESS IN S1
PUSHJ P,SCHFJB(S2) ;AND SEE IF THERE IS A JOB
JUMPF SCH2.5 ;NO JOB, NEXT OBJECT
;Here to Check to see if we we're Temporarily shut down
SCH.2A: MOVE S1,OBJSCH(P1) ;GET SCHEDULING BITS
TXZE S1,OBSHUT ;ARE WE TEMP SHUT DOWN ???
PUSHJ P,[TXZ S1,OBSIGN ;YES,,CLEAR THE IGNORE BIT
MOVEM S1,OBJSCH(P1) ; SAVE THE NEW SCHEDULING BITS
SETZM OBJTIM(P1) ; CLEAR THE WAKE-UP TIME
POPJ P, ] ; AND CONTINUE SCHEDULING
TXNE S1,OBSIGN ;IS THE IGNORE BIT SET ???
JRST SCH2.5 ;YES,,TRY THE NEXT OBJECT
LOAD S1,HDRPSB##+.QHLNK,QH.PTF ;POINTER TO FIRST PSB
;Here to find a PSB to send the SETUP Message to.
SCH2.3: JUMPE S1,SCH2.5 ;JUMP WHEN DONE
LOAD P2,OBJTYP(P1) ;GET THE OBJECT TYPE
LOAD S2,P3,NT.MOD ;GET THE OBJECT MODE (FROM STATUS BITS)
CAXN S2,DF.EMU ;IS THIS AN EMULATION NODE ???
MOVX P2,.OTIBM ;YES,,THEN SEARCH FOR EMULATION SPOOLER
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
LOAD P4,PSBFLG(S1),PSFNOT ;GET NUMBER OF OBJECT TYPES FOR
MOVNS P4 ;THIS PSB
HRLZS P4 ;FORM AN AOBJN POINTER
HRRI P4,PSBOBJ(S1) ;OF -NR OF OBJ TYPS,,PTR TO FIRST
CAME P2,0(P4) ;DO WE HAVE A MATCH?
AOBJN P4,.-1 ;NO, TRY NEXT OBJ IN THIS PSB
JUMPGE P4,SCH2.4 ;IF NO MATCHES, TRY NEXT PSB
LOAD P2,PSBLIM(S1),PSLCUR ;GET CURRENT NUMBER OF JOBS
LOAD S2,PSBLIM(S1),PSLMAX ;GET MAXIMUM NUMBER OF JOBS
CAML P2,S2 ;ROOM FOR MORE?
JRST SCH2.4 ;NO, NEXT PSB
LOAD P2,.QELNK(S1),QE.PTN ;GET NEXT NOW, SINCE PSB MAY DISSAPEAR
MOVE S2,P1 ;S1 HAS PSB ADDR, S2 HAS OBJ POINTER
PUSHJ P,SETUP ;SEND SETUP MSG TO APPROPRIATE PROCESSOR
JUMPT SCH2.5 ;SETUP OK??? IF SO GET NEXT OBJECT
MOVE S1,P2 ;NO, STEP TO NEXT PSB
JRST SCH2.3 ;AND TRY TO SET IT UP IF RIGHT TYPE ETC.
SCH2.4: LOAD S1,.QELNK(S1),QE.PTN ;GET POINTER TO NEXT PSB
JRST SCH2.3 ;AND LOOP
SCH2.5: LOAD P1,.QELNK(P1),QE.PTN ;GET POINTER TO NEXT OBJ
JRST SCH2.2 ;AND LOOP
SUBTTL SETUP -- Set up and do accounting for object setup
;SETUP is called with an object and appropriate PSB to accomplish the
; sending of a SETUP message. It also accounts for the OBJ
; being added to the PSB's list and checks for the processor going
; away.
;CALL IS: S1/ Pointer to PSB
; S2/ Pointer to OBJ
;
;TRUE RETURN: Processor has been sent a setup message
;FALSE RETURN: PID of PSB was dropped, indicating it is gone
SETUP: PUSHJ P,.SAVE4 ;SAVE FOUR PERM ACS
DMOVE P1,S1 ;AND SAVE OUR INPUT ARGUMENTS
MOVEI S1,SUP.SZ ;GET THE MESSAGE SIZE
MOVEI S2,MSGMSG ;GET THE MESSAGE ADDRESS
PUSHJ P,.ZCHNK ;CLEAR IT OUT
MOVEI P3,MSGMSG ;GET THE MESSAGE ADDRESS
MOVX S1,SUP.SZ ;GET SIZE OF SETUP MESSAGE
STORE S1,.MSTYP(P3),MS.CNT ;STORE INTO MESSAGE BLOCK
MOVX S1,.QOSUP ;GET CODE FOR SETUP MESSAGE
STORE S1,.MSTYP(P3),MS.TYP ;STORE INTO MESSAGE BLOCK
MOVEI S1,OBJTYP(P2) ;POINT TO THE SOURCE OBJECT
MOVEI S2,SUP.TY(P3) ;POINT TO THE DESTINATION
PUSHJ P,A$CPOB## ;AND COPY THE OBJECT BLOCK
MOVE S1,SUP.NO(P3) ;GET THE NODE WE ARE HEADING TO
PUSHJ P,N$NODE## ;FIND IT IN OUR DATA BASE
MOVE P4,S2 ;SAVE THE NODE DB ENTRY ADDRESS
LOAD S1,NETSTS(S2),NETIBM ;IS THIS AN IBM (DN60) REMOTE STATION
JUMPE S1,SETU.0 ;NO,,CHECK IF LOCAL AND SPECIAL DEVICE
LOAD S1,NETPTL(P4),NT.PRT ;GET THE NODE PORT NUMBER
STORE S1,SUP.CN(P3),CN$PRT ;SAVE IT IN THE MESSAGE
LOAD S1,NETPTL(P4),NT.LIN ;GET THE NODE LINE NUMBER
STORE S1,SUP.CN(P3),CN$LIN ;SAVE IT IN THE MESSAGE
LOAD S1,NETSTS(P4),NT.TYP ;GET THE REMOTE TYPE
STORE S1,SUP.CN(P3),CN$TYP ;SAVE IT IN THE MESSAGE
MOVEI S2,1 ;GET A 1
LOAD S1,NETSTS(P4),NT.MOD ;GET THE REMOTE MODE
CAIN S1,DF.EMU ;IS IT EMULATION ???
STORE S2,SUP.CN(P3),CN$ETF ;YES,,SAVE EMULATION/TERMINATION FLAG
LOAD S1,NETSTS(P4),NT.TOU ;GET THE PROTOCOL CATAGORY
CAIN S1,ST.PRI ;IS IT 'PRIMARY' ???
STORE S2,SUP.CN(P3),CN$PSP ;YES,,SAVE PRIMARY PROTOCALL FLAG
LOAD S1,NETSTS(P4),NT.TRA ;GET THE TRANSPARENCY CODE
CAIN S1,ST.ON ;IS IT ON ???
STORE S2,SUP.CN(P3),CN$TRA ;YES,,SAVE TRANSPARENCY ON FLAG
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
MOVE S1,NETCSD(P4) ;GET THE CLEAR-TO-SEND DELAY
STORE S1,SUP.CN(P3),CN$CTS ;SAVE IT IN THE MESSAGE
MOVE S1,NETSWL(P4) ;GET THE SILO WARNING LEVEL
STORE S1,SUP.CN(P3),CN$WRN ;SAVE IT IN THE MESSAGE
MOVE S1,NETBPM(P4) ;GET THE BYTES PER MESSAGE
STORE S1,SUP.CN(P3),CN$BPM ;SAVE IT IN THE MESSAGE
MOVE S1,NETRPM(P4) ;GET THE RECORDS PER MSG
STORE S1,SUP.CN(P3),CN$RPM ;SAVE IT IN THE MESSAGE
MOVE S1,NETIDN(P4) ;GET THE PORT/LINE HANDLE
STORE S1,SUP.CN(P3),CN$SIG ;SAVE IT IN THE MESSAGE
MOVE S1,NETSTS(P4) ;GET THE NODE STATUS/FLAG BITS
MOVEM S1,SUP.ST(P3) ;SAVE THEM FOR THE PROCESSOR
JRST SETU.1 ;CONTINUE ON !!!
SETU.0: LOAD S1,OBJSCH(P2),OBSSPL ;GET THE SPOOLING TO TAPE BITS
JUMPE S1,SETU.1 ;NOT SPOOLING TO TAPE,,SKIP THIS
SKIPN S1,OBJPRM+.OOTAP(P2) ;CHECK AND LOAD THE SPOOL DEVICE
JRST SETU.1 ;NO SPOOL DEVICE,,SKIP THIS
MOVEM S1,SUP.ST(P3) ;SAVE THE DEVICE NAME FOR LPTSPL
MOVX S1,SPLTAP ;GET THE SPOOL TO TAPE FLAG BIT
MOVEM S1,SUP.FL(P3) ;SAVE IT FOR THE PROCESSOR
SETU.1: MOVE S1,PSBPID(P1) ;GET PID FOR THIS PROCESSOR
STORE S1,MSGPDB+.IPCFR ;STORE AS RECEIVER'S PID
MOVE S1,[XWD SUP.SZ,MSGMSG] ;GET MSG LENGTH,,ADDRESS
STORE S1,MSGPDB+.IPCFP ;STORE INTO IPCF PDB
SETZM MSGPDB+.IPCFL ;CLEAR THE FLAG WORD
$SAVE AP ;USE THE ARGUMENT POINTER AC
MOVEI AP,MSGPDB ;TO POINTER TO PACKET DESCRIPTOR BLOCK
PUSHJ P,C$SEND## ;SEND THE MESSAGE AWAY
MOVE S1,PSBPID(P1) ;GET PID FOR THIS PROCESSOR
PUSHJ P,A$FPSB## ;TRY TO LOOK UP THIS PSB AGAIN
JUMPF .RETF ;NOT FOUND,,MUST BE GONE !!!
INCR PSBLIM(S1),PSLCUR ;ADD ONE TO CURRENT ACTIVE SLOTS
LOAD S1,PSBPID(S1) ;GET THE PROGRAM'S PID
STORE S1,OBJPID(P2) ;AND STORE IT
MOVX S1,OBSSIP ;GET "SET UP IN PROGRESS" BIT
IORM S1,OBJSCH(P2) ;AND STORE INTO STATUS FOR THIS OBJECT
MOVEI S1,3 ;NUMBER OF MINUTES TO WAIT
PUSHJ P,I$AFT## ; BEFORE GETTING UPSET THAT
STORE S1,OBJTIM(P2) ; WE HAVEN'T RECEIVED A RESPONSE
PJRST G$STIM## ;GET THE TIMER GOING
SUBTTL S$SHUT -- Send a SHUTDOWN message to a component for an object
;A SHUTDOWN message is sent for an object for a number of reasons:
; 1. Operator requested shutdown
; 2. Node is no longer on-line
; 3. If Object is remote and no queue entries
;Call: S1/ address of OBJ
INTERN S$SHUT ;MARK SHUTDOWN AS GLOBAL
SHTINT: SKIPA S2,[-1] ;INDICATE AN INTERNAL CALL TO SHUTDOWN
S$SHUT: SETZ S2, ;INDICATE NORMAL CALL TO SHUTDOWN
MOVEM S2,SHUTYP ;SAVE IT FOR LATER
$SAVE AP ;SAVE THE ARGUMENT POINTER AC
PUSHJ P,.SAVE1 ;SAVE A PERM AC
MOVE P1,S1 ;AND SAVE OUR INPUT ARGUMENT
DOSCHD ;FORCE ANOTHER SCHEDULING PASS
MOVE S1,OBJSCH(P1) ;GET SCHEDULER FLAGS
TXNN S1,OBSSUP+OBSSIP ;IS IT SETUP OR SETUP IN PROGRESS ???
JRST SHUT.1 ;NO,,JUST SHUT IT DOWN.
MOVEI S1,SUP.SZ ;ZERO OUT THE MESSAGE
MOVEI S2,MSGMSG ;BLOCK SINCE IT MAY BE RE-USED
PUSHJ P,.ZCHNK ;FOR OTHER THINGS
MOVX S1,SUP.SZ ;GET SIZE OF SETUP MESSAGE
STORE S1,MSGMSG+.MSTYP,MS.CNT ;STORE INTO MESSAGE BLOCK
MOVX S1,.QOSUP ;GET CODE FOR SETUP MESSAGE
STORE S1,MSGMSG+.MSTYP,MS.TYP ;STORE INTO MESSAGE BLOCK
MOVEI S1,OBJTYP(P1) ;GET ADR OF SOURCE OBJ
MOVEI S2,MSGMSG+SUP.TY ;GET ADR OF DESTINATION OBJ
PUSHJ P,A$CPOB## ;AND COPY THEM
MOVX S1,SUFSHT ;MOST IMPORTANTLY, GET THE
IORM S1,MSGMSG+SUP.FL ; SHUTDOWN FLAG AND SET IT
SETZM MSGPDB+.IPCFL ;CLEAR THE PDB FLAG WORD
MOVE S1,OBJPID(P1) ;GET PID TO SEND TO
STORE S1,MSGPDB+.IPCFR ;STORE AS RECEIVER'S PID
MOVE S1,[XWD SUP.SZ,MSGMSG] ;GET SIZE AND ADDRESS OF MESSAGE
STORE S1,MSGPDB+.IPCFP ;STORE INTO IPCF PDB
MOVEI AP,MSGPDB ;AS PTR TO PACKET DESCRIPTOR BLK
PUSHJ P,C$SEND## ;SEND THE MESSAGE AWAY
MOVE S1,OBJSCH(P1) ;GET THE SCHEDULING BITS.
TXZ S1,OBSSEJ ;CLEAR SHUTDOWN AT EOJ BIT
MOVEM S1,OBJSCH(P1) ;SAVE THE SCHEDULING BITS BACK
TXNE S1,OBSFRR ;IF THIS IS FREE RUNNING
$RETT ;IF SO,,THEN RETURN NOW
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
SHUT.1: MOVE S1,OBJPID(P1) ;GET THE GUY'S PID
PUSHJ P,A$FPSB## ;FIND THE PSB
SKIPF ;IF NOT THERE,,JUST CONTINUE
DECR PSBLIM(S1),PSLCUR ;ELSE, GIVE HIM 1 OFF
SETZM OBJPID(P1) ;ZAP THE CONTROLLING PID.
MOVE S1,OBJNOD(P1) ;GET THIS GUYS NODE
PUSHJ P,N$NODE## ;FIND IT IN OUR DATA BASE
LOAD S1,NETSTS(S2),NETIBM ;GET THE IBM REMOTE INDICATOR
JUMPE S1,SHUT.2 ;NOT AN IBM REMOTE,,SKIP THIS
MOVE S1,S2 ;GET NODE DB ADDRESS IN S1
MOVE S2,P1 ;AND THE OBJECT ADDRESS IN S2
PUSHJ P,N$NOFF## ;SET POSSIBLE NODE OFFLINE !!!
SHUT.2: SKIPE SHUTYP ;IF THIS IS AN INTERNAL CALL
$RETT ; THEN JUST RETURN
$WTO (Shutdown,,OBJTYP(P1)) ;TELL THE OPERATORS WHAT HAPPENED.
LOAD S1,OBJTYP(P1) ;GET THE OBJECT TYPE.
CAIN S1,.OTBAT ;IS IT A BATCH STREAM ???
AOS G$NBAT## ;YES,,BUMP BATCH COUNT BY 1.
MOVE AP,P1 ;GET THE CELL ADDRESS.
$SAVE H ;SAVE H JUST IN CASE
MOVEI H,HDROBJ## ;GET THE HEADER ADDRESS.
PJRST M$RFRE## ;DELETE THE OBJECT ENTRY AND RETURN.
SUBTTL RESPONSE-TO-SETUP -- Function 23
;The RESPONSE-TO-SETUP message is sent to QUASAR by a known component as
; the response to a SETUP message.
S$RSETUP::
DOSCHD ;SCHEDULE!!
PUSHJ P,.SAVE2 ;SAVE P1 & P2
LOAD S1,.MSTYP(M),MS.CNT ;GET MESSAGE LENGTH
CAIGE S1,RSU.SZ ;BIG ENOUGH?
PJRST E$MTS## ;NO, LOSE
MOVE S1,G$SND## ;GET THE SENDER'S PID
PUSHJ P,A$FPSB## ;FIND HIS PSB
JUMPE S1,E$NKC## ;NOT A KNOWN COMPONENT
MOVE P1,PSBPID(S1) ;GET THE PID
MOVEI S1,RSU.TY(M) ;POINT TO THE SPECIFIED OBJECT
PUSHJ P,A$FOBJ## ;FIND THE OBJ ENTRY
JUMPF E$NYO## ;ITS NOT HIS
CAME P1,OBJPID(S1) ;SEE IF IT REALLY IS HIS
PJRST E$NYO## ;ITS NOT
MOVE P1,S1 ;SAVE THE OBJECT ADDRESS IN P1
;Check the OBJECT Status
LOAD S1,OBJSCH(P1),OBSSIP ;IS SETUP IN PROGRESS?
JUMPN S1,RSET.0 ;YES,,SKIP BUSY CHECK
LOAD S1,OBJSCH(P1),OBSFRR ;GET FREE RUNNING BIT.
JUMPN S1,RSET.0 ;IF SET,,THEN DONT RE-QUEUE.
LOAD S1,OBJSCH(P1),OBSBUS ;GET BUSY BIT
JUMPE S1,RSET.0 ;RETURN IF NOT BUSY
;If Busy, Gen a Requeue MSG and Requeue the Request Being Processed
MOVX S1,REQ.SZ ;GET MESSAGE SIZE
PUSH P,M ;SAVE THE ORIGIONAL MESSAGE ADDRESS
PUSHJ P,M%GMEM ;GET SOME MEMORY
MOVE M,S2 ;PUT THE ADDRESS IN M
MOVX S2,REQ.SZ ;GET SIZE OF REQUUE MESSAGE
STORE S2,.MSTYP(M),MS.CNT ;STORE IT
MOVX S2,.QOREQ ;GET REQUEUE FUNCTION
STORE S2,.MSTYP(M),MS.TYP ;STORE IT
LOAD S2,OBJITN(P1) ;GET THE ITN
STORE S2,REQ.IT(M) ;STORE IT
MOVX S2,RQ.RLC ;RESTART AT LAST CHECKPOINT
STORE S2,REQ.FL(M) ;STORE FLAGS
PUSH P,M ;SAVE M
PUSHJ P,Q$REQUE## ;REQUEUE THE JOB
POP P,S2 ;GET MESSAGE BLOCK BACK
MOVX S1,REQ.SZ ;AND THE LENGTH
PUSHJ P,M%RMEM ;RETURN THE CORE
POP P,M ;RESTORE ORIGIONAL MSG ADDRESS.
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
RSET.0: ZERO OBJTIM(P1) ;ZERO THE TIME
SETZM P2 ;CLEAR P2
MOVE S1,OBJNOD(P1) ;GET THIS GUYS NODE NAME/NUMBER
PUSHJ P,N$NODE## ;FIND IT IN OUR DATA BASE
LOAD S1,NETSTS(S2),NETIBM ;IS THIS AN IBM REMOTE STATION ???
SKIPE S1 ;CHECK THE BIT !!
MOVE P2,S2 ;YES,,SAVE THE DATA BASE ENTRY ADDRESS
MOVE S1,RSU.CO(M) ;GET RESPONSE CODE
CAXE S1,%RSUOK ;SETUP OK?
JRST RSET.1 ;NO, TRY OTHERS
;Here if the Object Was Setup OK.
MOVX S1,OBSSUP!OBSDAA ;GET SETUP+ATTAVAIL
IORM S1,OBJSCH(P1) ;YES, SET THE SETUP FLAG
ZERO OBJSCH(P1),OBSSIP ;CLEAR SETUP-IN-PROGRESS
LOAD S1,RSU.DA(M) ;GET THE ATTRIBUTES
MOVEM S1,OBJDAT(P1) ;AND STORE IN THE OBJ
JUMPE P2,.RETT ;NOT AN IBM REMOTE,,RETURN NOW
MOVE S1,P2 ;PASS THE NODE DB ADDRESS IN S1
MOVE S2,P1 ;PASS THE OBJECT ADDRESS IN S2
PUSHJ P,N$NONL## ;IF IBM,,SET ONLINE AND TELL THE WORLD
$RETT ;RETURN
RSET.1: MOVE S2,P1 ;GET THE OBJECT ADDRESS IN S2
SKIPE S1,P2 ;CHECK AND LOAD THE IBM NODE DB ADDRESS
PUSHJ P,N$NOFF## ;IF IBM,,SET OFFLINE AND TELL THE WORLD
MOVE S1,RSU.CO(M) ;GET THE RESPONSE-2-SETUP CODE.
CAXE S1,%RSUDE ;OBJECT DOESN'T EXIST?
JRST RSET.2 ;NO, TRY OTHERS
;Here if the Object Does Not Exist.
MOVX S1,OBSSUP+OBSSIP ;GET OBJECT SETUP+IN PROGRESS BIT
ANDCAM S1,OBJSCH(P1) ;CLEAR IT (WE DONT SEND SHUTDOWN MSG)
MOVE S1,P1 ;GET THE OBJECT ADDRESS IN S1
PUSHJ P,S$SHUT ;SHUT DOWN THE OBJECT
$RETT ;AND RETURN
RSET.2: CAXE S1,%RSUNA ;OBJECT NOT AVAIL NOW?
$RETT ;NO,,JUST RETURN
;Here if the Object is Not Available Right Now.
MOVX S1,OBSBUS+OBSSUP+OBSSIP+OBSSEJ
ANDCAM S1,OBJSCH(P1) ;CLEAR LOTS OF BITS.
MOVX S1,OBSIGN ;GET IGNORE BIT.
IORM S1,OBJSCH(P1) ;AND TURN IT ON.
MOVE S1,P1 ;GET THE OBJ ADDRESS.
PUSHJ P,A$OBST## ;UPDATE THE STATUS.
SKIPE S1,RSU.CD(M) ;DID HE SEND BACK A SPECIFIC STATUS CODE
MOVEM S1,OBJSTS(P1) ;YES,,SAVE IT
MOVX S1,TIMONA ;NUMBER OF MINUTES TO WAIT
PUSHJ P,I$AFT## ;GET TIME TO MAKE AVAILABLE AGAIN
STORE S1,OBJTIM(P1) ;AND STORE IT
PUSHJ P,G$STIM## ;SET THE TIMER
MOVE S1,P1 ;GET THE OBJECT ADDRESS IN S1
PJRST SHTINT ;RETURN THROUGH SHUTDOWN CODE
SUBTTL CHKTIM -- Check various timing conditions
;CHKTIM is called at the top of the scheduler to check all OBJECTs to
; decide if any have running timers which have expired. The
; appropriate action is taken for each one found.
;In addition, CHKTIM checks each queue to see if its best AFTER job
; has come of age, and if so, it forces a scheduling pass.
CHKTIM: PUSHJ P,.SAVE1 ;SAVE P1
LOAD P1,HDROBJ##+.QHLNK,QH.PTF ;POINT TO FIRST OBJECT
CHKT.1: JUMPE P1,CHKT.5 ;NO MORE, CHECK QUEUES
SKIPE S2,OBJTIM(P1) ;IS THERE A TIMER SET?
CAMLE S2,G$NOW## ;YES, IS IT EXPIRED?
JRST CHKT.4 ;NO, NEXT OBJECT PLEASE
ZERO OBJTIM(P1) ;CLEAR THE TIMER WORD
MOVX S2,OBSIGN ;GET THE IGNORE BIT
TDNN S2,OBJSCH(P1) ;IS IT SET?
JRST CHKT.2 ;NO, CONTINUE ON
ANDCAM S2,OBJSCH(P1) ;YES, CLEAR IT
DOSCHD ;AND FORCE A SCHED PASS
LOAD S1,OBJTYP(P1) ;GET THE OBJECT TYPE
CAIN S1,.OTNOT ;IS IT ARCHIVE NOTIFICATION ???
SETOM G$NTFY## ;YES,,SCHEDULE IT
CHKT.2: LOAD S2,OBJSCH(P1),OBSBUS ;GET BUSY BIT
JUMPN S2,CHKT.3 ;JUMP IF IT IS SET
LOAD S2,OBJSCH(P1),OBSSIP ;SETUP-IN-PROGRESS?
JUMPE S2,CHKT.4 ;NOT SET, GET NEXT OBJECT
CHKT.3: $SAVE AP ;SAVE AP BECAUSE WE NEED IT
MOVE AP,P1 ;PUT OBJ POINTER IN AP FOR A MINUTE
MOVX S1,RCK.SZ ;GET MESSAGE LENGTH
STORE S1,MSGMSG+.MSTYP,MS.CNT ;STORE IT
MOVX S1,.QORCK ;GET MESSAGE TYPE
STORE S1,MSGMSG+.MSTYP,MS.TYP ;AND STORE IT
MOVEI S1,OBJTYP(AP) ;GET ADDRESS OF OBJECT BLOCK
MOVEI S2,MSGMSG+RCK.TY ;PLACE TO MOVE IT TO
PUSHJ P,A$CPOB## ;MOVE IT
MOVE S2,OBJITN(AP) ;GET JOB ITN
STORE S2,MSGMSG+RCK.IT ;STORE IT
LOAD S2,OBJPID(AP) ;AND GET THE PID
MOVEI AP,MSGPDB ;LOAD ADDRESS OF IPCF PDB
MOVEM S2,.IPCFR(AP) ;STORE RECEIVER'S PID
ZERO .IPCFL(AP) ;CLEAR THE FLAGS
MOVX S2,<RCK.SZ,,MSGMSG> ;GET LEN,ADR
MOVEM S2,.IPCFP(AP) ;SAVE IT
TXO AP,IPS.ID ;DONT SEND IF OTHERS QUEUED FOR PID
PUSHJ P,C$SEND ;SEND THE MESSAGE
MOVX S1,SPLMBC ;GET MINUTES BETWEEN CHECKPOINTS
PUSHJ P,I$AFT## ;GET TIME IN THE FUTURE
STORE S1,OBJTIM(P1) ;SAVE IT
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
CHKT.4: SKIPE S1,OBJTIM(P1) ;GET TIMER AND SKIP IF 0
PUSHJ P,G$STIM## ;ELSE SET THE ALARM CLOCK
LOAD P1,.QELNK(P1),QE.PTN ;POINT TO NEXT OBJECT
JRST CHKT.1 ;AND LOOP
;HERE TO LOOP THROUGH THE QUEUES TO SEE IF ANY AFTER JOBS HAVE COME OF AGE
CHKT.5: MOVSI P1,-NQUEUE## ;GET -VE LENGTH,,0
HRRI P1,TBLHDR## ;FORM AOBJN POINTER TO QUEUE HDRS
CHKT.6: SKIPE S1,.QHAFT(P1) ;IS THERE AN AFTER JOB OF IMPORTANCE?
CAML S1,G$NOW## ;YES, IS IT OLD ENOUGH?
JRST CHKT.7 ;NO, ON TO NEXT QUEUE
SETZM .QHAFT(P1) ;YES, CLEAR THE TIMER
DOSCHD ;FORCE A SCHEDULING PASS
CHKT.7: SKIPE S1 ;SKIP IF NO TIMER
PUSHJ P,G$STIM## ;ELSE, SET THE ALARM CLOCK
ADDI P1,QHSIZE-1 ;BUMP TO NEXT HDR (-1 FOR AOBJN)
AOBJN P1,CHKT.6 ;AND LOOP
$RETT ;RETURN WHEN DONE
SUBTTL CHKOBJ - ROUTINE TO CHK OBJECTS AND SHUT THEM DOWN IF NECESSARY
;CALL: P1/ OBJECT ADDRESS
;
;RET: TRUE ALWAYS
CHKOBJ: LOAD S1,OBJSCH(P1) ;GET THE OBJECT SCHEDULING BITS
TXNE S1,OBSINT ;IS INTERNAL SHUTDOWN BIT LIT ???
JRST CHKO.1 ;YES,,LETS DO IT
MOVE S1,OBJNOD(P1) ;GET THE NODE NAME/NUMBER
PUSHJ P,N$NODE## ;FIND THE NODE IN OUR DATA BASE
MOVE S2,NETSTS(S2) ;GET THE NODE STATUS BITS
TXNE S2,NETIBM ;IS THIS AN IBM TYPE NODE ???
$RETT ;YES,,NO INTERNAL SHUTDOWN
PUSHJ P,N$LOCL## ;SEE IF IT IS THE CENTRAL SITE.
JUMPT .RETT ;IF SO,,NO SHUTDOWN
CHKO.1: MOVE S1,P1 ;GET THE OBJECT ADDRESS IN S1.
PUSHJ P,SHTINT ;SHUT DOWN THE OBJECT
MOVX S1,OBSSUP+OBSBUS+OBSSEJ+OBSSIP+OBSINT ;GET LOTS OF BITS
ANDCAM S1,OBJSCH(P1) ;AND CLEAR THEM
MOVEI S1,5 ;WAIT FOR 5 MINUTES
PUSHJ P,I$AFT## ;CONVERT IT TO UNV DATE/TIME
STORE S1,OBJTIM(P1) ;SAVE IT.
PUSHJ P,G$STIM## ;SET THE TIMER
MOVX S1,OBSIGN+OBSHUT ;GET THE IGNORE+SHUTDOWN BIT
IORM S1,OBJSCH(P1) ;AND SET IT
MOVE S1,P1 ;GET THE OBJECT ADDRESS
PUSHJ P,A$OBST## ;UPDATE THE OBJECT STATUS
$RETT ;RETURN
SUBTTL Queue Dependent Functions
;The functions which vary from queue to queue are handled via a
; 'scheduling vector' associated with each queue. The address
; of this vector is part of the queue header. A queue dependent
; routine is called by:
; load arguments in correct ACs
; LOAD xx,<HDRyyy+.QHPAG>,QH.SCH
; PUSHJ P,disp(xx)
;The entries are (not in order):
; SCHLNK called by everybody to link an entry into a queue
; call: AP/ address of entry
; H/ address of queue header
; SCHFJB called by scheduler (S$SCHD) to find a job for an object
; call: S1/ address of OBJ entry
; T rtn: S1/ address of available .QE
; F rtn: no jobs available for the object
; SCHDEF called by Q$CREATE to fill in defaults in CREATE message
; call: M/ address of CREATE message
; SCHMOD call by Q$MODIFY to do modify queue dependent parameters
; call: S1/ address of group header
; AP/ address of request (.EQ)
; SCHSCH called by the scheduler (S$SCHD) to actually schedule and
; interlock a job on an OBJECT.
; call: S1/ address of the queue request
; S2/ address of the OBJ entry
; SCHRJI called by Q$RELEASE, Q$REQUEUE, KILPSB (in QSRADM) to clean up
; a job-OBJECT interlock.
; call: AP/ address of request being un-interlocked
SUBTTL INP -- Input queue dependent functions
;The INP queue scheduler vector
S$INPT:: JRST INPLNK ;LINK IN A NEW ENTRY
JRST INPSCH ;SCHEDULE A JOB FOR AN OBJECT
JRST INPDEF ;FILL IN DEFAULTS FOR A JOB
JRST INPMOD ;MODIFY INP PARAMETERS
JRST INPRJI ;RELEASE JOB INTERLOCK
JRST INPFJB ;FIND A JOB FOR AN OBJECT
;<- - - - - - - - - - - - - - - - - - - - - - - - ->
INPLNK: GETLIM S1,.QELIM(AP),TIME ;GET /TIME PARAMETER
GETLIM S2,.QELIM(AP),DEPN ;GET /DEPEND
SKIPE S2 ;IS THERE A DEPENDENCY?
HRLOI S1,777 ;YES, MAKE IT LOOK BAD
MOVEI S2,^D10 ;LOAD AGING FACTOR
JRST LNKPRI ;AND LINK IT IN
INPSCH: PUSHJ P,.SAVE2 ;SAVE P1 AND P2
DMOVE P1,S1 ;SAVE ARGS FOR A SEC
GETLIM S1,.QELIM(P1),TIME ;GET THE TIME LIMIT
$SAVE AP ;SAVE AP
MOVE AP,P1 ;PUT REQUEST ADDRESS IN AP
LOAD S1,OBJUNI(P2) ;GET 'STREAM NUMBER' IN S1
PUSHJ P,I$UQST## ;SET THE UNIQNESS ENTRY
DMOVE S1,P1 ;GET ARGS BACK
PJRST NEXTJB ;SEND THE NEXTJOB AND RETURN
INPRJI: LOAD S1,.QEOBJ(AP) ;GET ADDRESS OF OBJECT
LOAD S1,OBJUNI(S1) ;GET UNIT NUMBER
PUSHJ P,I$UQCL## ;CLEAR IT
PJRST JOBDUN ;AND FINISH UP
INPFJB: PUSHJ P,.SAVE4 ;SAVE P1-P4
MOVE P1,S1 ;COPY OBJ ADR INTO P1
SKIPN G$LOGN## ;ARE LOGINS ALLOWED?
$RETF ;NO, RETURN
ZERO HDRINP##+.QHAFT ;PREPARE FOR A NEW AFTER CHECK
LOAD P4,HDRINP##+.QHLNK,QH.PTF ;POINT TO THE FIRST ENTRY
INPF.1: JUMPE P4,.RETF ;NO JOBS, JUST RETURN
MOVE S1,.QEROB+.ROBND(P4) ;GET THIS JOBS REQUESTED NODE
PUSHJ P,N$CSTN## ;CONVERT FOR ROUTING.
CAME S1,OBJNOD(P1) ;DO WE MATCH ????
JRST INPF.3 ;NO,,SKIP THIS JOB.
LOAD S1,.QECRE(P4) ;GET JOB CREATION TIME
CAMLE S1,G$NOW## ;IN THE FUTURE?
JRST [CAML S1,HDRINP##+.QHAFT ;YES, IS THERE ONE SOONER?
SKIPN HDRINP##+.QHAFT ;NO, UNLESS WORD WAS ZERO
MOVEM S1,HDRINP##+.QHAFT ;THIS IS THE SOONEST AND BEST
MOVE S1,HDRINP##+.QHAFT ;GET THE AFTER TIME
PUSHJ P,G$STIM## ;SET THE ALARM CLOCK
JRST INPF.3] ;BUT IGNORE JOB FOR NOW
GETLIM S2,.QELIM(P4),DEPN ;GET DEPENDENCY COUNT
JUMPN S2,INPF.3 ;NON-ZERO DEPEND, TRY LATER
LOAD S2,.QESEQ(P4),QE.HBO ;GET HOLD BY OPR BIT
JUMPN S2,INPF.3 ;SET, GO ON TO NEXT JOB
LOAD S2,.QESEQ(P4),QE.PRI ;GET EXTERNAL PRIORITY
LOAD P2,OBJPRM+.OBPRI(P1),OBPMIN ;GET MINIMUM
LOAD P3,OBJPRM+.OBPRI(P1),OBPMAX ;GET MAXIMUM
CAML S2,P2 ;GREATER THAN MIN?
CAMLE S2,P3 ;LESS THAN MAX?
JRST INPF.3 ;NO, LOSE
GETLIM S1,.QELIM(P4),TIME ;GET TIME LIMIT IN SECONDS.
IDIVI S1,^D60 ;CALC TIME LIMIT IN MINUTES.
LOAD P2,OBJPRM+.OBTIM(P1),OBPMIN ;GET MIN
LOAD P3,OBJPRM+.OBTIM(P1),OBPMAX ;GET MAX
CAML S1,P2 ;GREATER THAN MIN?
CAMLE S1,P3 ;AND LESS THAN MAX?
JRST INPF.3 ;NO, LOSE
GETLIM S2,.QELIM(P4),TIME ;GET THE TIME LIMIT IN SECONDS.
SKIPE G$KSYS## ;CHECK NUMBER OF SECONDS TILL KSYS
CAMGE S2,G$KSYS## ;IS RUNTIME LESS THE TIME LEFT TIL KSYS
SKIPA ;NO KSYS or RUNTIME LESS,,THEN CONTINUE
JRST INPF.3 ;HE LOSES,,NEXT PLEASE
INPF.2: LOAD S1,OBJPRM+.OBFLG(P1),.OPRIN ;GET OBJECT OPR INTRVN BITS
GETLIM S2,.QELIM(P4),OINT ;FOR QUEUE ENTRY ALSO
CAME S1,S2 ;MUST BE THE SAME..
CAIN S1,.OPINY ; OR OBJECT MUST BE OPR INTRVN ALLOWD
SKIPA ;IF EITHER OF THE ABOVE HE WINS !!
JRST INPF.3 ;ELSE THIS QUEUE ENTRY LOSES !!!
;CONTINUED ON FOLLOWING PAGE
;CONTINUED FROM PREVIOUS PAGE
IFN INPCOR,<
LOAD S2,.QELM2(P4),QE.COR ;GET /CORE SWITCH
LOAD P2,OBJPRM+.OBCOR(P1),OBPMIN ;GET MIN
LOAD P3,OBJORM+.OBCOR(P1),OBPMAX ;GET MAX
CAML S2,P2 ;CHECK THE RANGE
CAMLE S2,P3 ;TO SEE IF IT WILL FIT
JRST INPF.3 ;GUESS NOT
CAMLE S2,G$XCOR## ;IS IT LESS THAN CORMAX?
JRST INPF.3 ;NO, LOSE
> ;END IFN INPCOR
EXCH AP,P4 ;SAVE AP GET P4
PUSHJ P,I$UQCH## ;SEE IF WE CAN RUN THIS ONE
SKIPF ;SKIP IF IT CANT BE RUN
PUSHJ P,Q$CDEP## ;EVALUATE ALL DEPENDENCIES
JUMPF [EXCH AP,P4 ;RESTORE AP
JRST INPF.3] ;AND ON TO THE NEXT ONE
MOVE S1,AP ;LOAD THE WINNER
$RETT ;AND RETURN
INPF.3: LOAD P4,.QELNK(P4),QE.PTN ;GET THE NEXT
JRST INPF.1 ;AND LOOP
SUBTTL INPDEF - ROUTINE TO DEFAULT THE BATCH EQ ENTRY
;CALL: M/ Create Msg Address
;
;RET: True Always
INPDEF: MOVE S1,G$LNAM## ;GET OUR CENTRAL SITE NODE ID
SKIPN .EQROB+.ROBND(M) ;DID HE SPECIFY A PROCESSING NODE ???
MOVEM S1,.EQROB+.ROBND(M) ;NO,,SAVE CENTRAL SITE ID
PUSHJ P,EQDFLT ;DEFAULT THE EQ
PDFALT S1,.EQLIM(M),OUTP,INPLOG ;SET DEFAULT /OUTPUT:
PDFALT S1,.EQLIM(M),UNIQ,%EQUYE ;SET DEFAULT /UNIQUE:YES
PDFALT S1,.EQLIM(M),REST,%EQRNO ;SET DEFAULT /RESTART:NO
PDFALT S1,.EQLIM(M),TIME,INPTIM ;SET DEFAULT TIME VALUE
PDFALT S1,.EQLIM(M),SLPT,INPPGS ;SET DEFAULT PAGE VALUE
PDFALT S1,.EQLIM(M),SCDP,INPCDS ;SET DEFAULT CARD VALUE
PDFALT S1,.EQLIM(M),SPTP,INPPTP ;SET DEFAULT PAPER TAPE VALUE
PDFALT S1,.EQLIM(M),SPLT,INPPLT ;SET DEFAULT PLOTTER VALUE
PDFALT S1,.EQLIM(M),OINT,.OPINY ;OPERATOR INTERVENTION REQUIRED
PDFALT S1,.EQLIM(M),BLOG,%BAPND ;SET DEFAULT BATCH LOG TYPE
GETLIM S1,.EQLIM(M),ONOD ;GET OUTPUT NODE NUMBER
SKIPN S1 ;HE SET IT, SO SKIP THIS
PUSHJ P,I$ONOD## ;NOT SET,,GO DEFAULT IT
GETLIM S1,.EQLIM(M),CORE ;GET /CORE VALUE
SKIPN S1 ;IS THERE ONE?
MOVX S1,INPCOR ;NO, USE DEFAULT
CAMGE S1,G$MCOR## ;IS IT GREATER THAN MINIMUM
MOVE S1,G$MCOR## ;NO, GET MINIMUM
STOLIM S1,.EQLIM(M),CORE ;NO, SET TO SYSTEM MINIMUM
LOAD S1,.EQSPC(M),EQ.NUM ;GET NUMBER OF FILES IN REQUEST
GETLIM T1,.EQLIM(M),BLOG ;GET THE LOG FILE TYPE
CAIE T1,%BSPOL ;IS IT A SPOOLED LOG FILE,
CAIG S1,1 ; OR IS THERE NO LOG FILE ???
SKIPA ;YES TO EITHER,,SKIP
$RETT ;ELSE RETURN
PUSHJ P,.SAVE1 ;SAVE P1 FOR A MINUTE
MOVE P1,M ;GET ADDRESS OF THE EQ
LOAD S2,.EQLEN(P1),EQ.LOH ;GET LENGTH OF THE HEADER
ADD P1,S2 ;POINT TO FIRST FP
LOAD S2,.FPLEN(P1),FP.LEN ;GET LENGTH OF THE FP
ADD P1,S2 ;POINT TO THE FD
LOAD S2,.FDLEN(P1),FD.LEN ;GET FD LENGTH
ADD P1,S2 ;HERE'S WHERE WE PUT THE NEXT FP
MOVE S1,P1 ;GET THE NEXT FILE-SPEC ADDR IN S2
SUB S1,M ;CALC THE REAL MESSAGE LENGTH
STORE S1,.MSTYP(M),MS.CNT ;AND SAVE IT IN THE MESSAGE
MOVEI S1,2 ;GET THE FILE COUNT
STORE S1,.EQSPC(M),EQ.NUM ;SAVE IT IN THE MESSAGE
MOVEI S1,FPMSIZ ;GET THE FP SIZE
STORE S1,.FPLEN(P1),FP.LEN ;STORE IT
MOVEI S1,1 ;GET THE STARTING POINT
STORE S1,.FPFST(P1) ;STORE IT
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
MOVX S1,FP.FLG ;GET THE LOG FLAG BIT
CAIE T1,%BSPOL ;IS IT A SPOOLED FILE ???
JRST INPD.1 ;NO,,SKIP THIS 'SPOOL' ONLY CODE
MOVX S2,EQ.SPL ;GET "SPOOLED FILES HERE" BIT
IORM S2,.EQSEQ(M) ; THEN STORE IT
TXO S1,FP.SPL+FP.DEL ;ADD 'SPOOL+DELETE' TO FP INFO
INPD.1: STORE S1,.FPINF(P1) ;STORE THE FP FLAGS
MOVE S2,P1 ;GET THE FP ADDRESS IN S2
ADDI P1,FPMSIZ ;POINT TO THE FD
MOVE S1,P1 ;GET THE FD ADDRESS IN S1
PUSHJ P,I$LGFD## ;GENERATE THE LOG FILE FD
LOAD S2,.MSTYP(M),MS.CNT ;GET MESSAGE LENGTH
ADDI S2,FPMSIZ ;ADD THE FP SIZE
LOAD S1,.FDLEN(P1),FD.LEN ;GET THE FD SIZE
ADD S2,S1 ;ADD IT IN
STORE S2,.MSTYP(M),MS.CNT ;STORE THE MESSAGE LENGTH AWAY
$RETT ;AND RETURN
;ROUTINE TO DO INP QUEUE SPECIFIC REQUEST MODIFICATION
INPMOD: PUSHJ P,.SAVE4 ;SAVE A FEW REGS FIRST
LOAD P1,MOD.GN(S1),MODGLN ;NUMBER OF GROUP 1 ELEMENTS
SOJLE P1,.RETT ;0 IS ACCEPTABLE, ADJUST FOR THE LOOP
CAILE P1,NINPPM ;MORE THAN CURRENTLY IMPLEMENTED
MOVEI P1,NINPPM ;YES, USE ONLY THE KNOWN VALUES
MOVNS P1 ;NEGATE IT
HRLZS P1 ;P1 = AOBJN POINTER
MOVEI P2,MOD.GE(S1) ;POINT TO FIRST GROUP ELEMENT
INPM.1: MOVE P3,0(P2) ;GET AN ELEMENT
CAME P3,[-1] ;DID IT CHANGE
XCT INPMTB(P1) ;YES, STORE NEW VALUE
INCR P2 ;TO NEXT ELEMENT
AOBJN P1,INPM.1 ;GET THEM ALL
$RETT ;RETURN TO Q$MODIFY FOR NEXT GROUP
INPMTB: STOLIM P3,.EQLIM(AP),CORE ; 0 = /CORE
STOLIM P3,.EQLIM(AP),TIME ; 1 = /TIME
STOLIM P3,.EQLIM(AP),SLPT ; 2 = /PAGES
STOLIM P3,.EQLIM(AP),SCDP ; 4 = /CARDS
STOLIM P3,.EQLIM(AP),SPTP ; 4 = /FEET
STOLIM P3,.EQLIM(AP),SPLT ; 5 = /TPLOT
PUSHJ P,MODDEP ; 6 = /DEPENDENCY
STOLIM P3,.EQLIM(AP),UNIQ ; 7 = /UNIQUE
STOLIM P3,.EQLIM(AP),REST ; 8 = /RESTART
STOLIM P3,.EQLIM(AP),OUTP ; 9 = /OUTPUT
PUSHJ P,MODBEG ;10 = /BEGIN
STOLIM P3,.EQLIM(AP),ONOD ;11 = /DESTINATION NODE
NINPPM==<.-INPMTB> ;NUMBER CURRENTLY IMPLEMENTED
MODDEP: HLRZ P4,P3 ;GET CHANGE TYPE
HRRZS P3 ;CLEAR THE CHANGE TYPE
CAIN P4,.MODAB ;ABSOLUTE CHANGE
JRST MODD.2 ;YES, GO STORE IT
CAIN P4,.MODPL ;ADDITIVE
JRST MODD.1 ;YES, GO ADD THEM TOGETHER
CAIE P4,.MODMI ;SUBTRACTIVE
$RETT ;NO, DON'T STORE FOR UNKNOWN TYPE
MOVNS P3 ;SUBTRACTING, NEGATE THE VALUE
MODD.1: GETLIM P4,.EQLIM(AP),DEPN ;GET OLD VALUE
ADDB P3,P4 ;ADD (OR SUBTRACT) THEM
SKIPGE P3 ;DON'T LET IT GO NEGATIVE
ZERO P3 ;IT DID, MAKE IT ZERO
CAILE P3,177777 ;OR DON'T LET IT GET TOO BIG
MOVEI P3,177777 ;IT DID, SET TO MAXIMUM
MODD.2: STOLIM P3,.EQLIM(AP),DEPN ;STORE NEW (OR ADJUSTED) VALUE
$RETT ;RETURN FOR NEXT
MODBEG: LOAD P4,.EQLEN(AP),EQ.LOH ;GET LENGTH OF HEADER
ADD P4,AP ;GET ADDRESS OF FIRST FP
STORE P3,.FPFST(P4) ;STORE THE /BEGIN IN CTL FP
$RETT ;AND RETURN
SUBTTL S$INRL - ROUTINE TO PROCESS BATCH RELEASE MESSAGES
;This routine is called by Q$RELEASE to process the special extended RELEASE
; message for INP jobs.
;Call: M = THE RELEASE MESSAGE
; AP = ENTRY BEING RELEASED (.QExxx)
S$INRL:: PUSHJ P,.SAVE1 ;SAVE P1
PUSHJ P,.SAVET ;SAVE T1 THRU T4
$SAVE AP ;SAVE AP
$SAVE M ;SAVE M
LOAD P1,.MSTYP(M),MS.CNT ;GET LENGTH OF RELEASE MESSAGE
SUBI P1,REL.SZ ;EXPECT A LONG ONE FROM BATCON
JUMPLE P1,.RETT ;NOT FROM BATCON (OR A BUG IN BATCON)
STORE AP,<BATLGO+CLM.JB>,CL.BQE ;SAVE THE BATCH QUEUE ENTRY ADDRESS
LOAD T2,REL.BJ(M),RL.JOB ;GET BATCH JOB NUMBER
STORE T2,<BATLGO+CLM.JB>,CL.JOB ;SAVE FOR EVENTUAL FAKE LOGOUT
SOJE P1,BJLOGO ;ADJUST P1, JUMP IF WAS /OUTPUT:0
CAIGE P1,FDMSIZ ;MESSAGE TOO SMALL
JRST BJLOGO ;ANOTHER BUG IN BATCON
MOVEI T1,BATSPL ;POINT TO 'MY' CANONICAL SPOOL MESSAGE
STORE T2,CSM.JB(T1),CS.JOB ;STORE JOB NUMBER, CLEAR THE REST
ZERO CSM.JB(T1),CS.FLG ;NO FLAGS HERE
MOVX S1,.OTLPT ;GET DEVICE LPT
STORE S1,CSM.RO+.ROBTY(T1) ;STORE IN THE CSM
GETLIM S1,.QELIM(AP),ONOD ;GET OUTPUT NODE
STORE S1,CSM.RO+.ROBND(T1) ;AND STORE IT
MOVE T2,.QEOID(AP) ;GET OWNER ID
STORE T2,CSM.OI(T1) ;SAVE THAT
PUSHJ P,I$QESM## ;MOVE SYS DEPENDANT INFO FROM QE TO CSM
MOVEI S1,REL.FD(M) ;POINT TO THE LOG FILE FD AREA
LOAD S2,.FDLEN(S1),FD.LEN ;GET THE FD LENGTH
CAME S2,P1 ;THE RIGHT LENGTH?
JRST BJLOGO ;NO, LOSE
STORE S1,CSM.FD(T1),CS.FDA ;SAVE FOR Q$INCL
PUSHJ P,Q$FSPL## ;FIND MATCHING SPOOL REQUEST
MOVX T2,FP.FLG ;GET THE LOG FILE FLAG
LOAD S1,REL.BJ(M) ;GET RELEASE INFO WORD
TXNE S1,RL.DLG ;/DISP:DELETE
TXO T2,FP.DEL ;YES, SET THE DELETE BIT
TXNE S1,RL.SPL ;IS THE LOG FILE SPOOLED?
TXO T2,FP.SPL ;YES, SET THE SPOOLED BIT
MOVEM T2,CSM.FP(T1) ;STORE THE FLAG SETTINGS
PUSHJ P,Q$INCL## ;INCLUDE THE LOG FILE
MOVE S1,AP ;GET THE ADDRESS INTO S1
PUSHJ P,F$WRRQ## ;SAVE THE REQUEST
LOAD S2,SPLJOB(E),SPYDPA ;GET THE OLD DPA
STORE S1,SPLJOB(E),SPYDPA ;STORE NEW RETREIVAL POINTER
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
SKIPE S1,S2 ;GET OLD DPA IF THERE IS ONE
PUSHJ P,F$RLRQ## ;AND RELEASE OLD FAILSOFT COPY
MOVE S1,AP ;COPY THE PAGE OVER
PUSHJ P,M%RPAG ;RELEASE OLD COPY
BJLOGO: MOVEI M,BATLGO ;POINT TO THE LOGOUT BLOCK
MOVX S1,.QIFNC ;GET THE INTERNAL FLAG
IORM S1,.MSTYP(M) ;INDICATE BATCH CALL TO LOGOUT
PJRST Q$LOGOUT## ;FAKE A LOGOUT MESSAGE
BATSPL: BLOCK CSMSIZ ;ARGUMENT BLOCK FOR Q$FSPL, Q$INCL
BATLGO: BLOCK CLMSIZ ;LOGOUT BLOCK
SUBTTL S$REQU - ROUTINE TO PROCESS BATCH REQUEUE MESSAGES
;This routine is called by Q$REQUEUE to generate a fake LOGOUT
; so that spooled files generated before the REQUEUE will be
; printed now.
;Call: AP = ENTRY BEING REQUEUED (.QExxx)
;Ret: True Through Q$LOGOUT
INTERN S$REQU ;MAKE IT GLOBAL
S$REQU: $SAVE AP ;SAVE AP ACROSS THE Q$LOGOUT CALL
$SAVE M ;SAVE M ACROSS THE Q$LOGOUT CALL
MOVEI M,BATLGO ;GET THE LOGOUT MESSAGE ADDRESS
LOAD S1,.QEJBN(AP),QE.BJN ;GET THE BATCH JOB NUMBER
JUMPE S1,.RETT ;NONE THERE,,JUST RETURN
STORE S1,CLM.JB(M),CL.JOB ;SAVE THE JOB NBR IN THE LOGOUT MSG
STORE AP,CLM.JB(M),CL.BQE ;SAVE THE BATCH QE ENTRY ADDRESS
MOVX S1,.QIFNC ;GET THE INTERNAL FUNCTION BIT
STORE S1,.MSTYP(M) ;SAVE IT IN THE LOGOUT MSG
PJRST Q$LOGOUT## ;LEAVE THROUGH Q$LOGOUT
SUBTTL LPT -- Lineprinter queue dependent functions
;The LPT queue scheduler vector
S$LPT:: JRST LPTLNK ;LINK IN A NEW ENTRY
JRST LPTSCH ;SCHEDULE A JOB FOR AN OBJECT
JRST LPTDEF ;FILL IN DEFAULTS FOR A JOB
JRST LPTMOD ;MODIFY LPT PARAMETERS
JRST LPTRJI ;RELEASE A JOB INTERLOCK
JRST LPTFJB ;FIND A JOB FOR AN OBJECT
;<- - - - - - - - - - - - - - - - - - - - - - - - ->
LPTLNK: GETLIM S1,.QELIM(AP),OLIM ;GET OUTPUT LIMIT
MOVEI S2,^D60 ;AND AGING FACTOR
PJRST LNKPRI ;AND LINK IT IN
LPTMOD: JRST OUTMOD ;MODIFY IS SAME FOR ALL OUTPUT QUEUES
LPTSCH: JRST NEXTJB ;JUST SEND A NEXTJOB MESSAGE
LPTRJI: JRST JOBDUN ;USE COMMON ROUTINE TO CLEAN UP
LPTFJB: PUSHJ P,.SAVE2 ;SAVE P1 AND P2
MOVE P1,S1 ;SAVE OBJ ADDRESS IN P1
ZERO HDRLPT##+.QHAFT ;PREPARE FOR A NEW AFTER CHECK
LOAD P2,HDRLPT##+.QHLNK,QH.PTF ;GET FIRST ITEM IN THE QUEUE
LPTF.1: JUMPE P2,.RETF ;FAIL IF NO JOBS
LOAD S1,OBJSCH(P1),OBSSPL ;GET THE SPOOLING TO TAPE BIT
JUMPN S1,LPTF.2 ;IF SPOOLING TO TAPE,,SKIP ATTR CHK
LOAD S2,.QEROB+.ROBAT(P2) ;GET THE ATTRIBUTES
TXNE S2,RO.PHY ;DID HE SPECIFY A PHYSICAL UNIT
JRST LPTF.2 ;YES, SKIP ATTRIBUTES CHECK
LOAD S1,OBJSCH(P1) ;GET ALL THE SCHEDULER FLAGS
TXNN S1,OBSSUP!OBSDAA ;SKIP IF SETUP OR ATTR ARE AVAIL
JRST LPTF.2 ;ELSE, SKIP ATTRIBUTES CHECK
TDZ S2,OBJDAT(P1) ;YES, MASK THEM OUT
JUMPN S2,LPTF.4 ;LOSE IF NOT SATISFIED
LPTF.2: MOVE S1,G$KSYS## ;GET SECONDS TILL KSYS
SKIPE S1 ;SKIP IF NONE SET
CAIL S1,<^D60*^D15> ;IGNORE IT MORE THAN 15 MINS AWAY
JRST LPTF.3 ;EFFECTIVELY NO KSYS SET
IDIVI S1,6 ;AVG 600LPM IS APPROX. 1PG EVERY 6SECS
GETLIM S2,.QELIM(P2),OLIM ;GET ACTUAL LIMIT
CAMGE S1,S2 ;ENOUGH TIME?
JRST LPTF.4 ;NO, IGNORE THE JOB
LPTF.3: MOVE S1,P2 ;COPY OVER THE REQUEST ADDRESS
MOVE S2,P1 ;PUT OBJ ADR INTO S2
PUSHJ P,OUTFJB ;RUN THRU SOME COMMON CODE
JUMPT .RETT ;WIN IF HE DID
LPTF.4: LOAD P2,.QELNK(P2),QE.PTN ;GET NEXT
JRST LPTF.1 ;AND LOOP
LPTDEF: MOVX S1,LPTDIV ;GET THE PER DISKBLK DIVISOR
MOVX S2,LPTMUL ;GET THE PER DSIKBLK MULTIPLIER
MOVX T1,INPPGS ;GET THE DEFAULT LIMIT
PUSHJ P,OUTDEF ;USE SOME COMMON CODE
LOAD S1,.EQSPC(M),EQ.NUM ;GET NUMBER OF FILES
LOAD S2,.EQLEN(M),EQ.LOH ;GET LENGTH OF HEADER
ADDI S2,(M) ;POINT TO FIRST FP
PUSH P,P1 ;SAVE P1
LPTD.1: VDFALT P1,.FPINF(S2),FP.FFF,.FPFAS ;DEFAULT /FILE:ASCII
VDFALT P1,.FPINF(S2),FP.FPF,%FPLAS ;DEFAULT /PRINT:ASCII
VDFALT P1,.FPINF(S2),FP.FCY,1 ;DEFAULT /COPIES:1
VDFALT P1,.FPINF(S2),FP.FSP,1 ;DEFAULT /SPACE:SINGLE
VDFALT P1,.FPFST(S2),,1 ;DEFAULT /BEGIN:1
LOAD P1,.FPLEN(S2),FP.LEN ;GET LENGTH OF THE FP
ADD S2,P1 ;POINT TO THE FD
LOAD P1,.FDLEN(S2),FD.LEN ;GET LENGTH OF THE FD
ADD S2,P1 ;POINT TO THE NEXT FP
SOJG S1,LPTD.1 ;AND LOOP
POP P,P1 ;RESTORE P1
$RETT ;AND RETURN
SUBTTL CDP -- Card-punch queue dependent functions
;The CDP queue scheduler vector
S$IBM:: ;SCHEDULE IBM QUEUE SAME AS CDP QUEUE
S$CDP:: JRST CDPLNK ;LINK IN A NEW JOB
JRST CDPSCH ;SCHEDULE A JOB FOR AN OBJECT
JRST CDPDEF ;FILL IN DEFAULTS FOR A JOB
JRST CDPMOD ;MODIFY CDP PARAMETERS
JRST CDPRJI ;RELEASE A JOB INTERLOCK
JRST CDPFJB ;FIND A JOB FOR AN OBJECT
;<- - - - - - - - - - - - - - - - - - - - - - - - ->
CDPDEF: MOVX S1,CDPDIV ;GET THE PER DISKBLK DIVISOR
MOVX S2,CDPMUL ;GET THE PER DISKBLK MULTIPLIER
MOVX T1,INPCDS ;GET THE DEAFULT LIMIT
JRST OUTDEF ;AND USE COMMON CODE
CDPLNK: GETLIM S1,.QELIM(AP),OLIM ;GET OUTPUT LIMIT
MOVEI S2,^D60 ;AND AGING FACTOR
PJRST LNKPRI ;AND LINK IT IN
CDPMOD: JRST OUTMOD ;MODIFY IS SAME FOR ALL OUTPUT QUEUES
CDPSCH: JRST NEXTJB ;SEND A NEXTJOB MESSAGE
CDPRJI: JRST JOBDUN ;COMMON CLEANUP ROUTINE
CDPFJB: PUSHJ P,.SAVE2 ;SAVE P1 AND P2
MOVE P1,S1 ;SAVE OBJ ADDRESS IN P1
ZERO HDRCDP##+.QHAFT ;START FRESH
LOAD S1,HDRCDP##+.QHLNK,QH.PTF ;GET FIRST ITEM IN THE QUEUE
CDPF.1: JUMPE S1,.RETF ;FAIL IF NO JOBS
MOVE P2,S1 ;COPY OVER THE REQUEST ADDRESS
MOVE S2,P1 ;PUT OBJ ADR INTO S2
PUSHJ P,OUTFJB ;RUN THRU SOME COMMON CODE
JUMPT .RETT ;WIN IF HE DID
LOAD S1,.QELNK(P2),QE.PTN ;GET NEXT
JRST CDPF.1 ;AND LOOP
SUBTTL PTP -- Papertape punch queue dependent functions
;The PTP queue scheduler vector
S$PTP:: JRST PTPLNK ;LINK IN A NEW JOB
JRST PTPSCH ;SCHEDULE A JOB FOR AN OBJECT
JRST PTPDEF ;FILL IN DEFAULTS FOR A JOB
JRST PTPMOD ;MODIFY PTP PARAMETERS
JRST PTPRJI ;RELEASE A JOB INTERLOCK
JRST PTPFJB ;FIND A JOB FOR AN OBJECT
;<- - - - - - - - - - - - - - - - - - - - - - - - ->
PTPLNK: GETLIM S1,.QELIM(AP),OLIM ;GET OUTPUT LIMIT
MOVEI S2,^D60 ;AND AGING FACTOR
PJRST LNKPRI ;AND LINK IT IN
PTPDEF: MOVEI S2,0 ;LOAD A ZERO (ALSO USED IN OUTDEF CALL)
STOLIM S2,.EQLIM(M),OLIM ;AND CLEAR THE LIMIT WORD
MOVX S1,PTPDIV ;GET THE PER DISKBLK DIVISOR
MOVX S2,PTPMUL ;GET THE PER DISKBLK MULTIPLIER
MOVX T1,INPPTP ;GET THE DEFAULT LIMIT
JRST OUTDEF ;AND USE COMMON CODE
PTPMOD: JRST OUTMOD ;OUTPUT IS SAME FOR ALL OUTPUT QUEUES
PTPSCH: JRST NEXTJB ;SEND NEXTJOB MESSAGE
PTPRJI: JRST JOBDUN ;CLEANUP AFTERWARDS
PTPFJB: PUSHJ P,.SAVE2 ;SAVE P1 AND P2
MOVE P1,S1 ;SAVE OBJ ADDRESS IN P1
ZERO HDRPTP##+.QHAFT ;START AFTER CHECK ALL OVER AGAIN
LOAD S1,HDRPTP##+.QHLNK,QH.PTF ;GET FIRST ITEM IN THE QUEUE
PTPF.1: JUMPE S1,.RETF ;FAIL IF NO JOBS
MOVE P2,S1 ;COPY OVER THE REQUEST ADDRESS
MOVE S2,P1 ;PUT OBJ ADR INTO S2
PUSHJ P,OUTFJB ;RUN THRU SOME COMMON CODE
JUMPT .RETT ;WIN IF HE DID
LOAD S1,.QELNK(P2),QE.PTN ;GET NEXT
JRST PTPF.1 ;AND LOOP
SUBTTL PLT -- Plotter queue dependent functions
;The PLT queue scheduler vector
S$PLT:: JRST PLTLNK ;LINK IN A NEW JOB
JRST PLTSCH ;SCHEDULE A JOB FOR AN OBJECT
JRST PLTDEF ;FILL IN DEFAULTS FOR A JOB
JRST PLTMOD ;MODIFY PLT PARAMETERS
JRST PLTRJI ;RELEASE A JOB INTERLOCK
JRST PLTFJB ;FIND A JOB FOR AN OBJECT
;<- - - - - - - - - - - - - - - - - - - - - - - - ->
PLTLNK: GETLIM S1,.QELIM(AP),OLIM ;GET OUTPUT LIMIT
MOVEI S2,^D60 ;AND AGING FACTOR
PJRST LNKPRI ;AND LINK IT IN
PLTDEF: MOVEI S2,0 ;LOAD A ZERO (ALSO USED IN OUTDEF CALL)
STOLIM S2,.EQLIM(M),OLIM ;AND CLEAR THE LIMIT WORD
MOVX S1,PLTDIV ;GET THE PER DISKBLK DIVISOR
MOVX S2,PLTMUL ;GET THE PER DISKBLK MULTIPLIER
MOVX T1,INPPLT ;GET THE DEFAULT LIMIT
JRST OUTDEF ;AND USE COMMON CODE
PLTMOD: JRST OUTMOD ;OUTPUT IS SAME FOR ALL OUTPUT QUEUES
PLTSCH: JRST NEXTJB ;SEND A NEXTJOB MESSAGE
PLTRJI: JRST JOBDUN ;CLEANUP AFTERWARDS
PLTFJB: PUSHJ P,.SAVE2 ;SAVE P1 AND P2
MOVE P1,S1 ;SAVE OBJ ADDRESS IN P1
ZERO HDRPLT##+.QHAFT ;PREPARE FOR A NEW AFTER CHECK
LOAD S1,HDRPLT##+.QHLNK,QH.PTF ;GET FIRST ITEM IN THE QUEUE
PLTF.1: JUMPE S1,.RETF ;FAIL IF NO JOBS
MOVE P2,S1 ;COPY OVER THE REQUEST ADDRESS
MOVE S2,P1 ;PUT OBJ ADR INTO S2
PUSHJ P,OUTFJB ;RUN THRU SOME COMMON CODE
JUMPT .RETT ;WIN IF HE DID
LOAD S1,.QELNK(P2),QE.PTN ;GET NEXT
JRST PLTF.1 ;AND LOOP
SUBTTL BIN -- Batch-Input queue dependent functions
;The BIN queue scheduler vector
S$BIN:: JRST BINLNK ;LINK IN A NEW JOB
JRST BINSCH ;SCHEDULE A JOB FOR AN OBJECT
JRST BINDEF ;FILL IN DEFAULTS FOR A JOB
JRST BINMOD ;MODIFY BIN PARAMETERS
JRST BINRJI ;RELEASE A JOB INTERLOCK
JRST BINFJB ;FIND A JOB FOR AN OBJECT
;<- - - - - - - - - - - - - - - - - - - - - - - - ->
BINDEF: PUSH P,.EQLIM+3(M) ;[HACK] SAVE THE CNOD LIMIT WORD
PUSHJ P,INPDEF ;DEFAULT THE EQ
POP P,.EQLIM+3(M) ;[HACK] RESTORE THE CNOD LIMIT WORD
LOAD S1,.EQLEN(M),EQ.LOH ;SKIP OVER THE HEADER
ADD S1,M ;POINT TO THE FP
VDFALT S2,.FPINF(S1),FP.RCF,.FPFAI ;DEFAULT THE RECORD TYPE
VDFALT S2,.FPINF(S1),FP.RCL,^D80 ;DEFAULT RECORD LENGTH TO 80
$RETT ;AND RETURN
BINLNK: JRST M$ELNK## ;LINK IN AT THE END
BINSCH: JRST NEXTJB ;JUST SEND A NEXTJOB MESSAGE
BINRJI: JRST JOBDUN ;CLEAN UP THE INTERLOCK
BINMOD: $RETT
BINFJB: LOAD S1,HDRBIN##+.QHLNK,QH.PTF ;GET POINTER TO FIRST
JUMPE S1,.RETF ;RETURN IF NOTHING THERE
$RETT ;ELSE, WIN
SUBTTL XFR -- File-transfer queue dependent functions
;The XFR queue scheduler vector
S$XFR:: JRST XFRLNK ;LINK IN A JOB
JRST XFRSCH ;SCHEDULE A JOB FOR AN OBJECT
JRST XFRDEF ;FILL IN DEFAULTS FOR A JOB
JRST XFRMOD ;MODIFY XFR PARAMETERS
JRST XFRRJI ;RELEASE A JOB INTERLOCK
JRST XFRFJB ;FIND A JOB FOR AN OBJECT
;<- - - - - - - - - - - - - - - - - - - - - - - - ->
XFRLNK: JRST M$ELNK## ;LINK IN AT THE END
XFRSCH: JRST NEXTJB ;FIRST COME FIRST SERVE
XFRDEF: PUSHJ P,EQDFLT ;COMMON DEFAULTS
$RETT ;AND RETURN
XFRMOD: $RETT ;JUST RETURN
XFRRJI: JRST JOBDUN ;CLEAN UP THE INTERLOCK
XFRFJB: LOAD S1,HDRXFR##+.QHLNK,QH.PTF ;GET POINTER TO FIRST
JUMPE S1,.RETF ;RETURN IF NOTHING THERE
$RETT ;ELSE, WIN
SUBTTL RDR -- Reader queue dependent functions
;The RDR queue scheduler vector
S$RDR:: JRST RDRLNK ;LINK IN A JOB
JRST RDRSCH ;SCHEDULE A JOB FOR AN OBJECT
JRST RDRDEF ;FILL IN DEFAULTS FOR A JOB
JRST RDRMOD ;MODIFY RDR PARAMETERS
JRST RDRRJI ;RELEASE A JOB INTERLOCK
JRST RDRFJB ;FIND A JOB FOR AN OBJECT
;<- - - - - - - - - - - - - - - - - - - - - - - - ->
RDRLNK: $RETT
RDRSCH: MOVE S1,S2 ;GET THE OBJECT ADDRESS.
PUSHJ P,A$OBST ;UPDATE THE STATUS
$RETT ;RETURN
RDRDEF: $RETT
RDRMOD: $RETT
RDRRJI: SETZM OBJITN(S1) ;CLEAR THE ITN WORD
SETZM OBJTIM(S1) ;CLEAR THE TIMER WORD
ZERO OBJSCH(S1),OBSBUS ;CLEAR THE BUSY BIT
PUSHJ P,A$OBST## ;UPDATE THE STATUS
$RETT ;RETURN
RDRFJB: $RETT
SUBTTL RET -- Retrieval queue dependant functions
S$RET:: JRST RETLNK ;LINK IN A JOB REQUEST
JRST RETSCH ;SCHEDULE A JOB FOR THE OBJECT
JRST RETDEF ;FILL IN DEFAULTS FOR A JOB
JRST RETMOD ;GO PERFORM THE MODIFY
JRST RETRJI ;GO RELEASE THE JOB INTERLOCKS
JRST RETFJB ;FIND A JOB FOR AN OBJECT
RETLNK: PJRST I$RLNK## ;LINK IN A JOB
RETSCH: PUSHJ P,.SAVE2 ;SAVE P1 & P2
DMOVE P1,S1 ;SAVE QUEUE REQUEST & OBJECT ADDRESS
PUSHJ P,I$RSCH## ;GO FIND A JOB TO SCHEDULE
JUMPF .RETF ;NONE THERE,,JUST RETURN
DMOVE S1,P1 ;RESTORE QUEUE REQUEST & OBJECT ADDRESS
PJRST NEXTJB ;GO SCHEDULE IT
RETDEF: PUSHJ P,EQDFLT ;GO DEFAULT THE EQ
PJRST I$RDEF## ;DEFAULT THE REST AND RETURN
RETMOD: $RETT ;JUST RETURN
RETRJI: PJRST JOBDUN ;GO RELEASE THE JOB INTERLOCKS
RETFJB: PJRST I$RFJB## ;FIND A JOB FOR AN OBJECT
SUBTTL NOT - Notification queue dependant functions
S$NOT:: JRST NOTLNK ;LINK IN A JOB
JRST NOTSCH ;SCHEDULE A JOB
JRST NOTDEF ;FILL IN DEFAULTS FOR A JOB
JRST NOTMOD ;MODIFY A JOB
JRST NOTRJI ;RELEASE JOB INTERLOCKS
JRST NOTFJB ;GO FIND A JOB FOR SCHEDULING
NOTLNK: PJRST I$NLNK## ;LINK THE JOB IN
NOTSCH: $RETT ;JUST RETURN
NOTDEF: PUSHJ P,I$NDEF## ;GO FILL IN THE DEFAULTS
NOTMOD: $RETT ;JUST RETURN
NOTRJI: PJRST JOBDUN ;GO RELEASE THE JOB INTERLOCKS
NOTFJB: PJRST I$NFJB## ;GO FIND A JOB
SUBTTL DBMS SCHEDULING VECTOR
S$DBM:: JRST DBMLNK ;LINK IN A NEW ENTRY
JRST DBMSCH ;SCHEDULE A JOB FOR AN OBJECT
JRST DBMDEF ;FILL IN DEFAULTS FOR A JOB
JRST DBMMOD ;MODIFY DBM PARAMETERS
JRST DBMRJI ;RELEASE A JOB INTERLOCK
JRST DBMFJB ;FIND A JOB FOR AN OBJECT
;<- - - - - - - - - - - - - - - - - - - - - - - - ->
DBMLNK: JRST M$ELNK## ;LINK IN AT THE END
DBMSCH: JRST NEXTJB ;FIRST COME FIRST SERVE
DBMDEF: PUSHJ P,EQDFLT ;COMMON DEFAULTS
$RETT ;AND RETURN
DBMMOD: $RETT ;JUST RETURN
DBMRJI: JRST JOBDUN ;CLEAN UP THE INTERLOCK
DBMFJB: LOAD S1,HDRDBM##+.QHLNK,QH.PTF ;GET POINTER TO FIRST
JUMPE S1,.RETF ;RETURN IF NOTHING THERE
$RETT ;ELSE, WIN
SUBTTL Local Subroutines
; OUTMOD Queue specific modify for LPT, PTP, PLT, CDP
; OUTDEF Fill in defaults for LPT, PTP, PLT, CDP
; OUTFJB Common routine for picking an output job
; EQDFLT Fill in queue-independent defaults in an EQ
; LNKPRI Compute priority and do linkin
; NEXTJB Send a NEXTJB message to schedule a job
; JOBDUN Clean up a job-OBJ interlock for some queues
SUBTTL OUTMOD -- Do queue dependent MODIFY for Output queues
;OUTMOD is dispatched to by the scheduling vector of the Output
; queues. See the description of the SCHMOD entry for details.
OUTMOD: PUSHJ P,.SAVE4 ;SAVE A FEW REGS FIRST
LOAD P1,MOD.GN(S1),MODGLN ;NUMBER OF GROUP 1 ELEMENTS
SOJLE P1,.RETT ;0 IS ACCEPTABLE, ADJUST FOR THE LOOP
CAILE P1,NOUTPM ;MORE THAN CURRENTLY IMPLEMENTED
MOVEI P1,NOUTPM ;YES, USE ONLY THE KNOWN VALUES
MOVNS P1 ;NEGATE IT
HRLZS P1 ;P1 = AOBJN POINTER
MOVEI P2,MOD.GE(S1) ;POINT TO FIRST GROUP ELEMENT
OUTM.1: MOVE P3,0(P2) ;GET AN ELEMENT
CAME P3,[-1] ;DID IT CHANGE
XCT OUTMTB(P1) ;YES, STORE NEW VALUE
INCR P2 ;TO NEXT ELEMENT
AOBJN P1,OUTM.1 ;GET THEM ALL
$RETT ;RETURN TO Q$MODIFY FOR NEXT GROUP
OUTMTB: STOLIM P3,.EQLIM(AP),FORM ; 0 = /FORMS
STOLIM P3,.EQLIM(AP),OLIM ; 1 = /LIMIT
STOLIM P3,.EQLIM(AP),NOT1 ; 2 = /NOTE (1ST HALF)
STOLIM P3,.EQLIM(AP),NOT2 ; 3 = /NOTE (2ND HALF)
PUSHJ P,MOUTHD ; 4 = /HEADER
PUSHJ P,MOUTSP ; 5 = /SPACING
PUSHJ P,MOUTPF ; 6 = /PRINT (/PAPER)
PUSHJ P,MOUTFF ; 7 = /FILE
PUSHJ P,MOUTDL ;10 = /DELETE
PUSHJ P,MOUTCP ;11 = /COPIES
PUSHJ P,MOUTR1 ;12 = /REPORT (1ST HALF)
PUSHJ P,MOUTR2 ;13 = /REPORT (2ND HALF)
PUSHJ P,MOUTBG ;14 = /BEGIN
NOUTPM==<.-OUTMTB> ;NUMBER CURRENTLY IMPLEMENTED
;OUTMOD IS CONTINUED ON THE NEXT PAGE
;HERE TO MODIFY FILE-SPECIFIC OUTPUT PARAMETERS
MOUTFP: ;BEGINNING OF FILE-SPECIFIC PARMS
MOUTHD: JSP P4,OUFSLP ; /HEADER
MOUTSP: JSP P4,OUFSLP ; /SPACING
MOUTPF: JSP P4,OUFSLP ; /PAPER
MOUTFF: JSP P4,OUFSLP ; /FILE
MOUTDL: JSP P4,OUFSLP ; /DELETE
MOUTCP: JSP P4,OUFSLP ; /COPIES
MOUTR1: JSP P4,OUFSLP ; /REPORT (1ST HALF)
MOUTR2: JSP P4,OUFSLP ; /REPORT (2ND HALF)
MOUTBG: JSP P4,OUFSLP ; /BEGIN
MOUTAB: STORE P3,.FPINF(T1),FP.NFH ; /HEADER
STORE P3,.FPINF(T1),FP.FSP ; /SPACING
STORE P3,.FPINF(T1),FP.FPF ; /PAPER
STORE P3,.FPINF(T1),FP.FFF ; /FILE
STORE P3,.FPINF(T1),FP.DEL ; /DELETE
STORE P3,.FPINF(T1),FP.FCY ; /COPIES
STORE P3,.FPFR1(T1) ; /REPORT (1ST HALF)
STORE P3,.FPFR2(T1) ; /REPORT (2ND HALF)
STORE P3,.FPFST(T1) ; /BEGIN
OUFSLP: PUSHJ P,.SAVET ;SAVE T1 THRU T4
SUBI P4,MOUTFP+1 ;GET INDEX IN MOUTFD TABLE
LOAD T1,.EQLEN(AP),EQ.LOH ;GET LENGTH OF HEADER IN EQ
ADD T1,AP ;GET ADDRESS OF FIRST FP
LOAD T2,.EQSPC(AP),EQ.NUM ;GET NUMBER OF FILESPECS
OUFS.1: XCT MOUTAB(P4) ;STORE THE PARAMETER
SOJLE T2,.RETT ;RETURN WHEN DONE
LOAD T3,.FPLEN(T1),FP.LEN ;GET LENGTH OF FP
ADD T1,T3 ;BUMP TO THE FD
LOAD T3,.FDLEN(T1),FD.LEN ;GET LENGTH OF FD
ADD T1,T3 ;BUMP TO THE NEXT FP
JRST OUFS.1 ;AND LOOP
SUBTTL OUTDEF -- Fill in defaults for Output queues
;OUTDEF is called by the queue-specific default fillers.
;
;CALL: S1/ The Per-Diskblk Divisor for calculating the limits
; S2/ The Per-Dsikblk Multiplier for calculating the limits
; T1/ Default limit if size of the files is not available
; M/ The CREATE message address
OUTDEF: PUSHJ P,.SAVE2 ;SAVE P1 & P2
GETLIM P1,.EQLIM(M),NBLK ;GET THE NUMBER OF DISK BLOCKS
JUMPE P1,OUTD.1 ;NOT SPECIFIED,,SKIP THIS & SAVE DEFAULT
IDIV P1,S1 ;CALCULATE THE NUMBER
SKIPE P2 ; OF PAGES, CARDS, FEET,
ADDI P1,1 ; ETC. CONTAINED IN X
IMUL P1,S2 ; NUMBER OF DISK BLOCKS (PAGES)
SKIPA ;SKIP THE DEFAULT LOADING
OUTD.1: MOVE P1,T1 ;GET THE DEFAULT IF BLOCKS NOT SPECIFIED
GETLIM S2,.EQLIM(M),OLIM ;DID HE ALREADY SPECIFY A LIMIT ???
SKIPN S2 ;YES,,DONT SAVE THE CALCULATED LIMIT
STOLIM P1,.EQLIM(M),OLIM ;NO,,SAVE THE CALCULATED LIMIT
PDFALT S1,.EQLIM(M),FORM,FRMNOR ;FILL IN DEFAULT FORMS
PUSHJ P,EQDFLT ;GO DEFAULT THE REST OF THE EQ.
$RETT ;AND RETURN
SUBTTL OUTFJB -- Common routine for picking an output job
;Called by the queue-dependent routines (SCHFJB entry) to decide whether
; a particular job fits all the parameter contstraints of an OBJ.
;
;Call: S1/ address of the queue request
; S2/ address of the OBJ entry
;
;True return: S1/ address of the queue entry picked
;
;False return: entry does not meet constraints
OUTFJB: PUSHJ P,.SAVE4 ;SAVE P1 - P4
DMOVE P1,S1 ;COPY THE ARGS OVER
LOAD S2,OBJSCH(P2),OBSQUH ;GET ADDRESS OF QUEUE HEADER
LOAD S1,.QECRE(P1) ;GET JOB CREATION TIME
CAMLE S1,G$NOW## ;IN THE FUTURE?
JRST [CAML S1,.QHAFT(S2) ;YES, IS THERE ONE SOONER?
SKIPN .QHAFT(S2) ;NO, UNLESS WORD WAS ZERO
MOVEM S1,.QHAFT(S2) ;THIS IS THE SOONEST AND BEST
MOVE S1,.QHAFT(S2) ;GET THE AFTER TIME
PUSHJ P,G$STIM## ;SET THE ALARM CLOCK
$RETF] ;BUT IGNORE JOB FOR NOW
LOAD S1,.QESEQ(P1),QE.HBO ;JOB HELD BY THE OPERATOR?
JUMPN S1,.RETF ;YUP, RETURN LOSSAGE
LOAD S1,.QEROB+.ROBAT(P1),RO.PHY ;USER SPECIFIED PHYSICAL DEVICE?
JUMPE S1,OUTF.1 ;NO CONTINUE ON NORMALLY
LOAD S1,.QEROB+.ROBAT(P1),RO.UNI ;YES, GET PHYSICAL UNIT
CAME S1,OBJUNI(P2) ;DO THE COMPARE
$RETF ;AND LOSE
;MORE OF "OUTFJB" ON THE FOLLOWING PAGE
;CONTINUED FROM THE PREVIOUS PAGE
OUTF.1: LOAD S1,.QEROB+.ROBND(P1) ;GET REQUESTED NODE
PUSHJ P,N$CSTN## ;CONVERT FOR ROUTING ETC.
CAME S1,OBJNOD(P2) ;COMPARE IT
$RETF ;GUESS NOT!
LOAD S1,.QESEQ(P1),QE.PRI ;GET JOBS EXTERNAL PRIORITY
LOAD P3,OBJPRM+.OOPRI(P2),OBPMIN ;GET MINIMUM
LOAD P4,OBJPRM+.OOPRI(P2),OBPMAX ;GET MAXIMUM
CAML S1,P3 ;SKIP IF LESS THAN MINIMUM
CAMLE S1,P4 ;SKIP IF LE THAN MAXIMUM
$RETF ;LOSE
GETLIM S1,.QELIM(P1),OLIM ;GET OUTPUT LIMIT
LOAD P3,OBJPRM+.OOLIM(P2),OBPMIN ;LOAD MINIMUM
LOAD P4,OBJPRM+.OOLIM(P2),OBPMAX ;LOAD MAXIMUM
CAML S1,P3 ;CHECK LOWER LIMIT
CAMLE S1,P4 ;CHECK UPPER LIMIT
$RETF ;LOSE
GETLIM S1,.QELIM(P1),FORM ;GET FORMS TYPE
XOR S1,OBJPRM+.OOFRM(P2) ;XOR WITH MOUNTED FORMS TYPE
AND S1,[EXP FRMSK1] ;AND WITH MASK TO CLEAR THE NOISE
JUMPN S1,.RETF ;LOSE IF DIFFERENT
$SAVE AP ;SAVE AP FOR A SECOND
MOVE AP,P1 ;POINT TO THE QE
PUSHJ P,Q$CDEP## ;EVALUATE ALL DEPENDENCIES
JUMPF .RETF ;AND FAIL
MOVE S1,P1 ;GET THE WINNER
PUSHJ P,I$ACTV## ;CHECK FOR VALID ACCOUNT STRING
JUMPF .RETF ;NO GOOD,,RETURN
MOVE S1,P1 ;RETURN THE EQ ADDRESS IN S1
$RETT ;AND RETURN
SUBTTL EQDFLT -- Default queue-independent fields in an EQ
;EQDFLT is called by the various default fillers to fill in the queue-
; independent fields in an EQ (i.e. a CREATE message).
;
;CALL: M/ address of CREATE message
EQDFLT: LOAD S1,.MSTYP(M),.QIFNC ;GET INTERNAL FCN BIT
JUMPN S1,EQDF.1 ;JUMP IF SET
LOAD S1,.EQLEN(M),EQ.VRS ;GET VERSION NUMBER
CAIE S1,%%.QSR ;IS IT CORRECT?
JRST E$WVN## ;WRONG VERSION NUMBER
MOVX S1,EQ.RDE!EQ.SPL!EQ.JBC ;LOAD SOME BITS
ANDCAM S1,.EQSEQ(M) ;AND ZERO THEM
PUSHJ P,I$WHEEL## ;IS SENDER A WHEEL?
MOVEI S1,1 ;ASSUME YES
SKIPT ;SKIP IF YES
SETZ S1, ;IT WAS NO
STORE S1,.EQSEQ(M),EQ.PRV ;AND STORE IT
LOAD S2,.EQSEQ(M),EQ.PRI ;GET SPECIFIED PRIORITY
SKIPN S1 ;IS USER A WHEEL?
CAIG S2,MXUPRI ;NO, DID HE SPECIFY TOO HIGH A PRIO
SKIPA ;EITHER A WHEEL OR PRIO IS OK
MOVX S2,MXUPRI ;LOAD MAX PRIO
STORE S2,.EQSEQ(M),EQ.PRI ;AND RE-STORE IT
MOVEI S1,EQCKSZ ;SIZE OF THE CHECKPOINT BLOCK
MOVEI S2,.EQCHK(M) ;AND THE ADDRESS
PUSHJ P,.ZCHNK ;ZERO IT OUT
MOVE S1,M ;POINT TO THE EQ
PUSHJ P,I$DFEQ## ;DEFAULT O/S DEPENDENT STUFF
JUMPT EQDF.1 ;SUCCESS,,CONTINUE ON.
SKIPN G$ERR## ;DO WE HAVE AN ERROR YET ??
JRST E$ICM## ;NO,,SET INVALID CREATE MESSAGE.
$RETF ;YES,,JUST RETURN.
EQDF.1: MOVE S1,[SIXBIT/XXXXXX/] ;GET A DUMMY JOB NAME
SKIPN .EQJOB(M) ;DO WE HAVE A JOB NAME YET ???
MOVEM S1,.EQJOB(M) ;NO,,SAVE THIS ONE !!!
LOAD S1,.EQSPC(M),EQ.NUM ;GET NUMBER OF FILES
JUMPE S1,E$INF## ;ILLEGAL NUMBER OF FILES
LOAD S2,.EQITN(M) ;GET THE ITN
ANDI S2,7777 ;AND IT DOWN SOME
ADDI S2,1 ;AND DONT ALLOW ZERO
LDFALT S1,.EQSEQ(M),EQ.SEQ,S2 ;DEFAULT SEQUENCE NUMBER
VDFALT S1,.EQSEQ(M),EQ.PRI,SPLPRI ;DEFAULT EXTERNAL PRIORITY
LDFALT S1,.EQSPC(M),EQ.PRO,G$SPRT## ;DEFAULT REQUEST PROTECTION
LDFALT S1,.EQAFT(M),,G$NOW## ;DEFAULT AFTER PARAMETER
;"EQDFLT" IS CONTINUED ON THE NEXT PAGE
;The following routine is a major part of QUASAR's security enforcement.
; There are two parts involved. The first is to insure that the
; FP.SPL is off since this bit causes the spoolers to not access
; check the file. The second is to insure (very carefully) that
; the lengths throughout the CREATE message are correct and con-
; sistent.
PUSHJ P,.SAVE4 ;SAVE P1-P4
LOAD S1,.EQSPC(M),EQ.NUM ;GET NUMBER OF FILES
LOAD S2,.EQLEN(M),EQ.LOH ;GET LENGTH OF HEADER
LOAD P1,.MSTYP(M),MS.CNT ;GET LENGTH OF MESSAGE
SUB P1,S2 ;DECREMENT IT
JUMPLE P1,E$MTS## ;LOSE
ADD S2,M ;POINT TO THE FIRST FP
EQDF.2: CAIGE P1,.FPLEN+1 ;CAN I GET THE LENGTH?
PJRST E$MTS## ;NO, LOSE
LOAD P2,.FPLEN(S2),FP.LEN ;GET THE FP LENGTH
CAIGE P2,FPMSIZ ;GREATER THAN MINIMUM?
PJRST E$ICM## ;NO LOSE
SUB P1,P2 ;DECREMENT THE COUNTER
JUMPLE P1,E$MTS## ;LOSE
LOAD P3,.MSTYP(M),.QIFNC ;GET INTERNAL FUNCTION BIT
LOAD P4,.EQSEQ(M),EQ.PRV ;GET THE PRIV BIT
ADD P3,P4 ;COMBINE THE PRIV & INTERNAL FCN BITS
SKIPN P3 ;SKIP IF EITHER ARE SET
ZERO .FPINF(S2),FP.SPL ;NOT PRIV OR INTERNAL,,ZERO THE SPL BIT
ADD S2,P2 ;POINT TO THE FD
CAIGE P1,.FDLEN+1 ;CAN I GET THE FD LENGTH
PJRST E$MTS## ;NO, LOSE
LOAD P2,.FDLEN(S2),FD.LEN ;GET THE FD SIZE
CAIGE P2,FDMSIZ ;BIG ENOUGH?
PJRST E$ICM## ;NO, LOSE
SUB P1,P2 ;DECREMENT
JUMPL P1,E$MTS## ;LOSE IF WE DONT HAVE THE WHOLE FD
ADD S2,P2 ;POINT TO THE NEXT FP
SOJG S1,EQDF.2 ;AND LOOP
$RETT ;AND RETURN
SUBTTL LNKPRI -- Compute linkin priority and do linkin
;LNKPRI is called by the various queue dependent linkin routines
; with parameters setup to compute the entrace priority and aging.
; The priority is computed and the entry is linked-in.
;CALL: S1/ Internal priority factor
; S2/ aging factor
; AP/ address of entry
; H/ queue header address
LNKPRI: DOSCHD ;SCHEDULE!!
PUSHJ P,.SAVE2 ;SAVE P1 AND P2
$SAVE E ;AND E
MOVE P2,S2 ;SAVE AGING FACTOR IN P2
MOVEM S1,.QEIPR(AP) ;SAVE PRIO FACTOR AS THE IPR
ZERO .QESEQ(AP),QE.RDE ;CLEAR THE RDE BIT
LOAD P1,.QESEQ(AP),QE.PRI ;GET THE PRIORITY
CAIN P1,1 ;IS IT PRIORITY 1 ???
PJRST M$ELNK## ;YES,,LINK IT IN AT THE END !!!
LOAD S1,.QESEQ(AP),QE.JBC ;HAS JOB BEEN CHECKPOINTED?
SKIPE S1 ;SKIP IF NOT
ADDI P1,1 ;IT HAS, MAKE PRIORITY A BIT HIGHER
LOAD E,.QHLNK(H),QH.PTF ;AND POINT TO THE FIRST IN THE QUEUE
LNKP.1: JUMPE E,M$ELNK## ;END-OF-LIST, LINK AT THE END
LOAD S1,.QESEQ(E),QE.PRI ;GET PRIO OF REQUEST
CAMGE S1,P1 ;IS OLD REQUEST LESS PRIO?
PJRST M$LINK## ;YES, LINK NEW ONE BEFORE IT
CAME S1,P1 ;NO, SKIP IF THEY ARE EQUAL
JRST LNKP.2 ;OLD REQUEST IS MORE, GET THE NEXT
PUSHJ P,LNKP.3 ;AGE THE OLD REQUEST
CAMLE S1,.QEIPR(AP) ;IS OLD REQUEST LESS?
PJRST M$LINK## ;YES, LINK NEW ONE IN BEFORE IT
LNKP.2: LOAD E,.QELNK(E),QE.PTN ;GET POINTER TO NEXT ENTRY
JRST LNKP.1 ;AND LOOP
;SUBROUTINE TO "AGE" ENTRY 'E'
LNKP.3: MOVE S2,.QECRE(E) ;GET CREATION TIME
MOVE S1,.QECRE(AP) ;GET CREATION TIME OF NEW ONE
PUSHJ P,I$AGE## ;GET DIFFERENCE IN SECONDS
IDIVI S1,(P2) ;DIVIDE BY THE FACTOR
MOVE S2,.QECRE(E) ;GET CREATION TIME OF OLD ONE
CAMG S2,.QECRE(AP) ;IS IT OLDER OR NEWER?
MOVNS S1 ;OLDER, NEGATE IT
ADD S1,.QEIPR(E) ;ADD IN THE ENTRY PRIOITY
$RETT ;AND RETURN
SUBTTL NEXTJB -- Function 5
;NEXTJB is called by a number of the queue dependent scheduling routines
; (SCHSCH entry) to send a NEXTJOB message to a known component.
;
;CALL IS: S1/ Pointer to the .QE
; S2/ Pointer to the OBJect block
;
;NEXTJB performs the following operations:
; 1) Read the request from disk
; 2) Move the queue entry from the processing queue to the USE queue
; 3) Validate the account string
; 4) Copy changable data from the .QE to the .EQ
; 5) Send the request to the known component
;
;If the IPCF send fails when sending the NEXTJOB messages, the A$KLPD
; routine gets called and all the data-structure associated with
; the component and the OBJ will be cleaned up. This implies that
; they must be in a consistent state before NEXTJB is called.
NEXTJB: PUSHJ P,.SAVE2 ;SAVE TWO PERM ACS
MOVE AP,S1 ;GET ARGUMENT POINTER SET UP
MOVE P1,S2 ;AND POINTER TO OBJECT BLOCK
MOVEM P1,.QEOBJ(AP) ;STORE POINTER TO OBJECT BLOCK
LOAD S1,.QESTN(AP),QE.DPA ;GET THE DPA
PUSHJ P,F$RDRQ## ;READ THE REQUEST
SKIPN 0(S1) ;DO A SMALL VALIDITY CHECK
$STOP(NBR,NEXTJOB'ING BAD REQUEST)
MOVE P2,S1 ;COPY ADR INTO P2
PUSHJ P,I$SACV## ;GO MAKE SURE THE ACCOUNT IS STILL VALID
MOVEI S1,HDRUSE## ;LOAD DESTINATION QUEUE HDR
LOAD H,OBJSCH(P1),OBSQUH ;POINT TO PROPER QUEUE HEADER
PUSHJ P,M$MOVE## ;AND MOVE THE ENTRY
$COUNT (MNXT) ;COUNT NEXTJOBS
LOAD S1,.QEITN(AP) ;NOW MAKE SURE ITN EXISTS
STORE S1,.EQITN(P2) ;STORE IT
STORE S1,OBJITN(P1) ;LET OBJECT REMEMBER IT TOO
MOVEI S1,.QONEX ;GET NEXTJOB FUNCTION
STORE S1,.MSTYP(P2),MS.TYP ;AND STORE IT IN THE MESSAGE
MOVSI S1,.QEJBB(AP) ;GET THE JIB SOURCE ADDRESS
HRRI S1,.EQJBB(P2) ;GET THE JIB DESTINATION ADDRESS
BLT S1,.EQJBB+JIBSIZ-1(P2) ;COPY THE JIB OVER
LOAD S1,.QECRE(AP) ;CREATION TIME
STORE S1,.EQAFT(P2) ;STORE THAT AS WELL
HRLI S1,.QELIM(AP) ;MOVE LIMIT WORDS FROM INTERNAL
HRRI S1,.EQLIM(P2) ;TO EXTERNAL REQUEST
BLT S1,.EQLIM+EQLMSZ-1(P2) ;FOR EXTRA DEFAULTED VALUES
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
MOVEI S1,OBJTYP(P1) ;POINT TO OBJECT TYPE
MOVEI S2,.EQROB+.ROBTY(P2) ;AND PLACE TO MOVE IT
PUSHJ P,A$CPOB## ;AND COPY THE OBJECT BLOCK OVER
LOAD S1,OBJTYP(P1) ;GET THE OBJECT TYPE
PUSHJ P,A$OB2Q## ;CONVERT IT TO A QUEUE HEADER
LOAD S1,.QHTYP(S1),QH.TYP ;GET THE QUEUE TYPE
LOAD S2,OBJPRM+.OOFLG(P1),.OFLEA ;GET THE QUEUE'S LIMIT-EX-ACTION
CAIN S1,.QHTOU ;IS THIS AN OUTPUT QUEUE ???
STOLIM S2,.EQLIM(P2),FLEA ;YES,,SAVE THE LIMIT-EX-ACTION
MOVE S1,P1 ;GET OBJECT ADDRESS
PUSHJ P,A$OBST## ;SETUP OBJECT STATUS
MOVEI S1,OBJST1(P1) ;POINT TO SPOOLER'S STATUS BLOCK
PUSHJ P,G$STTX## ;SETUP STRING
$TEXT(G$TEXT##,<Started at ^C/[-1]/^0>)
MOVX S1,IP.CFV ;GET PAGE-MODE BIT
MOVEM S1,MSGPDB+.IPCFL ;PUT IT IN THE FLAG WORD
MOVE S1,OBJPID(P1) ;GET PID OF OWNER
MOVEM S1,MSGPDB+.IPCFR ;STORE RECEIVERS PID
ADR2PG P2 ;MAKE A PAGE NUMBER
HRLI P2,PAGSIZ ;AND THE SIZE
MOVEM P2,MSGPDB+.IPCFP ;SAVE IT
MOVEI AP,MSGPDB ;ADDRESS OF PDB
PUSHJ P,C$SEND## ;SHIP THE MESSAGE OFF
$RETT ;AND RETURN
SUBTTL JOBDUN -- Common job release routine
;JOBDUN is called by a number of the queue dependent release routines
; (SCHRJI entry) to clean up the interlock between a job and an object.
;
;CALL: AP/ address of the .QE being released
JOBDUN: DOSCHD ;SCHEDULE!!
LOAD S1,.QEOBJ(AP) ;GET THE ADDRESS OF THE ALLEDGED OBJ
LOAD S2,.QEITN(AP) ;GET THIS GUY'S ITN
CAME S2,OBJITN(S1) ;MATCH?
$STOP(RUJ,Releasing Uninterlocked Job)
ZERO OBJITN(S1) ;CLEAR THE ITN WORD
ZERO OBJTIM(S1) ;CLEAR THE TIMER WORD
ZERO OBJSCH(S1),OBSBUS ;CLEAR THE BUSY FLAG
LOAD S1,.QEOBJ(AP) ;GET ADDRESS OF OBJECT BACK
ZERO .QEOBJ(AP) ;AND CLEAR THE REVERSE INTERLOCK
PUSHJ P,A$OBST## ;AND UPDATE THE STATUS
$RETT ;AND RETURN
END