Trailing-Edge
-
PDP-10 Archives
-
AP-D483B-SB_1978
-
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
SUBTTL Chuck O'Toole 13 Jan 77
;***Copyright (C) 1974, 1975, 1976, 1977, Digital Equipment Corp., Maynard, MA.***
SEARCH QSRMAC ;PARAMETER FILE
PROLOGUE(QSRSCH) ;GENERATE THE NECESSARY SYMBOLS
COMMENT\
Entry points found in QSRSCH
S$INIT Initialization Entry Point
S$SCHD Entry called to attempt a scheduling pass for any available PSB
S$RUSE Notification of Removal of a job from the USE queue
S$RELE Extension of Q$RELEASE for queue dependent functions
Base Entry Vectors For Processing Queues
S$AFTR The AFTER Queue
S$INPT The Input Queue
S$LPT The Line Printer Queue
S$PTP The Paper Tape Punch Queue
S$CDP The Card Punch Queue
S$PLT The Plotter Queue
S$RDE The RDE Queue
STOPCDs found in QSRSCH
IAO ILLEGAL AFTER QUEUE OPERATION
\
SUBTTL Some Useful Definitions
;MACRO TO FILL IN THE DEFAULTS FOR AN ENTRY
DEFINE FILLIN(AC,LOCN,FIELD,DEFALT,%DUMMY),<
LOAD (AC,LOCN,FIELD)
XLIST
JUMPN AC,%DUMMY
MOVX (AC,DEFALT)
STORE (AC,LOCN,FIELD)
%DUMMY:
LIST
SALL
> ;END OF DEFINE FILLIN
SUBTTL Initialization Entry Point
;CALLED BY QUASAR AT STARTUP TO INITIALIZE THE SCHEDULER DATA BASE
INTERN S$INIT
S$INIT: ZERO SCHZER ;CLEAR THE DATA BASE
MOVE S1,[SCHZER,,SCHZER+1] ;STANDARD BLT
BLT S1,ZERLAS ;GET IT ALL
POPJ P, ;AND RETURN
SUBTTL Scheduler Entry Point
INTERN S$SCHD
S$SCHD: PUSHJ P,.SAVE4## ;SAVE P1-P4
PUSHJ P,I$KSYS## ;GET TIME TO KSYS
MOVEM S1,KSYSTM ;REMEMBER FOR LATER CHECKS
SKIPE S1 ;IS IT SET TO HAPPEN
PUSHJ P,RETMIN ;YES, SET UP TO WATCH IT EVERY MINUTE
SCHD.0: LOAD P4,HDRPSB##+.QHLNK,QH.PTF ;FIND THE FIRST PSB
SCHD.1: PJUMPE P4,.POPJ## ;RETURN IF END OF PSB LIST
MOVX T1,PSYSCH ;THE AVAILABLE FOR SCHEDULING BIT
TDNN T1,PSBSTS(P4) ;IS THIS PROGRAM READY
JRST SCHD.2 ;NO, TRY THE NEXT
MOVX T1,PSYRDE ;GET RDE TEST
TDNN T1,PSBSTS(P4) ;CAN PROGRAM HANDLE RDE JOBS
JRST SCHD.5 ;NO, CONTINUE ON
MOVEI H,HDRRDE## ;YES, LOAD THE HEADER
PUSHJ P,RDESCH ;SCHEDULE AN RDE JOB
JUMPN AP,SCHD.6 ;AND JUMP IF WE GOT ONE
SCHD.5: LOAD H,PSBSTS(P4),PSYHDR ;FIND THE QUEUE HEADER FOR THIS PSB
LOAD T1,.QHPAG(H),QH.SCH ;GET THE ADDRESS OF THE SCHEDULING ROUTINE
PUSHJ P,SCHSCH(T1) ;ATTEMPT A SCHEDULING PASS
JUMPE AP,SCHD.2 ;JUMP IF NOTHING WAS SCHEDULED
SCHD.6: INCR PSBSTS(P4),PSYNJP ;ACCOUNT FOR THE NEW JOB
LOAD P3,.QELNK(P4),QE.PTP ;REMEMBER MY PREVIOUS
PUSH P,H ;SAVE THE HEADER AROUND Q$NEXT
PUSHJ P,NXTRCK ;COMPUTE TIME OF NEXT CHECKPOINT
STORE S1,PSBRCK(P4) ;SAVE FOR LATER LOOPS
MOVEI T1,(P4) ;PSB ADDRESS INTO T1
PUSHJ P,Q$NEXTJOB## ;SEND A NEXTJOB
POP P,H ;RESTORE H
LOAD P2,.QHLNK(H),QH.PTF ;IN CASE P4 IS THE FIRST PSB
SKIPE P3 ;DID IT HAVE A PREVIOUS
LOAD P2,.QELNK(P3),QE.PTN ;YES, FIND ITS NEXT
CAIE P2,(P4) ;IN CASE COMPONENT DISAPPEARED
JRST SCHD.0 ;IT DID, START AT THE TOP
JRST SCHD.1 ;NO, FIND ANOTHER JOB FOR IT (MAYBE)
SCHD.2: LOAD S1,PSBSTS(P4),PSYNJP ;THIS COMPONENT PROCESSING JOBS
JUMPE S1,SCHD.4 ;JUMP IF NO NEED FOR CHECKPOINTS
MOVE S1,G$NOW## ;CURRENT TIME
MOVE S2,PSBRCK(P4) ;TIME TO ASK FOR CHECKPOINT
CAMGE S1,S2 ;TIME YET
JRST SCHD.3 ;NO, SET UP SLEEP TIMERS
PUSHJ P,RETMIN ;COME BACK IN 1 MINUTE
PUSHJ P,NXTRCK ;COMPUTE TIME OF NEXT ONE
STORE S1,PSBRCK(P4) ;SAVE FOR LATER CHECKS
MOVE T1,PSBPID(P4) ;COMPONENTS PID
LOAD P4,.QELNK(P4),QE.PTN ;FIND THE NEXT NOW AS THE SEND MAY FAIL
PUSHJ P,A$RCK## ;REQUEST THE CHECKPOINT (SEE IF STILL ALIVE)
JRST SCHD.1 ;AND TRY THE NEXT PSB
SCHD.3: PUSHJ P,I$AGE## ;COMPUTE TIME TILL NEXT CHECKPOINT REQUEST
PUSHJ P,I$SVAL## ;SET UP FOR SLEEP
SCHD.4: LOAD P4,.QELNK(P4),QE.PTN ;FIND THE NEXT PSB
JRST SCHD.1 ;AND TRY SCHEDULING FOR IT
SUBTTL Scheduler Functions
;THESE ROUTINES ARE POINTED TO BY THE QUEUE HEADER (QH.SCH)
;CALL Arguments in Specified AC's
; LOAD xx,<HDRyyy+.QHPAG>,QH.SCH ;GET THE ADDRESS
; PUSHJ P,disp(xx)
;WHERE disp = SCHLNK TO LINK ENTRY 'AP' INTO QUEUE 'H'
; CALLED BY EVERYBODY
; = SCHSCH TO SCHEDULE FOR QUEUE 'H' FOR KNOWN COMPONENT WHOSE PSB IS IN 'P4'
; RETURNS 'AP' AS ENTRY SELECTED (0 IF NONE)
; CALLED BY S$SCHD
; = SCHDEF TO FILL IN THE DEFAULTS IN CREATE MESSAGE 'M'
; CALLED BY Q$CREATE
; = SCHMOD TO DO QUEUE DEPENDENT MODIFY FOR GROUP 'S1' ON EXTERNAL ENTRY 'AP'
; CALLED BY Q$MODIFY
;SCHSCH ENTRY IS CALLED BY S$SCHD AND HAS FULL USE OF ALL REGISTERS
;S1,S2, AND TEMP ARE ALWAYS SCRATCH AC'S
INTERN S$LPT,S$INPT,S$AFTR,S$CDP,S$PTP,S$PLT,S$RDE
S$LPT: JRST OUTLNK ;LINK IN A NEW ENTRY
JRST OUTSCH ;SCHEDULE AN ENTRY
JRST LPTDEF ;FILL IN LINE PRINTER DEFAULTS
JRST OUTMOD ;DO GROUP 1 MODIFY
S$INPT: JRST INPLNK ;LINK IN A NEW ENTRY
JRST INPSCH ;SCHEDULE A NEW JOB
JRST INPDEF ;FILL IN THE DEFAULTS
JRST INPMOD ;DO GROUP 1 MODIFY
S$AFTR: JRST AFTLNK ;LINK IN ORDER OF EXPIRATION
JFCL ;FALL INTO THE STOPCD
JFCL ;FALL INTO THE STOPCD
STOPCD (IAO,FATAL) ;++ILLEGAL AFTER QUEUE OPERATION
S$CDP: JRST OUTLNK ;LINK IN A NEW ENTRY
JRST OUTSCH ;SCHEDULE AN ENTRY
JRST CDPDEF ;FILL IN CARD PUNCH DEFAULTS
JRST OUTMOD ;DO GROUP 1 MODIFY
S$PTP: JRST OUTLNK ;LINK IN A NEW ENTRY
JRST OUTSCH ;SCHEDULE AN ENTRY
JRST PTPDEF ;FILL IN PAPER TAPE PUNCH DEFAULTS
JRST OUTMOD ;DO GROUP 1 MODIFY
S$PLT: JRST OUTLNK ;LINK IN A NEW ENTRY
JRST OUTSCH ;SCHEDULE AN ENTRY
JRST PLTDEF ;FILL IN PLOTTER DEFAULTS
JRST OUTMOD ;DO GROUP 1 MODIFY
S$RDE: JRST M$ELNK## ;LINK IN AT THE END
JFCL ;FALL INTO STOPCD
JFCL ;FALL INTO STOPCD
STOPCD (IRO,FATAL) ;++ILLEGAL RDE QUEUE OPERATION
; THE LINKIN FUNCTION FOR THE AFTER QUEUE
AFTLNK: SAVE E ;SAVE CALLERS ACCUMULATOR
LOAD S1,.QECRE(AP) ;GET THIS ENTRIES AFTER PARAMETER
LOAD E,.QHLNK(H),QH.PTF ;FIND THE FIRST ENTRY IN THIS QUEUE
AFTR.1: PJUMPE E,M$ELNK## ;END OF THE QUEUE, MAKE THIS LAST
CAMGE S1,.QECRE(E) ;AFTER PARAMETER OF THAT ENTRY
PJRST M$LINK## ;MINE WILL EXPIRE FIRST, E IS THE SUCCESSOR
LOAD E,.QELNK(E),QE.PTN ;FOLLOW THE CHAIN
JRST AFTR.1 ;AND KEEP LOOKING
; EXIT ROUTINE FOR THE SCHEDULING MODULES, RETURNS AP = 0
RETTMR: PUSHJ P,RETMIN ;RETURN IN 1 MINUTE
RETZER: ZERO AP ;INDICATE NO JOB SELECTED
POPJ P, ;RETURN
RETMIN: MOVEI S1,^D60 ;SET WAKEUP FOR 1 MINUTE
PJRST I$SVAL## ;TO SEE IF CONDITIONS CHANGE
;THE OUTPUT SCHEDULING ROUTINE CALLED BY S$SCHD ENTRY
OUTSCH: LOAD AP,.QHLNK(H),QH.PTF ;GET POINTER TO FIRST JOB
PJUMPE AP,.POPJ## ;NO JOBS, JUST RETURN EMPTY HANDED
LOAD P1,PSBSTS(P4),PSYNJP ;NUMBER CURRENTLY BEING PROCESSED
JUMPN P1,RETZER ;CAN ONLY PROCESS 1 AT A TIME
LOAD T1,PSBIN2(P4),PSYPGS ;GET MLIMIT
LOAD T2,PSBSTS(P4) ;GET THE STATUS
PUSHJ P,I$OPER## ;FIND OUT IF AN OPERATOR ON DUTY
JUMPN S1,OUTS.0 ;GO IF THERE IS ONE PRESENT
TXON T2,PSYFRZ ;NO, NOBODY TO CHANGE FROMS
PUSHJ P,RETMIN ;NOT FROZEN ALREADY, COME BACK LATER
OUTS.0: SETO P3, ;CLEAR FORMS CHANGE CODE
LOAD S1,PSBIN2(P4),PSYNXT ;GET 'NEXT' JOB REQUESTED BY OPERATOR
JUMPE S1,OUTS.2 ;NONE, BEGIN SCHEDULING LOOP
MOVE P2,AP ;SAVE CURRENT POINTER
PUSHJ P,FNDNXT ;FIND REQUESTED JOB IN THE QUEUE
JUMPE AP,OUTS.1 ;DIDN'T FIND IT, RESUME NORMAL PATH
PUSHJ P,OUTREJ ;DO REJECTION TESTS NOW
JUMPE S1,OUTS.1 ;JUMP IF REJECTED
ZERO PSBIN2(P4),PSYNXT ;CLEAR NEXT IF FOUND
LOAD S1,.QELM1(AP) ;GET FORMS TYPE FOR THIS ENTRY
ANDX S1,FRMSK1 ;MAKE IT UNIQUE
STORE S1,PSBIN1(P4) ;THAT IS THE CURRENTLY MOUNTED FORMS
POPJ P, ;RETURN WITH THAT JOB
OUTS.1: MOVE AP,P2 ;GET ORIGINAL AP BACK
OUTS.2: LOAD P1,.QELM2(AP),QE.PGS ;GET THIS JOBS PAGE REQUEST
CAILE P1,(T1) ;TOO LARGE
JRST OUTS.3 ;YES, IT'LL HAVE TO WAIT
PUSHJ P,OUTREJ ;DO SOME SIMPLE REJECTION TESTS
JUMPE S1,OUTS.3 ;JUMP IF REJECTED
MOVE P1,.QELM1(AP) ;GET FORMS TYPE FOR THIS ENTRY
ANDX P1,FRMSK1 ;MAKE IT UNIQUE
CAMN P1,PSBIN1(P4) ;SAME AS CURRENTLY MOUNTED
POPJ P, ;YES, TAKE THIS ONE
SKIPLE S1,KSYSTM ;IS KSYS SET?
CAIG S1,FRMKSY*^D60 ;YES, TO CLOSE FOR COMFORT?
JUMPN S1,OUTS.3 ;YES, DON'T CHANGE FORMS
TXNN T2,PSYFRZ ;NO, ARE FORMS CURRENTLY FROZEN
PUSHJ P,OUTFRM ;ACCUMULATE FORMS CHANGE PARAMETERS
OUTS.3: LOAD AP,.QELNK(AP),QE.PTN ;FIND THE NEXT ENTRY
JUMPN AP,OUTS.2 ;AND TRY TO SELECT IT
PJUMPL P3,.POPJ## ;RETURN 0 IF NO FORMS CHANGE
;FALL ONTO THE NEXT PAGE FOR AUTOMATIC FORMS CHANGE
;HERE TO SELECT THE BEST FORMS OF THE GROUP FOR AUTOMATIC CHANGE
MOVE P2,P3 ;SAVE THE ORIGINAL COUNT
OUTS.4: MOVE S2,FRMCNT(P3) ;NOW FIND THE LARGEST FORMS LIMIT
MOVEI T1,(P3) ;S2 = PAGES, T1 = INDEX INTO FORMS TABLES
OUTS.5: SOJL P3,OUTS.6 ;LOOKED AT THEM ALL YET
CAMLE S2,FRMCNT(P3) ;NO, IS THIS ONE BETTER
JRST OUTS.5 ;NO, KEEP LOOKING
JRST OUTS.4 ;YES, TAKE THIS ONE
OUTS.6: CAIGE S2,FRMTHR ;LARGEST COUNT BELOW THE THRESHOLD
JRST RETZER ;YES, NOT WORTH AN AUTOMATIC CHANGE
MOVE S2,FRMTYP(T1) ;GET THE NEW TYPE
MOVX S1,FRMNOR ;GET NAME OF "NORMAL" FORMS
ANDX S1,FRMSK1 ;DOWN TO UNIQUE NAME
CAME S1,S2 ;CHANGING BACK TO STANDARD
PUSHJ P,OUTOTP ;NO, LOOK FOR OTHERS AT THIS STATION
JUMPE S1,OUTS.7 ;SKIP THIS FORM CHANGE (TRY ANOTHER)
MOVEM S2,PSBIN1(P4) ;CHANGE THE FORMS
MOVE AP,FRMADR(T1) ;FIRST OF THIS NEW FORM
POPJ P, ;IS THE ONE TO SCHEDULE
OUTS.7: MOVE P3,P2 ;RESTORE LOOP COUNT
SETZM FRMCNT(T1) ;SET REQUEST = 0 PAGES
JRST OUTS.4 ;AND TRY ANOTHER FORM TYPE
;THE RDE QUEUE SCHEDULER
RDESCH: LOAD P1,PSBSTS(P4),PSYNJP ;GET NUMBER OF JOBS IN PROGRESS
JUMPN P1,RETZER ;RETURN ZERO IF BUSY
LOAD AP,.QHLNK(H),QH.PTF ;GET FIRST ITEM IN THE QUEUE
RDES.1: PJUMPE AP,.POPJ## ;RETURN IF NO JOBS
LOAD S1,PSBIN1(P4) ;GET FORMS TYPE
MOVEM S1,.QELM1(AP) ;SAVE IN REQUEST
PUSHJ P,SCHSTR ;CHECK THE STRUCTURE
PJUMPN S1,.POPJ## ;RETURN IF WE'VE WON
LOAD AP,.QELNK(AP),QE.PTN ;ELSE, GET THE NEXT JOB
JRST RDES.1 ;AND LOOP
;THE INPUT SCHEDULING ROUTINE
INPSCH: LOAD AP,.QHLNK(H),QH.PTF ;GET FIRST JOB IN QUEUE
PJUMPE AP,.POPJ## ;NO JOBS, RETURN
PUSHJ P,I$LOGN## ;OK TO RUN JOBS
JUMPE S1,RETTMR ;NO, RETURN ZERO AND COME BACK IN A MIN.
LOAD P1,PSBSTS(P4),PSYNJP ;GET NUMBER CURRENTLY BEING PROCESSED
LOAD P2,PSBIN2(P4),PSYMJB ;GET MJOB VALUE
CAIL P1,(P2) ;ALREADY ENOUGH JOBS RUNNING
JRST RETZER ;YES, RETURN A ZERO
MOVSI P1,-INPNUM ;FIND A SLOT IN THE TABLES
SKIPE INPITN(P1) ;EMPTY IS ITN = 0
AOBJN P1,.-1 ;KEEP GOING TILL FOUND
JUMPGE P1,RETZER ;MUST BE RUNNING ENOUGH JOBS
LOAD S1,PSBIN2(P4),PSYNXT ;GET OPERATOR SELECTION
JUMPE S1,INPS.2 ;RESUME NORMAL PATH IF NONE
MOVE P2,AP ;COPY ORIGINAL AP
PUSHJ P,FNDNXT ;FIND THE ONE SELECTED
JUMPE AP,INPS.1 ;NOT FOUND, GO NORMAL ROUTE
PUSHJ P,INPREJ ;DO SOME SIMPLE REJECTION TESTS
JUMPE S1,INPS.1 ;JUMP IF REJECTED
ZERO PSBIN2(P4),PSYNXT ;CLEAR NEXT WHEN FOUND
MOVEI S1,-1 ;GET A "LARGE" NUMBER
MOVEM S1,INPS.A ;SET SINGLE JOB TIME LIMIT
MOVEM S1,INPS.B ;SET TOTAL BATCH TIME LIMIT
MOVEM S1,INPS.C ;SET SINGLE JOB CORE LIMIT
MOVEM S1,INPS.D ;SET TOTAL BATCH CORE LIMIT
JRST INPS.4 ;TO ENSURE THIS JOB FITS
;MORE OF THE INPUT SCHEDULING ROUTINE ON THE NEXT PAGE
;CONTINUE WITH INPUT JOB SELECTION
INPS.1: MOVE AP,P2 ;RESTORE ORIGINAL AP
INPS.2: LOAD S1,PSBIN1(P4),PSYSJT ;VALUE OF MTIME
MOVEM S1,INPS.A ;STORE FOR LOOP
LOAD S1,PSBIN1(P4),PSYTBT ;AND TIME OPERATOR COMMANDS
MOVEM S1,INPS.B ;...
LOAD S1,PSBIN3(P4),PSYSJC ;SINGLE JOB CORE LIMIT
CAMGE S1,G$MCOR## ;SMALLER THAN SYSTEM MINIMUM
MOVE S1,G$MCOR## ;YES, USE THAT INSTEAD
MOVEM S1,INPS.C ;...
LOAD S1,PSBIN3(P4),PSYTBC ;AND TOTAL BATCH CORE
CAMGE S1,G$MCOR## ;...
MOVE S1,G$MCOR## ;...
MOVEM S1,INPS.D ;...
MOVE S1,KSYSTM ;GET TIME UNTIL KSYS
JUMPL S1,RETZER ;OVER, AND THIS IS NOT 'NEXT', DONT RUN
JUMPE S1,INPS.3 ;NOT SCHEDULED, USE OPERATOR VALUES
CAMG S1,INPS.B ;USE THE SMALLEST OF THAT OR OPERATORS VALUE
MOVEM S1,INPS.B ;USE KSYS TIMER
INPS.3: PUSHJ P,INPREJ ;DO SOME SIMPLE REJECTION TESTS
JUMPE S1,INPS.5 ;JUMP IF REJECTED
INPS.4: LOAD T4,.QELM2(AP),QE.TIM ;GET THIS JOBS /TIME: VALUE
LOAD T3,PSBSCH(P4),PSYSMT ;TIME ALREADY COMMITTED
ADD T3,T4 ;ACCUMULATE THIS JOB
CAMG T4,INPS.A ;OVER THE SINGLE JOB LIMIT
CAMLE T3,INPS.B ;OR WILL IT TAKE US OVER THE TOTAL
JRST INPS.5 ;YES, TRY ANOTHER JOB
LOAD S1,.QELM2(AP),QE.COR ;GET REQUESTED CORE
LOAD T4,PSBSCH(P4),PSYSMC ;AMOUNT ALREADY COMMITTED
ADD T4,S1 ;INCLUDE THIS JOB
CAMG S1,INPS.C ;OVER THE SINGLE JOB LIMIT
CAMLE T4,INPS.D ;OR WILL IT TAKE US OVER THE TOTAL
JRST INPS.5 ;YES, TRY ANOTHER JOB
STORE T1,INPUNI(P1),IN.UNI ;STORE THIS JOBS /UNIQUE VALUE
STORE T3,PSBSCH(P4),PSYSMT ;ACCUMULATED TOTAL COMMITTED
STORE T4,PSBSCH(P4),PSYSMC ;AND TOTAL FOR CORE
MOVE S1,P1 ;COPY STREAM NUMBER INTO S1
PUSHJ P,I$UQST## ;AND SET STREAM DIRECTORY
LOAD T1,.QEITN(AP) ;THE ITN
STORE T1,INPITN(P1) ;STORE FOR RELEASE
INCR INPNJP ;ADD ANOTHER JOB
POPJ P, ;AND TAKE THIS ONE
INPS.5: LOAD AP,.QELNK(AP),QE.PTN ;FIND THE NEXT JOB
JUMPN AP,INPS.3 ;TRY IT IF THERE IS ONE
POPJ P, ;ELSE, RETURN 0 SELECTION
INPS.A: BLOCK 1 ;SINGLE JOB TIME LIMIT
INPS.B: BLOCK 1 ;TOTAL BATCH TIME LIMIT
INPS.C: BLOCK 1 ;SINGLE JOB CORE LIMIT
INPS.D: BLOCK 1 ;TOTAL BATCH CORE LIMIT
;SUBROUTINES TO DO LINKIN FOR INPUT AND OUTPUT QUEUES
;CALLED WITH AP = THE ENTRY TO BE INCLUDED IN THE QUEUE
; H = THE QUEUE
OUTLNK: PUSHJ P,.SAVE3## ;SAVE P1-P3
SAVE E ;...
LOAD P2,.QELM2(AP),QE.PGS ;GET THE PAGE LIMIT FOR THIS REQUEST
MOVEI P3,^D60 ;FACTOR FOR AGEING IN PRICMP
JRST LNKPRI ;AND LINK IN PRIORITY ORDER
INPLNK: PUSHJ P,.SAVE3## ;SAVE A FEW REGS
SAVE E ;...
LOAD P2,.QELM2(AP),QE.TIM ;GET BASE FOR PRIORITY
MOVEI P3,^D10 ;FACTOR FOR PRICMP
ZERO P1 ;CLEAR ENTRANCE PRIORITY
LOAD S1,.QELM1(AP),QE.DEP ;GET VALUE OF DEPENDENCY
JUMPN S1,LNKP.1 ;IF SET, PUT IN AGE ORDER
LNKPRI: HRLOI P1,1 ;GET 1,,777777 INTO P1
IDIVI P1,(P2) ;FACTOR THE LIMIT REQUESTED
LOAD S1,.QESEQ(AP),QE.PRI ;GET THE EXTERNAL PRIORITY
SUBI S1,1 ;DECREMENT IT
IMULI P1,(S1) ;BUMP BY THE SPECIFIED VALUE
LSH P1,-1 ;BUT NOT BY TOO MUCH
LNKP.1: MOVEM P1,.QEIPR(AP) ;SAVE AS THE ENTRANCE PRIORITY
MOVEI E,(AP) ;COPY THE CURRENT ENTRY POINTER
PUSHJ P,PRICMP ;COMPUTE THE FULL PRIORITY
MOVE P1,S1 ;SAVE IT IN P1
LOAD E,.QHLNK(H),QH.PTF ;GET THE FIRST IN THIS QUEUE
LNKP.2: PJUMPE E,M$ELNK## ;IF AT THE END, MAKE THIS THE LAST
PUSHJ P,PRICMP ;COMPUTE FULL PRIORITY OF THIS ONE
CAMLE P1,S1 ;IS THE NEW ONE HIGHER
PJRST M$LINK## ;YES, E IS THE SUCCESSOR
CAME P1,S1 ;SPECIAL CASE IF EQUAL
JRST LNKP.3 ;NO, FOLLOW THE CHAIN
MOVE S1,.QECRE(E) ;NEEDED IF Q$CDIN IS RETURNING
CAMLE S1,.QECRE(AP) ;AN ENTRY TO THE PROCESSING QUEUE
PJRST M$LINK## ;PUT EQUAL PRIO IN AGE ORDER
LNKP.3: LOAD E,.QELNK(E),QE.PTN ;NO, FOLLOW THE CHAIN
JRST LNKP.2 ;TILL WE FIND OUR POSITION
;ROUTINE TO INCLUDE AGE FACTOR FOR QUEUES
PRICMP: MOVE S2,.QECRE(E) ;THIS ENTRIES CREATION TIME
MOVE S1,G$NOW## ;GET THE CURRENT TIME
PUSHJ P,I$AGE## ;GET THE AGE OF IT IN SECONDS
IDIVI S1,(P3) ;FACTOR BY DESIRED VALUE
ADD S1,.QEIPR(E) ;INCLUDE THE ENTRANCE PRIORITY
POPJ P, ;AND RETURN WITH PRI IN S1
; HERE WHEN CALLED BY Q$CREATE TO FILL IN DEFAULTS FOR A MESSAGE "M"
; FOR THE INPUT QUEUE
INPDEF: FILLIN S1,.EQLM1(M),EQ.OUT,%EQOLG ;SET DEFAULT /OUTPUT VALUE
FILLIN S1,.EQLM2(M),EQ.TIM,INPTIM ;SET DEFAULT TIME VALUE
FILLIN S1,.EQLM3(M),EQ.LPT,INPPGS ;SET DEFAULT PAGE VALUE
FILLIN S1,.EQLM3(M),EQ.CDP,INPCDS ;SET DEFAULT CARD VALUE
FILLIN S1,.EQLM4(M),EQ.PTP,INPPTP ;SET DEFAULT PAPER TAPE VALUE
FILLIN S1,.EQLM4(M),EQ.PLT,INPPLT ;SET DEFAULT PLOTTER VALUE
FILLIN S1,.EQLM2(M),EQ.COR,INPCOR ;SET DEFAULT CORE VALUE
MOVE S2,G$MCOR## ;GET THE SYSTEM MINIMUM
CAMGE S1,S2 ;VALUE ABOVE THE MINIMUM
STORE S2,.EQLM2(M),EQ.COR ;NO, SET TO SYSTEM MINIMUM
LOAD S1,.EQSPC(M),EQ.NUM ;GET NUMBER OF FILES IN REQUEST
CAIE S1,2 ;BETTER BE 2 FOR INPUT (.CTL, .LOG)
PJRST E$INF## ;ILLEGAL NUMBER OF FILES
PJRST CLRCHK ;CLEAR/FILLIN ADDITIONAL INFORMATION
; FOR THE OUTPUT QUEUES
PLTDEF: MOVX S1,INPPLT ;USE SAME AS INPUT PLOT LIMIT
MOVX S2,PLTFCT ;GET PLOTTER FACTOR
JRST OUTDEF ;ENTER COMMON CODE
PTPDEF: MOVX S1,INPPTP ;USE SAME AS INPUT TAPE LIMIT
MOVX S2,PTPFCT ;GET PAPER TAPE FACTOR
JRST OUTDEF ;ENTER COMMON CODE
CDPDEF: MOVX S1,INPCDS ;USE SAME AS INPUT CARD LIMIT
MOVX S2,CDPFCT ;GET CARD PUNCH FACTOR
JRST OUTDEF ;ENTER COMMON CODE
LPTDEF: MOVX S1,INPPGS ;USE SAME DEFAULT AS INPUT PAGE LIMIT
MOVX S2,LPTFCT ;GET LINE PRINTER FACTOR
OUTDEF: LOAD TEMP,.EQLM2(M),EQ.PGS ;GET LIMIT SPECIFIED
JUMPN TEMP,OUTD.3 ;OK IF ONE IS SPECIFIED
LOAD TEMP,.EQLM2(M),EQ.NBL ;NONE, GET NUMBER OF BLOCKS REQUESTED
JUMPE TEMP,OUTD.2 ;NONE, USE INPUT SIDE AS DEFAULT
MOVE S1,TEMP ;GET INTO BETTER REG
JUMPGE S2,OUTD.1 ;JUMP IF FACTOR IS A MULTIPLIER
MOVMS S2 ;A DIVISOR, GET THE MAGNITUDE
IDIVI S1,(S2) ;FACTOR THE BLOCKS
AOJA S1,OUTD.2 ;ROUND UP AND JUMP
OUTD.1: IMULI S1,(S2) ;FACTOR THE BLOCKS
OUTD.2: MOVE T1,S1 ;SAVE PARTIAL LIMIT
PUSHJ P,CLRCHK ;CLEAR/FILLIN ADDITIONAL STUFF
IMULI S1,SPLLIM ;BIAS*SUM(ALL COPIES)
ADD S1,T1 ;ADD IN THE LIMIT THUS FAR
STORE S1,.EQLM2(M),EQ.PGS ;STORE THE TOTAL LIMIT
SKIPA ;AND SKIP ALTERNATE CALL
OUTD.3: PUSHJ P,CLRCHK ;CLEAR/FILLIN ADDITIONAL INFORMATION
MOVX S1,FRMNOR ;GET NAME OF NORMAL FORMS
SKIPN .EQLM1(M) ;FORMS SPECIFIED
MOVEM S1,.EQLM1(M) ;NO, SET = "NORMAL"
POPJ P, ;AND RETURN
;SUBROUTINE TO FILL IN THE COMMON DEFAULTS FOR THE SCHDEF ENTRY
;
;RETURNS THE SUM OF THE COPIES OF ALL FILES IN S1
CLRCHK: PUSHJ P,.SAVET## ;SAVE T1-T4
PUSHJ P,.SAVE1## ;SAVE P1 AS WELL
ZERO CLRC.A ;CLEAR COPIES COUNTER
LOAD T4,.MSTYP(M),.QIFNC ;GET INTERNAL CREATE BIT FOR CHECKS
JUMPN T4,CLRC.2 ;SKIP SOME TESTS IF THIS IS ONE
ZERO .EQSEQ(M),EQ.RDE!EQ.SPL ;CLEAR INTERNAL BITS
LOAD S1,.EQLEN(M),EQ.VRS ;GET REQUEST VERSION NUMBER
CAIE S1,%%.QSR ;BETTER BE THE SAME AS QSRMAC
PJRST E$WVN## ;ISN'T, GIVE WRONG VERSION ERROR
MOVE S1,M ;POINT TO THE EQ
PUSHJ P,I$DFEQ## ;DEFAULT OS-DEP STUFF
PJUMPE S1,E$ICM## ;JUMP IF AN ILLEGAL CREATE
CLRC.1: PUSHJ P,I$WHEEL## ;FIND OUT IF CALLER IS PRIVILEGED
STORE S1,.EQSEQ(M),EQ.PRV ;STORE WHEEL STATUS FOR SPOOLERS
CLRC.2: LOAD S1,.EQSPC(M),EQ.NUM ;GET NUMBER OF FILES
PJUMPE S1,E$INF## ;BAD FILE COUNT
MOVE P1,S1 ;P1 = NUMBER OF 'REAL' FILES
LOAD S2,.EQLEN(M),EQ.LOH ;LETS FIND THE FIRST FILE
ADDI S2,(M) ;S2 = POINTER INTO '.FPxxx'
LOAD T3,.MSTYP(M),MS.CNT ;GET THE MESSAGE COUNT
ADDI T3,(M) ;T3 = FIRST ADDR NOT IN MESSAGE
CLRC.3: CAIL S2,.FPINF(T3) ;WILL I TOUCH AN ILLEGAL ADDRESS
PJRST E$ICM## ;YES, INVALID MESSAGE
MOVX T2,FP.SPL ;GET THE SPOOLED FILE BIT
SKIPN T4 ;SKIP IF INTERNAL CREATE
ANDCAM T2,.FPINF(S2) ;CAN ONLY BE SET ON INTERNAL REQUESTS
LOAD T1,.FPINF(S2),FP.FCY ;GET NUMBER OF COPIES
ADDM T1,CLRC.A ;AND ADD TO THE SUM
LOAD T2,.FPINF(S2),FP.IGN ;GET THE /REMOVE FLAG
SKIPE T2 ;IS THIS A 'REAL' FILE
SOS P1 ;NO, DECREMENT THE COUNT
LOAD T1,.FPSIZ(S2),FP.FHD ;SIZE OF FP AREA
LOAD T2,.FPSIZ(S2),FP.FFS ;SIZE OF FD AREA
CAIL T1,FPMSIZ ;LESS THAN THE MINIMUM FP SIZE
CAIGE T2,FDMSIZ ;OR LESS THAN THE MINIMUM FD SIZE
PJRST E$ICM## ;YES, AN INVALID MESSAGE
CAIG T1,FPXSIZ ;GREATER THAN MAXIMUM FP SIZE
CAILE T2,FDXSIZ ;OR GREATER THAN THE MAXIMUM FD SIZE
PJRST E$ICM## ;YES, AN ILLEGAL MESSAGE
ADDI S2,(T1) ;BUMP TO NEXT FILE PARAMETER AREA
ADDI S2,(T2) ;...
SOJG S1,CLRC.3 ;CONTINUE FOR ALL FILES
CAIE S2,(T3) ;THIS BETTER COME OUT EVEN
PJRST E$ICM## ;DIDN'T, AN INVALID MESSAGE
JUMPN P1,CLRC.4 ;JUMP IF THERE ARE SOME FILES LEFT
MOVX P1,EQ.RDE ;GET THE 'DOESNT EXIST' BIT
IORM P1,.EQSEQ(M) ;AND MARK THE REQUEST
;CONTINUE WITH THE DEFAULT FILLING ON THE NEXT PAGE
;HERE FOR MORE DEFAULT FILLING
CLRC.4: LOAD S1,.EQSEQ(M),EQ.SEQ ;GET THE SEQUENCE NUMBER
JUMPN S1,CLRC.5 ;GOT ONE, SKIP THIS
HRRZ S1,.EQITN(M) ;GET THE RH OF THE ITN
ANDI S1,^D8191 ;NICE LOOKING MASK
AOS S1 ;DON'T WANT A ZERO
STORE S1,.EQSEQ(M),EQ.SEQ ;THAT'S A NICE DEFAULT SEQUENCE
CLRC.5: LOAD S1,.EQJOB(M) ;GET THE JOB NAME
JUMPN S1,CLRC.6 ;IS ONE, SKIP THE DEFAULT
MOVE S1,[SIXBIT\NONAME\] ;WOULD YOU BELIEVE '.BAS'
MOVEM S1,.EQJOB(M) ;MUST HAVE A JOB NAME SO LIST WILL WORK
CLRC.6: JUMPN T4,CLRC.7 ;SKIP THIS IF INTERNAL CREATE
ZERO .EQCHK(M) ;CREATE CAN'T HAVE CHECKPOINT/REQUEUE INFO
HRRI S1,.EQCHK+1(M) ;SO LETS ZERO IT NOW
HRLI S1,.EQCHK(M) ;BUILD THE BLT
BLT S1,.EQCHK+4(M) ;CLEAR THE INFORMATION
CLRC.7: SKIPN S1,.EQAFT(M) ;IS THERE CREATION OR AFTER
MOVE S1,G$NOW## ;NO, USE CURRENT TIME
MOVEM S1,.EQAFT(M) ;AS DEFAULT CREATION TIME
LOAD S1,.EQSPC(M),EQ.PRO ;GET PROTECTION FIELD
SKIPN S1 ;WAS IT 0?
LOAD S1,G$SPRT## ;YES, DEF IT WITH SPOOL PROT
STORE S1,.EQSPC(M),EQ.PRO ;AND STORE IT
FILLIN S1,.EQSEQ(M),EQ.PRI,SPLPRI ;DEFAULT THE EXTERNAL PRIO
MOVE S1,CLRC.A ;LOAD RETURN ANSWER
POPJ P, ;AND RETURN FOR LINKIN
CLRC.A: BLOCK 1 ;SUM OF ALL COPIES FIELD
;FUNCTIONS TO DO QUEUE DEPENDENT GROUP 1 MODIFIES
;CALLED BY Q$MODIFY WITH
; AP = THE ENTRY BEING MODIFIED (.EQxxx FORM)
; S1 = GROUP 0 MODIFY BLOCK
OUTMOD: PUSHJ P,.SAVE3## ;SAVE A FEW REGS FIRST
LOAD P1,MOD.GN(S1),MODGLN ;NUMBER OF GROUP 1 ELEMENTS
SOJLE P1,.POPJ## ;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
POPJ P, ;RETURN TO Q$MODIFY FOR NEXT GROUP
OUTMTB: STORE P3,.EQLM1(AP) ; 0 = /FORMS
STORE P3,.EQLM2(AP),EQ.PGS ; 1 = /LIMIT
STORE P3,.EQLM3(AP) ; 2 = /NOTE (1ST HALF)
STORE P3,.EQLM4(AP) ; 3 = /NOTE (2ND HALF)
NOUTPM==<.-OUTMTB> ;NUMBER CURRENTLY IMPLEMENTED
;ROUTINE CORRESPONDS TO OUTMOD EXCEPT FOR THE INPUT QUEUE
;CALLED BY Q$MODIFY WITH THE SAME ARGUMENTS AS OUTMOD ENTRY
INPMOD: PUSHJ P,.SAVE4## ;SAVE A FEW REGS FIRST
LOAD P1,MOD.GN(S1),MODGLN ;NUMBER OF GROUP 1 ELEMENTS
SOJLE P1,.POPJ## ;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
POPJ P, ;RETURN TO Q$MODIFY FOR NEXT GROUP
INPMTB: STORE P3,.EQLM2(AP),EQ.COR ; 0 = /CORE
STORE P3,.EQLM2(AP),EQ.TIM ; 1 = /TIME
STORE P3,.EQLM3(AP),EQ.LPT ; 2 = /PAGES
STORE P3,.EQLM3(AP),EQ.CDP ; 3 = /CARDS
STORE P3,.EQLM4(AP),EQ.PTP ; 4 = /FEET (/METERS)
STORE P3,.EQLM4(AP),EQ.PLT ; 5 = /TPLOT
PUSHJ P,MODDEP ; 6 = /DEPENDENCY
STORE P3,.EQLM1(AP),EQ.UNI ; 7 = /UNIQUE
STORE P3,.EQLM1(AP),EQ.NRS ; 8 = /RESTART
STORE P3,.EQLM1(AP),EQ.OUT ; 9 = /OUTPUT
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
POPJ P, ;NO, DON'T STORE FOR UNKNOWN TYPE
MOVNS P3 ;SUBTRACTING, NEGATE THE VALUE
MODD.1: LOAD P4,.EQLM1(AP),EQ.DEP ;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: STORE P3,.EQLM1(AP),EQ.DEP ;STORE NEW (OR ADJUSTED) VALUE
POPJ P, ;RETURN FOR NEXT
SUBTTL Other Entry Points
;ROUTINE CALLED WHENEVER AN ENTRY IS REMOVED FROM THE USE QUEUE
;CALLED BY Q$RELEASE, Q$REQUEUE, KILPSB
;WITH
; AP = THE ENTRY BEING REMOVED
; T1 = THE PSB WHO USED TO BE PROCESSING THIS ENTRY (0 IF UNKNOWN)
INTERN S$RUSE
S$RUSE: LOAD S1,.QESTN(AP),QE.RQP ;GET THE RELATIVE QUEUE POINTER
ADDI S1,TBLHDR## ;MAKE A REAL QUEUE POINTER
LOAD S1,.QHTYP(S1),QH.TYP ;GET THE QUEUE TYPE
CAIE S1,.QHTIP ;IS IT THE INPUT QUEUE
JRST RUSE.1 ;NO, DECREMENT NJP FOR PSB
MOVSI S1,-INPNUM ;SET UP FOR ITN SEARCH FOR BATCH JOBS
MOVE S2,.QEITN(AP) ;GET THE ITN OF THE REQUEST
CAME S2,INPITN(S1) ;LOOK FOR IT IN THE BATCH TABLES
AOBJN S1,.-1 ;CONTINUE UNTIL FOUND
JUMPGE S1,RUSE.1 ;WHAT!!!!!
ZERO INPITN(S1) ;REMOVE FROM THE TABLES
ZERO INPUNI(S1) ;AND THE UNIQUE STUFF TOO
PUSHJ P,I$UQCL## ;CLEAR THE DIRECTORY
DECR INPNJP ;ONE LESS JOB RUNNING
JUMPE T1,.POPJ## ;RETURN NOW IF NO PSB
LOAD S1,PSBSCH(T1),PSYSMT ;TIME COMMITTED TO THIS PROCESS
LOAD S2,.QELM2(AP),QE.TIM ;THIS JOBS TIME LIMIT
SUB S1,S2 ;ACCOUNT FOR JOB REMOVAL
STORE S1,PSBSCH(T1),PSYSMT ;STORE ADJUSTED VALUE
LOAD S1,PSBSCH(T1),PSYSMC ;CORE COMMITTED TO THIS PROCESS
LOAD S2,.QELM2(AP),QE.COR ;THIS JOBS CORE LIMIT
SUB S1,S2 ;REMOVE THIS JOB
STORE S1,PSBSCH(T1),PSYSMC ;STORE ADJUSTED VALUE
RUSE.1: JUMPE T1,.POPJ## ;RETURN IF NO PSB AVAILABLE
DECR PSBSTS(T1),PSYNJP ;RUNNING ONE LESS JOB
POPJ P, ;RETURN TO CALLER
;THIS ROUTINE PROCESSES THE QUEUE DEPENDENT FUNCTIONS AT THE RELEASE MESSAGE
; Q$RELEASE HAS ALREADY VALIDATED AND PROCESSED THE MESSAGE
;CALLED BY Q$RELEASE WITH:
; M = THE RELEASE MESSAGE
; AP = ENTRY BEING RELEASED (.QExxx)
INTERN S$RELE
S$RELE: PUSHJ P,.SAVE1## ;SAVE P1
LOAD T2,.QESTN(AP),QE.RQP ;GET THE RELATIVE QUEUE POINTER
ADDI T2,TBLHDR## ;MAKE A REAL QUEUE POINTER
LOAD T2,.QHTYP(T2),QH.TYP ;NOW GET THE QUEUE TYPE
CAIE T2,.QHTIP ;THE INPUT QUEUE
POPJ P, ;NO, DON'T BOTHER WITH ALL THE WORK
LOAD P1,.MSTYP(M),MS.CNT ;GET LENGTH OF RELEASE MESSAGE
SUBI P1,REL.SZ ;EXPECT A LONG ONE FROM BATCON
JUMPLE P1,.POPJ## ;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
LOAD T2,.QEPRT(AP),DV.STN ;GET STATION OF THE INPUT REQUEST
STORE T2,CSM.JB(T1),CS.LOC ;MAKE SURE THE OUTPUT IS CORRECTLY ROUTED
ZERO CSM.JB(T1),CS.FLG ;NO FLAGS HERE
LOAD S1,.QEPRT(AP),QE.DMD ;GET DEVICE MODIFIERS
HRLI S1,'LPT' ;LOG GOES TO LPT THERE
PUSHJ P,I$MSDN## ;MAKE A SIXBIT DEVICE NAME FROM THAT
STORE S1,CSM.DV(T1) ;STORE FOR Q$FSPL
MOVE T2,.QEOID(AP) ;GET OWNER ID
STORE T2,CSM.OI(T1) ;SAVE THAT
MOVEI S1,REL.FD(M) ;POINT TO THE LOG FILE FD AREA
STORE S1,CSM.FD(T1),CS.FDA ;SAVE FOR Q$INCL
PUSHJ P,I$FSTR## ;EXTRACT THE STRUCTURE NAME
STORE S1,CSM.ST(T1) ;SAVE FOR Q$FSPL
STORE P1,CSM.FD(T1),CS.FDL ;FINALLY, THE LENGTH OF THE FD INVOLVED
PUSHJ P,Q$FSPL## ;FIND MATCHING SPOOL REQUEST
; CODE IS CONTINUED ON THE NEXT PAGE
;HERE WITH M = THE RELEASE MESSAGE
; AP = CURRENT SPOOLING REQUEST (.EQxxx)
; E = SPL QUEUE ENTRY FOR THIS JOB
; P1 = THE LENGTH OF THE LOG FILE FD
; T1 = THE CANONICAL SPOOL MESSAGE
MOVE T2,BATFLG ;DEFAULT LOG FILE SETTINGS
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.PRL ;PRINT THE LOG?
JRST RELE.1 ;YES, ALL IS WELL
TXZ T2,FP.FCY ;NO, ZERO COPIES
LOAD T3,.EQSPC(AP),EQ.NUM ;GET CURRENT NUMBER OF FILES
JUMPN T3,RELE.1 ;SOME ALREADY, JUST ADD
MOVX T3,EQ.RDE ;NONE, GET NOT REAL BIT
IORM T3,.EQSEQ(AP) ;SO DOESN'T GET LISTED
RELE.1: 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
ADR2PG AP ;CONVERT TO A PAGE NUMBER
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
SKIPE S1,S2 ;GET OLD DPA IF THERE IS ONE
PUSHJ P,F$RLRQ## ;AND RELEASE OLD FAILSOFT COPY
PUSHJ P,M$RELP## ;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
BATFLG: INSVL.(.FPFAS,FP.FFF)!INSVL.(1,FP.FSP)!FP.FLG!INSVL.(1,FP.FCY)
SUBTTL Scheduler Utilities
;ROUTINE TO ACCUMULATE SIZES IF FORMS ARE NOT FROZEN
; P3 = FORM COUNTER
; P1 = NEW TYPE (MASKED)
; AP = CURRENT ENTRY
;RETURNS WITH TABLES INCREMENTED
OUTFRM: JUMPL P3,OUTF.2 ;JUMP IF THIS IS THE FIRST CALL
ZERO S1 ;CLEAR SEARCH INDEX
OUTF.1: CAILE S1,(P3) ;END OF THE LIST
JRST OUTF.2 ;YES, APPEND TO THE END
CAME P1,FRMTYP(S1) ;FIND IN THE TABLE
AOJA S1,OUTF.1 ;NO, KEEP LOOKING
LOAD S2,.QELM2(AP),QE.PGS ;PAGE REQUEST FOR THIS ENTRY
ADDM S2,FRMCNT(S1) ;INCLUDE IN THE TOTAL
POPJ P, ;AND RETURN
OUTF.2: CAIL P3,FRMNUM-1 ;TABLE FULL
POPJ P, ;YES, DON'T INCLUDE THIS ONE
AOS P3 ;BUMP COUNT
MOVEM P1,FRMTYP(P3) ;STORE FORM NAME
MOVEM AP,FRMADR(P3) ;AND FIRST FOR THIS TYPE
LOAD S1,.QELM2(AP),QE.PGS ;PAGE REQUEST
MOVEM S1,FRMCNT(P3) ;AS THE FIRST COUNT
POPJ P, ;NOW RETURN
;ROUTINE TO DETERMINE IF ANOTHER DEVICE AT THE SAME STATION IS USING
; FORMS WE ARE ABOUT THE CHANGE TO.
;CALL S2 = FORMS DESIRED
; P4 = MY PSB
;RETURNS S1 = .FALSE. IF THERE ARE AND NOT TO DUPLICATE FORMS CHANGES
; = .TRUE. IF THERE ARE NONE AND OK TO CHANGE FORMS
;DESTROYS T2, T3
OUTOTP: LOAD S1,HDRPSB##+.QHLNK,QH.PTF ;FIND THE FIRST IN THE PSB QUEUE
OUTO.1: CAIN S1,(P4) ;LOOKING AT MYSELF
JRST OUTO.2 ;YES, SKIP THE TESTS
CAME S2,PSBIN1(S1) ;USING SAME FORMS AS I WANT
JRST OUTO.2 ;NO, TRY THE NEXT
LOAD T2,PSBSDV(S1),DV.STN ;STATION NUMBER
LOAD T3,PSBSDV(P4),DV.STN ;AND MY LOCATION
CAME T2,T3 ;SAME PLACE
JRST OUTO.2 ;NO, TRY THE NEXT
LOAD T2,PSBSTS(S1),PSYHDR ;QUEUE DRAWING FROM
LOAD T3,PSBSTS(P4),PSYHDR ;AND MY QUEUE
CAMN T2,T3 ;SAME QUEUE
PJRST .FALSE## ;YES, DON'T CHANGE FORMS
OUTO.2: LOAD S1,.QELNK(S1),QE.PTN ;LINK TO THE NEXT PSB
JUMPN S1,OUTO.1 ;AND LOOK IF ONE THERE
PJRST .TRUE## ;GIVE OK TO CHANGE RETURN
;ROUTINE TO DO OUTPUT REJECTION TESTS
;CALL AP = CURRENT ENTRY
; P4 = CURRENT PSB
;RETURNS S1 = .TRUE. IF OK TO SCHEDULE
; .FALSE. IF REJECTED
OUTREJ: LOAD S1,.QEPRT(AP),QE.DMD ;GET REQUEST DEVICE MODIFIERS
LOAD S2,PSBSTS(P4),PSYLLP ;GET LOWER CASE PRINTER BIT
TXNE S1,DV.LLP ;REQUEST NEED LOWER CASE PRINTER
PJUMPE S2,.FALSE## ;YES, JUMP IF THIS ISN'T ONE
TXNE S1,DV.LUP ;NOW TRY UPPER CASE
PJUMPN S2,.FALSE## ;YES, REJECT IF PRINTER IS LOWER CASE
PUSHJ P,A$CSTN## ;CONVERT FOR RE-ROUTING
LOAD S2,PSBSDV(P4),PSYDMD ;GET DEVICE MODIFIERS OF SPOOLERS
TXNN S1,DV.NUL ;REQUEST FOR GENERIC STATION
JRST OUTR.2 ;NO, TRY FOR DEVICE MATCH
XOR S1,S2 ;FOR MATCH CHECKS
TXNN S1,DV.STN ;STATION MATCH
PJRST SCHSTR ;YES, NOW GO CHECK STRUCTURE
PJRST .FALSE## ;WRONG STATION
OUTR.2: XOR S1,S2 ;FOR DEVICE CHECKS
TXNN S1,DV.STN!DV.UTN ;AN EXACT MATCH ON UNIT AND STATION
TXNE S2,DV.NUL ;YES, BUT DOES SPOOLER WANT THOSE
PJRST .FALSE## ;WANTS ONLY STATION OR WRONG UNIT
PJRST SCHSTR ;OK SO FAR, GO VERIFY STRUCTURE
;ROUTINE TO DO INPUT REJECTION TESTS
;CALL; AP = CURRENT ENTRY
;RETURNS S1 = .TRUE. IF OK TO SELECT THIS JOB
; .FALSE. IF REJECTED
; T1 = .TRUE. OR .FALSE. FOR /UNIQUE :YES OR :NO IF S1 IS .TRUE.
INPREJ: LOAD S1,.QELM1(AP),QE.DEP ;GET /DEPENDENCY:n VALUE
JUMPN S1,.FALSE## ;DON'T RUN IF NON-ZERO
ZERO T1 ;CLEAR THIS JOBS UNIQUENESS
LOAD S1,.QELM1(AP),QE.UNI ;GET /UNIQUE:value
CAIE S1,QE.UNO ;IS IT /UNIQUE:NO
MOVEI T1,1 ;NO, INDICATE /YES
SKIPN INPNJP ;ARE THERE ANY RUNNING NOW
PJRST SCHSTR ;NO, GO CHECK STRUCTURE
PUSHJ P,.SAVE1## ;SAVE P1
MOVSI P1,-INPNUM ;SET UP FOR SEARCH
INPR.1: HRRZ S1,P1 ;PUT STREAM NUMBER IN S1
PUSHJ P,I$UQCH## ;CHECK FOR UNIQNESS MATCH
JUMPE S1,INPR.2 ;JUMP IF NO MATCH
JUMPN T1,.FALSE## ;YES, JUMP IF THIS IS /UNIQUE:YES
LOAD S2,INPUNI(P1),IN.UNI ;GET OTHER JOBS UNIQUE VALUE
JUMPN S2,.FALSE## ;IT TOO MUST BE /UNIQUE:NO
INPR.2: AOBJN P1,INPR.1 ;CONTINUE FOR ALL JOBS
PJRST SCHSTR ;OK SO FAR, GO CHECK STRUCTURE
;ROUTINE TO VERIFY THAT A STRUCTURE NEEDED BY REQUEST 'AP' IN ONLINE
;RETURNS S1 = .TRUE. IF IT IS
; .FALSE. IF NOT
SCHSTR: LOAD S1,.QESTR(AP) ;GET STRUCTURE FOR THIS REQUEST
PUSHJ P,I$VSTR## ;VERIFY THAT IT IS ONLINE
STORE S2,.QESTR(AP) ;RE-STORE IN CASE VSTR CONVERTED IT
JUMPN S1,.POPJ## ;JUMP IF STR IS AVAILABLE
PUSHJ P,RETMIN ;TRY AGAIN IN 1 MINUTE
PJRST .FALSE## ;AND REJECT IT NOW
;ROUTINE TO FIND THE 'NEXT' REQUEST OF THE OPERATOR
; S1 = THE SEQUENCE REQUESTED
; AP = THE PLACE TO START LOOKING
;RETURNS AP = THE ONE OR ZERO
;DESTROYS S2
FNDNXT: LOAD S2,.QESEQ(AP),QE.SEQ ;GET THE SEQUENCE NUMBER OF THIS JOB
CAMN S2,S1 ;THE SAME AS REQUESTED
POPJ P, ;YES, THIS IS IT
LOAD AP,.QELNK(AP),QE.PTN ;FIND THE NEXT
JUMPN AP,FNDNXT ;JUMP IF THERE ARE MORE
POPJ P, ;RETURN AP = 0 IF NOT FOUND
;SUBROUTINE TO COMPUTE WHEN THE NEXT REQUEST FOR CHECKPOINT IS TO BE SENT OUT
;RETURNS S1 = THE TIME
;DESTROYS S2
NXTRCK: SKIPG S1,KSYSTM ;KSYS PENDING
SKIPA S1,[SPLMBC] ;NO, GET NORMAL INTERVAL
IDIVI S1,^D60 ;TO EVEN MINUTES
SKIPN S1 ;LESS THAN 1 MINUTE
MOVEI S1,1 ;YES, MAKE IT ONE
PJRST I$AFT## ;COMPUTE AND RETURN
SUBTTL Constants and Other Things
XLIST ;FORCED OUT LITERAL POOL HERE
LIT
LIST
SALL
SCHZER: ;FIRST LOCATION TO BE ZERO'ED AT INITIALIZATION
KSYSTM: BLOCK 1 ;SECONDS UNTIL KSYS TIME
FRMTYP: BLOCK FRMNUM ;TABLE FOR FORM NAMES (MASKED WITH PSYUNI)
FRMCNT: BLOCK FRMNUM ;PAGES REQUEST FOR THAT TYPE
FRMADR: BLOCK FRMNUM ;FIRST ENTRY THAT REQUESTED THAT TYPE
INPNJP: BLOCK 1 ;NUMBER OF JOBS CURRENTLY RUNNING
INPITN: BLOCK INPNUM ;TABLE OF BATCH JOB ITN'S
INPUNI: BLOCK INPNUM ;UNIQUENESS AND OTHER PARAMETERS
IN.UNI==1B0 ;INDICATES /UNIQUE:YES
ZERLAS==.-1 ;LAST LOCATION TO BE ZERO'ED AT INITIALIZATION
END