.TITLE BATMAN .IDENT /V2.48/ ;******************************************************************* ; ; BATMAN BATCH SYSTEM QUEUE MANAGER PROGRAM. ; THIS VERSION SUPPORTS MULTIPLE BATCH STREAMS ; ; SEE THE BATCH SYSTEM USER'S GUIDE FOR ; OPERATIONAL DETAILS OF THE BATCH SYSTEM. ; ; S.M. THOMPSON, DECEMBER 1979 ; ; MODIFICATIONS: ; 1. FIX LOGFILE DISPOSITION PROBLEM ; 2. FIX /NO SWITCH USE WITH SERIAL DESPOOLER ; 3. SUPPORT ACCOUNTING PACKAGE VERSION 7 ; 4. DON'T WAIT FOR HOLDS TO EXPIRE BEFORE EXITING ; 5. DON'T PUT ;0 IN FILE SPECIFICATIONS ; 6. SAVE ONLY R0-R3 WHEN AST OCCURS ; 7. REMOVE CHANGE TASK NAME OPTION (C$$TSK) ; 8. REMOVE OPTIONAL "BATCH SYSTEM" ABORT MESSAGE ; 9. MAKE VT: PRIVILEGED UNTIL AFTER COMMAND FILE IS ; STARTED TO TRY AND FIX PRIVILEGE VIOLATION PROBLEM ; FOR RSX-11M V4.0. ; 10. REPLACE "TKPS" BY "K$$TPS" FROM RSXMC.MAC. ; ;****************************************************************** .PAGE .MCALL FDBDF$,FDAT$A,FDOP$A,FINIT$,FSRSZ$ .MCALL FDAT$R,NMBLK$,CLOSE$,FDRC$A,PRINT$ .MCALL OPEN$W,PUT$,OPEN$A .MCALL GTIM$S,WSIG$S,ABODF$ .MCALL QUEDF$,UCBDF$,TCBDF$ .MCALL DIR$,ASTX$S,MRKT$,DSAR$S,ENAR$S .MCALL QIOW$,QIO$ .MCALL SPWN$,STSE$,STOP$S,STSE$S .MCALL EXST$S QUEDF$ <:>,<=> ; DEFINE QUEUE PACKET OFFSETS GLOBALLY ; NB. THE QUEDF$ MACRO IS PART OF THE BATCH ; SYSTEM. ALL OTHER MACROS CALLED IN .MCALL ; DIRECTIVES ARE STANDARD RSX11M SYSTEM MACROS. ABODF$ ; DEFINE TASK ABORT CODES TCBDF$ ; DEFINE TCB OFFSETS UCBDF$ <:>,<=> ; DEFINE UCB OFFSETS GLOBALLY .PAGE ; ; CONDITIONAL ASSEMBLY PARAMETERS ; P$$ARM = 0 ; DEFINE THIS SYMBOL IF CONSTRUCTION OF ; PARAMETER LISTS IS ALLOWED (SEE ALSO THE ; SOURCE CODE FOR BAT.TSK). THE VALUE ; GIVEN TO THE SYMBOL IS OF NO IMPORTANCE ; HERE (BUT IT IS IN BAT.TSK) P$$RNT = 1 ; DEFINE THIS SYMBOL FOR AUTOMATIC SPOOLING ; OF LOG FILES AT JOB END ; IF VALUE = 0, USE PRINT$ MACRO (PRT...) ; IF VALUE > 0, USE QUEUE MANAGER WITH DELETION L$$INE = 66. ; IF THIS SYMBOL IS DEFINED, EACH LOG FILE WILL ; BE CLOSED AND OPENED WITH APPEND AFTER THE ; SPECIFIED NUMBER OF LINES, TO PREVENT DATA LOSS ; IN THE EVENT OF A SYSTEM CRASH. T$$CLS = 200. ; SIMILAR TO L$$INE, BUT LOG FILE CONTENTS WILL BE ; SAVED EVERY T$$CLS CYCLES, IF THE FILE HAS BEEN ; WRITTEN TO SINCE THE PREVIOUS SAVE. (ONE CYCLE IS ; 15 SECONDS) ; NOTE THAT THIS IS A DIFFERENT OPTION TO L$$INE BUT ; ACCOMPLISHES A SIMILAR FUNCTION. S$$QUE = 0 ; IF THIS SYMBOL IS DEFINED, BATCH STREAM 1 WILL BE ; CONSIDERED A SHORT JOB QUEUE DURING DAYTIME HOURS. ; THIS IS ONLY EFFECTIVE IF MORE THAN ONE STREAM IS ; RUNNING. L$$CNT = 0 ; IF THIS SYMBOL IS DEFINED, JOBS WILL BE TERMINATED IF ; THEY EXCEED THEIR DESIGNATED OUTPUT LIMIT. ; THIS SYMBOL SHOULD ALSO BE DEFINED IN THE SOURCE FOR ; BAT.TSK A$$SYS = 0 ; DEFINE THIS SYMBOL FOR ACCOUNTING SYSTEM SUPPORT ; JOBS WILL THEN RUN WITH TIME LIMITS MEASURED ; IN TERMS OF CPU+I/O TIME .IF DF A$$SYS ACCDF$ ; DEFINE ACCOUNTING CONTROL BLOCK OFFSETS BITDF$ ; DEFINE ACCOUNTING BIT MASKS .ENDC ; DF A$$SYS ; ; LOCAL DATA ; COLUN = 1 ; CO: MASTER MESSAGE LUN VTLUN = 2 ; LUN FOR LOG FILE READS TO THE VIRTUAL ; TERMINAL DRIVER ON VT0: JBLUN = 3 ; BATCH STREAM MESSAGE LUN ; THIS LUN IS DYNAMICALLY ASSIGNED TO ; THE RELEVANT VIRTUAL TERMINAL LGLUN = 4 ; FIRST LUN AVAILABLE FOR LOG FILE USE. ; LUNS FOLLOWING THIS ARE ASSIGNED BY ; MACRO 'STREAM' EFN1 = 1 ; EVENT FLAG FOR COLUN EFN2 = 2 ; EVENT FLAG FOR JBLUN EFN3 = 3 ; EVENT FOR HEL/BYE WAIT EFN4 = 4 ; EVENT FLAG FOR MARK TIME EFN5 = 5 ; EVENT FLAG FOR LOG FILE READS TO VTDRV ; WE DON'T REALLY NEED AN EVENT FLAG FOR THIS ; READ SINCE IT IS SERVICED BY AN AST ROUTINE. ; THIS IS INCLUDED HERE FOR A POSSIBLE FUTURE ; EXPANSION. EFN6 = 6 ; EVENT FLAG FOR WAIT AFTER ISSUANCE OF @ FILE HT = 11 ; HORIZONTAL TAB LF = 12 ; LINEFEED CR = 15 ; CARRIAGE RETURN ESC = 33 ; ESCAPE SPA = 40 ; SPACE DPT = '. ; DECIMAL POINT COMMA = ', ; COMMA PLUS = '+ ; PLUS FOR CARRIAGE CONTROL DOLLAR = '$ ; DOLLAR FOR CARRIAGE CONTROL SLASH = '/ ; SLASH COLON = ': ; COLON SEMI = '; ; SEMI-COLON CYCLE = 15. ; CYCLE LENGTH IN SECONDS TIMINT = ; CYCLE LENGTH IN TICKS BUFSIZ = 100. ; SIZE OF OUTPUT BUFFER INPSIZ = 162. ; BUFFER SIZE FOR READS TO VTDRV (MUST BE GREATER ; THAN 3 OR VTDRV RETURNS IE.BAD) DEFSIZ = 5 ; INITIAL SIZE FOR LOG FILES (BLOCKS) EXTSIZ = 5 ; EXTEND SIZE FOR LOG FILES (BLOCKS) .PAGE ; ; BATCH COMMAND BIT MASK VALUES ; ; *** I M P O R T A N T *** ; ; THESE BIT MASKS MUST HAVE THE SAME VALUE AS DEFINED ; IN THE SOURCE CODE FOR THE BATCH COMMAND. ; ; MRKABO = 100000 ; JOB MARKED FOR ABORT MRKEXE = 40000 ; JOB IS RUNNING EXMASK = 20 ; /EX SWITCH MASK TRMASK = 40 ; /TR SWITCH MASK DEMASK = 100 ; /DE SWITCH MASK HFMASK = 200 ; /HF SWITCH MASK HUMASK = 400 ; /HU SWITCH MASK KEMASK = 4000 ; /KE SWITCH MASK NOMASK = 10000 ; /NO SWITCH MASK .PAGE ; ; MACROS ; .MACRO CALL SUB JSR PC,SUB .ENDM .MACRO SWSTK$ ADDR EMT 376 .WORD ADDR .ENDM .MACRO PUSH$ REG,NOPUSH .IF B NOPUSH MOV REG,-(SP) .IFF MOV REG,(SP) .ENDC .ENDM .MACRO POP$ REG,NOPOP .IF B NOPOP MOV (SP)+,REG .IFF MOV (SP),REG .ENDC .ENDM .MACRO OPRMSG ERR,ERRSZ MOV ERR,CODPB+Q.IOPL MOV ERRSZ,CODPB+Q.IOPL+2 DIR$ #CODPB .ENDM .MACRO JOBMSG ERR,ERRSZ MOV ERR,JBDPB+Q.IOPL MOV ERRSZ,JBDPB+Q.IOPL+2 CALL $JBDPB .ENDM .MACRO STREAM NUM .PSECT FDBADR .WORD $FDB'NUM .PSECT FDBTAB $FDB'NUM: FDBDF$ LUN=LUN+1 FDAT$A R.VAR,FD.FTN,,DEFSIZ,EXTSIZ FDRC$A ,INPBUF+1,INPSIZ-1 FDOP$A LUN,,$DEF'NUM,FO.WRT,FA.ENB!FA.DLK .PSECT DEFADR .WORD $DEF'NUM .PSECT DEFTAB $DEF'NUM: .IF DF P$$RNT .IF GT P$$RNT NMBLK$ ,LOG,,LB,0 .IFF NMBLK$ ,DMP,,LB,0 .ENDC ; GT P$$RNT .IFF NMBLK$ ,LOG,,LB,0 .ENDC ; DF P$$RNT .IF DF L$$CNT ! T$$CLS ! L$$INE ; *SMT* .PSECT LINES .WORD $VIRT'NUM'+U.JPKT .ENDC .PSECT NSTR=NSTR+1 .ENDM .PAGE ; ; DIRECTIVE PARAMETER BLOCKS ; .EVEN CODPB: QIOW$ IO.WBT,COLUN,EFN1,,,, ; CO: I/O DPB VTDPB: QIO$ IO.RLB,VTLUN,EFN5,,RDSTAT,$IOAST, ; VT0: READ DPB JBDPB: QIOW$ IO.WBT,JBLUN,EFN2,,,, ; BATCH STREAM I/O MARK: MRKT$ EFN4,TIMINT,1 ; MARK TIME DPB ISSMRK: MRKT$ EFN6,<2*K$$TPS>,1 ; WAIT 2 SECONDS AFTER ISSUING @ FILE ISSSTP: STSE$ EFN6 ; WAIT FOR IT .IF DF M$$MUP SPHEL: SPWN$ MCR...,,,1,2,EFN3,,,OUTBUF,3,0,VT SPBYE: SPWN$ MCR...,,,1,2,EFN3,,,BYE,BYESZ,0,VT .ENDC SPIND: SPWN$ MCR...,,,1,2,,,,OUTBUF,3,0,VT .IF DF P$$RNT .IF GT P$$RNT SPRNT: SPWN$ MCR...,,,1,2,,,,OUTBUF,3,0,VT .ENDC .ENDC STOP: STSE$ EFN3 ; HEL/BYE WAIT PAUSE: STSE$ EFN4 ; MARK TIME WAIT BATUCB: .WORD 0 ; UCB ADDRESS OF BATCH STREAM .IF DF A$$SYS PKTADR: .WORD 0 ; DSR CORE BLOCK ADDRESS LOGPTR: .WORD 0 ; LOG...'S TCB ADDRESS LOGNAM=. .RAD50 /LOG.../ ; LOGGING TASK NAME (OVERLAYS OUTBUF) .=LOGNAM .ENDC ; DF A$$SYS ; ; *NOTE* THE NEXT BUFFER (OUTBUF) MUST START ON A WORD BOUNDARY ; OUTBUF: .BLKB BUFSIZ ; OUTPUT BUFFER INPBUF: .BLKB INPSIZ ; INPUT BUFFER (FROM VT0: TO LOG FILES) .EVEN RDSTAT: .BLKW 2 ; I/O STATUS BLOCK FOR VT0: READS TIMBUF: .BLKW 8. ; TIME PARAMETERS BUFFER .IF EQ PRVFLG: .BLKW 1 ; PRIVILEGES FLAG (0=NO, 1=YES) .ENDC ; EQ .PSECT DEFDIR $DNAM:: .WORD "LB ; DEFAULT LOG FILE DEVICE NAME $DEVU:: .WORD 0 ; DEFAULT LOG FILE DEVICE UNIT NUMBER $DUFD:: .ASCII /[001,071]/ ; IF /KE WAS NOT SPECIFIED AT JOB SUBMISSION ; TIME THEN THIS STRING GIVES THE DIRECTORY ; INTO WHICH THE LOG FILE WILL BE WRITTEN. DIRSZ=.-$DUFD .=.+1 ; (UFD STRING MUST HAVE AN EVEN NUMBER OF CHARS. ; FOR GBLPAT) .PSECT .EVEN BINUFD: .WORD 0 ; BINARY DEFAULT DIRECTORY FOR LOG FILES ; ; TEXT MESSAGES ; .NLIST BEX .ENABL LC MSG1: .ASCII /BATMAN -- Exiting/ MSG1SZ=.-MSG1 JOBST: .ASCIZ /JOB / SPE: .ASCII /** BATCH -- Spawn error **/ SPESZ=.-SPE .IF DF M$$MUP BYE: .ASCII /BYE/ BYESZ=.-BYE HEL: .ASCIZ /HEL / .ENDC .IF DF P$$RNT .IF GT P$$RNT PRNT: .ASCIZ /PRINT J/ .ENDC .ENDC OPEN: .ASCIZ /Log file open error / NFLAG: .ASCIZ %/-FL/LE:62.=% ; *SMT APRIL 7,1981 * .EVEN .PSECT FDBADR $FDB: ; LABEL OF LOG FILE FDB TABLE .PSECT DEFADR $DEF: ; LABEL OF LOG FILE DEFAULT FILENAME BLOCK TABLE .IF DF L$$CNT ! T$$CLS ! L$$INE ; *SMT* .PSECT LINES $JOB: ; TABLE OF POINTERS TO JOB PACKETS FOR LINE COUNTS .PSECT .ENDC ; DF L$$CNT ! T$$CLS ! L$$INE ; *SMT* .PSECT NSTR=0 LUN=LGLUN-1 STREAM 1 ; DEFINE DATA STRUCTURES FOR BATCH STREAM #1 STREAM 2 ; DEFINE DATA STRUCTURES FOR BATCH STREAM #2 STREAM 3 ; DEFINE DATA STRUCTURES FOR BATCH STREAM #3 STREAM 4 ; DEFINE DATA STRUCTURES FOR BATCH STREAM #4 ; IF ADDITIONAL BATCH STREAMS ARE REQUIRED, SIMPLY ; INSERT "STREAM 3", "STREAM 4" ETC. HERE. BEAR IN ; MIND THAT ENOUGH VT:'S MUST BE SYSGENED INTO THE ; SYSTEM AND THE LIMITATION ON THE MAXIMUM SIZE ; OF PRIVILEGED TASKS IN RSX11M. ; THE NUMBER OF STREAMS MAY BE LESS THAN THE NUMBER ; OF VT:'S IN THE SYSTEM. .IF DF L$$INE .PSECT LINCNT ; DEFINE TABLE TO CONTAIN LOG FILE LINE COUNTS $LIN: .REPT NSTR .WORD L$$INE .ENDR .PSECT .ENDC ; DF L$$INE .IF DF T$$CLS .PSECT CYCCNT ; TABLE TO CONTAIN CYCLE COUNTS FOR FILE SAVES $CYC: .REPT NSTR .WORD T$$CLS .ENDR .PSECT .ENDC ; DF T$$CLS .IIF EQ NSTR .ERROR ; MACRO 'STREAM' NOT USED FSRSZ$ NSTR ; ALLOCATE FSR .PAGE .SBTTL MAIN PROGRAM $BTMEP:: ; XFR ADDRESS ; ; INITIALISE CONTROL BLOCK FOR ACCOUNTING SYSTEM COMMUNICATION ; .IF DF A$$SYS MOV #LOGNAM,R3 ; GET NAME OF LOGGING TASK CALL $SRSTD ; SEARCH SYSTEM TASK DIRECTORY BCS EXIT ; IF NOT INSTALLED WE CAN'T GO ON MOV R0,LOGPTR ; SAVE THE RESULT SWSTK$ 1$ ; SWITCH STACKS MOV #B.LTSF,R1 ;; GET LENGTH OF CONTROL BLOCK TO ALLOCATE CLR PKTADR ;; SET NO BLOCK ALLOCATED CALL $ALOCB ;; GET A DSR BLOCK BCS 2$ ;; IF CS ERROR MOV R0,PKTADR ;; SAVE CONTROL BLOCK ADDRESS 2$: RETURN ;; RETURN TO USER STATE 1$: TST PKTADR ; DID WE GET A CORE BLOCK? BEQ EXIT ; IF NO, EXIT .ENDC ; DF A$$SYS ; ; INITIALISE FSR AND SET UP DEFAULT DIRECTORY WORD ; MOV #OUTBUF+2,R2 ; GET ADDRESS+2 OF DEFAULT DIRECTORY DESCRIPTOR MOV #$DUFD,(R2) ; FILL IN ASCII DIRECTORY STRING ADDRESS MOV #DIRSZ,-(R2) ; AND ITS SIZE MOV #BINUFD,R3 ; GET ADDRESS OF LOCATION FOR DEFAULT DIRECTORY WORD CALL .ASCPP ; CONVERT UFD STRING TO BINARY BCS EXIT ; IF CS THEN IT WAS ILLEGAL FINIT$ ; ; ; LOG SYSTEM ACCOUNT ON TO VT0: ; MOV #$VIRT0,R0 ; GET UCB ADDRESS OF VT0: MOV #401,U.UIC(R0) ; SET DEFAULT UIC *SMT* MOV #401,U.LUIC(R0) ; AND LOGON UIC *SMT* BIC #U2.LOG,U.CW2(R0) ; LOG ON VT0: BIS #U2.PRV,U.CW2(R0) ; AND SET IT PRIVILEGED ; ; SET UP AST'S AND START MARK TIME CYCLE ; 5$: DIR$ #VTDPB ; ISSUE A READ TO VTDRV BCS EXIT ; IF ERROR THEN EXIT ; AN ERROR MIGHT OCCUR IF VTDRV IS NOT ; LOADED, AMONG OTHER THINGS. DIR$ #MARK ; ISSUE MARK TIME BCS EXIT ; ERROR BR 15$ ; WAIT FOR CYCLE TO FINISH 10$: DIR$ #MARK ; RESTART CYCLE CALL $MKCYC ; EXAMINE THE QUEUES 15$: DIR$ #PAUSE ; WAIT FOR CYCLE TO FINISH BR 10$ ; DO IT ALL OVER AGAIN EXIT: OPRMSG #MSG1,#MSG1SZ ; EXITING MESSAGE EXST$S #EX$SEV ; EXIT WITH SEVERE ERROR .PAGE .SBTTL VT: READ REQUEST AST ROUTINE ;+ ; ; *** $IOAST ; ; THIS ROUTINE IS ENTERED AS A RESULT OF AN AST CAUSED BY ; A READ REQUEST TO THE VIRTUAL TERMINAL DRIVER BEING ; SATISFIED. THE LINE OF INPUT RECEIVED IS WRITTEN TO THE ; APPROPRIATE LOG FILE. ; ;- $IOAST: PUSH$ R0,NOPUSH ; SAVE R0, REPLACING THE TRAP DEPENDENT ; PARAMETER (I/O STATUS BLOCK ADDRESS) ON ; THE STACK PUSH$ R1 ; SAVE R1 PUSH$ R2 ; SAVE R2 PUSH$ R3 ; SAVE R3 CMPB #IS.SUC,RDSTAT ; WAS THE READ SUCCESSFUL? BNE IOASTR ; IF NE THEN AN ERROR, FORGET IT MOV RDSTAT+2,R1 ; GET BYTE COUNT DEC R1 ; REMOVE VT: UNIT FLAG BYTE FROM COUNT CLR R2 ; CLEAR R2 READY FOR UNIT NUMBER BISB INPBUF,R2 ; SET UNIT NUMBER IN R2 BLE IOASTR ; IF LE THEN IT'S ILLEGAL CMP R2,#NSTR ; UNIT NUMBER TOO BIG? BGT IOASTR ; YES, TRY ANOTHER READ DEC R2 ; REMOVE VT0: BIAS ASL R2 ; CONVERT TO INDEX MOV $FDB(R2),R0 ; GET FDB ADDRESS PUT$ ,,R1 ; WRITE THE RECORD TO THE LOG FILE .IF DF L$$CNT MOV @$JOB(R2),R1 ; GET JOB PACKET ADDRESS INC Q.LINE(R1) ; UPDATE LINE COUNT .ENDC ; DF L$$CNT .IF DF L$$INE .IIF LE L$$INE-10., .ERROR ; ILLEGAL L$$INE VALUE DEC $LIN(R2) ; UPDATE LINE COUNT BNE IOASTR ; IF NE NOT TIME TO CLOSE YET MOV #L$$INE,$LIN(R2) ; RESET LINE COUNT CALL $SAVE ; CLOSE LOG FILE AND REOPEN WITH APPEND .ENDC ; L$$INE IOASTR: DIR$ #VTDPB ; ISSUE ANOTHER READ POP$ R3 ; RESTORE R3 POP$ R2 ; RESTORE R2 POP$ R1 ; RESTORE R1 POP$ R0 ; RESTORE R0 ASTX$S ; END OF AST ROUTINE .PAGE .SBTTL MARK TIME CYCLE ROUTINE ;+ ; *** $MKCYC ; THIS ROUTINE IS ENTERED AT THE END OF EVERY MARK TIME ; INTERVAL. IT CHECKS THE STATUS OF THE BATCH QUEUE. ; ALL BATCH QUEUE OPERATION IS SUPERVISED BY THIS ; ROUTINE. ; ;- $MKCYC: BIT #QQ.EXT,$QSTAT ; BATCH MARKED FOR EXIT? BEQ 1$ ; NO TST $CURJ ; YES, ANY EXECUTING JOBS? BNE 1$ ; YES, CAN'T EXIT YET DSAR$S ; INHIBIT AST RECOGNITION CLR VTDPB+Q.IOAE ; NO AST REQUIRED MOV #IO.KIL,VTDPB+Q.IOFN ; SET UP TO KILL VT: I/O DIR$ #VTDPB ; DO IT BCS 99$ ; JUST IN CASE STSE$S #EFN5 ; WAIT FOR KILL TO COMPLETE 99$: JMP EXIT ; AND EXIT 1$: TST $NUMQ ; ANY JOBS IN THE QUEUE? BEQ MKCYCR ; NO, RETURN CALL $QLOCK ; LOCK THE BATCH SYSTEM LISTS MOV #$HOLDQ,R2 ; GET HOLD QUEUE LISTHEAD ADDRESS 2$: MOV (R2),R1 ; GET NEXT ENTRY ADDRESS BEQ 8$ ; IF EQ THEN END OF LIST SUB #TIMINT,Q.HOLD+2(R1) ; UPDATE HOLD TIME SBC Q.HOLD(R1) ; BLT 4$ ; IF LT THEN JOB IS OUT OF HOLD MOV R1,R2 ; POINT TO NEXT ENTRY BR 2$ ; AND TRY IT 4$: BIC #HFMASK!HUMASK,Q.MASK(R1) ; CLEAR HOLD BITS MOV (R1),(R2) ; CLOSE UP LIST AND REMOVE ENTRY BNE 6$ ; IF NE THEN NOT AT END OF LIST MOV R2,$HOLDQ+2 ; END OF LIST SO CORRECT LISTHEAD 6$: CALL $QLINK ; LINK INTO JOB QUEUE ; (ALL REGISTERS MUST BE PRESERVED) BR 2$ ; KEEP GOING 8$: CALL $QUNLK ; UNLOCK BATCH SYSTEM LISTS .IF GT NSTR-1 MOV #$VTDCB,R0 ; GET ADDRESS OF VT: DCB MOV #NSTR,R4 ; GET # VT:'S ; NOT INCLUDING VT0: MOV D.UCBL(R0),R3 ; SAVE LENGTH OF EACH UCB MOV #$VIRT1,R5 ; POINT R5 TO VT1: .IFF MOV #$VIRT1,BATUCB ; POINT BATCH STREAM TO VT1: .IFT 20$: MOV R5,BATUCB ; SAVE UCB ADDRESS .IFTF CALL $CHECK ; PERFORM QUEUE CHECK ON THIS UNIT .IFT ADD R3,R5 ; POINT TO NEXT UCB DEC R4 ; ARE THERE ANY? BNE 20$ ; YES .ENDC MKCYCR: RETURN ; NO, RETURN TO CALLER .PAGE .SBTTL QUEUE CHECK ROUTINE ;+ ; *** $CHECK ; ; THIS ROUTINE IS CALLED EVERY MARK TIME CYCLE. ITS FUNCTION ; IS TO CHECK THE STATUS OF EACH BATCH STREAM, AND TO ; START OR FINISH BATCH JOBS AS APPROPRIATE. ; ; ON INPUT, "BATUCB" CONTAINS THE UCB ADDRESS OF THE BATCH ; STREAM TO CHECK. ; ;- $CHECK: .IF GT NSTR-1 JSR R5,$SAVRG ; SAVE R3,R4 AND R5 .ENDC MOV BATUCB,R0 ; GET BATCH UCB ADDRESS MOV U.JPKT(R0),R5 ; GET JOB PACKET ADDRESS BIT #U2.LOG,U.CW2(R0) ; BATCH LOGGED ON? BEQ 20$ ; YES TST R5 ; NO, IS THERE A JOB ACTIVE? BEQ 15$ ; NO, SEE IF WE CAN START ONE CALL $ABRT1 ; MAKE SURE NOTHING IS RUNNING BECAUSE... ; ... BATCH TERMINAL IS LOGGED OFF CALL $JBEND ; FORCE THE END OF THE JOB (NOTE THAT SINCE ; NO WAIT FOLLOWS THE CALL TO $ABRT1, WE MAY ; LOSE SOME TKTN MESSAGES IN THE LOG FILE ; IN RARE CIRCUMSTANCES) 15$: BIT #QQ.RDN,$QSTAT ; IS THE QUEUE IN RUNDOWN? BNE CHECKR ; YES, DON'T START THE NEXT JOB BIT #FE.NLG,$FMASK ; NO, BUT ARE LOGINS DISABLED? BNE CHECKR ; YES, DON'T START THE NEXT JOB CALL $NEXTJ ; NO, LOOK FOR NEXT JOB TO START BCS CHECKR ; IF CS NO ELIGIBLE JOBS CALL $START ; START THE NEXT JOB BCS 15$ ; ERROR, TRY LOOKING AGAIN BR CHECKR ; OK, NO MORE THIS CYCLE 20$: BIT #MRKABO,Q.MASK(R5) ; IS THE JOB MARKED FOR ABORT? BEQ 25$ ; NO BIC #MRKABO,Q.MASK(R5) ; YES, CLEAR THE MARKER MOV #2,R0 ; SET ABORT CODE CALLR $ABORT ; ABORT THE JOB AND END CYCLE 25$: ; .IF DF L$$CNT CMP Q.LINE(R5),Q.MXLN(R5) ; JOB EXCEEDED OUTPUT LIMIT? BLT 26$ ; NO, OR JUST ABOUT TO MOV #30000.,Q.MXLN(R5) ; YES, SET HIGH LIMIT SO THAT BYE WILL ; NOT BE TERMINATED MOV #3,R0 ; SET ABORT CODE CALLR $ABORT ; AND ABORT THE JOB 26$: ; REF. LABEL .ENDC ; DF L$$CNT SWSTK$ 45$ ; SWITCH STACKS CLR 2(SP) ;; SET FLAG FOR TASK CHECK ;; 2(SP) IS THE USER STATE R0 MOV $TSKHD,R5 ;; GET SYSTEM TASK DIRECTORY LIST HEAD ;; $TSKHD RATHER THAN #$TSKHD CAUSES ;; THE FIRST ENTRY IN THE LIST (THE LOADER) ;; TO BE SKIPPED. 30$: TST T.TCBL(R5) ;; NULL TASK? BEQ 40$ ;; YES, END OF LIST CMP T.UCB(R5),BATUCB ;; IS TASK IN BATCH STREAM? BNE 35$ ;; NO CMP R5,$MCRPT ;; MCR? BEQ 35$ ;; YES BIT #TS.EXE,T.STAT(R5) ;; TASK ACTIVE? BNE 35$ ;; NO CMP $TKTCB,R5 ;; IS IT US? BEQ 35$ ;; YES, DON'T INCLUDE US INC 2(SP) ;; LET FLAG SHOW TASK ACTIVE AT BATUCB BR 40$ ;; ONE IS ENOUGH TO SHOW THAT JOB ;; IS STILL RUNNING 35$: MOV T.TCBL(R5),R5 ;; POINT TO NEXT TASK BR 30$ ;; AND CHECK IT 40$: RETURN ;; 45$: TST R0 ; TEST BATCH JOB STATUS BGT 55$ ; JOB IS STILL RUNNING 50$: CALL $LGOFF ; JOB FINISHED, LOG OFF THE USER BR 15$ ; START NEXT JOB 55$: CALL $JOBTM ; SEE IF TIME LIMIT HAS EXPIRED MOV Q.TIME(R5),R1 ; GET ORIGINAL TIME LIMIT MOV Q.TIME+2(R5),R2 ; SUB Q.HOLD+2(R5),R2 ; SUBTRACT TIME USED SO FAR SBC R1 ; SUB Q.HOLD(R5),R1 ; BGE 60$ ; IF GE JOB HAS TIME LEFT MOV #1,R0 ; SET TIME EXPIRED ABORT CODE CALLR $ABORT ; ABORT THE JOB BECAUSE THE TIME ; LIMIT HAS EXPIRED 60$: ; REF. LABEL .IF DF T$$CLS MOV BATUCB,R0 ; GET BATCH STREAM UCB ADDRESS CLR R2 ; CLEAR REGISTER FOR UNIT NUMBER BISB U.UNIT(R0),R2 ; GET UNIT NUMBER DEC R2 ; REMOVE VT0: BIAS ASL R2 ; CONVERT TO AN INDEX DEC $CYC(R2) ; TIME TO SAVE LOG FILE? BNE CHECKR ; NO, JUST RETURN .IF DF L$$INE CMP $LIN(R2),#L$$INE ; ANYTHING WRITTEN SINCE LAST SAVE? BEQ CHECKR ; NO, JUST RETURN .ENDC ; DF L$$INE MOV #T$$CLS,$CYC(R2) ; RESET COUNT MOV $FDB(R2),R0 ; GET LOG FILE FDB ADDRESS DSAR$S ; DISABLE AST RECOGNITION CALL $SAVE ; SAVE LOG FILE ENAR$S ; ENABLE AST RECOGNITION .ENDC ; DF T$$CLS CHECKR: RETURN ; RETURN TO CALLER .PAGE .SBTTL LOG FILE SAVE ROUTINE ;+ ; *** $SAVE ; ; THIS ROUTINE IS CALLED WHEN IT IS TIME TO SAVE THE CONTENTS ; OF A LOG FILE, TO AVOID DATA LOSS IN THE EVENT OF A CRASH. ; THE FILE IS CLOSED AND OPENED WITH APPEND ACCESS. ; ; INPUTS: ; R0 FDB ADDRESS ; R2 DATA STRUCTURE TABLE INDEX ; *SMT* ; ; OUTPUTS: ; R0 PRESERVED ; R1,R2,R3 ARE USED ; ;- .IF DF T$$CLS ! L$$INE $SAVE: MOV @$JOB(R2),R1 ; GET JOB PACKET ADDRESS ; *SMT* MOV Q.LUIC(R1),R1 ; GET LOGON UIC FOR OWNERSHIP ; *SMT* CALL .WFOWN ; WRITE FILE OWNER WORD ; *SMT* MOV #INPBUF,R1 ; GET ADDRESS OF BUFFER TO SAVE FILENAME BLOCK MOV R0,R2 ; POINT R2 TO FILENAME BLOCK ADD #F.FNB,R2 ; MOV #S.FNB,R3 ; GET SIZE OF FILENAME BLOCK 10$: MOVB (R2)+,(R1)+ ; COPY A BYTE DEC R3 ; DONE YET? BNE 10$ ; NO CLOSE$ R0 ; CLOSE THE FILE MOV #S.FNB,R3 ; GET SIZE OF FILENAME BLOCK AGAIN 20$: MOVB -(R1),-(R2) ; MOVE A BYTE BACK DEC R3 ; DONE? BNE 20$ ; NO OPEN$A R0 ; REOPEN LOG FILE FOR APPEND RETURN ; AND RETURN .ENDC ; DF T$$CLS ! L$$INE .PAGE .SBTTL JOB TIME FIND ROUTINE ;+ ; *** $JOBTM ; ; THIS ROUTINE IS CALLED EVERY SO OFTEN TO UPDATE THE JOB TIME ; USED IN EACH EXECUTING JOB'S PACKET. IF THE TIME LIMIT IS FOUND ; TO HAVE EXPIRED, THE JOB IS MARKED FOR ABORT. ; THIS ROUTINE REQUIRES THAT SUPPORT FOR THE "TSF" COMMAND HAS ; BEEN GENERATED INTO THE ACCOUNTING SYSTEM. ; ; INPUTS: ; R5 JOB PACKET ADDRESS ; BATUCB UCB ADDRESS OF BATCH STREAM TO CHECK ; ; OUTPUTS: ; R5 PRESERVED ; ;- $JOBTM: .IF DF A$$SYS SWSTK$ 20$ ; SWITCH STACKS MOV PKTADR,R1 ;; GET ADDRESS OF CONTROL BLOCK MOV $TKTCB,B.TTCB(R1) ;;INSERT OUR TCB ADDRESS MOV #,B.MASK(R1) ;;INSERT COMMAND MASK MOV #,B.TTYP(R1) ;;COMMAND TYPE MASK (TELL ALL) MOV BATUCB,B.UCB(R1) ;; INSERT BATCH STREAM UCB ADDRESS MOV LOGPTR,R0 ;; GET LOG...'S TCB ADDRESS CALL $EXRQF ;; QUEUE PACKET AND START LOG... CALLR $STPCT ;; STOP US UNTIL WE GET A REPLY 20$: MOV PKTADR,R0 ; GET ADDRESS OF THE PACKET WE FOUND MOV B.CSF(R0),Q.HOLD(R5) ; PUT RESULTS INTO JOB PACKET MOV B.CSF+2(R0),Q.HOLD+2(R5) ; .IFF ADD #TIMINT,Q.HOLD+2(R5) ; UPDATE TIME USED ADC Q.HOLD(R5) ; .ENDC ; DF A$$SYS RETURN ; .PAGE .SBTTL SELECTIVE NEXT JOB ROUTINE ;+ ; *** $RMJOB ; ; THIS ROUTINE IS CALLED TO REMOVE A JOB SELECTIVELY FROM THE ; NORMAL JOB QUEUE. IF IT IS NOT VT1:, OR THE TIME LIMIT IS ; ACCEPTABLE FOR A DAYTIME JOB, OR IT IS NOT DAYTIME, A JOB IS ; REMOVED, ELSE A CARRY SET INDICATION IS RETURNED. ; ON ENTRY TO THIS ROUTINE, WE ARE ON THE SYSTEM STACK WITH ; CONTEXT SWITCHING INHIBITED. ; ; ; INPUTS: ; R0 QUEUE LISTHEAD ADDRESS ; ;- .IF GT NSTR-1 .IF DF S$$QUE $RMJOB: CMP BATUCB,#$VIRT1 ;; IS JOB TO BE ON VT1:? BEQ 5$ ;; *SMT* IF EQ YES CMP BATUCB,#$VIRT4 ;; *SMT*IS JOB TO BE ON VT4:? BNE QRM ;; *SMT* NO, OK TO START WHATEVER TIME LIMIT IS MOV (R0),R1 ;; *SMT* GET FIRST JOB PACKET ADDRESS BEQ 20$ ;; *SMT* IF EQ QUEUE WAS EMPTY CMP Q.TIME+2(R1),#$TVT4 ;; *SMT* JOB SHORT ENOUGH TO START? BLE QRM ;; *SMT* IF LE YES BR 20$ ;; *SMT* ELSE NO 5$: MOV (R0),R1 ;; GET FIRST JOB PACKET ADDRESS BEQ 20$ ;; IF EQ, QUEUE WAS EMPTY MOV #$TNITE,R2 ;; ASSUME NIGHT TIME JOB LIMIT CMP $TTNS-6,#$DAY ;; IS IT DAYTIME? BLT 10$ ;; NO, CHECK JOB AGAINST NIGHT LIMIT CMP $TTNS-6,#$NIGHT ;; IS IT NIGHTIME? BGE 10$ ;; YES, CHECK JOB AGAINST NIGHT LIMIT MOV #$TDAY,R2 ;; IT'S DAYTIME, SET JOB LIMIT 10$: CMP Q.TIME+2(R1),R2 ;; IS JOB SHORT ENOUGH TO START? BLE QRM ;; YES, REMOVE FROM QUEUE 20$: SEC ;; SET FAILURE BR RMJOBR ;; AND RETURN QRM: CALLR $QRMVF ;; REMOVE JOB FROM QUEUE RMJOBR: RETURN ;; AND RETURN TO CALLER .ENDC ; DF S$$QUE .ENDC ; GT NSTR-1 .PAGE .SBTTL NEXT JOB SEARCH ROUTINE ;+ ; *** $NEXTJ ; THIS ROUTINE SCANS THE BATCH QUEUE TO GET THE ; NEXT JOB ELIGIBLE FOR STARTING. ; IF FOUND, THE JOB IS LINKED INTO THE ; EXECUTING JOB LIST, AND IS MARKED AS ; BEING IN EXECUTION. THE ; RELEVANT PACKET AND UCB AREAS ARE INITIALISED. ; ; OUTPUT: (WHEN BACK IN USER STATE AFTER CALL) ; CARRY SET - NO JOBS ELIGIBLE FOR EXECUTION ; CARRY CLEAR - JOB FOUND, PACKET ADDRESS IN R5 ; ;- $NEXTJ: SWSTK$ NEXTJR ; SWITCH STACKS MOV #$EXPRQ,R0 ;; TRY EXPRESS QUEUE FIRST CALL $QRMVF ;; REMOVE A JOB FROM THE QUEUE BCC 5$ ;; GOOD, WE GOT ONE MOV #$QUEHD,R0 ;; OK, TRY THE NORMAL JOB QUEUE .IF GT NSTR-1 .IF DF S$$QUE CALL $RMJOB ;; GET THE NEXT JOB FROM THE QUEUE .IFF CALL $QRMVF ;; GET NEXT ELIGIBLE JOB .ENDC ;; DF S$$QUE .IFF CALL $QRMVF ;; .ENDC ;; GT NSTR-1 BCC 5$ ;; OK, GOT ONE MOV @$HEADR,R0 ;; NO JOBS ELIGIBLE FOR EXECUTION, SO ;; GET USER STATE STACK POINTER INC 6(R0) ;; SET THE CARRY BIT IN USER PS WORD BR NEXTJR ;; RETURN TO USER LEVEL AND CALLER 5$: MOV R1,14(SP) ;; SET USER LEVEL R5 TO PACKET ADDRESS BIS #MRKEXE,Q.MASK(R1) ;; MARK JOB AS EXECUTING MOV BATUCB,R2 ;; GET BATCH STREAM UCB ADDRESS MOV R2,Q.UCB(R1) ;; SET UCB ADDRESS IN JOB PACKET MOV R1,U.JPKT(R2) ;; SET PACKET ADDRESS IN UCB CLR Q.HOLD(R1) ;; SHOW NO TIME USED BY JOB YET CLR Q.HOLD+2(R1) ;; MOV #$CURJ,R0 ;; GET EXECUTING JOBS LISTHEAD ADDRESS CALLR $QINSF ;; INSERT JOB INTO LIST NEXTJR: RETURN ;; RETURN TO USER LEVEL AND CALLER .PAGE .SBTTL BATCH JOB MESSAGE ROUTINE ;+ ; *** $JBDPB ; ; THIS ROUTINE ASSIGNS JBLUN TO THE CURRENT BATCH STREAM ; AND TYPES OUT A MESSAGE ; THE MESSAGE PARAMETERS ARE ASUUMED TO HAVE ALREADY BEEN SET ; UP IN THE DPB ; ; INPUTS: ; R5 JOB PACKET ADDRESS ; ; ALL REGISTERS ARE PRESERVED ;- $JBDPB: SWSTK$ 10$ ; SWITCH STACKS MOV $HEADR,R0 ;; GET OUR HEADER ADDRESS MOV Q.UCB(R5),H.LUN+<4*>(R0) ;; ;; ASSIGN LUN (WRITE UCB ADDRESS IN HEADER) RETURN ;; RETURN TO USER STATE 10$: DIR$ #JBDPB ; WRITE MESSAGE TO BATCH JOB RETURN ; RETURN TO CALLER .PAGE .SBTTL FILE SPECIFICATION FORMAT ROUTINE ;+ ; *** $FILE ; ; THIS ROUTINE IS CALLED TO FILL IN THE FILE SPECIFICATION ; FOR A JOB THAT IS ABOUT TO BE STARTED OR FOR A LOG FILE ; THAT IS ABOUT TO BE SPOOLED. ; ; INPUTS: ; R0 BUFFER ADDRESS ; R5 JOB PACKET POINTER ; INPUTS (IF ENTRY AT $FIL1): ; R0 BUFFER ADDRESS ; R1 LOG FILE DEVICE UNIT NUMBER (BINARY) ; R3 BINARY UFD IN WHICH LOG FILE SITS ; R5 POINTER TO FILENAME INFORMATION ; ; OUTPUTS: ; R0 UPDATED ; R5 PRESERVED ; R1,R2,R3 USED ; ;- .IF DF P$$RNT .IF GT P$$RNT $FIL1: PUSH$ R5 ; SAVE R5 BR FILE0 ; GO FORMAT PARTIAL SPEC. .ENDC .ENDC $FILE: PUSH$ R5 ; SAVE R5 MOV Q.DUIC(R5),R3 ; PUT DIRECTORY UIC IN R3 ADD #Q.DEVN,R5 ; POINT R5 TO DEVICE NAME MOVB (R5)+,(R0)+ ; MOVE IT IN (USE MOVB'S BECAUSE... MOVB (R5)+,(R0)+ ; ...BUFFER MAY NOT BE WORD ALIGNED) MOV (R5)+,R1 ; GET UNIT NUMBER FILE0: CALL $OCTAL ; CONVERT TO OCTAL MOVB #COLON,(R0)+ ; INSERT DEVICE/UIC SEPARATOR CALL $FUIC ; INSERT THE UIC CALL $RAD50 ; FILENAME, PART 1 CALL $RAD50 ; FILENAME, PART 2 CALL $RAD50 ; FILENAME, PART 3 MOVB #DPT,(R0)+ ; NAME/TYPE SEPARATOR CALL $RAD50 ; FILETYPE MOV (R5)+,R1 ; GET VERSION NUMBER BEQ 10$ ; IF EQ SKIP IT MOVB #SEMI,(R0)+ ; TYPE/VERSION SEPARATOR CALL $OCTAL ; CONVERT TO OCTAL 10$: POP$ R5 ; RESTORE R5 RETURN ; AND RETURN .PAGE .SBTTL QUEUE LINK ROUTINE ;+ ; *** $QLINK ; ; THIS ROUTINE IS CALLED TO LINK A JOB PACKET INTO ; THE RIGHT JOB QUEUE WHEN IT HAS BEEN REMOVED FROM ; THE HOLD QUEUE AFTER EXPIRATION OF THE HOLD TIME. ; EVERYTHING IS DONE AT SYSTEM LEVEL, AND AS A ; CONSEQUENCE OF THIS, ALL REGISTERS ARE ; PRESERVED. ; ; INPUT: ; R1 JOB PACKET ADDRESS ; ; OUTPUT: ; ALL REGISTERS PRESERVED ; ;- $QLINK: SWSTK$ QLINKR ; SWITCH STACKS MOV R1,R5 ;; COPY JOB PACKET ADDRESS TO R5 MOV #$EXPRQ,R0 ;; ASSUME THAT IT'S EXPRESS BIT #EXMASK,Q.MASK(R5) ;; IS IT AN EXPRESS JOB? BEQ 5$ ;; NO, IT MUST BE A NORMAL JOB CALLR $QINSF ;; LINK ON TO END OF EXPRESS QUEUE 5$: MOV #$QUEHD,R1 ;; GET LISTHEAD ADDRESS (NORMAL JOBS) 10$: MOV R1,R0 ;; SAVE CURRENT ENTRY ADDRESS MOV (R0),R1 ;; GET ADDRESS OF NEXT ENTRY BEQ 20$ ;; IF EQ, END OF LIST CMP Q.TIME+2(R5),Q.TIME+2(R1) ;; DOES THE NEW ENTRY HAVE... ;; .. A HIGHER OR SAME TIME LIMIT? BGE 10$ ;; YES, IT DOESN'T GO HERE MOV R1,(R5) ;; LINK CURRENT TO NEW JOB ENTRY BR 30$ ;; 20$: MOV R5,$QUEHD+2 ;; SET ADDRESS OF NEW LAST ENTRY CLR (R5) ;; CLEAR LINK TO NEXT ENTRY 30$: MOV R5,(R0) ;; LINK NEW TO PREVIOUS ENTRY QLINKR: RETURN ;; BACK TO USER LEVEL AND CALLER .PAGE .SBTTL JOB ISSUE ROUTINE ;+ ; *** $ISSUE ; THIS ROUTINE STARTS A NEW BATCH JOB CRUNCHING ; BY ISSUING THE COMMAND FILE TO ...AT. ; ; INPUT: ; R5 JOB PACKET ADDRESS ; ; OUTPUT: ; CC SPAWN OK ; CS SPAWN FAILURE ;- $ISSUE: MOV #OUTBUF,R0 ; GET BUFFER ADDRESS MOVB #'@,(R0)+ ; INSERT "@" CALL $FILE ; FILL IN FILE SPECIFICATION MOV Q.MASK(R5),R4 ; AND GET SWITCH MASK BIT #TRMASK,R4 ; /TR SPECIFIED? BEQ 15$ ; NO MOVB #SLASH,(R0)+ ; YES, INSERT "/TR" MOVB #'T,(R0)+ ; MOVB #'R,(R0)+ ; 15$: BIT #DEMASK,R4 ; /DE SPECIFIED? BEQ 20$ ; NO MOVB #SLASH,(R0)+ ; YES, INSERT "/DE" MOVB #'D,(R0)+ ; MOVB #'E,(R0)+ ; 20$: ; REF. LABEL .IF DF P$$ARM MOV R0,R4 ; COPY BUFFER POINTER TO R4 30$: MOV R5,R0 ; POINT R0 TO PARAMETER LISTHEAD ADD #Q.PARM,R0 ; CALL $QRMVF ; REMOVE A PACKET (NOBODY ELSE WILL ; REFERENCE THIS LIST, SO WE DON'T ; REALLY NEED TO SWITCH STACKS) BCS 50$ ; IF CS NO MORE PARAMETERS MOV R1,R3 ; COPY PACKET ADDRESS TO R3 ADD #4,R3 ; POINT TO START OF PARAMETER MOVB #SPA,(R4)+ ; SEPARATE PARAMETERS WITH A SPACE 40$: MOVB (R3)+,(R4)+ ; MOVE IN THE PARAMETER BNE 40$ ; LOOP TO END DEC R4 ; REMOVE THE NULL BYTE MOV R1,R0 ; COPY PARAMETER PACKET ADDRESS TO R0 MOV 2(R0),R1 ; GET PACKET SIZE SWSTK$ 30$ ; SWITCH STACKS CALLR $DEACB ;; DEALLOCATE THE PARAMETER PACKET TO ;; THE POOL AND TRY THE NEXT ONE 50$: MOV R4,R0 ; RESTORE BUFFER POINTER TO R0 CMP R0,#OUTBUF+79. ; IS THE COMMAND NOW TOO LONG? BLOS 60$ ; NO, IT'S OK MOV #OUTBUF+79.,R0 ; YES, TRIM IT TO FIT .ENDC ; DF P$$ARM 60$: MOVB #CR,(R0)+ ; PUT IN CARRIAGE RETURN SUB #OUTBUF,R0 ; CALCULATE STRING LENGTH MOV #SPIND,R4 ; GET SPAWN DPB ADDRESS MOV R0,S.PWCL(R4) ; SET COMMAND LINE LENGTH CALL $SETSP ; SET SPAWN PARAMETERS JOBMSG #OUTBUF,R0 ; TYPE OUT COMMAND LINE ; THIS GOES TO THE LOG FILE .IF EQ CALL SPRIV1 ; REMEMBER PRIVILEGE STATUS .IFTF CALL $SPAWN ; SPAWN INDIRECT FILE PROCESSOR BCS 70$ ; SPAWN ERROR DIR$ #ISSMRK ; MARK TIME FOR A WHILE BCS 75$ ; JUST IN CASE DIR$ #ISSSTP ; WAIT FOR MARK TIME TO COMPLETE BR 75$ ; AND RETURN 70$: JOBMSG #SPE,#SPESZ ; SPAWN FAILURE MESSAGE 75$: ; REF.LABEL .IFT CALL SPRIV2 ; RESET PRIVILEGE STATUS .ENDC ; EQ ISSUER: RETURN ; RETURN TO CALLER .PAGE .SBTTL PRIVILEGE SET/RESET ROUTINES ;+ ; *** SPRIV1 ; *** SPRIV2 ; ; THESE ROUTINES CAUSE THE VIRTUAL TERMINAL TO BECOME PRIVILEGED ; FOR THE DURATION OF THE @ ISSUANCE SEQUENCE (V4.0 ONLY), IN AN ; ATTEMPT TO FIX A REALLY OBSCURE PRIVILEGE VIOLATION PROBLEM. ; ; INPUT: ; R5 JOB PACKET ADDRESS ; ; OUTPUT: ; R3 USED ; PRVFLG USED ; ;- .IF EQ SPRIV1: CLR PRVFLG ; ASSUME NOT PRIVILEGED MOV Q.UCB(R5),R3 ; GET UCB ADDRESS BIT #U2.PRV,U.CW2(R3) ; ARE WE PRIVILEGED? BEQ 10$ ; IF EQ NO INC PRVFLG ; YES, SET FLAG 10$: BIS #U2.PRV,U.CW2(R3) ; FORCE PRIVILEGES RETURN ; AND RETURN SPRIV2: TST PRVFLG ; SHOULD WE BE PRIVILEGED? BNE 10$ ; IF NE YES MOV Q.UCB(R5),R3 ; NO, GET UCB ADDRESS BIC #U2.PRV,U.CW2(R3) ; AND CLEAR PRIVILEGE BIT 10$: RETURN ; RETURN TO CALLER .ENDC ; EQ .PAGE .SBTTL SET SPAWN PARAMETERS ROUTINE ;+ ; *** $SETSP ; ; THIS ROUTINE SETS UP SPAWN PARAMETERS IN THE DPB ; PRIOR TO IT BEING EXECUTED. ; ; INPUT: ; R4 SPAWN DPB ADDRESS ; R5 JOB PACKET ADDRESS ; ; R3 IS USED BY THIS ROUTINE ;- $SETSP: .IF DF M$$MUP MOVB U.LUIC(R5),S.PWUM(R4) ; SET MEMBER CODE MOVB U.LUIC+1(R5),S.PWUG(R4) ; AND GROUP CODE .ENDC $STSP1: MOV Q.UCB(R5),R3 ; GET BATCH JOB UCB ADDRESS CLR S.PWVT(R4) ; CLEAR ALL BITS IN VT: UNIT NUMBER BISB U.UNIT(R3),S.PWVT(R4) ; SET UP UNIT NUMBER RETURN ; BACK TO CALLER .PAGE .SBTTL ISSUE SPAWN DIRECTIVE ROUTINE ;+ ; *** $SPAWN ; ; THIS ROUTINE ISSUES A SPAWN DIRECTIVE. IF IT FAILS ; BECAUSE OF A LACK OF DYNAMIC MEMORY, A WAIT FOR ; SIGNIFICANT EVENT IS MADE AND THE DIRECTIVE IS ISSUED ; AGAIN. ; ; INPUT: ; R4 SPAWN DPB ADDRESS ; ;- $SPAWN: DIR$ R4 ; ISSUE DIRECTIVE BCC SPAWNR ; IF CC OK SO RETURN CMP $DSW,#IE.UPN ; DID IT FAIL DUE TO INSUFFICIENT ; DYNAMIC MEMORY? BNE SPAWNS ; NO, RETURN WITH CARRY SET WSIG$S ; YES, WAIT FOR SIGNIFICANT EVENT BR $SPAWN ; AND TRY AGAIN SPAWNS: SEC ; SET THE CARRY BIT SPAWNR: RETURN ; AND RETURN .PAGE .SBTTL OPERATOR MESSAGE ROUTINE ;+ ; ; *** $OPMSG ; ; THIS ROUTINE IS CALLED WHEN A JOB IS STARTED TO SEND A ; MESSAGE TO THE OPERATOR'S CONSOLE SAYING WHICH JOB IS ; JUST BEGINNING. ; ; INPUT: ; R5 JOB PACKET ADDRESS ; ;- $OPMSG: MOV #OUTBUF,R0 ; GET BUFFER ADDRESS MOV #JOBST,R1 ; AND ADDRESS OF JOB STARTING MESSAGE 5$: MOVB (R1)+,(R0)+ ; MOVE IT IN BNE 5$ ; LOOP TO END OF MESSAGE DEC R0 ; REMOVE NULL BYTE MOV Q.JOBN(R5),R1 ; GET JOB NUMBER CALL $OCTAL ; CONVERT TO OCTAL CALL $TFORM ; INSERT DATE AND TIME MOVB #SPA,(R0)+ ; INSERT A SPACE CALL $FILE ; FILL IN FILE SPECIFICATION MOVB #SPA,(R0)+ ; INSERT A SPACE MOV Q.UCB(R5),R3 ; GET BATCH STREAM UCB ADDRESS CALL $FMTDV ; AND FORMAT IT AS VTN: SUB #OUTBUF,R0 ; CALCULATE MESSAGE LENGTH OPRMSG #OUTBUF,R0 ; AND SEND IT TO OPERATOR'S CONSOLE RETURN ; .PAGE .SBTTL TIME FORMAT ROUTINE ;+ ; *** $TFORM ; THIS ROUTINE FORMATS THE TIME AND DATE. ; ; INPUT: ; R0 BUFFER POINTER ; ; OUTPUT: ; R0 UPDATED BUFFER POINTER ; ; TIME FORMAT IS " - DD-MMM-YY HH:MM:SS" ; ; $TFOR1 IS AN EXTRA ENTRY POINT WHICH BYPASSES THE LEADING " - ". ; ;- $TFORM: MOVB #SPA,(R0)+ ; INSERT A SPACE MOVB #'-,(R0)+ ; AND A DASH MOVB #SPA,(R0)+ ; AND ANOTHER SPACE $TFOR1: MOV #TIMBUF,R1 ; GET ADDRESS OF TIME PARAMETERS BUFFER GTIM$S R1 ; GET TIME PARAMETERS CALL $DAT ; FORMAT THE DATE MOVB #SPA,(R0)+ ; INSERT A SPACE MOV #3,R2 ; TIME FORMAT IS HH:MM:SS CALLR $TIM ; FORMAT THE TIME ; AND RETURN TO CALLER .PAGE .SBTTL JOB ABORT ROUTINE ;+ ; *** $ABORT ; ; THIS ROUTINE IS CALLED TO ABORT THE CURRENTLY ; ACTIVE BATCH JOB AT UCB IN "BATUCB" ; ; INPUT: ; R0 ABORT CODE ; ; IF ENTRY IS AT $ABRT1, NO ABORT CODE IS NEEDED SINCE NO ; MESSAGE IS SENT OUT. ; ;- ABTAB: .WORD AB1,AB1SZ ; ABORT MESSAGE TABLE .WORD AB2,AB2SZ .IF DF L$$CNT .WORD AB3,AB3SZ .IFTF AB1: .ASCII /** BATCH -- TIME LIMIT EXCEEDED **/ AB1SZ=.-AB1 AB2: .ASCII /** BATCH -- ABORTED BY REQUEST **/ AB2SZ=.-AB2 .IFT AB3: .ASCII /** BATCH -- OUTPUT LIMIT EXCEEDED **/ AB3SZ=.-AB3 .ENDC .EVEN $ABORT: ASL R0 ; CONVERT ABORT CODE TO INDEX ASL R0 ; (MULTIPLY BY FOUR) JOBMSG ABTAB-4(R0),ABTAB-2(R0) ; TYPE OUT ABORT CODE $ABRT1: SWSTK$ 15$ ; SWITCH STACKS MOV $TSKHD,R5 ;; GET START OF TASK LIST 5$: TST T.TCBL(R5) ;; NULL TASK TCB? BEQ 15$ ;; YES, DONE TST T.STAT(R5) ;; TASK ACTIVE? BMI 10$ ;; NO CMP BATUCB,T.UCB(R5) ;; TASK IN BATCH STREAM? BNE 10$ ;; NO CMP $MCRPT,R5 ;; MCR...? BEQ 10$ ;; YES TSTB T.ST2(R5) ;; TASK BEING ABORTED? BMI 10$ ;; YES MOV R5,R1 ;; COPY TCB ADDRESS TO R1 MOV #S.CABO,R0 ;; SET ABORT CODE FOR TKTN ;; "ABORTED BY DIRECTIVE OR MCR" CALL $ABTSK ;; ABORT THE TASK 10$: MOV T.TCBL(R5),R5 ;; POINT TO NEXT TASK IN LIST BR 5$ ;; KEEP GOING 15$: RETURN ;; BACK TO TASK LEVEL ; AND RETURN TO CALLER .PAGE .SBTTL JOB START ROUTINE ;+ ; *** $START ; ; THIS ROUTINE IS CALLED TO START A BATCH JOB. ; THE JOB IS PRESELECTED AND IS ALREADY IN THE ; EXECUTING JOB LIST. ; ; INPUT: ; R5 JOB PACKET ADDRESS ;- $START: MOV R5,R1 ; POINT R1 TO JOB TIME ADD #Q.TIME,R1 ; CALL $TCNVT ; CONVERT IT TO TICKS CALL $FOPEN ; OPEN A NEW LOG FILE BCS 10$ ; IF CS THEN AN OPEN FAILURE CALL $OPMSG ; SEND MESSAGE TO CO: CALL $LGON ; LOG ON THE USER BCS 10$ ; LOGON FAILURE, FORGET THIS JOB BIT #MRKABO,Q.MASK(R5) ; WAS JOB MARKED FOR ABORT? BEQ 5$ ; NO JOBMSG #AB2,#AB2SZ ; YES, SAY SO CALL $LGOFF ; LOG OFF THE TERMINAL AND END THE JOB BR 10$ ; AND RETURN 5$: DIR$ #ISSMRK ; MARK TIME FOR 2 SECONDS BCS 6$ ; IF CS, ERROR DIR$ #ISSSTP ; WAIT FOR INTERVAL TO ELAPSE 6$: CALL $ISSUE ; ISSUE COMMAND FILE CLC ; SET SUCCESS BR STARTR ; AND RETURN TO CALLER 10$: SEC ; SET FAILURE STARTR: RETURN ; RETURN TO CALLER .PAGE .SBTTL LOG FILE CLOSE ROUTINE ;+ ; *** $FCLOS ; ; THIS ROUTINE IS CALLED TO CLOSE THE LOG FILE RELEVANT ; TO THE JOB IN STREAM "BATUCB" ; ;- $FCLOS: MOV BATUCB,R3 ; GET UCB ADDRESS MOV U.JPKT(R3),R0 ; GET JOB PACKET ADDRESS MOV Q.LUIC(R0),R1 ; GET LOGON UIC FOR FILE OWNERSHIP CALL .WFOWN ; WRITE FILE OWNER WORD FOR CLOSE OPERATION CLR R1 ; CLEAR LOCATION FOR UNIT NUMBER BISB U.UNIT(R3),R1 ; GET UNIT NUMBER DEC R1 ; REMOVE VT0: BIAS ASL R1 ; CONVERT TO INDEX BIT #NOMASK,Q.MASK(R0) ; /NO SWITCH SPECIFIED? BEQ 10$ ; IF EQ NO CLOSE$ $FDB(R1) ; YES, CLOSE LOG FILE BR 20$ ; 10$: ; REF. LABEL .IF DF P$$RNT .IF GT P$$RNT CALL $PRINT ; USE PRINT COMMAND TO SPOOL LOG FILE .IFF PRINT$ $FDB(R1) ; SPOOL FILE TO PRINTER .ENDC .IFF CLOSE$ $FDB(R1) ; CLOSE LOG FILE .ENDC 20$: RETURN ; AND RETURN TO CALLER .PAGE .SBTTL LOG FILE OPEN ROUTINE ;+ ; *** $FOPEN ; ; THIS ROUTINE IS CALLED TO OPEN A NEW LOG FILE FOR ; A NEW JOB. THE UCB ADDRESS OF THE BATCH STREAM IS IN ; "BATUCB". ; ; INPUT: ; R5 JOB PACKET ADDRESS ; ;- $FOPEN: MOV BATUCB,R0 ; GET STREAM UCB ADDRESS CLR R1 ; CLEAR LOCATION FOR UNIT NUMBER BISB U.UNIT(R0),R1 ; GET UNIT NUMBER DEC R1 ; REMOVE VT0: BIAS ASL R1 ; CONVERT TO AN INDEX .IF DF L$$INE MOV #L$$INE,$LIN(R1) ; SET INITIAL LINE COUNT .ENDC .IF DF T$$CLS MOV #T$$CLS,$CYC(R1) ; RESET TIME CYCLES COUNT .ENDC ; DF T$$CLS MOV $FDB(R1),R0 ; GET FDB ADDRESS MOV $DEF(R1),R3 ; GET DEFAULT FILENAME BLOCK ADDRESS MOV $DNAM,N.DVNM(R3) ; ASSUME DEVICE FOR LOG FILE IS LB: ; (OR WHATEVER HAS BEEN PATCHED INTO $DNAM) MOV $DEVU,N.UNIT(R3) ; SET UP LOG FILE DEVICE UNIT AS WELL MOV BINUFD,R1 ; ASSUME LOG FILE UFD IS DEFAULTED BIT #KEMASK,Q.MASK(R5) ; DOES THE USER WANT THE LOG FILE? BEQ 10$ ; NO MOV Q.LUIC(R5),R1 ; YES, GET UFD FOR LOG FILE MOV Q.DEVN(R5),N.DVNM(R3) ; WRITE DEVICE NAME MOV Q.DEVU(R5),N.UNIT(R3) ; AND UNIT NUMBER 10$: CALL .WDFUI ; WRITE LOG FILE UFD INTO FSR MOV Q.FNAM(R5),N.FNAM(R3) ; SET UP FILENAME MOV Q.FNAM+2(R5),N.FNAM+2(R3) ; MOV Q.FNAM+4(R5),N.FNAM+4(R3) ; MOV Q.JOBN(R5),N.FVER(R3) ; VERSION NUMBER IS JOB NUMBER MOV Q.LUIC(R5),R1 ; SET UP FOR LOG FILE OWNER CALL .WFOWN ; WRITE FILE OWNER WORD FDAT$R R0,#R.VAR,,#DEFSIZ,#EXTSIZ ; SET UP FILE ATTRIBUTES OPEN$W R0 ; OPEN A LOG FILE BCC FOPENR ; OK, SO RETURN MOVB F.ERR(R0),R1 ; GET FCS ERROR CODE MOV #OUTBUF,R0 ; GET OUTPUT BUFFER ADDRESS MOV #OPEN,R2 ; GET OPEN ERROR MESSAGE ADDRESS 20$: MOVB (R2)+,(R0)+ ; MOVE IT INTO THE BUFFER BNE 20$ ; KEEP GOING UNTIL ALL IS DONE DEC R0 ; THEN REMOVE THE TRAILING NULL BYTE CLR R2 ; NO LEADING ZEROES REQUIRED CALL $CBDSG ; CONVERT TO SIGNED DECIMAL MOVB #DPT,(R0)+ ; INSERT A DECIMAL POINT MOVB #SPA,(R0)+ ; INSERT " J" MOVB #'J,(R0)+ ; MOV Q.JOBN(R5),R1 ; GET JOB NUMBER CALL $OCTAL ; INSERT IN BUFFER SUB #OUTBUF,R0 ; CALCULATE MESSAGE LENGTH OPRMSG #OUTBUF,R0 ; SEND OPEN FAILURE MESSAGE TO OPERATOR CALL $JBND1 ; TERMINATE THE BATCH JOB SEC ; SET CARRY BIT FOPENR: RETURN ; RETURN TO CALLER .PAGE .SBTTL LOG FILE SPOOL ROUTINE ;+ ; *** $PRINT ; ; THIS ROUTINE IS CALLED TO CLOSE AND SPOOL THE BATCH ; JOB'S LOG FILE USING THE PRINT COMMAND. ; ; INPUTS: ; R1 LOG FILE TABLE INDEX ; R3 BATCH JOB UCB ADDRESS ; ;- .IF DF P$$RNT .IF GT P$$RNT $PRINT: PUSH$ $FDB(R1) ; SAVE FDB ADDRESS MOV #OUTBUF,R0 ; GET OUTPUT BUFFER ADDRESS MOV #PRNT,R2 ; AND BEGINNING STRING FOR PRINT COMMAND 10$: MOVB (R2)+,(R0)+ ; MOVE A BYTE OF THE COMMAND BNE 10$ ; LOOP TO END DEC R0 ; REMOVE NULL BYTE MOV Q.JOBN(R5),R1 ; GET JOB NUMBER CALL $OCTAL ; CONVERT TO OCTAL MOV #NFLAG,R2 ; GET ADDRESS OF "/-FL/LE:62.=" TEXT *SMT* 11$: MOVB (R2)+,(R0)+ ; MOVE A CHARACTER *SMT* BNE 11$ ; LOOP TO END *SMT* DEC R0 ; REMOVE NULL BYTE *SMT* POP$ R2,NOPOP ; RESTORE FDB ADDRESS TO R2 MOVB F.FNB+N.DVNM(R2),(R0)+ ; MOVE IN DEVICE NAME MOVB F.FNB+N.DVNM+1(R2),(R0)+ ; MOV F.FNB+N.UNIT(R2),R1 ; GET DEVICE UNIT NUMBER MOV BINUFD,R3 ; ASSUME LOG FILE UFD WAS DEFAULTED BIT #KEMASK,Q.MASK(R5) ; DID THE USER GET THE LOG FILE? BEQ 20$ ; NO MOV Q.LUIC(R5),R3 ; YES, GET BINARY UFD 20$: PUSH$ R5 ; SAVE JOB DESCRIPTION PACKET ADDRESS MOV R2,R5 ; POINT R5 TO FILENAME INFORMATION ADD #,R5 ; CALL $FIL1 ; FILL IN FILE SPECIFICATION POP$ R5 ; RESTORE JOB PACKET ADDRESS BIT #KEMASK,Q.MASK(R5) ; KEEP LOG FILE? BNE 30$ ; YES MOVB #SLASH,(R0)+ ; NO, INSERT "/DE" MOVB #'D,(R0)+ ; MOVB #'E,(R0)+ ; 30$: MOV #SPRNT,R4 ; GET SPAWN DPB ADDRESS MOVB Q.LUIC(R5),S.PWUM(R4) ; SET UP UIC FOR PRINT MOVB Q.LUIC+1(R5),S.PWUG(R4) ; SUB #OUTBUF,R0 ; CALCULATE COMMAND LENGTH MOV R0,S.PWCL(R4) ; PUT THIS IN THE DPB OPRMSG #OUTBUF,R0 ; SEND STRING TO OPERATOR CLOSE$ (SP)+ ; CLOSE THE LOG FILE MOV Q.LUIC(R5),$VIRT0+U.UIC ; SET PROTECTION UIC FOR PRINT CALL $SPAWN ; SPAWN PRINT COMMAND PRINTR: RETURN ; RETURN TO CALLER .ENDC .ENDC .PAGE .SBTTL JOB END CLEAN UP ROUTINE ;+ ; *** $JBEND ; ; THIS ROUTINE IS CALLED AT EITHER LOGON TIME IF ; A LOGON FAILURE OCCURRED, OR AT LOGOFF TIME. ; IT CLEARS THE VARIOUS DATA AREAS ASSOCIATED WITH ; THE CURRENT JOB, READY FOR THE NEXT ONE. ; THE JOB PACKET IS DEALLOCATED AND RETURNED TO ; THE DYNAMIC STORAGE REGION. ; ;- $JBEND: CALL $FCLOS ; CLOSE THE LOG FILE $JBND1: SWSTK$ JBENDR ; SWITCH STACKS MOV BATUCB,R5 ;; GET BATCH UCB ADDRESS MOV #$CURJ,R1 ;; GET EXECUTING JOBS LISTHEAD ADDRESS 5$: MOV (R1),R0 ;; GET NEXT ENTRY ADDRESS BEQ 20$ ;; IF EQ THEN END OF LIST ;; WE SHOULDN'T NEED TO DO THIS. CMP R5,Q.UCB(R0) ;; IS THIS THE JOB WE NEED? BEQ 10$ ;; YES MOV R0,R1 ;; NO, POINT TO NEXT ENTRY BR 5$ ;; AND TRY IT 10$: MOV (R0),(R1) ;; CLOSE UP LIST AND REMOVE JOB BNE 15$ ;; IF NE THEN NOT AT END OF LIST MOV R1,$CURJ+2 ;; AT END OF LIST SO CORRECT LISTHEAD 15$: MOV #Q.LGTH,R1 ;; SET PACKET SIZE CALL $DEACB ;; RETURN IT TO THE POOL 20$: DEC $NUMQ ;; UPDATE NUMBER OF QUEUE ENTRIES 25$: MOV R5,R0 ;; MOVE BATCH UCB ADDRESS TO R0 ADD #U.STHD,R0 ;; POINT TO STACK LISTHEAD CALL $QRMVF ;; REMOVE AN ENTRY FROM THE STACK BCS 26$ ;; IF CS NO ENTRIES LEFT MOV R1,R0 ;; MOVE ENTRY ADDRESS TO R0 MOV 2(R0),R1 ;; GET SIZE OF DATA IN THIS PACKET ADD #4,R1 ;; INCLUDE LINK WORD AND DATA SIZE WORD CALL $DEACB ;; RETURN IT TO THE POOL BR 25$ ;; SEE IF THERE'S ANY MORE IN THE STACK 26$: ;; REF. LABEL .IF DF P$$ARM MOV U.JPKT(R5),R0 ;; GET JOB PACKET ADDRESS ADD #Q.PARM,R0 ;; POINT TO PARAMETER PACKET LISTHEAD CALL $QRMVF ;; REMOVE AN ENTRY ;; (ALTHOUGH NORMALLY THERE WILL BE NO ;; ENTRIES IN THE PARAMETER LIST AT THE END ;; OF A JOB, THIS CODE IS HERE TO DEALLOCATE ;; THE LIST IN THE CASE WHERE A JOB MAY NOT ;; HAVE GOT AS FAR AS SUBSTITUTING THE ;; PARAMETERS, FOR EXAMPLE, IN THE EVENT OF A ;; LOGON FAILURE OR A LOG FILE OPEN FAILURE) BCS 27$ ;; IF CS NO PACKETS LEFT IN LIST MOV R1,R0 ;; COPY PACKET ADDRESS TO R0 MOV 2(R0),R1 ;; GET PACKET SIZE (NOTE DIFFERENT FORMAT OF ;; DATA SIZE WORD HERE COMPARED TO THAT FOR ;; THE STACK PACKETS, ABOVE) CALL $DEACB ;; RETURN PACKET TO THE POOL BR 26$ ;; YAWN .ENDC ;; DF P$$ARM 27$: CLR U.STSZ(R5) ;; SET ZERO STACK SIZE CLR U.JPKT(R5) ;; AND JOB PACKET ADDRESS JBENDR: RETURN ;; RETURN TO USER STATE AND CALLER .PAGE .SBTTL LOGON ROUTINE ;+ ; *** $LGON ; ; THIS ROUTINE IS CALLED TO LOG A USER ON TO A ; BATCH TERMINAL. ; ; INPUT: ; R5 POINTER TO JOB PACKET ; ;- $LGON: .IF DF M$$MUP MOV #OUTBUF,R0 ; GET BUFFER ADDRESS MOV #HEL,R1 ; AND "HEL " STRING ADDRESS 5$: MOVB (R1)+,(R0)+ ; MOVE IT IN BNE 5$ ; LOOP TO END DEC R0 ; REMOVE NULL BYTE MOV Q.LUIC(R5),R3 ; GET LOGON UIC CALL $FUIC ; FORMAT THE UIC MOVB #'/,(R0)+ ; INSERT A SLASH PUSH$ R5 ; SAVE R5 ADD #Q.PSWD,R5 ; POINT TO PASSWORD MOV #6,R1 ; SET MAXIMUM CHARACTERS TO MOVE 10$: MOVB (R5)+,(R0)+ ; MOVE A BYTE BEQ 11$ ; IF EQ IT'S THE END OF A SHORT PASSWORD DEC R1 ; END OF PASSWORD YET? BNE 10$ ; NO, TRY SOME MORE BR 12$ ; YES, CONTINUE 11$: DEC R0 ; REMOVE THE NULL BYTE 12$: MOVB #CR,(R0)+ ; PUT IN CARRIAGE RETURN SUB #OUTBUF,R0 ; CALCULATE COMMAND LINE LENGTH POP$ R5 ; RESTORE R5 MOV #SPHEL,R4 ; GET SPAWN DPB ADDRESS MOV R0,S.PWCL(R4) ; SET COMMAND LINE LENGTH CALL $STSP1 ; SET SPAWN PARAMETERS CALL $SPAWN ; LOG ON THE USER BCC 13$ ; OK JOBMSG #SPE,#SPESZ ; TELL USER OF SPAWN ERROR BR 14$ ; 13$: DIR$ #STOP ; WAIT FOR LOG ON TO COMPLETE 14$: MOV BATUCB,R1 ; POINT TO BATCH STREAM BIT #U2.LOG,U.CW2(R1) ; LOGON SUCCESSFUL? BNE 15$ ; NO CLC ; YES BR LGONR ; 15$: CALL $JBEND ; LOGON FAILURE SEC ; INDICATE THIS .ENDC LGONR: RETURN ; RETURN TO CALLER .PAGE .SBTTL LOGOFF ROUTINE ;+ ; *** $LGOFF ; ; LOG USER OFF BATCH TERMINAL AND PERFORM ; JOB END CLEAN UP. ; ;- $LGOFF: .IF DF M$$MUP MOV BATUCB,R0 ; GET BATCH TI: UCB ADDRESS BIT #U2.LOG,U.CW2(R0) ; IS USER LOGGED ON? BNE 10$ ; NO MOV #SPBYE,R4 ; GET SPAWN DPB ADDRESS CALL $SETSP ; SET SPAWN PARAMETERS CALL $SPAWN ; LOG OFF THE USER BCS LGOFFR ; IF CS ERROR DIR$ #STOP ; WAIT FOR BYE TO COMPLETE .ENDC 10$: CALL $JBEND ; PERFORM JOB END CLEAN UP LGOFFR: RETURN ; .PAGE .SBTTL TIME CONVERT ROUTINE ;+ ; *** $TCNVT ; ; ; THIS ROUTINE CONVERTS A TIME (IN MINUTES) TO TICKS. ; ; INPUT: ; R1 - POINTER TO D.P. TIME IN MINUTES (HIGH WORD ZERO) ; ; OUTPUT: ; NUMBER AT R1 IS CONVERTED. ; OTHER REGISTERS ARE PRESERVED ; ;- $TCNVT: PUSH$ R2 ; SAVE R2 ON STACK PUSH$ R0 ; ALSO R0 PUSH$ R1 ; AND R1 MOV 2(R1),R1 ; SET MULTIPLICAND (JOB TIME) MOV #<60.*K$$TPS>,R0 ; AND MULTIPLIER (TICKS PER MIN.) CALL $MUL ; DO THE MULTIPLY MOV R1,R2 ; SAVE LOW ORDER RESULT POP$ R1 ; RESTORE R1 MOV R2,2(R1) ; STORE LOW RESULT MOV R0,(R1) ; STORE HIGH RESULT POP$ R0 ; RESTORE R0 POP$ R2 ; RESTORE R2 RETURN ; .END $BTMEP