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,,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,,CL.BQE ;SAVE THE BATCH QUEUE ENTRY ADDRESS LOAD T2,REL.BJ(M),RL.JOB ;GET BATCH JOB NUMBER STORE T2,,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