TITLE QSRQUE -- Batch Queue Message Handlers for QUASAR SUBTTL Larry Samberg Chuck O'Toole /CER 6 Jan 77 ;***Copyright (C) 1974, 1975, 1976, 1977, Digital Equipment Corp., Maynard, MA.*** SEARCH QSRMAC ;PARAMETER FILE PROLOGUE(QSRQUE) ;GENERATE THE NECESSARY SYMBOLS COMMENT\ STOPCDs found in QSRQUE BDN BAD DEVICE NAME INTERNALLY GENERATED CRD CREATE REJECTED DEFER DATA CRL CREATE REJECTED LOGOUT DATA CRM CREATE REJECTED MODIFY CRS CREATE REJECTED SPOOLING DATA NBR NEXTJOB'ING BAD REQUEST \ SUBTTL Queue Headers and Module Storage INTERN TBLHDR INTERN NQUEUE ;BUILD THE QUEUE HEADERS TBLHDR: QUEHDR NQUEUE==<.-TBLHDR>/QHSIZE LSTITN: BLOCK 1 ;LAST ITN ASSIGNED LISSIZ: BLOCK 1 ;NUMBER OF PAGES NEEDED FOR LAST ; COMPLETE QUEUE LISTING THSPSB: BLOCK 1 ;ADDRESS OF THE PSB OF THE ;SENDER OF THE CURRENT MESSAGE ;FILLED IN BY VALMSG MSGPDB: BLOCK IPCHSZ ;PDB SPACE FOR "NEXT", "ABORT", ; AND "LISTANSWER" MSGMSG: BLOCK ABO.SZ ;RESERVE THE SPACE FOR THE MESSAGES SUBTTL Queue Database Initialization Q$INIT::PUSHJ P,I$NOW## ;GET NOW MOVEM S1,LSTITN ;AND SAVE IT AS LAST ITN ZERO LISSIZ ;START WITH A CLEAN SLATE POPJ P, ;RETURN SUBTTL Batch and Spooling Message Handlers ;THE MESSAGE HANDLERS ARE TOP LEVEL ROUTINES WHICH PROCESS THE ; VARIOUS MESSAGES THAT ARE SENT TO QUASAR. THEY ARE ; CALLED DIRECTLY OUT OF THE MAIN PROCESSING LOOP WITH ; ACCUMULATOR "M" POINTING TO THE FIRST WORD OF THE MESSAGE. ; THE MESSAGE HANDLERS HAVE FULL USE OF ALL ACCUMULATORS ; EXCEPTING "M" AND THE "P" REGS. INTERN Q$RELEASE ;FUNCTION 2 -- RELEASE INTERN Q$CHECKPOINT ;FUNCTION 3 -- CHECKPOINT INTERN Q$REQUEUE ;FUNCTION 4 -- REQUEUE INTERN Q$NEXTJOB ;FUNCTION 5 -- NEXTJOB(*) INTERN Q$ABORT ;FUNCTION 6 -- ABORT(*) INTERN Q$CREATE ;FUNCTION 7 -- CREATE INTERN Q$LIST ;FUNCTION 10 -- LIST INTERN Q$MODIFY ;FUNCTION 11 -- MODIFY INTERN Q$KILL ;FUNCTION 12 -- KILL INTERN Q$LANSWER ;FUNCTION 13 -- LISTANSWER(*) ;FUNCTION 14 -- TEXT(*) INTERN Q$DEFER ;FUNCTION 16 -- DEFER ;SOME IPCC MESSAGES ARE SENT TO QUASAR FROM THE MONITOR EXEC PROCESS. ; THEY ARE TREATED IN THE SAME MANNER AS USER GENERATED ; CALLS (I.E. ACCUMULATOR "M" POINTS TO THE MESSAGE) INTERN Q$SPOOL ;SPOOLING FILE REQUEST -- FUNCTION .IPCSU (26) INTERN Q$LOGOUT ;LOGOUT OF A JOB -- FUNCTION .IPCSL (27) ;(*) NEXTJOB, ABORT, LISTANSWER, AND TEXT ARE SENT BY QUASAR ; THESE ARE NOT CALLED FROM THE MAIN LOOP BUT RATHER: ; ; NEXTJOB IS CALLED FROM THE SCHEDULING ROUTINES ; ABORT IS CALLED FROM THE KILL FUNCTION ; LANSWER IS CALLED FROM THE LIST FUNCTION ; TEXT IS HANDLED BY THE MAIN LOOP ITSELF ; ;IF .QIFNC IS SET IN THE OPERATION FIELD OF A MESSAGE, THE CALL IS ; CONSIDERED INTERNAL, AND SPECIAL HANDLING OR INTERPRETATION ; OF THE VARIOUS FIELDS IN THE MESSAGE, (PARTICULARLY THE ; OTHER 17 BITS OF THE TYPE FIELD) MAY OCCUR. ANY SPECIAL ; HANDLING OF THIS FORM WILL BE DESCRIBED IN THE ROUTINE ; HEADER COMMENTS. IF .QIFNC IS SET THE REST OF THE TYPE FIELD ; DOES NOT HAVE TO REFLECT THE MESSAGE TYPE SINCE IF Q$CREATE ; RECEIVES AN INTERNAL CALL, THE MESSAGE IS OBVIOUSLY A CREATE ; MESSAGE. SUBTTL RELEASE -- Function 2 ;THE RELEASE MESSAGE IS SENT TO QUASAR BY ONE OF THE KNOWN SYSTEM ; COMPONENTS TO RELEASE A JOB FROM THE QUEUE. Q$RELEASE: MOVEI T1,REL.SZ ;LOAD MINIMUM SIZE PUSHJ P,VALMSG ;VALIDATE THE MESSAGE SKIPE G$ERR## ;DID VALMSG SET THE ERROR FLAGS POPJ P, ;YES, REJECT THIS MESSAGE MOVE T1,REL.IT(M) ;GET THE TASKS ITN PUSHJ P,SRHUSE ;SEARCH THE USE QUEUE PJUMPE T1,E$SNY## ;NOT FOUND MOVE AP,T1 ;COPY ENTRY ADR INTO AP MOVE T1,G$SND## ;GET PID OF SENDER CAME T1,.QEPID(AP) ;DOES HE REALLY OWN THE REQ? PJRST E$SNY## ;NO, GIVE "NOT YOURS" ERROR MOVE T1,THSPSB ;GET ADDRESS OF HIS PSB PUSHJ P,S$RUSE## ;TELL SCHED ABOUT REMOVAL PUSH P,AP ;SAVE AP FIRST PUSHJ P,S$RELE## ;RELEASE THE REQUEST POP P,AP ;RESTORE REQUEST ADDRESS LOAD S1,.QESTN(AP),QE.DPA ;GET THE DISK ADDRESS PUSHJ P,F$RLRQ## ;AND RELS SPACE $COUNT (MREL) MOVEI H,HDRUSE ;LOAD ADR OF USE HEADER PJRST M$RFRE## ;AND RETURN THE ENTRY SUBTTL CHECKPOINT -- Function 3 ;A CHECKPOINT MESSAGE IS SENT PERIODICALLY BY THE VARIOUS ; KNOWN PROCESSORS. THE CHECKPOINT OPERATIONS CONSISTS ; OF UPDATING THE INCORE AND DISK ENTRIES WITH THE ; CHECKPOINT INFORMATION PROVIDED. Q$CHECKPOINT: MOVEI T1,CHE.SZ ;LOAD MINIMUM MESSAGE SIZE PUSHJ P,VALMSG ;VALIDATE THE MESSAGE SKIPE G$ERR## ;DID VALMSG SET THE ERROR FLAGS POPJ P, ;YES, REJECT THIS MESSAGE MOVE T1,CHE.IT(M) ;GET THE SPECIFIED ITN PUSHJ P,SRHUSE ;SEARCH THE USE QUEUE PJUMPE T1,E$SNY## ;NOT THERE!! MOVE T2,G$SND## ;GET PID OF SENDER CAME T2,.QEPID(T1) ;DOES HE OWN IT? PJRST E$SNY## ;NO, GIVE AN ERROR LOAD S1,.QESTN(T1),QE.DPA ;GET THE DPA PUSHJ P,F$RDRQ## ;READ THE REQUEST MOVE AP,S1 ;SAVE PAGE ADR IN AP HRRI S2,.EQCHK(S1) ;AND PLACE TO PUT IT HRLI S2,CHE.IN(M) ;FIRST OF THE INFORMATION WORDS BLT S2,.EQCHK+(S1) ;AND BLT IT PUSHJ P,F$WRRQ## ;WRITE IT OUT LOAD S2,.QESTN(T1),QE.DPA ;GET PREVIOUS DPA STORE S1,.QESTN(T1),QE.DPA ;STORE NEW DPA MOVE S1,S2 ;GET OLD DPA INTO S1 PUSHJ P,F$RLRQ## ;AND RELEASE IT $COUNT (MCHK) ADR2PG AP ;MAKE A PAGE NUMBER PJRST M$RELP## ;RELEASE THE PAGE AND RETURN SUBTTL REQUEUE -- Function 4 ;THE REQUEUE FUNCTION IS SENT BY A KNOWN COMPONENT USUALLY ; DUE TO OPERATOR REQUEST. THE REQUEUE MESSAGE CONTAINS ; THE SAME CHECKPOINT INFORMATION BUT HAS AN AFTER PARAMETER. ; ;REQUEUE PERFORMS THE FOLLOWING FUNCTIONS: ; 1) CHECKPOINT THE ENTRY ; 2) MOVE THE ENTRY FROM THE USE QUEUE TO THE ; APPROPRIATE PROCESSING QUEUE ; 3) RELEASE THE JOB FROM THE PSB Q$REQUEUE: MOVEI T1,REQ.SZ ;MINIMUM SIZE OF THE MESSAGE PUSHJ P,VALMSG ;VALIDATE THE SIZE OF IT SKIPE G$ERR## ;IS IT OK POPJ P, ;NO, RETURN NOW PUSHJ P,Q$CHECKPOINT ;DO A CHECKPOINT FIRST SKIPE G$ERR## ;DID CHECKPOINT REJECT THE REQUEST POPJ P, ;YES, SO WILL I MOVE T1,REQ.IT(M) ;GET THE ITN OF THE TASK PUSHJ P,SRHUSE ;LOCATE IN THE USE QUEUE MOVE AP,T1 ;SAVE FOR EVENTUAL MOVE ZERO .QEPID(AP) ;CLEAR THE INTERLOCK LOAD H,.QESTN(AP),QE.RQP ;GET RELATIVE QUEUE POINTER ADDI H,TBLHDR ;AND MAKE ADDRESS OF QUE HDR SKIPN S1,REQ.AF(M) ;IS THERE A /AFTER PARAMETER? JRST REQU.1 ;NO, CONTINUE NORMALLY MOVEI H,HDRAFT ;YES, LOAD ADDRESS OF AFTER HEADER PUSHJ P,I$AFT## ;GET AFTER TIME MOVEM S1,.QECRE(AP) ;AND STORE IN ENTRY REQU.1: MOVE S1,H ;PUT DESTINATION QUE IN S1 MOVEI H,HDRUSE ;LOAD H WITH SOURCE QUEUE PUSHJ P,M$MOVE## ;MOVE THE ENTRY $COUNT (MREQ) MOVE T1,THSPSB ;LOAD THE PSB ADDRESS PJRST S$RUSE## ;AND NOTIFY THE SCHEDULER SUBTTL NEXTJOB -- Function 5 ;NEXTJOB IS CALLED BY THE SCHEDULING ROUTINES IN QSRSCH WHEN ; AN ENTRY IS READY TO BE SCHEDULED FOR A KNOWN SYSTEM ; COMPONENT. ; ;NEXTJOB IS CALLED AS FOLLOWS: ; AP = ADDRESS OF THE ENTRY IN THE PROCESSING QUEUE (EG LPT QUEUE) ; T1 = ADDRESS OF THE PSB TO SCHEDULE IT FOR ; H = ADDRESS OF THE QUEUE HEADER OF THE PROCESSING QUEUE ; ;NEXTJOB PERFORMS THE FOLLOWING FUNCTIONS: ; 1) MOVE ENTRY FROM PROCESSING QUEUE TO "USE" QUEUE ; 2) READ THE QUEUE REQUEST FROM DISK ; 3) INCLUDE THE CHANGABLE DATA ; 4) SEND THE REQUEST TO THE PROCESSOR Q$NEXTJOB: $COUNT (MNXT) ;COUNT NEXTJOBS MOVEI S1,HDRUSE ;LOAD DESTINATION QUEUE HDR PUSHJ P,M$MOVE## ;AND MOVE THE ENTRY MOVE S1,PSBPID(T1) ;PID OF THE PROCESSOR MOVEM S1,.QEPID(AP) ;STORE THE INUSE NAME MOVE S1,PSBPDV(T1) ;GET THE PROCESSING DEVICE MOVEM S1,.QEDEV(AP) ;AND INCLUDE THE DEVICE ;NOW, READ IN THE PAGE AND SEND IT TO THE CORRECT PROCESSOR LOAD S1,.QESTN(AP),QE.DPA ;GET THE DPA PUSHJ P,F$RDRQ## ;READ THE REQUEST SKIPN 0(S1) ;DO A SMALL VALIDITY CHECK STOPCD(NBR,FATAL) ;++NEXTJOB'ING BAD REQUEST MOVEI T1,.QONEX ;GET NEXTJOB FUNCTION STORE T1,.MSTYP(S1),MS.TYP ;AND STORE IT IN THE MESSAGE LOAD T1,.QEITN(AP) ;NOW MAKE SURE ITN EXISTS STORE T1,.EQITN(S1) ;STORE IT LOAD T1,.QECRE(AP) ;CREATION TIME STORE T1,.EQAFT(S1) ;STORE THAT AS WELL LOAD T1,.QESEQ(AP),QE.SEQ ;THE SEQUENCE NUMBER STORE T1,.EQSEQ(S1),EQ.SEQ ;AND THAT LOAD T1,.QEPRT(AP),DV.STN ;GET STATION NUMBER FOR REQUEST STORE T1,.EQSEQ(S1),EQ.DSN ;SET PROPERLY FOR BATCON HRLI T1,.QELM1(AP) ;MOVE LIMIT WORDS FROM INTERNAL HRRI T1,.EQLM1(S1) ;TO EXTERNAL REQUEST BLT T1,.EQLM5(S1) ;FOR EXTRA DEFAULTED VALUES MOVX T1,IP.CFV ;GET PAGE-MODE BIT MOVEM T1,MSGPDB+.IPCFL ;PUT IT IN THE FLAG WORD MOVE T1,.QEPID(AP) ;GET PROCESSORS PID MOVEM T1,MSGPDB+.IPCFR ;STORE RECEIVERS PID ADR2PG S1 ;MAKE A PAGE NUMBER HRLI S1,1000 ;AND THE SIZE MOVEM S1,MSGPDB+.IPCFP ;SAVE IT MOVEI AP,MSGPDB ;ADDRESS OF PDB PJRST C$SEND## ;SHIP THE MESSAGE AND RETURN SUBTTL ABORT -- Function 6 ;ABORT IS CALLED BY THE "KILL" HANDLER WHEN THE JOB IN QUESTION IS ; IN THE USE QUEUE. CALL "ABORT" WITH T1 POINTING TO THE ; USE QUEUE ENTRY. ABORT SIMPLY SENDS AN ABORT MESSAGE ; TO THE PROCESSOR INTERLOCKING THE JOB. Q$ABORT: MOVEI AP,MSGPDB ;LOAD ADR OF THE PDB MOVEI T3,MSGMSG ;LOAD ADR OF THE MESSAGE ZERO .IPCFL(AP) ;NO FLAGS LOAD T4,.QEPID(T1) ;GET THE PROCESSOR'S PID MOVEM T4,.IPCFR(AP) ;STORE AS RECEIVER MOVE T4,[ABO.SZ,,MSGMSG] ;LOAD SIZE,,ADR MOVEM T4,.IPCFP(AP) ;AND STORE IT MOVE T4,[ABO.SZ,,.QOABO] ;LOAD THE MESSAGE HDR STORE T4,.MSTYP(T3) ;AND STORE IT LOAD T4,.QEITN(T1) ;GET THE ITN STORE T4,ABO.IT(T3) ;STORE IN ABORT MESSAGE MOVX T4,ABOUSR ;"ABORTED BY USER" STORE T4,ABO.CD(T3) ;STORE THE CODE LOAD T4,G$SID## ;GET ID OF SENDER STORE T4,ABO.ID(T3) ;AND STORE IN THE MESSAGE PJRST C$SEND## ;AND SEND IT SUBTTL CREATE -- Function 7 ;THE CREATE MESSAGE IS SENT TO QUASAR BY ANY UNKNOWN COMPONENT ; TO PLACE SOMETHING IN ONE OF THE PROCESSING QUEUES. ;IF THIS IS AN INTERNAL CALL (I.E. .QIFNC IS SET) THEN THE LOW-ORDER ; 17 BITS OF THE FUNCTION FIELD ARE TAKEN TO BE THE DPA IF THE ; REQUEST IS ALREADY FAILSOFT, AND IF THIS FIELD IS NON-ZERO, ; THE REQUEST IS NOT WRITTEN OUT. Q$CREATE: PUSHJ P,.SAVE3## ;SAVE P1 THRU P3 LOAD T1,.MSTYP(M),MS.CNT ;GET LENGTH OF MESSAGE CAIGE T1,EQHSIZ ;MUST BE AT LEAST EQHSIZ PJRST E$MTS## ;INDICATE MESSAGE TOO SHORT LOAD T1,.EQLEN(M),EQ.LOH ;MUST CHECK HEADER SIZE AS WELL CAIGE T1,EQHSIZ ;THAT IS ALSO THE MINIMUM VALUE PJRST E$MTS## ;TOO BAD, GIVE MESSAGE TOO SHORT LOAD S1,.EQRDV(M) ;GET SIXBIT DEVICE QUEUED TO LOAD S2,.EQSEQ(M),EQ.DSN ;CALLERS STATION NUMBER PUSHJ P,I$MIDS## ;CREATE INTERNAL DEVICE SPEC PJUMPE S1,E$IFD## ;JUMP IF ILLEGALLY FORMED MOVE P1,S1 ;SAVE FOR LATER COPY PUSHJ P,Q$FHDR ;FIND THE QUEUE HEADER SKIPN H,S1 ;LOAD INTO H AND SKIP PJRST E$UQS## ;UNKNOWN QUEUE SPECIFIED LOAD P3,.MSTYP(M),MS.TYP ;GET THE TYPE FIELD TXNE P3,.QIFNC ;IS IT INTERNAL? SKIPN T1,.EQITN(M) ;YES, LOAD OLD ITN IF NON-ZERO AOS T1,LSTITN ;GET A NEW ITN STORE T1,.EQITN(M) ;AND STORE IN MSG FOR LATER LOAD T1,.QHPAG(H),QH.SCH ;BASE OF SCHEDULING ENTRIES PUSHJ P,SCHDEF(T1) ;GO FILL THE DEFAULTS FOR THIS QUEUE SKIPE G$ERR## ;DID IT GET PAST THE CHECKS POPJ P, ;NO, SCHDEF REJECTED IT!! CREA.1: PUSH P,H ;SAVE "REAL" QUEUE HEADER MOVE S1,.EQAFT(M) ;GET THE AFTER PARAMETER TXNE P3,.QIFNC ;IS IT INTERNAL? JRST CREA.2 ;YES, JUST USE WHAT WE'VE GOT CAMGE S1,G$NOW## ;NO, IS IT BEFORE NOW? MOVE S1,G$NOW## ;YES, USE NOW. THIS DISALLOWS MOVEM S1,.EQAFT(M) ;/AFT:YESTERDAY TO GIVE HI-PRIO CREA.2: CAMLE S1,G$NOW## ;IS IT IN THE FUTURE? MOVEI H,HDRAFT ;YES, PUT ENTRY IN AFTER QUEUE PUSHJ P,M$GFRE## ;GET A FREE CELL ;"CREATE" IS CONTINUED ON NEXT PAGE ;CONTINUED FROM PREVIOUS PAGE MOVE S1,P3 ;COPY THE MESSAGE TYPE TXZE S1,.QIFNC ;IS IT INTERNAL? JUMPN S1,CREA.3 ;YES, IF DPA EXISTS, DON'T FAILSOFT MOVE S1,M ;NO, GET THE ADDRESS PUSHJ P,F$WRRQ## ;AND FAILSOFT IT CREA.3: STORE S1,.QESTN(AP),QE.DPA ;STORE THE DISK ADDRESS POP P,S1 ;GET "REAL" QUEUE HEADER SUBI S1,TBLHDR ;MAKE AN RQP STORE S1,.QESTN(AP),QE.RQP ;AND SAVE RQP IN ENTRY LOAD P2,.EQSPC(M),EQ.NUM ;GET NUMBER OF FILES IN THE REQUEST LOAD T1,.EQITN(M) ;GET THE ITN STORE T1,.QEITN(AP) ;AND STORE IT LOAD T1,.EQJOB(M) ;GET JOB NAME STORE T1,.QEJOB(AP) ;STORE IT MOVE S1,M ;POINT S1 TO THE EQ PUSHJ P,I$EQQE## ;MOVE INFO FROM EQ TO QE LOAD T1,.EQSEQ(M),EQ.SEQ ;GET EXT SEQ NUMBER STORE T1,.QESEQ(AP),QE.SEQ ;STORE IT LOAD T1,.EQSEQ(M),EQ.PRI ;GET THE PRIORITY FIELD STORE T1,.QESEQ(AP),QE.PRI ;STORE IT LOAD T1,.EQSEQ(M),EQ.RDE ;GET RDE FLAG STORE T1,.QESEQ(AP),QE.RDE ;AND MOVE IT LOAD T1,.EQSEQ(M),EQ.SPL ;GET SPL BIT STORE T1,.QESEQ(AP),QE.SPL ;AND STORE IT IN THE QE LOAD T1,.EQSPC(M),EQ.PRO ;GET THE PROTECTION FIELD STORE T1,.QEPRT(AP),QE.PRO ;STORE IT LOAD T1,.EQDED(M) ;GET DEADLINE STORE T1,.QEDED(AP) ;STORE IT LOAD T1,P1,DV.DMD ;GET DEVICE MODIFIERS FROM I$MIDS STORE T1,.QEPRT(AP),QE.DMD ;SAVE FOR SCHEDULER MOVSI T1,.EQLM1(M) ;SOURCE OF 5 LIMIT WORDS HRRI T1,.QELM1(AP) ;DESTINATION OF 5 LIMIT WORDS BLT T1,.QELM5(AP) ;BLT THEM ACROSS LOAD T1,.EQAFT(M) ;GET CREATE OR AFTER TIME STORE T1,.QECRE(AP) ;AND STORE IT ZERO .QEPID(AP) ;ZERO THE PID LOAD S1,.EQLEN(M),EQ.LOH ;NOW FIND THE FIRST FILE IN THE REQUEST ADDI S1,(M) ;FIND FIRST FP AREA LOAD S2,.FPSIZ(S1),FP.FHD ;LENGTH OF THE FIRST FP ADDI S1,(S2) ;S1 = FIRST FD AREA PUSHJ P,I$FSTR## ;EXTRACT THE FILE STRUCTURE FROM THE FD STORE S1,.QESTR(AP) ;STORE FOR SCHEDULER LOAD T1,.QESEQ(AP),QE.RDE ;GET THE JOBS RDE BIT JUMPE T1,CREA.4 ;NOT RDE, CONTINUE MOVEI H,HDRRDE-TBLHDR ;GET RQP FOR RDE QUEUE STORE H,.QESTN(AP),QE.RQP ;STORE IT ADDI H,TBLHDR ;POINT TO RDE QUEUE ;"CREATE" IS CONTINUED ON THE NEXT PAGE ;CONTINUED FROM THE PREVIOUS PAGE CREA.4: LOAD T1,.QHPAG(H),QH.SCH ;GET BASE OF SCHED VECTOR PUSHJ P,SCHLNK(T1) ;AND LINK IN THE REQUEST $COUNT (SCRE) ;NUMBER OF SUCCESSFUL CREATES SKIPN G$ACK## ;DOES CALLER WANT ACKNOWLEDGEMENT POPJ P, ;NO, ALL DONE MOVE S1,P1 ;GET IDS OF REQUEST PUSHJ P,I$MSDN## ;MAKE PRINTABLE SIXBIT DEVICE PUSHJ P,G$CSIX## ;PUT IT INTO THE STRING MOVEI S1,":" ;ISOLATE THE QUEUE NAME PUSHJ P,G$CCHR## ;NOW HAVE DEV: MOVE S1,.QEJOB(AP) ;THE JOB NAME PUSHJ P,G$CSIX## ;ADD THAT TO THE DEVICE MOVEI S1,[ASCIZ\=/Seq:\] PUSHJ P,G$CSTG## ;ADD SOME MORE TEXT LOAD S1,.QESEQ(AP),QE.SEQ ;GET THE SEQUENCE NUMBER PUSHJ P,G$CDEC## ;THAT IS A DECIMAL NUMBER LOAD S1,.QESTN(AP),QE.RQP ;GET RELATIVE QUEUE POINTER LOAD S1,TBLHDR+.QHTYP(S1),QH.TYP ;GET QUEUE TYPE CAIN S1,.QHTIP ;INPUT QUEUE JRST CREA.5 ;YES, GIVE ANOTHER MESSAGE MOVEI S1,[ASCIZ\/Limit:\] ;TELL REQUEST LIMIT PUSHJ P,G$CSTG## ;APPEND LOAD S1,.QELM2(AP),QE.PGS ;GET REQUEST LIMIT IN UNITS PUSHJ P,G$CDEC## ;PROBABLY OUGHT TO TRY /FEET/PAGES MOVEI S1,[ASCIZ/, /] ;ALIGNMENT PUSHJ P,G$CSTG## ;ADD THAT MOVE S1,P2 ;GET THE NUMBER OF FILES IN THE REQUEST MOVEI S2,[ASCIZ/ File/] ;STRING TO PLURALIZE PUSHJ P,TYPPLR ;DO THE RIGHT THING JRST CREA.6 ;SEND THE ACK AND RETURN ;"CREATE" IS CONTINUED ON THE NEXT PAGE ;CONTINUED FROM THE PREVIOUS PAGE CREA.5: MOVEI S1,[ASCIZ\/Time:\] ;TIME LIMIT PUSHJ P,G$CSTG## ;APPEND LOAD T1,.QELM2(AP),QE.TIM ;NUMBER OF SECONDS REQUESTED IDIVI T1,^D3600 ;HOURS IN T1 IDIVI T2,^D60 ;MINUTES IN T2, SECONDS IN T3 MOVE S1,T1 ;GET HOURS PUSHJ P,G$CDEC## ;OUTPUT THAT MOVEI S1,":" ;TIME ALIGNMENT PUSHJ P,G$CCHR## ;ISOLATE PARTS MOVEI S1,"0" ;IN CASE .LT.10 CAIGE T2,^D10 ;NEED THE LEADING ZERO PUSHJ P,G$CCHR## ;YES, MAKE THE OUTPUT PRETTY MOVE S1,T2 ;GET MINUTES PUSHJ P,G$CDEC## ;OUTPUT IT MOVEI S1,":" ;TIME ALIGNMENT PUSHJ P,G$CCHR## ;ISOLATE PARTS MOVEI S1,"0" ;IN CASE .LT.10 CAIGE T3,^D10 ;NEED THE LEADING ZERO PUSHJ P,G$CCHR## ;YES, MAKE THE OUTPUT PRETTY MOVE S1,T3 ;GET SECONDS PUSHJ P,G$CDEC## ;AND ADD THAT IFN INPCOR,< MOVEI S1,[ASCIZ\/Core:\] ;NOW TYPE CORE VALUE PUSHJ P,G$CSTG## ;APPEND LOAD S1,.QELM2(AP),QE.COR ;GET THE VALUE PUSHJ P,G$CDEC## ;OUTPUT THE NUMBER MOVEI S1,"P" ;THAT NUMBER WAS IN PAGES PUSHJ P,G$CCHR## ;SINCE LEAVING THAT OFF MEANS "K" > ;END IFN INPCOR CREA.6: MOVX S1,TX.MOR ;INFORMATIONAL, MORE TO COME PJRST G$MSND## ;SEND THE "ACK" AND RETURN SUBTTL LIST -- Function 10 ;THE PRIMARY PURPOSE OF THIS ROUTINE IS TO VALIDATE A LIST ; REQUEST. ONCE THIS IS DONE, THE LIST-ANSWER ROUTINE ; (Q$LANSWER) DOES THE REST. Q$LIST: LOAD T1,.MSTYP(M),MS.CNT ;GET THE MESSAGE SIZE CAIGE T1,LIS.SZ ;BIG ENOUGH? PJRST E$MTS## ;INDICATE MESSAGE TOO SHORT $COUNT (MLST) ;NUMBER OF LIST MESSAGES LOAD T1,LIS.QN(M) ;GET THE QUEUE NAME JUMPE T1,Q$LANSWER ;ZERO INDICATES ALL QUEUES MOVE S1,T1 ;COPY FOR CONVERSION ZERO S2 ;DON'T CARE ABOUT STATION PUSHJ P,I$MIDS## ;CONVERT TO INTERNAL FORM PJUMPE S1,E$IFD## ;GIVE ERROR IF MALFORMED PUSHJ P,Q$FHDR ;FIND THE HEADER SKIPN T1,S1 ;COPY HDR ADR INTO T1 PJRST E$UQS## ;AND LOSE IF UNKNOWN QUEUE LOAD T2,.QHTYP(S1),QH.LST ;GET "LISTABLE" BIT PJUMPE T2,E$CLQ## ;LOSE IF NOT SET JRST Q$LANSWER ;AND GIVE HIM THE LISTING SUBTTL MODIFY -- Function 11 ;THE MODIFY MESSAGE IS SENT TO QUASAR BY ANY UNKNOWN COMPONENT TO CHANGE ; THE PARAMETERS OF A REQUEST IN A PROCESSING OR AFTER QUEUE ;MODIFY PREFORMS THE FOLLOWING FUNCTIONS: ; 1 ) VALIDATE THE ARGUMENTS ; 2 ) BUILD A TEMPORARY QUEUE OF REQUESTS THAT MATCH ; 3 ) PERFORM THE MODIFY REQUEST ON EACH ELEMENT OF THE TEMPORARY QUEUE ; 4 ) CALL Q$CREATE FOR THE RESULTANT MODIFIED REQUEST Q$MODIFY: PUSHJ P,.SAVE4## ;SAVE P1-P4 $COUNT (MMOD) ;NUMBER OF MODIFY MESSAGES LOAD P1,.MSTYP(M),MS.CNT ;GET THE COUNT FIELD CAIGE P1,MOD.SZ ;TOO SMALL PJRST E$MTS## ;INDICATE MESSAGE TOO SHORT LOAD S1,MOD.QN(M) ;GET THE QUEUE NAME ZERO S2 ;DON'T CARE ABOUT STATION PUSHJ P,I$MIDS## ;CONVERT TO INTERNAL FORM PJUMPE S1,E$IFD## ;GIVE ERROR IF MALFORMED PUSHJ P,Q$FHDR ;FIND THE QUEUE HEADER SKIPN H,S1 ;PUT INTO H PJRST E$UQS## ;NONE FOUND, FORGET IT ;BEFORE ACTUAL PROCESSING, CHECK THE REQUEST FOR INVALID LENGTHS AND GROUPS ADDI P1,(M) ;P1 = FIRST WORD NOT IN THE MESSAGE MOVEI P2,MOD.FG(M) ;P2 = THE FIRST GROUP HEADER MODI.1: CAIG P1,MOD.GN(P2) ;OFF THE END OF THE MESSAGE JRST MODI.2 ;YES, NOW BEGIN PROCESSING LOAD P3,MOD.GN(P2),MODGPN ;GET THE GROUP NUMBER LOAD P4,MOD.GN(P2),MODGLN ;AND NUMBER OF GROUP ELEMENTS PJUMPE P4,E$BMG## ;CANNOT BE ZERO ADDI P4,(P2) ;P4 = NEXT GROUP HEADER CAIG P3,NGROUP ;INVALID GROUP NUMBER CAIGE P1,(P4) ;OR INVALID LENGTH PJRST E$BMG## ;YES, BAD MESSAGE FORMAT MOVEI P2,(P4) ;POINT TO THE NEXT GROUP JRST MODI.1 ;CONTINUE FOR ALL PROVIDED GROUPS ;HAVING VERIFIED THE LENGTHS, BEGIN FINDING THE SPECIFIED REQUESTS MODI.2: PUSH P,G$ACK## ;SAVE CALLERS "ACK" STATUS ZERO G$ACK## ;SO DON'T GET MESSAGES FROM CREATE ZERO MODI.C+0 ;ZERO NUMBER OF REQUESTS MODIFIED SETOM MODI.C+1 ;INITIALLY, DON'T PRINT NUMBER OF FILES ZERO MODI.C+2 ;NOT CANCELLING JOBS ZERO MODHDR+.QHLNK ;CLEAR LINKS OF FAKE HEADER PUSHJ P,MODSET ;SET UP ARGUMENTS FOR FNDREQ PUSHJ P,FNDREQ ;FIND REQUESTS IN REQUESTED QUEUE MOVEM S1,MODI.C+3 ;START COUNTING PROTECTION FAILURES PUSHJ P,MODSET ;RESET THE ARGUMENTS MOVEI H,HDRAFT ;BUT THIS TIME USE THE AFTER QUEUE PUSHJ P,FNDREQ ;FIND ANY THERE ADDM S1,MODI.C+3 ;MORE PROTECTION FAILURES MOVEM M,MODI.A ;SAVE ORIGINAL MESSAGE ADDRESS ;"MODIFY" IS CONTINUED ON THE NEXT PAGE ;CONTINUED FROM PREVIOUS PAGE ;NOW, FLUSH THE TEMPORARY QUEUE, MODIFYING, RE-CREATING AS WE GO MODI.3: LOAD AP,MODHDR+.QHLNK,QH.PTF ;GET THE TOP OF THE TEMPORARY QUEUE JUMPE AP,MODI.6 ;PROCESSED THEM ALL (OR NONE) LOAD H,.QESTN(AP),QE.RQP ;GET THE RELATIVE QUEUE POINTER ADDI H,TBLHDR ;MAKE A REAL POINTER OUT OF IT LOAD S1,.QESTN(AP),QE.DPA ;GET THE RETREIVAL POINTER PUSHJ P,F$RDRQ## ;READ IN THE ORIGINAL REQUEST MOVEM S1,MODI.B ;SAVE FOR LATER RELEASE MOVE AP,S1 ;ARGUMENT FOR MODIFIER ROUTINES MOVE M,MODI.A ;GET MODIFY MESSAGE BACK LOAD P1,.MSTYP(M),MS.CNT ;NOW LOOP FOR ALL GROUP HEADERS ADDI P1,(M) ;P1 = FIRST WORD NOT IN THE MESSAGE MOVEI P2,MOD.FG(M) ;P2 = THE FIRST GROUP MODI.4: CAIG P1,MOD.GN(P2) ;OFF THE END OF THE MESSAGE JRST MODI.5 ;YES, DONE WITH THIS MATCH LOAD P3,MOD.GN(P2),MODGPN ;GET THE GROUP NUMBER MOVEI S1,(P2) ;ARGUMENT FOR MODIFIERS PUSHJ P,@GRPDIS(P3) ;CALL THE PROPER MODIFIER FOR THIS GROUP LOAD P3,MOD.GN(P2),MODGLN ;ADJUST FOR THE NEXT GROUP ADDI P2,(P3) ;P2 = THE NEXT GROUP JRST MODI.4 ;CONTINUE FOR ALL GROUPS PROVIDED ;HERE AFTER ALL GROUP MODIFIES HAVE BEEN DONE, LINK IN THE NEW REQUEST MODI.5: MOVE M,MODI.B ;ARGUMENT FOR CREATE = MODIFIED REQUEST MOVX T1,.QIFNC ;THIS IS AN INTERNAL CALL STORE T1,.MSTYP(M),MS.TYP ;SET FOR Q$CREATE PUSHJ P,Q$CREATE ;PUT MODIFIED REQUEST BACK IN PLACE SKIPE G$ERR## ;DID THE CREATE WORK STOPCD(CRM,FATAL) ;++CREATE REJECTED MODIFY LOAD AP,MODHDR+.QHLNK,QH.PTF ;GET OLD QUEUE ENTRY BACK LOAD S1,.QESTN(AP),QE.DPA ;THE RETREIVAL POINTER PUSHJ P,F$RLRQ## ;RELEASE OLD FAILSOFT COPY MOVEI H,MODHDR ;POINT TO THE TEMPORARY QUEUE PUSHJ P,M$DLNK## ;REMOVE ENTRY ALREADY MODIFIED LOAD H,.QEPID(AP) ;QUEUE THIS ENTRY CAME FROM (PROC, OF AFTER) PUSHJ P,M$PFRE## ;RETURN TO PROPER FREE LIST MOVE AP,MODI.B ;ADDRESS OF OLD FAILSOFT COPY ADR2PG AP ;MAKE A PAGE NUMBER PUSHJ P,M$RELP## ;NO LONGER NEED IT JRST MODI.3 ;GET ANY OTHER MATCHING REQUESTS ;NOW, GENERATE "ACK" AND RETURN TO THE CALLER MODI.6: POP P,G$ACK## ;RESTORE "ACK" STATUS MOVEI T1,MODI.C ;ARGUMENT BLOCK FOR BLDKMS MOVEI T2,[ASCIZ/ Modified/] ;TEXT TO APPEND PJRST BLDKMS ;BUILD KILL/MODIFY STRING AND RETURN ; SUBROUTINES USED BY MODIFY ;ROUTINE CALL BE MODIFY LOOP TO SET UP ARGUMENTS FOR FNDREQ MODSET: MOVNI T1,1 ;INDICATE MODIFY REQUEST MOVEI T2,MOD.RQ(M) ;RDB FOR KILL/MODIFY MOVE T3,H ;NEED AN RQP SUBI T3,TBLHDR ;SO GENERATE ONE FOR THIS QUEUE MOVEI T4,MODS.1 ;SUBROUTINE TO CALL FOR MATCHES POPJ P, ;RETURN FOR CALL TO FNDREQ ;HERE WHEN FNDREQ FINDS A MATCH FOR THE MODIFY BLOCK, ACCUMULATE IN THE TEMP QUEUE MODS.1: STORE H,.QEPID(AP) ;SAVE QUEUE THAT CONTAINED THIS ENTRY PUSHJ P,M$DLNK## ;REMOVE FROM PROCESSING OR AFTER QUEUE MOVEI H,MODHDR ;POINT TO THE TEMPORARY QUEUE PUSHJ P,M$ELNK## ;LINK IN AT THE END AOS MODI.C+0 ;INCREMENT COUNT OF MODIFIED REQS POPJ P, ;RETURN FOR NEXT MATCH ;THE DISPATCH TABLE FOR GROUP MODIFIES GRPDIS: EXP MAJMOD ;GROUP 0 = MAJOR QUEUE PARAMETERS EXP GRPMOD ;GROUP 1 = QUEUE DEPENDENT PARAMETERS EXP MODFIL ;GROUP 2 = FILE-SPECIFIC PARAMETERS NGROUP==<.-GRPDIS>-1 ;HIGHEST KNOWN GROUP NUMBER GRPMOD: LOAD P3,.QHPAG(H),QH.SCH ;GET SCHEDULING BASE PJRST SCHMOD(P3) ;DO QUEUE DEPENDENT MODIFY MODFIL: SKIPGE MODI.C+1 ;ALREADY HERE ONCE SETZM MODI.C+1 ;NO, START COUNTING FILES MODIFIED PUSHJ P,FILMOD ;DO THE MODIFY ADDM S1,MODI.C+1 ;ADD NUMBER OF FILES THAT MATCHED POPJ P, ;GET ANOTHER GROUP MODHDR: BLOCK QHSIZE ;HEADER FOR THE TEMPORARY QUEUE MODI.A: BLOCK 1 ;ORIGINAL 'M' MODI.B: BLOCK 1 ;WHERE REQUEST HAS BEEN READ BY FAILSOFT MODI.C: BLOCK 4 ;ARGUMENT BLOCK FOR BLDKMS SUBTTL KILL -- Function 12 ;THE KILL MESSAGE IS SENT TO QUASAR BY ANY UNKNOWN COMPONENT TO ; DELETE AN ENTRY FROM A QUEUE. ;KILL PERFORMS THE FOLLOWING FUNCTIONS: ; 1) VALIDATE THE ARGUMENTS ; 2) LOOP THROUGH THE USE QUEUE ABORTING MATCHES. ; 3) LOOP THROUGH THE PROCESSING QUEUE DELETING MATCHES. ; 4) LOOP THROUGH THE AFTER QUEUE DELETING MATCHES. Q$KILL: PUSHJ P,.SAVE3## ;SAVE P1-P3 $COUNT (MKIL) ;NUMBER OF KILL MESSAGES LOAD T1,.MSTYP(M),MS.CNT ;GET MESSAGE SIZE CAIGE T1,KIL.SZ ;BIG ENOUGH? PJRST E$MTS## ;INDICATE MESSAGE TOO SHORT LOAD S1,KIL.QN(M) ;GET THE QUEUE NAME ZERO S2 ;DON'T CARE ABOUT STATION PUSHJ P,I$MIDS## ;CONVERT TO INTERNAL FORM PJUMPE S1,E$IFD## ;GIVE ERROR IF MALFORMED PUSHJ P,Q$FHDR ;AND FIND THE QUEUE HEADER SKIPN H,S1 ;LOAD HDR ADR INTO H PJRST E$UQS## ;UNKNOWN QUEUE SPECIFIED MOVE P3,S1 ;GET ADR OF QUE HDR SUBI P3,TBLHDR ;AND MAKE AN RQP FROM IT ZERO P1 ;INDICATE KILL REQUEST MOVEI P2,KIL.RQ(M) ;REQUEST DESCR BLOCK FOR FNDREQ ZERO KILL.A+0 ;ZERO NUMBER KILLED SETOM KILL.A+1 ;DON'T COUNT FILES ZERO KILL.A+2 ;NUMBER CANCELLED ;NOW, SETUP AND LOOP THRU THE NECESSARY QUEUES KILL.1: PUSH P,H ;SAVE PROCESSING QUEUE HDR MOVE T4,[P1,,T1] ;MOVE PERMENANT ARGS TO REAL ARGS BLT T4,T3 ;COPY P1 - P3 MOVEI T4,KILL.9 ;SUBROUTINE TO CALL MOVEI H,HDRUSE ;LOAD ADR OF USE QUEUE HDR PUSHJ P,FNDREQ ;FIND A MATCHING REQUEST MOVEM S1,KILL.A+3 ;START COUNTING PROT FAILURES MOVE T4,[P1,,T1] ;NEED ARGUMENTS AGAIN BLT T4,T3 ;SO MOVE THEM MOVEI T4,KILL.8 ;NEW ROUTINE TO CALL POP P,H ;GET ADR OF PROCESSING Q HDR PUSHJ P,FNDREQ ;AND CHECK IT ADDM S1,KILL.A+3 ;COUNT PROTECTION FAILURES MOVEI H,HDRAFT ;LOAD ADR OF AFT HEADER MOVE T4,[P1,,T1] ;ONE MORE TIME BLT T4,T3 ;BUT NOW FNDREQ IS USABLE BY Q$MODIFY MOVEI T4,KILL.8 ;SAME PLACE FOR THE AFTER QUEUE PUSHJ P,FNDREQ ;LOOP THRU THE AFTER QUEUE ADDM S1,KILL.A+3 ;MORE PROTECTION FAILURES MOVEI T1,KILL.A ;ARGUMENT BLOCK FOR BLDKMS MOVEI T2,[ASCIZ/ Killed/] ;TEXT TO APPEND PJRST BLDKMS ;BUILD KILL/MODIFY STRING AND RETURN ; SUBROUTINES USED DURING KILL ;FOLLOWING ARE THE CO-ROUTINES (SORT OF) WHICH ARE CALLED BY FNDREQ ; ;ROUTINE TO ACTUALLY TAKE A REQUEST OUT OF A PROCESSING QUEUE OR THE ; AFTER QUEUE. KILL.8: AOS KILL.A+0 ;INCREMENT KILL COUNT MOVE T1,AP ;COPY CELL ADDRESS LOAD T2,.QESEQ(AP),QE.SPL ;DOES REQ CONTAIN SPOOLED FILES? JUMPN T2,KIL.8A ;YES, SET RDE AND RETURN LOAD S1,.QESTN(AP),QE.DPA ;NO, GET DISK ADDRESS PUSHJ P,F$RLRQ## ;RELEASE THE DISK REQUEST PUSHJ P,M$RFRE## ;RELEASE THE QUEUE ENTRY POPJ P, ;AND RETURN TO KILLUP KIL.8A: SAVE H ;SAVE THE QUEUE HEADER PUSHJ P,SETRDE ;SET THE RDE BIT IN QE AND EQ MOVEI S1,HDRRDE ;GET THE RDE HEADER PJRST M$MOVE## ;AND MOVE THE REQUEST ;ROUTINE TO CAUSE AN ABORT MESSAGE TO BE SENT TO A KNOWN COMPONENT ; ON A KILL OF A JOB IN THE USE QUEUE. KILL.9: SAVE AP ;SAVE CALLERS AP MOVE T1,AP ;GET ADR OF QE AREA PUSHJ P,SETRDE ;SET RDE IN BOTH .EQ AND .QE MOVE T1,AP ;LOAD ARGUMENT FOR ABORT AOS KILL.A+2 ;INCREMENT ABORTED COUNT PJRST Q$ABORT ;SEND THE ABORT AND RETURN KILL.A: BLOCK 4 ;ARGUMENT BLOCK FOR BLDKMS SUBTTL LISTANSWER -- Function 13 ;LISTANSWER IS CALLED TO SEND AN ANSWER BACK ON A LIST REQUEST. ; CALL WITH T1 CONTAINING ADDRESS OF QUEUE HEADER FOR THE ; QUEUE TO BE LISTED, OR ZERO IF ALL QUEUES ARE TO BE LISTED. Q$LANSWER: PUSHJ P,.SAVE2## ;SAVE P1 AND P2 PUSHJ P,I$NOIN## ;DON'T ALLOW INTERRUPTS MOVE S1,LISSIZ ;GET SIZE OF LAST COMPL LISTING SKIPE P1,T1 ;DOES HE JUST WANT A PARTIC. Q? LOAD S1,.QHPAG(T1),QH.NTL ;YES, GET IT'S NUMBER ADDI S1,1 ;PAD IT A LITTLE PUSHJ P,M$PCNT## ;SEE IF WE CAN GET IT PJUMPE S1,E$CBL## ;NO, LOSE NOW! MOVX S1,TX.NMS ;NO MESSAGE FLAG SKIPE G$ACK## ;DOES USER WANT AN ACK? PUSHJ P,G$MSND## ;YES, SEND IT MOVE T2,[LANS.A,,LANS.A+1] ;SETUP A BLT POINTER CLEARM LANS.A ;CLEAR PAGE SEQ NUMBER BLT T2,LANS.Z ;AND CLEAR THE OTHER LOCALS PUSH P,[EXP LANEND] ;PLACE TO GO BEFORE RETURNING JUMPE P1,LANS.1 ;JUMP IF HE WANTS ALL QUEUES PUSHJ P,LANQUE ;DO THE LISTING MOVE S1,LANS.A ;GET NUMBER OF PAGES NEEDED STORE S1,.QHPAG(P1),QH.NTL ;SAVE IT FOR NEXT TIME POPJ P, ;AND RETURN LANS.1: MOVEI P2,0 ;START AT QUEUE 0 LANS.2: CAIL P2,NQUEUE ;GOT THEM ALL? JRST LANS.3 ;YUP, FINISH UP AND RETURN MOVE P1,P2 ;NO, GET QUEUE NUMBER IMULI P1,QHSIZE ;CONVERT TO OFFSET ADDI P1,TBLHDR ;GET ADDRESS IN P1 LOAD T2,.QHTYP(P1),QH.LST ;GET "LISTABLE" BIT SKIPE T2 ;SKIP IF NOT SET PUSHJ P,LANQUE ;ELSE LIST THE QUEUE AOJA P2,LANS.2 ;AND LOOP LANS.3: MOVE S1,LANS.A ;GET NUMBER OF PAGES NEEDED MOVEM S1,LISSIZ ;SAVE FOR NEXT TIME POPJ P, ;AND RETURN ;HERE TO LIST QUEUE WHOSE HEADER ADDRESS IS IN P1 LANQUE: PUSHJ P,.SAVE2## ;SAVE P1 AND P2 MOVE P2,P1 ;GET ADR OF Q HDR SUBI P2,TBLHDR ;MAKE AN RQP MOVEI H,HDRUSE ;START WITH USE QUEUE LOAD T1,.QHLNK(H),QH.PTF ;GET ADDRESS OF FIRST JUMPE T1,LANQ.3 ;NONE, GO DO AFT QUEUE LANQ.1: LOAD T2,.QESTN(T1),QE.RQP ;GET RQP FROM REQUEST CAME P2,T2 ;CORRECT QUEUE? JRST LANQ.2 ;NO, GET NEXT ENTRY LOAD T2,.QESEQ(T1),QE.RDE ;GET THE RDE BIT JUMPN T2,LANQ.2 ;REQUEST DOESN'T EXIST!! PUSHJ P,LANMSG ;YES, GET SPACE PUSHJ P,LANMOV ;MOVE COMMON STUFF MOVE T2,.QECRE(T1) ;GET CREATION TIME CAIN H,HDRAFT ;IS THIS THE AFTER QUEUE? MOVEM T2,LST.AF(AP) ;YES, STORE IT MOVE T2,.QEDEV(T1) ;GET PROCESSING DEVICE CAIN H,HDRUSE ;IS THIS THE USE QUEUE? MOVEM T2,LST.PV(AP) ;YES, STORE IT LANQ.2: LOAD T1,.QELNK(T1),QE.PTN ;GET PTR TO NEXT ENTRY JUMPN T1,LANQ.1 ;AND LOOP LANQ.3: CAIN H,HDRAFT ;E-O-LIST, WERE WE DOING AFT? JRST LANQ.4 ;YES, GO DO THE EXTERNAL QUEUE MOVEI H,HDRAFT ;NO, DO THE AFTER LOAD T1,.QHLNK(H),QH.PTF ;GET PTR TO FIRST JUMPN T1,LANQ.1 ;GO TO IT ;HERE TO LIST THE EXTERNAL QUEUE LANQ.4: MOVE H,P1 ;GET ADDRESS OF HEADER LOAD T1,.QHLNK(H),QH.PTF ;GET POINTER TO FIRST JUMPE T1,.POPJ## ;DONE IF NONE LANQ.5: PUSHJ P,LANMSG ;GET SOME SPACE PUSHJ P,LANMOV ;MOVE COMMON STUFF LOAD T1,.QELNK(T1),QE.PTN ;GET POINTER TO NEXT JUMPN T1,LANQ.5 ;AND LOOP OVER WHOLE QUEUE POPJ P, ;WE ARE DONE!! ;"LISTANSWER" IS CONTINUED ON NEXT PAGE ;HERE AT THE END OF LIST, TO TERMINATE THE LAST PAGE AND FORCE IT OUT LANEND: PUSHJ P,LANMSG ;GET SOME SPACE (AVOID BOUNDRY PROBLEMS) MOVE T1,LANS.B ;GET CURRENT PAGE NUMBER PG2ADR T1 ;MAKE IT AN ADDRESS MOVX T2,1B0 ;LOAD BIT ZERO IORM T2,.MSTYP(T1) ;SET "LAST PAGE" FLAG PJRST LANSND ;AND SEND THE LAST PAGE ;SUBROUTINE TO MOVE COMMON STUFF FROM ENTRY TO LISTANSWER. ; T1=ENTRY AP=ANSWER LANMOV: MOVE T2,.QEJOB(T1) ;GET JOB NAME MOVEM T2,LST.JB(AP) ;STORE IN ANSWER MOVE T2,.QESTR(T1) ;GET STRUCTURE CONTAINING THE REQUEST MOVEM T2,LST.ST(AP) ;STORE FOR LISTER LOAD T2,.QESEQ(T1),QE.SEQ ;GET SEQUENCE FIELD STORE T2,LST.SQ(AP),LS.SEQ ;AND STORE IN ANSWER LOAD T2,.QEPRT(T1),QE.PRO ;GET PROTECTION OF REQUEST STORE T2,LST.SQ(AP),LS.PRO ;AND STORE IT MOVE T2,.QEOID(T1) ;THE OWNER ID MOVEM T2,LST.OI(AP) ;AND STORE MOVSI T2,.QELM1(T1) ;POINT TO LIMIT WORDS HRRI T2,LST.LM(AP) ;AND MAKE A BLT POINTER BLT T2,LST.LM+4(AP) ;AND BLT THE FIVE OF THEM LOAD T2,.QHTYP(P1),QH.NAM ;GET THE QUEUE NAME LOAD S1,.QEPRT(T1),QE.DMD ;GET DEVICE MODIFIERS FOR THIS REQUEST HRL S1,T2 ;INCLUDE DEVICE NAME (QUEUE NAME) PUSHJ P,A$CSTN## ;CONVERT STATIONS IF NECESSARY PUSHJ P,I$MSDN## ;TURN INTO A DEVICE NAME STORE S1,LST.DV(AP) ;INTO CURRENT ANSWER LOAD T2,.QESEQ(T1),QE.PRI ;GET EXTERNAL PRIORITY STORE T2,LST.PI(AP),LS.PRI ;AND STORE IT MOVE S1,T1 ;POINT S1 TO THE QE PUSHJ P,I$QELA## ;MOVE OS DEPENDENT STUFF POPJ P, ;AND RETURN ;"LISTANSWER" IS CONTINUED ON NEXT PAGE ;MORE SUBROUTINES FOR LISTANSWER ;HERE TO GET SPACE FOR A LISTANSWER ENTRY. RETURN ADR IN AP. LANMSG: SOSLE LANS.C ;ANY ROOM LEFT IN CURRENT PAGE? JRST LANM.1 ;YES, GO GET IT PUSHJ P,.SAVET## ;NO, SAVE T1-T4 SKIPE LANS.B ;IT THIS THE FIRST TIME THRU? PUSHJ P,LANSND ;NO, SEND CURRENT PAGE $COUNT (NLAP) ;NUMBER OF LIST ANSWER PAGES PUSHJ P,M$ACQP## ;GET A PAGE MOVEM AP,LANS.B ;SAVE PAGE NUMBER PG2ADR AP ;MAKE AN ADDRESS MOVE S1,AP ;COPY ADDRESS TO S1 PUSHJ P,.ZPAGA## ;AND ZAP IT AOS T1,LANS.A ;INCREMENT SEQ # AND LOAD IT HRLZS T1 ;GET SEQ#,,0 HRRI T1,.QOLAN ;GET SEQ#,,FUNCTION STORE T1,.MSTYP(AP) ;AND STORE IN MESSAGE HEADER MOVEI T1,LST.NU ;GET NUMBER OF ENTRIES/PAGE MOVEM T1,LANS.C ;AND STORE COUNTER MOVEI AP,LST.FT(AP) ;GET ADDRESS OF FIRST ENTRY MOVEM AP,LANS.D ;SAVE IT POPJ P, ;AND RETURN ;HERE IF SPACE EXISTS IN CURRENT PAGE LANM.1: MOVEI AP,LST.SZ ;GET SIZE OF AN ENTRY ADDB AP,LANS.D ;GET ADR OF NEXT AND SAVE IT POPJ P, ;AND RETURN ;HERE TO SEND THE CURRENT PAGE LANSND: MOVEI AP,MSGPDB ;LOAD ARGUMENT FOR C$SEND MOVX T1,IP.CFV ;GET PAGE-MODE BIT MOVEM T1,.IPCFL(AP) ;STORE FLAG WORD MOVE T1,G$SND## ;GET CURRENT SENDER'S PID MOVEM T1,.IPCFR(AP) ;AND SET RECEIVE MOVSI T1,1000 ;GET PAGE SIZE,,0 HRR T1,LANS.B ;GET PAGE SIZE,,PAGE NUMBER MOVEM T1,.IPCFP(AP) ;STORE IT TXO AP,IPS.TF ;IGNORE LANSWER ORDER PJRST C$SEND## ;SEND THE MESSAGE AND RETURN LANS.A: BLOCK 1 ;SEQ NUMBER OF CURRENT PAGE LANS.B: BLOCK 1 ;NUMBER OF CURRENT PAGE LANS.C: BLOCK 1 ;# ENTRIES LEFT IN CURRENT PAGE LANS.D: BLOCK 1 ;ADDRESS OF CURRENT ENTRY LANS.Z==.-1 SUBTTL TEXT -- Function 14 ;THE TEXT MESSAGE IS ASSEMBLED AND SENT BY THE GLOBAL ROUTINES ; G$CSTG, G$CSIX, G$CDEC, G$CCHR, AND G$MSND. ;SINCE THE TEXT MESSAGE IS SENT ONLY WHEN THE CALLER REQUESTS "MS.ACK" ; AND THE MESSAGE IS DERIVED FROM THE GLOBAL ERROR CODE, THERE IS ; NO CODE IN QSRQUE TO PROCESS OR SEND THE TEXT RESPONSE. ;IT IS THE RESPONSIBILITY OF THE MAIN PROCESSING LOOP IN MODULE QUASAR SUBTTL DEFER -- Function 16 ;THE DEFER MESSAGE IS SENT TO QUASAR BY ANY UNKNOWN COMPONENT TO ; RELEASE OR KILL DEFERED SPOOL REQUESTS ; ;DEFER PERFORMS THE FOLLOWING FUNCTIONS: ; 1)VALIDATE THE ARGUMENTS ; 2)LOOP THROUGH THE SPOOL QUEUE FINDING ENTRIES FOR THIS JOB ; 3)CALL Q$CREATE FOR MATCHES, SETTING EQ.RDE IF THIS IS A KILL ; 4)RETURN AN ACK IF WANTED SAYING HOW MANY JOBS, FILES WERE ; RELEASED OR KILLED; ALSO HOW MANY "PROTECTION" FAILURES ; I.E. JOB NUMBER MATCHES WITH WRONG DIRECTORY Q$DEFER: PUSHJ P,.SAVE4## ;SAVE P1-P4 $COUNT (MDEF) ;NUMBER OF DEFER MESSAGES LOAD T1,.MSTYP(M),MS.CNT ;GET LENGTH OF MESSAGE CAIGE T1,DFR.SZ ;IS IT ALL THERE PJRST E$MTS## ;NOT LONG ENOUGH, GIVE ERROR ZERO DEFE.A+0 ;CLEAR COUNT OF JOBS AFFECTED ZERO DEFE.A+1 ;AND OF FILES ZERO DEFE.A+2 ;NOT CANCELLING JOBS ZERO DEFE.A+3 ;AND OF PROTECTION FAILURES LOAD P1,DFR.JB(M),DF.JOB ;GET JOB NUMBER FROM MESSAGE LOAD P2,,QH.PTF ;GET THE FIRST ENTRY IN THE SPOOL QUEUE LOAD T1,DFR.JB(M),DF.FNC ;GET THE FUNCTION REQUESTED ZERO P3 ;INDICATE RELEASE (FOR LOOP) CAIN T1,.DFKIL ;IS IT KILL? MOVEI P3,1 ;YES, INDICATE FOR LOOP LOAD P4,DFR.QN(M) ;PICK UP DEVICE NAME IN MESSAGE JUMPE P4,DEFE.1 ;GO AHEAD IF ZERO MOVE S1,P4 ;COPY FOR MIDS ZERO S2 ;DON'T REALLY CARE ABOUT STATION PUSHJ P,I$MIDS## ;ELSE CONVERT IT TO INTERNAL FORM PJUMPE S1,E$IFD## ;BAD NAME IN MESSAGE LOAD P4,S1,DV.GDN ;NEED ONLY THE GENERIC DEVICE NAME DEFE.1: JUMPE P2,DEFE.4 ;END OF SPOOL QUEUE, RETURN LOAD T2,SPLJOB(P2),SPYJOB ;GET THE JOB # FROM THIS QUEUE ENTRY LOAD T1,SPLQUE(P2),DV.GDN ;AND THE DEVICE NAME CAME T1,P4 ;IS DEVICE NAME OF ENTRY SAME AS JUMPN P4,DEFE.3 ;NO, JUMP IF REQUESTED SPECIFIC QUEUE CAME T2,P1 ;IS THIS FOR THE RIGHT JOB JRST DEFE.3 ;WRONG JOB OR WRONG QUEUE LOAD T1,SPLOID(P2) ;GET OWNER ID OF THIS ENTRY LOAD T2,G$SID## ;GET SENDER'S ID CAME T1,T2 ;IS IT THE SAME AS SENDER'S? JRST DEFE.2 ;NO,PROTECTION FAILURE AOS DEFE.A+0 ;FOUND A MATCHING JOB, COUNT IT LOAD S1,SPLJOB(P2),SPYDPA ;GET THE DPA PUSHJ P,F$RDRQ## ;READ THE REQUEST LOAD T1,.EQSPC(S1),EQ.NUM ;PICK UP THE # OF FILES IN THE REQUEST ADDM T1,DEFE.A+1 ;COUNT THEM FOR ACK PUSH P,S1 ;SAVE THE REQUEST ADDR MOVE M,S1 ;POINT TO IT ;Q$DEFER IS CONTINUED ON THE NEXT PAGE ;CONTINUED FROM THE PREVIOUS PAGE MOVX S1,.QIFNC ;LOAD INTERNAL FUNCTION CODE STORE S1,.MSTYP(M),MS.TYP ;AND SAVE IN REQUEST STORE P3,.EQSEQ(M),EQ.RDE ;SET RDE BIT IF THIS WAS A KILL PUSHJ P,Q$CREATE ;CALL CREATE SKIPE G$ERR## ;ANY ERROR? STOPCD(CRD,FATAL) ;++CREATE REJECTED DEFER DATA POP P,AP ;AND ADDR OF REQUEST ADR2PG AP ;MAKE IT A PAGE NUMBER PUSHJ P,M$RELP## ;RELEASE IT LOAD S1,SPLJOB(P2),SPYDPA ;GET THE POINTER TO THE DISK PUSHJ P,F$RLRQ## ;RELEASE THE OLD REQUEST MOVEI H,HDRSPL ;GET THE HEADER OF THE SPOOL QUEUE MOVE AP,P2 ;GET THE CURRENT ENTRY LOAD P2,.QELNK(P2),QE.PTN ;STEP TO NEXT ENTRY PUSHJ P,M$RFRE## ;FREE UP THIS ONE JRST DEFE.1 ;GO LOOP THROUGH QUEUE DEFE.2: AOS DEFE.A+3 ;COUNT PROTECTION FAILURES DEFE.3: LOAD P2,.QELNK(P2),QE.PTN ;STEP TO NEXT ENTRY JRST DEFE.1 ;AND LOOP ON DEFE.4: MOVEI T1,DEFE.A ;ARGUMENT BLOCK FOR BLDKMS MOVEI T2,[ASCIZ/ Killed/] ;ASSUME WE KILLED THEM SKIPN P3 ;DID WE MOVEI T2,[ASCIZ/ Released/] ;NO, SAY RELEASED PJRST BLDKMS ;SEND ACK IF REQUESTED DEFE.A: BLOCK 4 ;ARGUMENT BLOCK FOR BLDKMS SUBTTL SPOOL -- IPCC Function .IPCSU (26) ;THE SPOOL MESSAGE IS SENT TO QUASAR BY THE OPERATING SYSTEM UPON ; THE CLOSE OF A SPOOLED FILE. ;AFTER CONVERTING THE ACTUAL SPOOL MESSAGE FROM [SYSTEM]IPCC INTO THE ; CANONICAL FORM, ALL SPOOLING HANDLERS WILL USE THAT DATA STRUCTURE Q$SPOOL: MOVEI S1,(M) ;POINT TO IPCC'S MESSAGE PUSHJ P,I$CSM## ;CONVERT TO STANDARD FORMAT MOVEI T1,(S1) ;USE THAT FROM NOW ON MOVX T2,CS.DFR ;CHECK FOR DEFERRED MODE SPOOLING TDNE T2,CSM.JB(T1) ;DID THE USER REQUEST IT JRST SPOO.1 ;YES, GO ADD TO THE SPL QUEUE $COUNT (ISPL) ;NUMBER OF IMMEDIATE SPOOLS PUSHJ P,SPROTO ;BUILD EXTERNAL PROTOTYPE PUSHJ P,Q$INCL ;INCLUDE THE NEW FILE (ONLY) PUSH P,AP ;SAVE ADDR OF PROTOTYPE BUILT MOVE M,AP ;MAKE IT THE MESSAGE PUSHJ P,Q$CREATE ;CALL THE CREATE PROCESSOR SKIPE G$ERR## ;WAS THERE AN ERROR? STOPCD(CRS,FATAL) ;++CREATE REJECTED SPOOLING DATA POP P,AP ;RESTORE ADDRESS ADR2PG AP ;TO A PAGE NUMBER PJRST M$RELP## ;RETURN THROUGH RELEASE PAGE SPOO.1: $COUNT (DSPL) ;NUMBER OF DEFERED SPOOLS PUSHJ P,Q$FSPL ;FIND THE MATCHING REQUEST PUSHJ P,Q$INCL ;INCLUDE THIS FILE LOAD S1,.MSTYP(AP),MS.CNT ;GET CURRENT REQUEST SIZE STORE S1,SPLRQZ(E),SPYLEN ;SAVE IN SPOOL QUEUE MOVE S1,AP ;GET REQUEST ADDRESS ADR2PG AP ;CONVERT REQUEST TO PAGE NUMBER PUSHJ P,F$WRRQ## ;WRITE IT OUT LOAD S2,SPLJOB(E),SPYDPA ;LOAD THE OLD DPA INTO S2 STORE S1,SPLJOB(E),SPYDPA ;SAVE THE NEW RETRIEVAL POINTER SKIPE S1,S2 ;GET OLD DPA ( 0 IF INITIAL BUILD) PUSHJ P,F$RLRQ## ;RELEASE OLD COPY IF THERE IS ONE PJRST M$RELP## ;RETURN THE PAGE AND EXIT SUBTTL LOGOUT -- IPCC Function .IPCSL (27) ;THE LOGOUT MESSAGE IS SENT BY THE OPERATING SYSTEM UPON ; EXECUTION OF A LOGOUT UUO OR LGOUT JSYS. ;IF .QIFNC IS SET INDICATING AN INTERNAL CALL, THEN COMING FROM S$RELEASE ; AT THE END OF A BATCH JOB. CL.BQE IN CLM.JB IS THE ADDRESS OF THE ; .QExxx FORM OF THAT BATCH JOB Q$LOGOUT: PUSHJ P,.SAVE4## ;SAVE P1-P4 ZERO P4 ;INDICATE NOT A BATCH CALL LOAD T1,.MSTYP(M),.QIFNC ;GET INTERNAL CALL INDICATOR SKIPE T1 ;A QUICK CHECK FOR INTERNAL CALL LOAD P4,CLM.JB(M),CL.BQE ;IS, GET THE BATCH JOB QUEUE ENTRY MOVEI S1,(M) ;GET ADDRESS OF SYSTEM LOGOUT MESSAGE JUMPN T1,LOGO.1 ;JUMP IF INTERNAL CALL NOW PUSHJ P,I$CLM## ;CONVERT TO CANONICAL LOGOUT MESSAGE LOAD T1,CLM.JB(S1),CL.BAT ;GET THE BATCH JOB BIT PJUMPN T1,.POPJ## ;IGNORE IT HERE, BATCON WILL RELEASE IT LOGO.1: LOAD P1,CLM.JB(S1),CL.JOB ;GET THE JOB NUMBER FOR THE LOOP LOAD P2,,QH.PTF ;GET THE FIRST IN THE SPL QUEUE JUMPE P4,LOGO.2 ;JUMP IF NOT A BATCH JOB LOAD S1,.QESTN(P4),QE.DPA ;ELSE GET THE DPA PUSHJ P,F$RDRQ## ;READ THE INPUT REQUEST MOVE P4,S1 ;AND STORE ADDRESS IN P4 LOGO.2: PJUMPE P2,LOGO.5 ;END OF THE QUEUE, RETURN LOAD T1,SPLJOB(P2),SPYJOB ;JOB NUMBER OF THIS ENTRY CAME T1,P1 ;SAME JOB JRST LOGO.4 ;NO, TRY THE NEXT LOAD S1,SPLJOB(P2),SPYDPA ;GET THE DPA PUSHJ P,F$RDRQ## ;READ THE REQUEST JUMPE P4,LOGO.3 ;JUMP IF THIS IS NOT A BATCH JOB ZERO S2 ;IN CASE WE DON'T FIND A MATCH LOAD T1,SPLQUE(P2),DV.GDN ;GET THE QUEUE NAME CAIN T1,'LPT' ;WATCH THIS BRUTE FORCE METHOD LOAD S2,.EQLM3(P4),EQ.LPT ;YES, GET PAGE REQUEST CAIN T1,'CDP' ;LOOKING AT THE PUNCH QUEUE LOAD S2,.EQLM3(P4),EQ.CDP ;YES, GET CARD LIMIT CAIN T1,'PTP' ;THE PAPER TAPE QUEUE LOAD S2,.EQLM4(P4),EQ.PTP ;YES, GET INPUT TAPE REQUEST CAIN T1,'PLT' ;LAST CHANCE, THE PLOTTER LOAD S2,.EQLM4(P4),EQ.PLT ;YES, GET THAT SKIPE S2 ;FIND ONE ( OR DON'T LIMIT IT) STORE S2,.EQLM2(S1),EQ.PGS ;STORE SOMETHING AS JOB LIMIT LOAD T1,.EQJOB(P4) ;GET BATCH JOB NAME STORE T1,.EQJOB(S1) ;AS OUTPUT NAME LOAD T1,.EQSEQ(P4),EQ.SEQ ;GET SEQUENCE NUMBER STORE T1,.EQSEQ(S1),EQ.SEQ ;STORE IT LOAD T1,.EQSEQ(P4),EQ.PRI ;GET EXT-PRIO FIELD STORE T1,.EQSEQ(S1),EQ.PRI ;STORE IT LOAD T1,.EQSPC(P4),EQ.PRO ;GET REQUEST PROTECTION STORE T1,.EQSPC(S1),EQ.PRO ;STORE IT AWAY MOVSI T1,EQISIZ(P4) ;BEGINING OF OS DEP DATA HRRI T1,EQISIZ(S1) ;IN BOTH REQUESTS BLT T1,EQHSIZ-1(S1) ;AND BLT IT ;Q$LOGOUT IS CONTINUED ON THE NEXT PAGE ; NOW, CREATE THE REQUEST POINTED TO BY 'S1' LOGO.3: PUSH P,S1 ;SAVE REQUEST ADDRESS MOVE M,S1 ;POINT TO IT MOVX S1,.QIFNC ;LOAD INTERNAL FUNCTION CODE STORE S1,.MSTYP(M),MS.TYP ;AND SAVE IN THE REQUEST PUSHJ P,Q$CREATE ;CREATE THE REQUEST SKIPE G$ERR## ;WAS THERE AN ERROR? STOPCD(CRL,FATAL) ;++CREATE REJECTED LOGOUT DATA POP P,AP ;GET THE ADR BACK ADR2PG AP ;CONVERT TO PAGE NUMBER PUSHJ P,M$RELP## ;RELEASE IT LOAD S1,SPLJOB(P2),SPYDPA ;GET THE RETRIEVAL POINTER PUSHJ P,F$RLRQ## ;AND DELETE THE OLD REQUEST MOVEI H,HDRSPL ;GET A QUEUE HEADER MOVE AP,P2 ;CURRENT ENTRY LOAD P2,.QELNK(P2),QE.PTN ;FIND THE NEXT PUSHJ P,M$RFRE## ;RETURN SPL QUEUE CELL JRST LOGO.2 ;GET THE NEXT ENTRY LOGO.4: LOAD P2,.QELNK(P2),QE.PTN ;FIND THE NEXT JRST LOGO.2 ;GET THE NEXT ENTRY ;HERE WHEN WE ARE ALL DONE LOGO.5: PJUMPE P4,.POPJ## ;RETURN IF NOT A BATCH JOB ADR2PG P4 ;ELSE MAKE A PAGE NUMBER MOVE AP,P4 ;MOVE IT OVER PJRST M$RELP ;AND RELEASE IT SUBTTL Global Subroutines ;ENTRY POINTS INTERN Q$CKAF ;CHECK THE AFTER QUEUE INTERN Q$FSPL ;FIND A MATCHING SPOOLING REQUEST INTERN Q$INCL ;INCLUDE A FILE INTO A PROTOTYPE AREA INTERN Q$FHDR ;FIND QUEUE HEADER SUBTTL Q$CKAF -- Routine to check the AFTER queue ;Q$CKAF IS CALLED FROM THE MAIN PROCESSING LOOP TO CHECK THE ; AFTER QUEUE FOR JOBS WHICH HAVE BECOME "OF AGE". IF ; ONE IS FOUND, IT IS MERGED INTO THE CORRECT SCHEDULING ; QUEUE. ; Q$CKAF: MOVEI H,HDRAFT ;AND POINT TO THE AFTER HEADER MOVE S1,G$NOW## ;LOAD NOW TIME LOAD AP,.QHLNK(H),QH.PTF ;GET TOP ENTRY IN THE QUEUE PJUMPE AP,.POPJ## ;NOTHING THERE, RETURN CAMLE S1,.QECRE(AP) ;HAS THE FIRST COME OF AGE? JRST CKAF.1 ;YES, REMOVE IT MOVE S2,.QECRE(AP) ;AND WHEN IT WILL PUSHJ P,I$AGE## ;GET DIFFERENCE IN SECONDS PJRST I$SVAL## ;SET SLEEP INTERVAL AND RETRUN CKAF.1: ZERO .QEPID(AP) ;CLEAR THE INTERLOCK WORD MOVEM S1,.QECRE(AP) ;AND SAVE THE CREATION TIME LOAD S1,.QESTN(AP),QE.RQP ;GET REL QUEUE PTR ADDI S1,TBLHDR ;AND MAKE A REAL QUEUE HEADER PUSHJ P,M$MOVE## ;AND MOVE THE ENTRY JRST Q$CKAF ;AND LOOP SUBTTL Q$FSPL -- Find a SPL Queue entry ;Q$FSPL IS CALLED WITH T1 POINTING TO THE CANONICAL SPOOL MESSAGE. ; IT WILL FIND THE APPROPRIATE REQUEST IN THE SPL QUEUE THAT ; CAN ACCEPT ANOTHER FILE (Q$INCL) FOR THE CRITERIA DESCRIBED ; IN THE DEFINITION OF THE CANONICAL SPOOL MESSAGE ;RETURN E = THE SPL QUEUE ENTRY (WILL MAKE ONE IF NONE) ; AP = THE EXTERNAL QUEUE REQUEST READY FOR CREATE CALL Q$FSPL: LOAD S1,CSM.DV(T1) ;S1 = THE REQUESTED DEVICE LOAD S2,CSM.JB(T1),CS.LOC ;S2 = THE USERS DEFAULT STATION PUSHJ P,I$MIDS## ;CREATE INTERNAL DEVICE SPECIFICATION SKIPN S1 ;DID THAT WORK STOPCD(BDN,FATAL) ;++BAD DEVICE NAME INTERNALLY GENERATED MOVEM S1,FSPL.A ;SAVE FOR LATER LOAD S2,CSM.OI(T1) ;S2 = THE OWNER ID LOAD T2,CSM.JB(T1),CS.JOB ;T2 = THE USERS JOB NUMBER LOAD T3,CSM.ST(T1) ;T3 = STRUCTURE CONTAINING THE FILE LOAD T4,CSM.FD(T1),CS.FDL ;T4 = THE LENGTH OF THE FD TO BE INCLUDED LOAD E,,QH.PTF ;FIND FIRST IN SPL QUEUE JUMPE E,FSPL.6 ;EMPTY QUEUE, START IT FSPL.1: LOAD TEMP,SPLOID(E) ;GET THE OWNER ID FOR THE REQUEST CAME S2,TEMP ;FOR THE SAME USER JRST FSPL.5 ;NO, TRY NEXT LOAD TEMP,SPLJOB(E),SPYJOB ;GET THE JOB NUMBER IFN FTSPLIT,< CAMN T3,SPLSTR(E) ;FOR THE SAME STRUCTURE > ;END OF IFN FTSPLIT CAME TEMP,T2 ;FOR THE SAME JOB JRST FSPL.5 ;NO, TRY NEXT LOAD TEMP,SPLRQZ(E),SPYLEN ;GET CURRENT SIZE ADDI TEMP,FPMSIZ(T4) ;SIZE OF FILE TO BE INCLUDED CAILE TEMP,1000 ;REQUEST BECOME TOO BIG JRST FSPL.5 ;YES, LOOK FOR ANOTHER MOVE TEMP,SPLQUE(E) ;GET IDS FOR THE SPOOL REQUEST XOR TEMP,S1 ;FOR EASIER CHECKS JUMPE TEMP,FSPL.4 ;IF AN EXACT MATCH, INCLUDE THE FILE TXNE TEMP,DV.GDN!DV.STN ;SAME QUEUE AND STATION JRST FSPL.5 ;NO, TRY ANOTHER ENTRY TXNN S1,DV.LLP!DV.LUP ;IS THIS REQUEST FOR LL: OR LU: JRST FSPL.2 ;NO, DO DEVICE MATCHING TXNE TEMP,DV.NUL ;YES, CURRENT GENERIC (XOR FLIPPED IT) JRST FSPL.5 ;NO, CANNOT INCLUDE LL/LU WITH IT XOR TEMP,S1 ;RE-GET THE SPL QUEUE MODIFIERS TXNN TEMP,DV.LLP!DV.LUP ;IS THIS REQUEST FOR LL/LU JRST FSPL.3 ;NO, CHANGE IT TO LL/LU AND INCLUDE JRST FSPL.5 ;YES BUT WASN'T A COMPLETE MATCH ; Q$FSPL IS CONTINUED ON THE NEXT PAGE ; HERE TO DO DEVICE MATCHING AFTER LL:/LU: HAS BEEN TAKEN CARE OF FSPL.2: TXNE S1,DV.NUL ;WANT GENERIC STATION JRST FSPL.4 ;YES, THIS IS IT TXNE TEMP,DV.NUL ;IF CURRENT REQUEST IS DEVICE SPECIFIC TXNE TEMP,DV.LLP!DV.LUP ; OR FOR LL: OR LU: JRST FSPL.5 ;CAN'T MERGE SPECIFIC DEVICES FSPL.3: MOVEM S1,SPLQUE(E) ;CONVERT OLD GENERIC TO NEW SPECIFIC FSPL.4: LOAD S1,SPLJOB(E),SPYDPA ;GET THE DPA PUSHJ P,F$RDRQ## ;READ THE REQUEST MOVE AP,S1 ;SAVE ADR IN AP LOAD S1,SPLQUE(E),DV.STN ;GET CURRENT STATION STORE S1,.EQSEQ(AP),EQ.DSN ;SET CURRENT DEFAULT STATION MOVE S1,SPLQUE(E) ;NOW GET FULL IDS MOVE T2,S1 ;MAKE A COPY PUSHJ P,I$MSDN## ;CONVERT TO SIXBIT DEVICE NAME TXNE T2,DV.LLP ;NOW, WAS IT LL: MOVSI S1,'LL ' ;YES, SET AS SUCH TXNE T2,DV.LUP ;CHECK IF LU: MOVSI S1,'LU ' ;THIS IS DONE FOR CORRECT VALUES STORE S1,.EQRDV(AP) ;IN THE FAILSOFT DATA BASE POPJ P, ;AND RETURN FSPL.5: LOAD E,.QELNK(E),QE.PTN ;FIND THE NEXT JUMPN E,FSPL.1 ;LOOK AT IT IF THERE FSPL.6: MOVEI H,HDRSPL ;GET A QUEUE HEADER PUSHJ P,M$GFRE## ;GET A CELL MOVE E,AP ;WANT IT IN E PUSHJ P,M$ELNK## ;LINK IT IN AT THE END MOVE S1,FSPL.A ;GET RESULT OF I$MIDS STORE S1,SPLQUE(E) ;STORE INTO THE SPL QUEUE LOAD S1,CSM.OI(T1) ;GET THE USERS ID STORE S1,SPLOID(E) ;STORE THAT TOO LOAD S1,CSM.JB(T1),CS.JOB ;GET THE JOB NUMBER STORE S1,SPLJOB(E),SPYJOB ;SAVE THAT TOO ZERO SPLJOB(E),SPYDPA ;NOT FAILSOFT YET LOAD S1,CSM.ST(T1) ;GET THE STRUCTURE AGAIN MOVEM S1,SPLSTR(E) ;SAVE IN SPL QUEUE MOVEI S1,EQHSIZ ;ALL REQUEST START AT THIS SIZE STORE S1,SPLRQZ(E),SPYLEN ;STORE THE INITIAL LENGTH PJRST SPROTO ;BUILD THE PROTOTYPE AND RETURN FSPL.A: BLOCK 1 ;SAVED IDS FROM I$MIDS SUBTTL Q$INCL -- Append a File to a Request ;Q$INCL IS CALLED WITH: ; AP = THE CURRENT SPOOL REQUEST ; T1 = THE CANONICAL SPOOL MESSAGE FOR THE NEW FILE ;RETURNS WITH THE NEW FILE INCLUDED IN THE REQUEST AP Q$INCL: MOVE S2,CSM.FP(T1) ;GET THE FLAG SETTINGS MOVEI S1,1 ;GET A BIT TXNE S2,FP.SPL ;IS IT A SPOOLED FILE? STORE S1,.EQSEQ(AP),EQ.SPL ;YES, SET SPOOLING REQUEST FLAG LOAD TEMP,.MSTYP(AP),MS.CNT ;GET LENGTH OF CURRENT MESSAGE MOVE S2,TEMP ;MAKE A COPY LOAD S1,CSM.FD(T1),CS.FDL ;S1 = LENGTH OF NEW FILE TO BE INCLUDED ADDI TEMP,FPMSIZ(S1) ;TEMP = LENGTH OF NEW REQUEST STORE TEMP,.MSTYP(AP),MS.CNT ;INCLUDE LENGTH FOR THIS FILE ADD S2,AP ;AP + OLD LEN = NEXT FILE POINTER STORE S1,.FPSIZ(S2),FP.FFS ;STORE LENGTH OF FD FOR NEW FILE MOVEI TEMP,FPMSIZ ;LENGTH OF DEFAULT FP AREA STORE TEMP,.FPSIZ(S2),FP.FHD ;STORE THAT AS WELL MOVE TEMP,CSM.FP(T1) ;GET FLAGS REQUESTED BY THE CALLER STORE TEMP,.FPINF(S2) ;AS FILE INFORMATION MOVEI TEMP,1 ;START AT LINE 1 STORE TEMP,.FPFST(S2) ;STORE STARTING POINT ZERO .FPFR1(S2) ;/REPORT WORD 1 ZERO .FPFR2(S2) ; AND WORD 2 MOVEI S2,FPMSIZ(S2) ;BUMP TO FD AREA LOAD TEMP,CSM.FD(T1),CS.FDA ;POINT TO THE FD TO INCLUDE HRLS TEMP ;SET UP FOR BLT HRRI TEMP,(S2) ;DESTINATION ADDI S2,(S1) ;COMPUTE THE LAST LOCATION (S1 FROM ABOVE) BLT TEMP,-1(S2) ;MOVE THE NEW FILE SPEC INTO THE REQUEST INCR .EQSPC(AP),EQ.NUM ;BUMP NUMBER OF FILES IN REQUEST LOAD S1,CSM.FS(T1) ;GET THE NUMBER OF BLOCKS IN THE FILE LOAD S2,.EQLM2(AP),EQ.NBL ;GET BLOCKS IN REQUEST ADD S1,S2 ;INCLUDE THE NEW FILE STORE S1,.EQLM2(AP),EQ.NBL ;UPDATE COUNTERS SKIPE .EQJOB(AP) ;ANY JOB NAME YET POPJ P, ;YES, RETURN NOW LOAD S1,CSM.EN(T1) ;GET THE 'ENTERED' NAME STORE S1,.EQJOB(AP) ;MAKE THAT THE REQUEST NAME POPJ P, ;AND RETURN SUBTTL Q$FHDR -- Subroutine to find a Queue Header ;Q$FHDR IS CALLED WITH A IDS IN S1. IT SCANS THE LIST OF EXTERNAL QUEUE ; HEADERS FOR THE QUEUE REPRESENTING THE SPECIFIED DEVICE AND RETURNS ; THE ADDRESS OF THE MATCHED QUEUE HEADER IN S1. IF NO MATCH IS ; FOUND, A "FALSE" INDICATION IS RETURNED. Q$FHDR: LOAD T2,S1,DV.GDN ;GET GENERIC DEVICE NAME MOVEI S1,TBLHDR ;LOAD ADDRESS OF FIRST QUEUE HDR HRLZI T3,-NQUEUE ;MAKE AN AOBJN POINTER FHDR.1: LOAD T4,.QHTYP(S1),QH.NAM ;GET THE QUEUE NAME CAMN T2,T4 ;GOT A MATCH? JRST FHDR.2 ;YES, MAKE SURE IT'S EXTERNAL ADDI S1,QHSIZE ;MOVE UP TO THE NEXT ONE AOBJN T3,FHDR.1 ;AND LOOP PJRST .FALSE## ;LOSE FHDR.2: LOAD T2,.QHTYP(S1),QH.TYP ;GET THE QUEUE TYPE CAIE T2,.QHTQS ;IS IT INTERNAL TO QUASAR? POPJ P, ;NO, RETURN SUCCESS PJRST .FALSE## ;YES, LOSE SUBTTL Subroutines ; VALMSG VALIDATE MESSAGES FROM KNOWN COMPONENTS ; SRHUSE SEARCH THE USE QUEUE FOR A GIVEN ITN ; FNDREQ UTILITY FOR KILL/MODIFY TO FIND ALL MATCHES IN A QUEUE ; SPROTO BUILD SPOOL TO QUEUE PROTOTYPE ; MAJMOD PERFORM MODIFY ON GLOBAL QUEUE PARAMETERS ; FILMOD PERFORM FILE-SPECIFIC MODIFIES ; BLDKMS BUILD THE KILL/MODIFY/DEFER ACKNOWLEDGEMENT STRING ; TYPPLR ROUTINE TO PLURALIZE A MESSAGE ; SETRDE SET THE EQ.RDE FLAG IN FAILSOFT REQUEST SUBTTL VALMSG -- Routine to validate message from known component ;VALMSG IS CALLED WITH THE MINIMUM SIZE OF THE MESSAGE IN T1. IF ; THE MESSAGE IS INVALID, EXIT THROUGH QSR??% TO SET GLOBAL ERROR ; CALLER MUST CHECK G$ERR TO DETERMINE IF OK TO PROCEED ; ;ON SUCCESS, LOCATION THSPSB IS FILLED WITH THE ADDRESS OF THE PSB ; FOR THE SENDER VALMSG: LOAD T2,.MSTYP(M),MS.CNT ;GET SIZE OF MESSAGE CAMGE T2,T1 ;GREATER OR EQUAL? PJRST E$MTS## ;INDICATE MESSAGE TOO SHORT MOVE S1,G$SND## ;GET PID OF CURRENT SENDER PUSHJ P,A$FPSB## ;FIND HIS PSB PJUMPE S1,E$NKC## ;INDICATE NO PSB MOVEM S1,THSPSB ;SAVE THE PSB POPJ P, ;AND RETURN SUBTTL SRHUSE -- Routine to search the USE queue ;CALL SRHUSE WITH T1 CONTAINING THE ITN. IF THE ENTRY IS FOUND, ; RETURN THE ADDRESS OF THE ENTRY IN T1, ELSE RETURN ZERO. SRHUSE: MOVEI H,HDRUSE ;ADDRESS OF USE QUEUE HDR MOVE T2,T1 ;COPY THE ITN INTO T2 LOAD T1,.QHLNK(H),QH.PTF ;GET POINTER TO FIRST SRHU.1: JUMPE T1,.POPJ## ;RETURN IN END OF CHAIN CAMN T2,.QEITN(T1) ;COMPARE POPJ P, ;MATCH!! RETURN LOAD T1,.QELNK(T1),QE.PTN ;LOAD POINTER TO NEXT JRST SRHU.1 ;AND LOOP SUBTTL FNDREQ -- Utility for KILL/MODIFY to find all matches ;FNDREQ IS CALLED WITH THE FOLLOWING ARGUMENTS ; H = THE QUEUE TO SEARCH ; T1 = CODE (0 = KILL, -1 = MODIFY) ; T2 = ADDRESS OF AN RDB TO MATCH AGAINST ; T3 = RQP ; T4 = SUBROUTINE TO CALL UPON FINDING A MATCH ;USES AP TO TRAVERSE THE QUEUE ;THE SUBROUTINE WHICH IS CALLED UPON FINDING A MATCHING REQUEST (@T4) ; IS CALLED WITH THE ADDRESS OF THE REQUEST IN "AP", AND "H" ; SETUP. IT MAY USE T1-T4,AP, AND H. ; ;RETURNS NUMBER OF PROTECTION FAILURES IN S1 FNDREQ: CLEARB S1,FNDR.E ;CLEAR THE # PROT FAILS LOAD AP,.QHLNK(H),QH.PTF ;GET FIRST IN QUEUE PJUMPE AP,.POPJ## ;DON'T BOTHER IF EMPTY PUSHJ P,.SAVE1## ;NEED ANOTHER REG MOVEM T1,FNDR.A ;SAVE THE ORIGINAL ARGUMENTS MOVEM T2,FNDR.B ;SO THAT THE CALLER CAN USE MOVEM T3,FNDR.C ;THEM WHEN I CALL THE SUBROUTINE MOVEM T4,FNDR.D ;UPON FINDING A MATCH FNDR.1: LOAD T4,.QESTN(AP),QE.RQP ;GET RQP OF THIS ENTRY CAME T4,FNDR.C ;FOR THE SAME QUEUE JRST FNDR.4 ;NO, TRY THE NEXT IN THE QUEUE MOVE S1,FNDR.B ;POINT TO THE MASK BLOCK FOR CHKMCH PUSHJ P,I$RMCH## ;SEE IF THIS THE A MATCHING REQUEST JUMPE S1,FNDR.4 ;JUMP IF NOT A MATCH ;WITH A REQUEST IN AP THAT MATCHES, DO A LITTLE ACCESS CHECKING LOAD S1,.QESEQ(AP),QE.RDE ;REQUEST ALREADY GONE? JUMPN S1,FNDR.4 ;YES, DON'T GET IT AGAIN FNDR.2: LOAD S1,G$SID## ;GET MESSAGE SENDER ID LOAD S2,.QEOID(AP) ;REQUEST OWNER ID CAMN S2,S1 ;DOING SOMETHING TO OWN REQUEST SKIPL FNDR.A ;YES, TRYING TO MODIFY IT SKIPA ;NO, NEED TO DO ACCESS CHECKS JRST FNDR.3 ;USER MAY ALWAYS MODIFY OWN REQUEST LOAD S1,.QEPRT(AP),QE.PRO ;GET REQUEST PROTECTION HRLI S1,ACC.KM ;CHECK ACCESS TYPE PUSHJ P,I$CHAC## ;CHECK REQUESTORS RIGHTS JUMPN S1,FNDR.3 ;JUMP IF ACCESS ALLOWED AOS FNDR.E ;COUNT PROTECTION FAILURES JRST FNDR.4 ;AND TRY THE NEXT ;"FNDREQ" IS CONTINUED ON THE NEXT PAGE ;CONTINUED FROM PREVIOUS PAGE ;SINCE ITS OK TO KILL/MODIFY THIS REQUEST, CALL THE CALLERS SUBROUTINE FNDR.3: PUSH P,H ;MAKE US IMMUNE FROM IT LOAD P1,.QELNK(AP),QE.PTN ;FIND NEXT IN CASE ITS REMOVED PUSHJ P,@FNDR.D ;DO SOMETHING TO THIS REQUEST MOVE AP,P1 ;NOW POINT TO THE NEXT POP P,H ;RESTORE ORIGINAL HEADER CAIN H,HDRUSE ;A LITTLE SPECIAL CHECK LOAD AP,.QHLNK(H),QH.PTF ;THE USE QUEUE COULD BE CHANGED BY Q$CDIN SKIPA ;SKIP OVER THE LOAD, ALREADY HAVE AP FNDR.4: LOAD AP,.QELNK(AP),QE.PTN ;FIND THE NEXT JUMPN AP,FNDR.1 ;CHECK FOR ALL ENTRIES MOVE S1,FNDR.E ;LOAD NUMBER OF PROT FAILURES POPJ P, ;QUEUE EXHAUSTED, RETURN ;LOCAL STORAGE FNDR.A: BLOCK 1 ; KILL = 0, MODIFY = -1 FNDR.B: BLOCK 1 ;KILL/MODIFY REQ DESC BLOCK FNDR.C: BLOCK 1 ;RQP OF REQUESTED QUEUE FNDR.D: BLOCK 1 ;ADDRESS OF PROCESSING ROUTINE FNDR.E: BLOCK 1 ;# OF PROTECTION FAILURES SUBTTL SPROTO -- Build a CREATE Message Prototype ;SPROTO IS CALLED WITH T1 = THE CANONICAL SPOOL MESSAGE TO BUILD THE ; PROTOTYPE EXTERNAL QUEUE ENTRY FOR THE FIRST FILE IN DEFERRED ; MODE OR THE ONLY FILE IF IMMEDIATE MODE ;RETURN AP = THE BUILT PROTOTYPE READY FOR Q$INCL SPROTO: PUSHJ P,M$ACQP## ;GET A PAGE FOR THE PROTOTYPE PG2ADR AP ;TO AN ADDRESS HRLI T2,(AP) ;BUILD A BLT POINTER HRRI T2,1(AP) ;NEED A CLEAN HEADER SETZM (AP) ;CLEAR THE FIRST WORD BLT T2,EQHSIZ-1(AP) ;GET IT ALL MOVX T2, ;GET SIZE AND INTERNAL CREATE STORE T2,.MSTYP(AP) ;AS THE MESSAGE HEADER MOVX T2,<%%.QSR,,EQHSIZ> ;VERSION,,HEADER SIZE STORE T2,.EQLEN(AP) ;AS EXTERNAL QUEUE LENGTHS LOAD T2,CSM.DV(T1) ;GET THE REQUESTED DEVICE STORE T2,.EQRDV(AP) ;STORE FOR CREATE LOAD T2,CSM.JB(T1),CS.LOC ;THE DEFAULT STATION NUMBER STORE T2,.EQSEQ(AP),EQ.DSN ;SAVE FOR CREATE MOVE T2,G$SPRT## ;GET SYSTEM PROTECTION OF SPOOLED FILES STORE T2,.EQSPC(AP),EQ.PRO ;AS THE REQUEST PROTECTION MOVE S1,T1 ;POINT S1 TO CSM PJRST I$SMEQ## ;AND MOVE SYSTEM DEPENDENT ; STUFF AN RETURN SUBTTL MAJMOD -- Perform MODIFY on Major Queue Items ;CALLED BY Q$MODIFY WITH ; AP = THE ENTRY BEING MODIFIED (.EQxxx FORM) ; S1 = GROUP 0 MODIFY BLOCK MAJMOD: PUSHJ P,.SAVE3## ;SAVE A FEW REGS FIRST LOAD P1,MOD.GN(S1),MODGLN ;NUMBER OF GROUP 0 ELEMENTS SOJLE P1,.POPJ## ;0 IS ACCEPTABLE, ADJUST FOR THE LOOP CAILE P1,NMAJPM ;MORE THAN CURRENTLY IMPLEMENTED MOVEI P1,NMAJPM ;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 MAJM.1: MOVE P3,0(P2) ;GET AN ELEMENT CAME P3,[-1] ;DID IT CHANGE XCT MAJMTB(P1) ;YES, STORE NEW VALUE INCR P2 ;TO NEXT ELEMENT AOBJN P1,MAJM.1 ;GET THEM ALL POPJ P, ;RETURN TO Q$MODIFY FOR NEXT GROUP MAJMTB: STORE P3,.EQAFT(AP) ; 0 = /AFTER STORE P3,.EQSEQ(AP),EQ.PRI ; 1 = /PRIORITY STORE P3,.EQDED(AP) ; 2 = /DEADLINE STORE P3,.EQSPC(AP),EQ.PRO ; 3 = /PROTECTION NMAJPM==<.-MAJMTB> ;NUMBER CURRENTLY IMPLEMENTED SUBTTL FILMOD -- Perform File-Specific MODIFY ;CALLED BY Q$MODIFY WITH ; AP = THE ENTRY BEING MODIFIED (.EQxxx FORM) ; S1 = GROUP 2 MODIFY BLOCK ;RETURNS S1 = NUMBER OF FILES THAT MATCHED THE SPEC FILMOD: PUSHJ P,.SAVET## ;SAVE T1-T4 PUSHJ P,.SAVE2## ;AND P1-P2 ZERO FILM.E ;CLEAR FILE COUNT FOR THIS PASS LOAD T2,MOD.GN(S1),MODGLN ;NUMBER OF WORDS IN GROUP 2 CAIG T2,MOD.FD ;ENOUGH FOR THE INFO WORD JRST FILM.5 ;NO, IGNORE IT LOAD T1,MOD.FI(S1),MODFDL ;T1 = LENGTH OF AN FD IN MODIFY CAIL T1,FDMSIZ ;RANGE CHECK FOR TOO SMALL CAILE T1,FDXSIZ ;OR TOO LARGE JRST FILM.5 ;OUT OF RANGE, IGNORE IT MOVE T3,T1 ;NOW CHECK THE NUMBER OF ELEMENTS ADDI T3,MOD.FD(T1) ;COMPUTE 2*FD + OFFSET SUB T2,T3 ;T2 = NUMBER OF REAL ELEMENTS JUMPLE T2,FILM.5 ;NONE OR BAD, IGNORE IT CAILE T2,NFILPM ;MORE THAN I KNOW ABOUT MOVEI T2,NFILPM ;YES, USE ONLY WHATS THERE ADDI T3,(S1) ;T3 = FIRST PARM MOVEM T3,FILM.D ;SAVE FOR LOOP MOVEI T3,MOD.FD(S1) ;FIRST FD MOVEM T3,FILM.A ;SAVE FOR I$FMCH ADDI T3,(T1) ;MASKS MOVEM T3,FILM.C ;SAVE THAT TOO LOAD T3,.EQSPC(AP),EQ.NUM ;T3 = NUMBER OF FILES IN REQUEST LOAD T4,.EQLEN(AP),EQ.LOH ;NOW FIND FIRST FILE IN REQUEST ADDI T4,(AP) ;T4 = FIRST FP AREA IN ORIGINAL ;NOW LOOP THROUGH ALL FILES IN ORIGINAL LOOKING TO MATCH MODIFY REQUEST ;DURING THE LOOP: ; T1 = THE LENGTH OF FD ; T2 = NUMBER OF ELEMENTS SPECIFIED IN MODIFY ; T3 = NUMBER OF FILES IN ORIGINAL REQUEST ; T4 = FP AREA IN ORIGINAL FILM.1: LOAD S2,.FPSIZ(T4),FP.FFS ;GET SIZE OF THIS FD LOAD P1,.FPSIZ(T4),FP.FHD ;GET SIZE OF THIS FP ADDI P1,(T4) ;P1 = FD FOR THE ORIGINAL REQUEST CAIE S2,(T1) ;FD LENGTHS MATCH JRST FILM.4 ;NO, THEN MASKS WON'T EITHER MOVEM P1,FILM.B ;SAVE ADDR OF 2ND FD FOR I$FMCH MOVEI S1,FILM.A ;ADDRESS OF ARGUMENT BLOCK PUSHJ P,I$FMCH## ;COMPARE THE FD AREAS JUMPE S1,FILM.3 ;JUMP IF THEY DIDN'T LOAD S1,.FPINF(T4),FP.IGN ;DOES THIS FILE EXIST JUMPN S1,FILM.3 ;JUMP IF /REMOVE'D BEFORE ;FILMOD IF CONTINUED ON THE NEXT PAGE ;CONTINUE WITH FILMOD AOS FILM.E ;ADD A MATCH MOVN P2,T2 ;GET NUMBER OF ELEMENTS HRLZS P2 ;P2 = AOBJN POINTER MOVE S2,FILM.D ;POINT TO FIRST ELEMENT FILM.2: MOVE S1,0(S2) ;GET AN ELEMENT CAME S1,[-1] ;DID IT CHANGE XCT FILMTB(P2) ;YES, STORE NEW VALUE INCR S2 ;POINT TO NEXT AOBJN P2,FILM.2 ;GET THEM ALL FILM.3: MOVE S2,T1 ;COPY THE FD LENGTH FILM.4: MOVE T4,P1 ;FD AREA ADDI T4,(S2) ;+FD LENGTH = NEXT FILE IN ORIGINAL SOJG T3,FILM.1 ;GET THE NEXT FILE FILM.5: MOVE S1,FILM.E ;GET NUMBER OF FILES MODIFIED POPJ P, ;ALL DONE WITH GROUP 2 FILMTB: STORE S1,.FPINF(T4),FP.IGN ; 0 = /REMOVE STORE S1,.FPINF(T4),FP.NFH ; 1 = /HEADER STORE S1,.FPINF(T4),FP.FSP ; 2 = /SPACING STORE S1,.FPINF(T4),FP.FPF ; 3 = /PAPER STORE S1,.FPINF(T4),FP.FFF ; 4 = /FILE STORE S1,.FPINF(T4),FP.DEL ; 5 = /DELETE STORE S1,.FPINF(T4),FP.FCY ; 6 = /COPIES STORE S1,.FPFR1(T4) ; 7 = /REPORT (1ST HALF) STORE S1,.FPFR2(T4) ; 8 = /REPORT (2ND HALF) STORE S1,.FPFST(T4) ; 9 = /TAG OR /BEGIN NFILPM==<.-FILMTB> ;NUMBER CURRENTLY IMPLEMENTED FILM.A: BLOCK 1 ;ADDRESS OF 1ST FD (SPEC) FILM.B: BLOCK 1 ;ADDRESS OF 2ND FD (ORIGINAL) FILM.C: BLOCK 1 ;ADDRESS OF MASKS FILM.D: BLOCK 1 ;ADDRESS OF FIRST GROUP ELEMENT FILM.E: BLOCK 1 ;NUMBER OF FILES MODIFIED THIS PASS SUBTTL BLDKMS -- Routine to build KILL/MODIFY/DEFER acknowledgement string ;BLDKMS IS CALLED WITH T1 POINTING TO AN ARGUMENT BLOCK CONTAINING: ; +0 = NUMBER OF "THINGS" DONE (KILLED, MODIFIED, DEFERRED) ; +1 = NUMBER OF FILES (MODIFY, DEFER) ; +2 = NUMBER OF CANCEL MESSAGES SENT (KILL ONLY) ; +3 = NUMBER OF PROTECTION FAILURES ; AND T2 = "THING" STRING ADDRESS (ASCIZ FORMAT) ;ASSEMBLES THE CORRECT MESSAGE (USES TYPPLR TO PLURALIZE THE PARTS) AND CALLS G$MSND BLDKMS: SKIPN G$ACK## ;CALLER WANT THIS MESSAGE POPJ P, ;NO, NEVER MIND MOVE S1,0(T1) ;GET "THINGS" DONE PUSHJ P,TYPPLJ ;TYPE CORRECT "JOB(S)" SKIPL T3,1(T1) ;DON'T TYPE FILES SKIPN 0(T1) ;YES, BUT WERE THERE ANY JOBS JRST BLDK.1 ;DONT BOTHER MOVEI S1,[ASCIZ/ (/] ;ALIGN THE OUTPUT SKIPN T3 ;ANY FILES MOVEI S1,[ASCIZ/ (But /] ;NO, POINT THAT OUT PUSHJ P,G$CSTG## ;INCLUDE THAT MOVE S1,T3 ;GET NUMBER OF FILES MOVEI S2,[ASCIZ/ File/] ;SAY FILE(S) INSTEAD OF JOB(S) PUSHJ P,TYPPLR ;OUTPUT CORRECT ENGLISH MOVEI S1,[ASCIZ/)/] ;MAKE IT LOOK NICE PUSHJ P,G$CSTG## ;BY ADDING THE CLOSURE BLDK.1: MOVE S1,T2 ;NOW FOR THE "THING" STRING PUSHJ P,G$CSTG## ;APPEND THE STRING SKIPN T2,2(T1) ;ANY JOBS CANCELLED JRST BLDK.2 ;NO, AVOID THE OUTPUT MOVEI S1,[ASCIZ/, /] ;PUNCTUATION PUSHJ P,G$CSTG## ;ALIGN THE NEXT COMMENT MOVE S1,T2 ;GET NUMBER OF THEM DONE PUSHJ P,TYPPLJ ;AND SAY "n JOB(S)" MOVEI S1,[ASCIZ/ Cancelled/] ;WHAT WAS DONE PUSHJ P,G$CSTG## ;INCLUDE THAT BLDK.2: SKIPN T3,3(T1) ;ANY PROTECTION FAILURES JRST BLDK.3 ;NO, AVOID THAT TOO MOVEI S1,[ASCIZ/, /] ;PUNCTUATION PUSHJ P,G$CSTG## ;ALIGN THE NEXT COMMENT MOVE S1,T3 ;GET THE COUNT OF PROTECTION FAILURES MOVEI S2,[ASCIZ/ Protection Failure/] PUSHJ P,TYPPLR ;TYPE NUMBER AND PLURALIZE THE MESSAGE BLDK.3: ZERO S1 ;THIS IS AN INFORMATIONAL MESSAGE PJRST G$MSND## ;SEND "ACK" AND RETURN SUBTTL TYPPLR -- Routine to pluralize a message ;TYPPLR IS CALLED WITH S1 CONTAINING A NUMBER "N" AND S2 CONTAINING ; THE ADDRESS OF AN ASCIZ STRING "FOO". IF N IS 0, TYPPLR ; WILL SEND TO THE CURRENT TEXT MESSAGE "NO FOOS". IF N IS 1, ; "1 FOO" WILL BE SENT, OTHERWISE, "N FOOS" WILL BE SENT. ; ;ENTER AT "TYPPLJ" IF THE STRING IS "JOB". TYPPLJ: MOVEI S2,[ASCIZ \ Job\] ;LOAD DEFAULT STRING TYPPLR: MOVEM S2,TYPP.A ;SAVE ADDRESS OF THE STRING CAIE S1,1 ;ONE "THING" DONE JRST TYPP.1 ;NO, TRY ANOTHER PUSHJ P,G$CDEC## ;TYPE OUT THE ONE MOVE S1,TYPP.A ;GET STRING PJRST G$CSTG## ;TYPE IT AND RETURN TYPP.1: JUMPN S1,TYPP.2 ;JUMP IF IT WAS IT "SOME THINGS" MOVEI S1,[ASCIZ /No/] ;GET STRING "NO" INSTEAD OF TYPING 0 PUSHJ P,G$CSTG## ;TYPE A STRING SKIPA ;SKIP ALTERNATE ENTRY TYPP.2: PUSHJ P,G$CDEC## ;TYPE DECIMAL NUMBER MOVE S1,TYPP.A ;GET STRING BACK PUSHJ P,G$CSTG## ;AND TYPE IT MOVEI S1,"s" ;AND PLURAL ENDING PJRST G$CCHR## ;TYPE IT AND RETURN TYPP.A: BLOCK 1 ;LOCAL STORAGE SUBTTL SETRDE -- Routine to set "REQUEST DOESN'T EXIST" in a request ;SETRDE IS CALLED WITH THE ADDRESS OF A QUEUE ENTRY (QE) IN T1. IT READS ; IN THE FAILSOFT COPY, SETS EQ.RDE, SETS QE.RDE, WRITES IT OUT, ; AND STORES THE NEW DPA BACK IN THE QUEUE ENTRY. SETRDE: SAVE AP ;SAVE CALLERS REGISTER LOAD S1,.QESTN(T1),QE.DPA ;GET THE DPA PUSHJ P,F$RDRQ## ;AND READ THE REQUEST MOVEI S2,1 ;LOAD A BIT STORE S2,.EQSEQ(S1),EQ.RDE ;SET RDE BIT STORE S2,.QESEQ(T1),QE.RDE ;SET IN THE INTERNAL QUEUE AS WELL MOVE AP,S1 ;SAVE ADDRESS IN AP PUSHJ P,F$WRRQ## ;WRITE OUT THE REQUEST LOAD S2,.QESTN(T1),QE.DPA ;LOAD THE OLD DPA STORE S1,.QESTN(T1),QE.DPA ;STORE THE NEW DPA MOVE S1,S2 ;COPY OVER THE OLD ONE INTO S1 PUSHJ P,F$RLRQ## ;RELEASE FAILSOFT SPACE ADR2PG AP ;CONVERT ADDRESS TO A PAGE # PJRST M$RELP## ;RELEASE THE PAGE AND RETURN END