Google
 

Trailing-Edge - PDP-10 Archives - bb-d868c-bm_tops20_v4_2020_distr - 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