Trailing-Edge
-
PDP-10 Archives
-
bb-d868b-bm_tops20_v3a_2020_dist
-
3a-sources/qsrque.mac
There are 44 other files named qsrque.mac in the archive. Click here to see a list.
TITLE QSRQUE -- Batch Queue Message Handlers for QUASAR
SUBTTL Larry Samberg Chuck O'Toole /CER 6 Jan 77
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1974, 1975, 1976, 1977, 1978 BY
; DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
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+<EQCKSZ-1>(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,<HDRSPL+.QHLNK>,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,<HDRSPL+.QHLNK>,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,<HDRSPL+.QHLNK>,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,<INSVL.(EQHSIZ,MS.CNT)!.QIFNC> ;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