.title SPW - Watch spooler tasks .ident "V1.4" .ENABL LC .nlist me,bex,cnd ; Author: Henry R. Tumblin ; Date: 20-Feb-79 ; Version: 1.4 ; Module Name: SPW -- Spooler Watch ; For: Systems/Utilities ; Residence: DB1:[1,20]SPW.MAC ; Indirect Command File: SPW.CMD ; Machine/System: PDP-11/70 IAS V3.1 ; Type/Language: Main/Assembler ; Abstract: This module reports on the various status of ; the De-spooler tasks. ; Edits: ; Date By Reason ; --------- ----- ------------------------------------------------ ;01 22-Feb-79 HRT Added STATUS indicator. ;01 22-Feb-79 HRT Added Forms. ;02 22-Feb-79 HRT Fixed bug in copies. ;03 27-Feb-79 HRT Fixed status order so TMO will be seen. ;04 06-Mar-79 HRT Added "Spoolers Checkpointed" message. ;05 19-JUN-79 HRT MODIFIED FOR IAS V3.0 .sbttl Description ; Currently, while in the process of printing ; a file using the de-spooler task, SPR2.., the ; user is unable to check the progress of their ; file in terms of: ; ; 1) The total number of blocks to print. ; 2) The number of blocks printed so far. ; 3) Whether or not the printer is suspended, ; to be resumed, timed-out, or active, or ; checkpointed but active. ; ; The SPooler Watch utility has been designed to help ; to show these important areas so as to more closely ; monitor the output de-spooling process. ; SPW will display all currently active printers, ; whether they are LP: or other spooled devices, as long ; as SPR2.. is used in the de-spooling process. SPW ; scans the Active Task List(ATL) for a copy of SPR2.. . ; When found, SPW then remaps APR3 so that it references the ; first 4-KW of that task. Referring to the SPR2.. sources, ; a context table is kept, along with the FDB, in this first ; 4-KW. After mapping, the needed information is retrieved, ; and the ATL scan is continued. When the end of the ATL ; is reached, then the status of each device is displayed ; to the user. As an aside, the PUD is scanned for each device ; and is also displayed along with the # of copies to be printed. ;+04 If SPW finds that the spooler task is checkpointed, then ;+04 a checkpoint count will be displayed to indicate how many ;+04 spoolers, that are still active, have been checkpointed. ;+04 This is usefull especially on a loaded system. ; .sbttl Examples ; Possible uses of such a utility are shown by the following ; examples: ; Example #1: ; ; Situation: Printer has stopped for some reason. QUE /ALL ; shows the printer as still active. ; ; PDS> SPW ; ; IAS V3.1 Current Spooler Status ; ;Device Current/Total - %Complete Filename Copies/Forms Status ;TT5: 00004/00020 20% TT .SPR;1 00001/00000 TMO ; ; Explanation: This shows that the printer, TT5:, has timed-out. ; This is probably due to a paper jam, or operator ; intervention. Clearing the printer, then issueing ; a SPOOL/RE:FILE will restart the file from the ; beginning, or SPOOL/RE:RE will resume the file ; from the stall point. If this still doesn't work, ; then perhaps the line is stalled by an XOF(^S) ; from the printer. Use the XON utilty to clear ; this problem. ; ; Example #2: ; ; Situation: System is loaded, response is sluggish. The ; printer prints several lines, then stops, prints ; another several lines, then stops. ; ; PDS> SPW ; ; No de-Spoolers active ; 00001 Spoolers Checkpointed ; ; Explanation: This shows that when the request was made, that the ; currently active printer had been checkpointed and ; was not currently in memory. This means that even ; if the device is slow, that it is still active. ; SPW cannot determine the status of a spooler ; unless it is active in memory. ; .sbttl Mcalls,macro definitions, and symbolic definitions .MCALL FDOF$L,DIR$,QIOW$,EXIT$S .MACRO PRINT,A,B MOV A,WRITE+Q.IOPL MOV B,WRITE+Q.IOPL+2 DIR$ #WRITE .ENDM PRINT .MACRO PURE .PSECT SPWPUR,RO,I,REL .ENDM .MACRO IMPURE .PSECT SPWIMP,RW,D,REL .ENDM IMPURE C$C ; Define control characters .SBTTL DEFINE CONTEXT BUFFER OFFSETS - DISCUSSION ;+ ; ; DEFINE CONTEXT BUFFER OFFSETS: ; ; THE CONTEXT BUFFER CONSISTS OF THE FOLLOWING: ; ; 1. AN FDB THAT IS KEPT OPEN FOR THE DURATION OF THE I/O TRANSFER ; OPERATION. ; 2. EXTRA WORDS THAT THE DESPOOLER USES TO MAINTAIN ; CONTEXT FOR THE DESPOOL OPERATION. ; ; THE CONTEXT WORD OFFSETS AND THEIR FUNCTION ARE ; DEFINED AND BRIEFLY DISCUSSED BELOW: ; ; NOTE: THESE OFFSETS ARE OF THE FORM 'F.XZZZ', WHERE 'ZZZ' ; IS A TWO OR THREE LETTER DESIGNATOR ; ;- FDOF$L ; LOCALLY DEFINE FDB OFFSETS ; F.XDEV ==S.FDB ; DEVICE DESPOOLING IS DONE TO (ASCII) F.XUN ==F.XDEV+2 ; OUTPUT DEVICE UNIT NUMBER and flags F.XOPR ==F.XUN+2 ; CURRENT OPERATION TYPE (BYTE) ; VALUES FOR 'F.XOPR' ARE AS FOLLOWS: ; FC.TOF ==0 ; QUEUE TOF AT NEXT I/O DONE AST FC.IO ==FC.TOF+1 ; NORMAL I/O IN PROGRESS FC.XIO ==FC.IO+1 ; SPECIAL I/O IN PROGRESS FC.DET ==FC.XIO+1 ; QUEUE DETACH DEVICE REQUEST FC.KIL ==FC.DET+1 ; QUEUE KILL I/O REQUEST FC.DNE ==FC.KIL+1 ; CLOSE/DELETE THE INPUT FILE FC.BNR ==FC.DNE+1 ; SERVICE BANNERS ; ; F.XBNR ==F.XOPR+1 ; CURRENT BANNER OPERATION ; VALUES FOLLOW ; FB.INF ==0 ; BANNER INFO LINES FB.BN1 ==FB.INF+1 ; FIRST BANNER LINE FB.BN2 ==FB.BN1+1 ; SECOND BANNER LINE FB.CLS ==FB.BN2+1 ; FINAL BANNER LINES ; F.XOP2 ==F.XBNR ; RECORD LENGTH FOR COBOL CC ; USE SAME BYTE AS BANNER OPERATION F.XFLU ==F.XBNR+1 ; USER FLAGS FROM RCVD$ NODE (BYTE) F.XCOP ==F.XFLU+1 ; NUMBER OF COPIES SPECIFIED (BYTE) ; ; F.XFL1 ==F.XCOP+1 ; DESPOOLER MAINTAINED CONTEXT FLAGS ; THE FOLLOWING ARE BIT DEFINITIONS FOR THIS WORD: ; UFF.OC ==1 ; THIS TABLE ENTRY IS OCCUPIED UFF.WT ==2 ; THIS DEVICE IN SUSPEND STATE UFF.RS ==4 ; RESTART I/O WHEN POSS. ON THIS DEV. UFF.AB ==10 ; OPERATOR ABORT IN EFFECT UFF.TT ==20 ; TERMINAL DEVICE UFF.FF ==40 ; FORM FEED SEEN UFF.BF ==100 ; COBOL CARRIAGE CONTROL BEFORE RECORD UFF.RF ==200 ; RESTART AT TOP OF FORM UFF.CR ==400 ; ERROR ON OUTPUT UFF.AT ==1000 ; DEVICE HAS BEEN SUCCESFULLY ATTACHED UFF.FA ==2000 ; CLEAR FORM FEED FROM FIRST RECORD UFF.MC ==4000 ; MULTIPLE COPIES UFF.TO ==10000 ; TIMEOUT INDICATOR UFF.BC ==20000 ; LARGE/SMALL BANNER ; F.XR1 ==F.XFL1+2 ; MARK INFORMATION AT FORM ; FEED DETECTION (THREE WORDS) F.XSAV ==F.XR1+6 ; PREVIOUS MARK INFORMATION F.XPRI ==F.XSAV+6 ; PRIORITY OF DESPOOL REQUEST (BYTE) F.UIC ==F.XPRI+2 ; ACCOUNT NUMBER (UFD) OF REQUEST ; S.TAB ==F.UIC+2 ; DEFINE SIZE OF TABLE ENTRY IN BYTES .sbttl Other buffers, counters, and message strings IMPURE .sbttl Impure storage TSKNAM: .RAD50 "SPR2.." ; Look at each of the spoolers NBRTSK = 10. ; Max number of spooler tasks SAVTBL: ; Save table. .REPT NBRTSK ; Set up the holding table. .BLKW 1 ; (0)For the Device name .BLKW 1 ; (2)For the Device number .BLKW 2 ; (4)For the max # of blks. .BLKW 2 ; (8)For the current blk #. .BLKW 1 ; (12)For the file device name .BLKW 1 ; (14)For the file device # .BLKW 3 ; (16)For the RAD-50 filename .BLKW 1 ; (22)For the RAD-50 filetype .BLKW 1 ; (24)For the version # .BLKW 1 ; (26)For the # of copies. .BLKW 1 ; (28)For the context flags .ENDR TBLESZ=<.-SAVTBL>/NBRTSK ; The size of a table entry COUNT:: .WORD 0 ; Count of spoolers active WRITE: QIOW$ IO.WLB,1,1,100,,,<0,0,40> ; Terminal write Q-I/O PRTBUF: .BLKB 90. ; Output buffer CKPCNT: .WORD 0 ; +04 Checkpoint count MSG1: .ASCII "Current Spooler Status IAS V3.1" .ASCII "Device Current/Total - %Complete Filename" .ASCII " Copies/Forms Status" MSG1S=.-MSG1 ERR1: .ASCII "SPW - No de-spoolers active" ERR1S=.-ERR1 STS1: .ASCII "SUS" STS2: .ASCII "RES" STS3: .ASCII "TMO" STS4: .ASCII "ACT" STS5: .BYTE CR,LF ; +04 Checkpointed tasks message NBR: .BLKB 5 ; +04 Buffer for ASCII count .ASCII " - Spooler tasks checkpointed." .BYTE CR,LF STS5S=.-STS5 .sbttl Mainline code .sbttl Scan ATL .enabl lsb PURE START: MOV .ATLLH,R0 ; Get the ATL listhead .INH0 ; Inhibit task switching MOV R0,R1 ; Save start/ending point 10$: MOV (R0),R0 ; Point to next ATL entry CMP R0,R1 ; Are we at the end already? BNE 20$ ; NE - nope, see if this is it CALL ..ENB0 ; Else re-enable task switch TST COUNT ; Any found?? BNE 110$ ; NE - then there were some active PRINT #ERR1,#ERR1S ; Else tell the user none found. BR 100$ ; Go exit 110$: CALL OTPUT ; Go to output section TST CKPCNT ; +04 Were there any checkpointed? BEQ 100$ ; +04 EQ - nope MOV #STS5,R0 ; +04 Set up for conversion MOV CKPCNT,R1 ; +04 Binary count to R1 MOV #1,R2 ; +04 No zero suppress CALL $CBDMG ; +04 Convert to ASCII PRINT #STS5,#STS5S ; +04 And print the message 100$: EXIT$S ; And exit gracefully(always) 20$: MOV A.TD(R0),R2 ; Point to the STD entry CMP TSKNAM,S.TN(R2) ; Is the task name the same? BNE 10$ ; NE - check next ATL node CMP TSKNAM+2,S.TN+2(R2) ; Check next three digits BNE 10$ ; NE - then check next ATL node CMPB A.TS(R0),#TS.RUN ; Is the task in a legitamite status BLO 11$ ; +04 LO - nope CMPB A.TS(R0),#TS.WF4 ; check again BLOS 12$ ; +04 LOS - It's what we want 11$: INC CKPCNT ; +04 Bump up checkpoint count BR 10$ ; +04 Go look at the next node .sbttl Re-map into the de-spooler task ; At this point, we have found one of the spooler ; tasks. Re-map APR3 to its header, then to its ; task space. 12$: INC COUNT ; Bump up the count PUSH <#77606,A.HA(R0)> ; Set up to re-map CALL ..SPD3 ; Map to it's header MOV #60000,R2 ; Make APR3 relative PUSH ; Push PAR,PDR pair for page 0 CALL ..SPD3 ; Map there CMP (SP)+,(SP)+ ; Clean off old PAR,PDR pair .sbttl Save the file information ; Now we're into the 1st 4-kw of the spooler task. ; This is the impure area. Now we find the ; start of the CONTXT area. This symbol can be ; resolved thru the task builder. Simply re-link ; the SPR2.. task, obtaining a load map only. ; From this map, obtain the value for the symbol ; "CNTXT" and use it in the GBLDEF=CNTXT:xxxxxx ; in the task build option list. ; MOV #CNTXT+60000,R3 ; Point to the context table ; The first 96. bytes of the context area is the ; FDB of the file being printed. Therefore, all FDB ; offsets are relative off of R3. Let's get some information ; about this file and save it in our task space. MOV #TBLESZ,R5 ; Table entry size MOV COUNT,R4 ; Count to R4 DEC R4 ; -1 for starting offset MUL R4,R5 ; Get offset to table ADD #SAVTBL,R5 ; Add in the base MOV F.XDEV(R3),(R5) ; Get the despooler device MOVB F.XUN(R3),2(R5) ; The device unit number MOV F.VBN(R3),4.(R5) ; The current block being processed MOV F.VBN+2(R3),6.(R5) ; ...(Double word) MOV F.EFBK(R3),8.(R5) ; The EOF-BLK-NBR MOV F.EFBK+2(R3),10.(R5) ; ...(Double word) MOV F.FNB+N.DVNM(R3),12.(R5) ; The Input device name MOV F.FNB+N.UNIT(R3),14.(R5) ; And the Unit # MOV F.FNB+N.FNAM(R3),16.(R5) ; The File name (3 words) MOV F.FNB+N.FNAM+2(R3),18.(R5) ; (word 2) MOV F.FNB+N.FNAM+4(R3),20.(R5) ; (word 3) MOV F.FNB+N.FTYP(R3),22.(R5) ; The File type (1 word) MOV F.FNB+N.FVER(R3),24.(R5) ; The file version # MOVB F.XCOP(R3),26.(R5) ; The number of copies MOV F.XFL1(R3),28.(R5) ; +01 The Context flags .sbttl Unmap and continue scan ; Now we have saved all the info that we are going to display ; to the user. So, go back and continue scanning the ATL for ; more de-spooler tasks. CALL ..SPD3 ; Map back to our own task CMP (SP)+,(SP)+ ; Clean up the stack JMP 10$ ; Go look for next occurence. .dsabl lsb .sbttl OTPUT - Output information section .ENABL LSB OTPUT: ; First output the header line PRINT #MSG1,#MSG1S ; Print header ; Now format the Device string MOV #SAVTBL,R3 ; Point to info table 10$: MOV #PRTBUF,R0 ; Point to output area MOV (R3),(R0)+ ; Move the dev name. MOV 2(R3),R1 ; Set up to convert to ascii CLR R2 ; Zero suppress CALL $CBOMG ; Convert to ASCII MOVB #':,(R0)+ ; Insert a colon PUSH <#12.> ; Push col to be in. CALL FILL ; Fill to col 7. ; Now format the Current Block number MOV R3,R1 ; Point to ADD #4,R1 ; the DP # MOV #1,R2 ; No zero suppress CALL $CDDMG ; Convert to ascii MOVB #'/,(R0)+ ; Insert a separator ; Now format the last block number MOV R3,R1 ; Point to ADD #8.,R1 ; the DP # MOV #1,R2 ; No zero suppress CALL $CDDMG ; Convert to ASCII PUSH <#28.> ; Move CALL FILL ; to column 26 ; Now format the % printed AC0=%0 AC1=%1 SETF ; Use the FPP SETL LDCLF 8.(R3),AC0 ; Get the divisor LDCLF 4(R3),AC1 ; Get the dividend DIVF AC0,AC1 ; Divide to get % printed LDCLF #100.,AC0 ; Load multiplier MULF AC0,AC1 ; Multiply by 100% STCFI AC1,R1 ; Store in R1 for conversion CLR R2 ; Zero suppress CALL $CBDMG ; Convert to ASCII MOVB #'%,(R0)+ ; Append a % sign PUSH <#38.> ; Set to fill to CALL FILL ; Column 37. ; Now format the file string MOV 12.(R3),(R0)+ ; Device name MOV 14.(R3),R1 ; Unit # CLR R2 ; Zero suppress CALL $CBOMG ; Convert unit # MOVB #':,(R0)+ ; Insert a colon MOV #3,R5 ; Set count MOV R3,R4 ; Set pointer ADD #16.,R4 ; Adjust offset 34$: MOV (R4)+,R1 ; Setup R1 CALL $C5TA ; Convert to ASCII SOB R5,34$ ; Loop till thru MOVB #'.,(R0)+ ; Insert a period MOV 22.(R3),R1 ; Get the file type CALL $C5TA ; Convert it also MOVB #73,(R0)+ ; Append a semi-colon MOV 24.(R3),R1 ; Get the version # also CLR R2 ; Zero suppress CALL $CBOMG ; Convert to ascii ; Now convert the # of copies PUSH <#60.> ; Move to CALL FILL ; Column 60. MOV 26.(R3),R1 ; +02 Get copy count MOV #1,R2 ; No zero suppress CALL $CBDMG ; +02 Convert to ASCII .Sbttl Scan the PUD for the forms type ;+01 Now convert the Forms Type ; Now perform a quick PUD scan in order to get the ; forms type. MOV .PUDBA,R4 ; +01 Get PUD base address 70$: CMP .PUDEA,R4 ; +01 Are we at the end? BEQ 76$ ; +01 EQ - then quit scan CMP U.DN(R4),(R3) ; +01 Is this the device? BEQ 74$ ; +01 EQ - Maybe 72$: ADD #U.SZ,R4 ; +01 Else point to next dev. BR 70$ ; +01 And check it also 74$: CMPB U.UN(R4),2(R3) ; +01 Are the unit # alike? BNE 72$ ; +01 NE - Check next device MOVB U.FO(R4),R1 ; +01 Store the forms type 76$: MOVB #'/,(R0)+ ; +01 Insert a / MOV #1,R2 ; +01 No zero suppress CALL $CBDMG ; +01 Convert to ASCII ; Now output the status PUSH <#74.> ; +01 Position to column 74 CALL FILL BIT #UFF.WT,28.(R3) ; +01 Is it suspended? BEQ 78$ ; +01 Eq - no, check other MOV #STS1,R1 ; +01 Point to status message BR 90$ ; +01 Go add it to the line 78$: BIT #UFF.TO,28.(R3) ; +01/+03 Is it timedout? BEQ 79$ ; +01 Eq - no, check other MOV #STS3,R1 ; +01/+03 Point to message BR 90$ ; +01 Go add it to the line 79$: BIT #UFF.RS,28.(R3) ; +01/+03 Is it to be resumed? BEQ 80$ ; +01 Eq - no, check other MOV #STS3,R1 ; +01/+03 Point to message BR 90$ ; +01 Go add it to the line 80$: MOV #STS4,R1 ; +01 Else mark it as active 90$: MOVB (R1)+,(R0)+ ; +01 Move into place MOVB (R1)+,(R0)+ ; +01 Move into place MOVB (R1)+,(R0)+ ; +01 Move into place ; Now output the mess of a line SUB #PRTBUF,R0 ; Get line length PRINT #PRTBUF,R0 ; Output to user DEC COUNT ; Reduce the overall count BEQ 55$ ; EQ - then all thru ADD #TBLESZ,R3 ; Point to next entry JMP 10$ ; Go do for next device 55$: RETURN ; Return to caller .sbttl Support Subroutines .enabl lsb FILL: ; This subroutine fills the output buffer ; pointer to in R0 to the specified column #. ; We already know where the start of the buffer is, ; so we can use R1 to our advantage. MOV R0,R1 ; Point to start of buffer SUB #PRTBUF,R1 ; Get current position CMP 2(SP),R1 ; Are they the same? BLOS 40$ ; LOS - then it's OK SUB R1,2(SP) ; Else get # of blanks to insert MOV 2(SP),R1 ; Set count in R1 10$: MOVB #40,(R0)+ ; Move into place SOB R1,10$ ; Loop till thru 40$: MOV (SP)+,(SP) ; Clean off stack RETURN ; Return to calling proc. .dsabl lsb .end start