.TITLE TSKLOG .IDENT /07.22/ ; ; JAMES G. DOWNWARD ; KMS FUSION, INC. ; 3941 RESEARCH PARK DR. ; ANN ARBOR, MICH. 48104 ; (313)-769-8500 ; ; ; RSX11M V3.2 TASK ACCOUNTING. ; ; THIS PROGRAM IS A START AT PROVIDING THE RSX11M COMMUNITY ; WITH A VIABLE TASK ACCOUNTING PACKAGE WHICH MAY BE USED AS A PERFORMANCE ; MEASUREMENT TOOL. IT IS PATERENED AFTER THE WORK G. BASSET DID WITH ; ACCLOG. AT THIS TIME THE GOAL IS TO PROVIDE THE USER WITH A VERY LIMITED ; AMMOUNT OF INFORMATION ON THE EXECUTION STATISTICS FOR A LIST OF TASKS. ; ; THE SEQUENCE IS AS FOLLOWS. ; ; FIRST THE USER STARTS SYSLOG. THIS ENABLES CPU TIME ACCOUNTING. IF THE ; USER WANTS TO GATHER QIO STATISTICS ON THE TASKS TO BE ACCOUNTED FOR, HE ; MUST ALSO ENABLE USER BY USER QIO ACCOUNTING(/UQIO) AS OPPOSED TO SYSTEM ; WIDE QIO ACCOUNTING. THE USER ACTIVATES TASKLOG VIA A 'ACC /TASK' COMMAND. ; TASKLOG WILL ONLY RUN IF CPU ACCOUNTING IS ENABLED. TASKLOG WILL ; THEN PROMPT FOR A LIST OF TASKS(LATER ON WE WILL LET TASKLOG READ THESE ; TASKS FROM A FILE). TASKLOG IS ALSO STOPED VIA 'ACC' BY EITHER A /STOP ; COMMAND OR A '/NOTASK' COMMAND. THE DATA GATHERED VIA TASKLOG CONSISTS ; OF THE CLOCK TIME FOR EACH TASK, THE TOTAL TIME THE TASK TOOK TO COMPLETE, ; THE CPU TIME USED BY THE TASK, AND THE NUMBER OF QIO'S ISSUED BY THE TASK(OPTIONAL). ; THIS DATA IS SENT OFF TO 'LOGTSK' WHICH WRITES IT OFF TO SYSLOG.DAT. ; AS AN OPTIONAL FEATURE, TSKLOG WILL ALSO DISPLAY THE RESULTS ON TI: ; AS EACH TASK EXITS. ; ; CODE EXISTS FOR BOTH MEMORY MANAGEMENT AND NON-MEMORY MANAGEMENT SYSTEMS. HOWEVER ; ONLY THE CODE FOR MEMORY MANAGEMENT SYSTEMS HAS BEEN TESTED AND WILL BE SUPPORTED. ; HENCE, MEMORY MANAGNEMENT IS A REQUIREMENT. ; ALSO THE KMS CHANGES FOR ACCOUNTING(SYSLOG) ALL MUST HAVE BEEN MADE. ; .MCALL QIOW$C,QIOW$,DIR$,EXIT$S,GTIM$C .MCALL PKTDF$,TCBDF$,HWDDF$,UCBDF$ .MCALL USTP$,SDAT$,RQST$,GTSK$ PKTDF$ ; DEFINE PACKET OFFSETS TCBDF$ ; DEFINE TCB OFFSETS HWDDF$ ; DEFINE HARDWARE UCBDF$ ; DEFINE UCB OFFSETS ; THE TICS/SEC MUST BE DEFINED DEPENDING ON WHETHER OR NOT ONE HAS A REAL TIME ; CLOCK OR A LINE CLOCK. ; FOR CONVENIENCE DEFINE THIS VIA A TASK BUILD TIME PATCH. ;$$TKPS=100. ; 100 TICS/SEC REAL TIME CLOCK T$$KAC=1 ; DEFINE TASK ACCOUNTING******TEMP UNTIL INCORP IN RSXMC.MAC ; LOCAL OFFSETS ; ; .IF DF M$$MUP ; MULTI USER PROTECTION BETTER BE PRESENT FOR ; THE OFFSETS TO WORK .IFDF M$$CLI ; IF MULTIPLE CLI SUPPORT PRESENT FOR DECNET BASE=U.CLI ; OUR OFFSET LOCATION IS SET BY U.CLI .IFF ; IF NORMAL SYSTEM BASE=U.LUIC ; OUR OFFSET IS SET BY U.LUIC .ENDC ; .END M$$CLI .IF DF T$$CPU ; IF CPU TIME ACCOUNTING DEFINED U.ACN=BASE-4 ; OFFSET INTO EXPANDED UCB FOR ACCOUNT NUMBER U.TIC2=BASE-6 ; HIGH ORDER CPU TIME IN TICS U.TIC1=BASE-10 ; LOW ORDER CPU TIME IN TICS .IFF ; IF CPU TIME ACCOUNTING NOT CHOSEN .ERROR ; SYSTEM IS NOT CONFIGURED FOR CPU ACCOUNTING .ENDC ; T$$CPU .IF DF Q$$CNT ; IF QIO ACCOUNTING IS DEFINED U.QIO2=BASE-20 ; QIO COUNTER HIGH VAL U.QIO1=BASE-22 ; QIO COUNTER LO VAL .ENDC ; Q$$CNT .ENDC ; M$$MUP ; ; B.TSK1=0 ; ACCOUNTING BLOCK LINK WORD B.TSK2=2 ; TCB ADDRESS OF TASK B.CLK2=4 ; WALL TIME, HIVAL B.CLK1=6 ; WALL TIME, LOVAL B.CPU2=10 ; CPU TIME HIVAL B.CPU1=12 ; CPU TIME LOVAL B.TOT2=14 ; TOTAL ELAPSED CPU TIME(HIVAL) B.TOT1=16 ; TOTAL ELAPSED CPU TIME(LOVAL) B.QIO2=20 ; QIO COUNT HIVAL B.QIO1=22 ; QIO COUNT LOVAL ; ; ACCOUNTING DATA STRUCTURES ; ; >>>>>NOTE WELL<<<<<< ; IF BLKSIZ IS EVER CHANGED THE NEW VALUE MUST BE ALSO USED IN ACC. BLKSIZ=24 ;>>>>>>>><<<<<<<<<<<<< ; FORMAT OF ACCOUNTING BLOCK ; .WORD 0 ; ACCOUNTING LIST LINK WORD ; .WORD 0 ; TCB ADDRESS OF TASK TO BE ACCOUNTED FOR ; .WORD 0 ; INITIALLY START TIME OF JOB IN TICS, (HI VAL) ; .WORD 0 ; LATER BECOMING ELAPSED WALL TIME(LO VAL) ; .WORD 0 ; START CPU TIME(HIVAL) ; ACNT # ; .WORD 0 ; START CPU TIME(LOVAL) ; TERM ID ; .WORD 0 ; ELAPSED CPU TIME(HIVAL) ; .WORD 0 ; " " " _(LOVAL) ; .WORD 0 ; QIO COUNT(HIVAL) ; .WORD 0 ; QIO COUNT(LOVAL) CODNOD: .WORD 0 ; CODE NODE ADDRESS IOST: .BLKW 2 ; I/O STATUS BLOCK NODADD: .WORD 0 ; NODE ADDRESS TO REPORT ON TSKLST: .BLKW 25. ; TASK TCB LIST TSKCNT: .WORD 0 ; # OF TASKS IN TSKLST INPBUF: .BLKB 20. ; INPUT BUFFER AND TIME BUFFER TSKR50: .BLKW 2 ; TEMP. BUFFER ERROR: .WORD 0 ; ALLOCATION FAILURE ERROR SWITCH SNDBUF: .WORD 9. ; TYPE 9 DATA RECORD TO LOGTSK .BLKW 12. ; REST OF SEND DATA BLOCK ; DIRECTIVE PARAMETER BLOCKS QIODPB: QIOW$ IO.WVB,2,2,,,,<0,0,0> ATTDPB: QIOW$ IO.ATT,2,2 DETDPB: QIOW$ IO.DET,2,2 SNDDAT: SDAT$ LOG...,SNDBUF ; SEND DATA TO LOGGING TASK RQSTLG: RQST$ LOG... ; START UP LOGGING TASK IF NOT STOPPED USTPLG: USTP$ LOG... ; UNSTOP LOGGING TASK IF STOPPED GETTSK: GTSK$ TSKLST ; GET OUR NAME IN TSKLST .SBTTL TEXT MESSAGES .NLIST BEX ; M1: .ASCII /ENTER TASK NAME: / M1S=.-M1 M2: .ASCIZ <15><12>/TSKLOG -- TASK NOT INSTALLED/<15><12> M3: .ASCII <15><12>/*****************/<15><12> .ASCII <15><12>/TASK NAME: / TNAME: .BLKB 6 .ASCII <15><12>/ TIME: / DATE: .BLKB 21. M31: .BYTE 12 .ASCIZ <15><12>/TOTAL ELAPSED TIME/ M4: .ASCII <15><12>/HOURS: / HOURS: .BLKB 6 M5: .ASCII <15><12>/MINUTES: / MINS: .BLKB 4 M6: .ASCII <15><12>/SECONDS: / SECNDS: .BLKB 4 M7: .ASCII <15><12>/TICKS: / TICKS: .BLKB 4 M8: .ASCIZ <15><12><12>/TOTAL CPU TIME/ M9: .ASCII <15><12>/TOTAL QIO'S ISSUED: / QIOS: .BLKB 12. M10: .ASCIZ <15><12>/TSKLOG -- MEMORY ALLOCATION FAILURE/<15><12> M11: .ASCIZ <15><12>/TSKLOG -- INPUT ERROR/<15><12> M12: .ASCIZ <15><12>/TSKLOG -- EXITING/<15><12> M13: .ASCIZ <15><12>/TSKLOG -- FATAL, SYSTEM ACCOUNTING NOT ACTIVE/<15><12> M14: .ASCIZ <15><12>/>/ M15: .ASCIZ <15><12>/TSKLOG -- WARNING, SEND DATA FAILURE TO LOG.../<15><12> M16: .ASCIZ <15><12>/TSKLOG -- WARNING, LOG... COULD NOT BE UNSTOPPED OR STARTED/<15><12> M17: .ASCIZ <15><12>/TSKLOG -- FATAL, NOT RUN WITH NAME 'TSKLOG'/ M18: .ASCIZ <15><12>/TSKLOG -- FATAL, MORE THAN 25 TASKS NOT ALLOWED/<15><12> MYNAME: .RAD50 /TSKLOG/ .EVEN ; FORMAT OF SEND DATA PACKET TO LOG... ; ; 9.,HOUR,MIN,SEC,ACNT #,TSKNM1,TSKNM2,CLKTIME1,CLKTIME2,CPUTIME1,CPUTIME2,QIOCT1,QIOCT2 ; ; WHERE TSKNM1,TSKNM2 ARE IN RAD50 ; CLKTIME1,CLKTIME2,CPUTIME1,CPUTIME2 ARE IN TICS ; AND HOUR,MIN,SEC IS THE TIME(OR CLOSE TO THE TIME) WHEN THE TASK STOPPED. ; MACRO DEFINITIONS .MACRO PRINT STRING MOV #STRING,R0 CALL PNTLIN .ENDM PRINT .PAGE .SBTTL ACCOUNTING INITALIZATION CODE .ENABL LSB START: ; REF. LABEL DIR$ #GETTSK ; GET OUR NAME CMP TSKLST,MYNAME ; IS OUR NAME 'TSKLOG' BNE 1$ ; IF NE,NO CMP TSKLST+2,MYNAME+2 ; CHECK LAST HALF OF NAME BEQ 2$ ; ALL OK IF EQ 1$: PRINT M17 ; WARN USER NAME IS BAD JMP XIT ; AND GET OUT 2$: TST $ACMSK ; IS ACCOUNTING ACTIVE BNE 4$ ; IF NE, YES PRINT M13 ; WARN USER SYSLOG MUST BE RUNNING FIRST JMP XIT ; EXIT 4$: CLR ERROR ; CLEAR ERROR INDICATOR CLR TSKCNT ; CLEAR NUMBER OF TASKS REQUESTED MOV #TSKLST,R5 ; GET TCB LIST ADDRESS CLR INPBUF ; CLEAR THE INPUT BUFFER CLR INPBUF+2 CLR INPBUF+4 DIR$ #ATTDPB ; ATTACH TI: CALL $LOCKL ; LOCK THE LISTS 10$: QIOW$C IO.RPR,2,2,,IOST,, BCS 13$ ; IF QIO FAILS TSTB IOST ; WAS READ SUCCESSFUL? BPL 15$ ; YES. CONTINUE WITH CHECK 13$: JMP DEVERR ; JMP TO DEVICE ERROR 15$: TST IOST+2 ; IS THIS A NULL LINE? BEQ 30$ ; YES. NO MORE TASK NAMES MOV #INPBUF,R0 ; GET INPUT BUFFER ADDRESS CALL $CAT5 ; CONVERT TO RADIX 50 MOV #TSKR50,R4 ; GET BUFFER ADDRESS TO STORE R50 NAME MOV R1,(R4) ; STORE FIRST 3 CHARS. CALL $CAT5 ; CONVERT NEXT 3 MOV R1,2(R4) ; AND STORE THEM MOV R4,R3 ; COPY R50 BUFFER ADDRESS CALL $SRSTD ; SCAN THE STD FOR A MATCH BCC 20$ ; GOT ONE! PRINT M2 ; PRINT TASK NOT INSTALLED BR 10$ ; TRY AGAIN 20$: MOV R0,(R5)+ ; STORE TCB ADDRESS AWAY INC TSKCNT ; COUNT THIS TCB CMP TSKCNT,#25. ; BE VERY SURE NOT MORE THAN 25 TASK ENTERED BLT 10$ ; IF LT OK CONTINUE PRINT M18 ; ELSE WARN USER JMP XIT ; AND GET OUT ; BR 10$ ; GET ANOTHER ONE 30$: ; DIR$ #DETDPB ; DETACH TI: PRINT M14 ; DROP DOWN A LINE TST TSKCNT ; ANY TASKS TO ACCOUNT BNE 35$ ; YES. BEGIN JMP 106$ ; NO. EXIT 35$: ; REF. LABEL .IF NDF M$$MGE MOV #CODST,CODNOD ; ASSUME NO NODE NEEDED MOV $TKTCB,R5 ; GET OUR TCB ADDRESS BIT #T2.CHK,T.ST2(R5) ; ARE WE CHECKPOINTABLE? BNE 50$ ; IF NO, THEN NO NODE NEEDED .ENDC ; NDF M$$MGE CLR CODNOD ; CLEAR FLAG TO STORE CODE NODE MOV #CODSIZ,R1 ; GET CODE SIZE CALL $SWSTK,50$ ; SWITCH TO SYSTEM STATE CALL $ALOCB ;; ALLOCATE THE CODE BLOCK FROM DSR BCS 40$ ;; IF UNABLE THEN LEAVE FLAG 0 MOV R0,CODNOD ;; STORE NODE ADDRESS 40$: RETURN ;; EXIT FROM SYSTEM STATE 50$: MOV CODNOD,R5 ; GET NODE ADDRESS MOV R5,R0 ; COPY TO R0 BNE 55$ ; IF .NE. 0 THEN WE GOT ONE INC ERROR ; INDICATE AN ERROR HAS OCCURRED JMP 106$ ; ALLOCATION FAILURE 55$: MOV #CODSIZ,R1 ; GET TOTAL CODE SIZE INC R1 ; ROUND UP TO WORD BOUNDARY ASR R1 ; CONVERT TO WORDS MOV #CODST,R2 ; GET CODE STARTING ADDRESS 60$: MOV (R2)+,(R0)+ ; STORE WORD DEC R1 ; ANY MORE TO TRANSFER? BNE 60$ ; YES. CONTINUE MOV $TKTCB,ACCPTR-CODST(R5) ; SAVE TSKLOG TCB ADDRESS ADD #ACCHD-CODST,R5 ; GET REAL ADDRESS OF ACCOUNTING NODE MOV R5,$QIOCT+10 ; SET ADDRESS IN TO SYSCM FOR SYSLOG TO USE MOV CODNOD,R5 ; RESTORE R5, WE NEED IT ; ; INSERT INTERCEPTS INTO THE EXEC ; CLR ERROR ; CLEAR ALLOCATION ERROR SWITCH MOV #ADDTAB,R1 ; GET ADDRESS OF INTERC. ADDRESS TABLE MOV #OFFTAB,R2 ; GET NODE OFFSETS TABLE ADDRESS MOV #3,R3 ; GET # OF INTERCEPTS MOV #4737,R4 ; PUT A "JSR PC" INTO R4 CALL $SWSTK,75$ ; SWITCH TO SYSTEM STATE 65$: MOV (R1)+,R0 ;; GET INTERCEPT ADDRESS MOV R4,(R0)+ ;; PUT A "JSR PC" THERE MOV R5,(R0) ;; PLACE NODE ADDRESS IN THERE ADD (R2)+,(R0) ;; ADD OFFSET INTO NODE DEC R3 ;; ARE WE DONE YET? BNE 65$ ;; NO. CONTINUE ON ; ; ALLOCATE CONTROL BLOCK FOR EACH TASK REQUESTED ; ADD #ACCHD-CODST,R5 ;; POINT R5 TO ACCOUNT LISTHEAD MOV R5,R4 ;; COPY IT TO R4 MOV R4,2(R4) ;; SET UP LISTHEAD ADDRESS MOV #TSKLST,R4 ;; GET POINTER TO TCB LIST 70$: MOV #BLKSIZ,R1 ;; GET CONTROL BLOCK SIZE CALL $ALOCB ;; ALLOCATE A BLOCK FROM DSR BCS ALLERR ;; IF FAILURE THEN CLEANUP MOV (R4)+,2(R0) ;; STORE NEXT TCB ADDRESS IN PACKET MOV R0,R1 ;; MOVE BLOCK ADDRESS INTO R1 MOV R5,R0 ;; GET LISTHEAD ADDRESS CALL $QINSF ;; INSERT INTO ACCOUNTING LIST DEC TSKCNT ;; ANY MORE TO ACCOUNT FOR? BNE 70$ ;; YUP. WE'ED BETTER CONTINUE RETURN ;; EXIT FROM SYSTEM STATE ALLERR: INC ERROR ;; INDICATE AN ERROR HAS OCCURED RETURN ;; EXIT FROM SYSTEM STATE .PAGE .SBTTL TASK ACCOUNTING CODE ; ; NOW WE GO TO SLEEP AND WAIT FOR A TASK TO EXIT, AT WHICH TIME ; THE STOP CODE (IN THE NODE) WILL QUEUE IT TO OUR ; RECEIVE QUEUE AND START US BACK UP AGAIN. ; 75$: BIS #2000,$ACMSK ; SHOW TASK ACCOUNTING IS ACTIVE CALL $UNLKL ; UNLOCK THE SYSTEM LISTS TST ERROR ; DID AN ERROR OCCUR? BEQ 80$ ; NO. CONTINUE JMP 105$ ; YES. PRINT, CLEAN UP AND EXIT 80$: MOV $TKTCB,R0 ; GET OUR TCB ADDRESS ADD #T.RCVL,R0 ; POINT R0 TO OUR RECEIVE LISTHEAD CLR NODADD ; CLEAR THE NODE FOUND SWITCH CALL $SWSTK,100$ ; SWITCH TO SYSTEM STATE CALL $QRMVF ;; REMOVE ENTRY FROM RECEIVE LIST BCC 90$ ;; GOT ONE! REMEMBER IT CALLR $STPCT ;; NOTHING THERE. GO TO SLEEP....... 90$: MOV R1,NODADD ;; SAVE THE NODE ADDRESS RETURN ;; EXIT FROM SYSTEM STATE 100$: MOV NODADD,R5 ; DID WE GET ONE? BEQ 80$ ; NOPE. TRY AGAIN. BIT #1,2(R5) ; IS THIS AN EXIT NODE FROM ACCOFF? BEQ 1001$ ; NO, CONTINUE AND PROCESS A TASK EXIT PACKET JMP EXIT ; YES, CLEANUP AND EXIT 1001$: MOV R5,-(SP) ; STORE NODE ADDRESS FOR FUTURE USE ; ; A TASK HAS EXITED. TAKE THE NODE GIVEN TO US AND PROCESS THE INFORMATION ; IN IT AND PRINT IT OUT. THEN RESTORE THE PACKET TO THE LIST ; AND ENABLE IT TO BE ACCOUNTED AGAIN. ; CALL $LOCKL ; LOCK THE SYSTEM LISTS MOV 2(R5),R0 ; PICK UP THE TCB ADDRESS MOV T.NAM(R0),R1 ; GET THE FIRST HALF OF THE TASK NAME MOV T.NAM+2(R0),-(SP) ; SAVE THE SECOND HALF FOR A LITTLE LATER CALL $UNLKL ; UNLOCK THE SYSTEM LISTS GTIM$C INPBUF ; GET THE CURRENT TIME AND DATE MOV INPBUF+6,SNDBUF+2 ; SET HOUR IN SEND BUFFER MOV INPBUF+10,SNDBUF+4 ; SET MIN IN SEND BUFFER MOV INPBUF+12,SNDBUF+6 ; SET SEC IN SEND BUFFER MOV B.CPU1(R5),SNDBUF+10 ; GET THE USER'S ACNT NUMBER MOV R1,SNDBUF+12 ; GET FIRST HALF OF RAD50 TASKNAME MOV (SP),SNDBUF+14 ; GET SECOND HALF OF RAD50 TASK NAME MOV B.CLK1(R5),SNDBUF+16 ; GET RUN TIME(LOVAL) MOV B.CLK2(R5),SNDBUF+20 ; GET RUN TIME(HIVAL) MOV B.TOT1(R5),SNDBUF+22 ; GET CPU TIME(LOVAL) MOV B.TOT2(R5),SNDBUF+24 ; GET CPU TIME(HIVAL) MOV B.QIO1(R5),SNDBUF+26 ; GET QIO COUNT(LOVAL) MOV B.QIO2(R5),SNDBUF+30 ; GET QIO COUNT(HIVAL) BIT #4000,$ACMSK ; SHOULD WE WRITE THE STUFF OUT TO TI:(CO0:)? BEQ 101$ ; IF EQ, NO, SKIP OVER DIR$ #ATTDPB ; ATTACH TO THE TERMINAL MOV #TNAME,R0 ; GET TASK NAME BUFFER ADDRESS CALL $C5TA ; CONVERT TO ASCII MOV (SP)+,R1 ; GET THE SECOND HALF OF THE NAME CALL $C5TA ; CONVERT IT TO ASCII MOV #INPBUF,R1 ; POINT TO THE DATE MOV #DATE,R0 ; GET PRINT STRING ADDRESS CALL $DAT ; CONVERT TO ASCII MOVB #' ,(R0)+ ; INSERT A SPACE MOV #4,R2 ; MAKE THE FORMAT "HH:MM:SS.S" CALL $TIM ; AND CONVERT THE TIME PRINT M3 ; PRINT TASK NAME MESSAGE PRINT M31 ; PRINT ELAPSED TIME HEADER MOV (SP),R0 ; GET NODE ADDRESS MOV 4(R0),R1 ; GET HIGH ORDER START TIME MOV 6(R0),R2 ; AND LOW ORDER CALL PRNTIM ; PRINT ELAPSED TIME PRINT M8 ; PRINT CPU HEADER MESSAGE MOV (SP),R0 ; RESTORE NODE ADDRESS MOV 14(R0),R1 ; GET HIGH ORDER CPU TIME MOV 16(R0),R2 ; AND LOW ORDER CALL PRNTIM ; AND PRINT IT MOV (SP)+,R1 ; RESTORE NODE ADDRESS ONE LAST TIME ADD #20,R1 ; POINT R1 TO NUMBER OF QIO'S MOV #QIOS,R0 ; POINT R0 TO RIGHT PLACE IN BUFFER CLR R2 ; SUPPRESS ZERO'S CALL $CDDMG ; CONVERT TO D.P. ASCII MOVB #'.,(R0)+ ; END IT WITH PERIOD CLRB (R0) ; MAKE IT ASCIZ PRINT M9 ; AND PRINT IT PRINT M14 ; ISSUE A CR,LF '>' DIR$ #DETDPB ; DETACH THE TERMINAL 101$: ; REF LABLE BIT #4000,$ACMSK ; SHOULD WE LOG DATA TO TERMINAL BNE 104$ ; IF NE, YES SO WE WON'T SEND DATA TO LOG... DIR$ #SNDDAT ; SEND DATA TO LOG... BCC 102$ ; IF CC, ALL OK PRINT M15 ; WARN USER THAT A SEND DATA FAILURE TO LOG... OCCURED BR 104$ ; DON'T TRY ANY MORE 102$: DIR$ #USTPLG ; TRY UNSTOPPING LOG... BCC 104$ ; IT WORKED, SO CONTINUE DIR$ #RQSTLG ; IT DIDN'T WORK, TRY STARTING IT BCC 104$ ; IF CC, OK PROCEED PRINT M16 ; WARN USER LOG... COULD NOT BE UNSTOPPED/STARTED 104$: ; REF LABLE ; ; REPLACE NODE INTO ACCOUNTING LIST ; CALL $SWSTK,80$ ; SWITCH TO SYSTEM STATE MOV NODADD,R1 ;; GET NODE ADDRESS MOV CODNOD,R0 ;; POINT TO CODE NODE ADDRESS ADD #ACCHD-CODST,R0 ;; POINT TO ACCOUNTING LISTHEAD CALLR $QINSF ;; INSERT INTO QUEUE AND RETURN .PAGE .SBTTL ACCOUNTING RUNDOWN CODE ; ; THIS CODE WILL DEALLOCATE ALL NODES TO THE POOL, ; PRINT SYSTEM STATISTICS, AND ; WILL EXIT TSKLOG. ; EXIT: ; REF. LABEL MOV R5,R0 ; COPY NODE ADDRESS MOV #BLKSIZ,R1 ; GET EXIT NODE SIZE CALL $SWSTK,105$ ; SWITCH TO SYSTEM STATE CALLR $DEACB ;; RETURN IT TO THE POOL 105$: ; CALL CLEAN ; RETURN ALL NODES TO THE POOL 106$: TST ERROR ; IS THIS AN ERROR CONDITION? BEQ 107$ ; NO. SKIP ERROR MESSAGE PRINT M10 ; ALLOCATION FAILURE 107$: ; REF. LABEL XIT: ; PRINT M12 ; PRINT TASK EXITING MESSAGE EXIT$S ; AND DO IT ; ; INPUT DEVICE ERROR ; DEVERR: PRINT M11 ; PRINT DEVICE ERROR MESSAGE BR 107$ ; AND EXIT .PAGE .SBTTL RUNDOWN CLEAN UP ROUTINE ; ; THIS ROUTINE WILL CLEAN UP ALL THE NODES AND RETURN THEM TO THE POOL ; CLEAN: MOV #ADDTAB,R0 ; GET INTERCEPT ADDRESS TABLE MOV #INTTAB,R1 ; GET INTERCEPT INSTRUCTION TABLE MOV #3,R2 ; GET COUNTER CALL $SWSTK,125$ ; SWITCH TO SYSTEM STATE BIC #6000,$ACMSK ; SHOW NO TASK ACCOUNTING ACTIVE CLR $QIOCT+10 ; ZERO ADDRESS FOR TASK ACCOUNTING NODE 108$: MOV (R0)+,R3 ;; GET INTERCEPT ADDRESS MOV (R1)+,(R3)+ ;; MOVE FIRST WORD OF INSTRUCTION MOV (R1)+,(R3) ;; " SECOND " " " DEC R2 ;; IS THIS THE LAST INTERCEPT? BNE 108$ ;; NO. CONTINUE MOV CODNOD,R5 ;; GET CODE NODE ADDRESS MOV R5,R4 ;; SAVE IT IN R4 ADD #ACCHD-CODST,R4 ;; POINT IT TO THE LISTHEAD CALL REMOVE ;; REMOVE ALL ENTRIES MOV $TKTCB,R4 ;; GET OUR TCB ADDRESS ADD #T.RCVL,R4 ;; POINT IT TO OUR RECEIVE QUEUE CALL REMOVE ;; REMOVE ALL ENTRIES .IF NDF M$$MGE CMP #CODST,R5 ;; IS THIS CODE IN A NODE? BEQ 125$ ;; NO. DON'T RETURN IT .ENDC ;; NDF M$$MGE MOV R5,R0 ;; RETRIEVE THE NODE ADDRESS MOV #CODSIZ,R1 ;; GET THE SIZE OF IT CALLR $DEACB ;; AND RETURN IT TO THE POOL 125$: RETURN ; ; THIS ROUTINE REMOVES ALL ENTRIES FROM A PARTICULAR QUEUE ; REMOVE: MOV R4,R0 ;; GET LISTHEAD ADDRESS CALL $QRMVF ;; REMOVE AN ENTRY BCS 125$ ;; IF NONE, THEN RETURN MOV R1,R0 ;; COPY ENTRY ADDRESS TO R0 MOV #BLKSIZ,R1 ;; GET SIZE OF ENTRY CALL $DEACB ;; RETURN IT TO THE POOL BR REMOVE ;; KEEP GOING ; ; INTERCEPT ADDRESS TABLE ; ADDTAB: .WORD $TSKRT+STOFF ; START TASK TIME INTERCEPT(IN REQSB) .WORD $CEXIT ; STOP TASK TIME INTERCEPT(IN DREIF) .WORD $NONSI+CSOFF ; CONTEXT SWITCH INTERCEPT ; .WORD $IOFIN ; I/O COUNT INTERCEPT ; ; INTERCEPT INSTRUCTION TABLE ; INTTAB: BIC (SP),(R3)+ CLR (SP) CALL @#$DRCMT MOV R5,@#$TKTCB ; MOV I.IOSB+4(R3),R2 ; ; CODE OFFSETS IN NODE ; OFFTAB: .WORD SETSTT-CODST ; START TASK INTERCEPT .WORD STPTIM-CODST ; STOP TASK INTERCEPT .WORD CNTSW-CODST ; CONTEXT SWITCH INTERCEPT .PAGE .SBTTL PRINTING ROUTINES ; ; THIS ROUTINE WILL PRINT THE TIME ON THE TERMINAL ; AND SUPPRESS ANY ZERO VALUES ; ; INPUTS: ; ; R1 - HIGH ORDER TIME ; R2 - LOW ORDER TIME ; PRNTIM: MOV #$$TKPS,R0 ; GET TICKS/SECOND CALL $DDIV ; DO D.P. DIVIDE MOV R0,-(SP) ; STORE IT MOV #60.,R0 ; GET SECONDS/MINUTE CALL $DDIV ; DO DIVIDE MOV R0,-(SP) ; STORE # OF SECONDS MOV #60.,R0 ; GET MINUTES/HOUR CALL $DDIV ; DO DIVIDE MOV R0,-(SP) ; STORE # OF MINUTES MOV R2,R1 ; COPY HOURS TO R1 BEQ 130$ ; IF NO HOURS THEN SKIP MOV #HOURS,R0 ; GET ADDRESS FOR HOURS CALL CNVT ; CONVERT PRINT M4 ; PRINT HOURS: NNN 130$: MOV (SP)+,R1 ; GET MINUTES BEQ 140$ ; IF NONE, THEN SKIP MOV #MINS,R0 ; GET BUFFER ADDRSS CALL CNVT ; CONVERT PRINT M5 ; PRINT MINUTES: 140$: MOV (SP)+,R1 ; GET NUMBER OF SECONDS BEQ 150$ ; IS NONE THEN SKIP MOV #SECNDS,R0 ; GET BUFFER ADDRESS CALL CNVT ; CONVERT PRINT M6 ; PRINT SECONDS: 150$: MOV (SP)+,R1 ; GET TICKS MOV #TICKS,R0 ; BUFFER ADDRESS CALL CNVT ; CONVERT PRINT M7 ; PRINT TICKS: 160$: RETURN ; ; THIS ROUTINE WILL CONVERT A NUMBER, ADD A '.' AND MAKE IT ASCIZ ; CNVT: CLR R2 ; SUPPRESS ZEROES CALL $CBDMG ; CONVERT TO ASCII MOVB #'.,(R0)+ ; ADD A '.' CLRB (R0) ; MAKE IT ASCIZ RETURN ; AND RETURN ; ; THIS ROUTINE WILL PRINT AN ASCIZ LINE ; PNTLIN: MOV #-1,R1 ; GET COUNT INITIALIZED MOV R0,QIODPB+Q.IOPL ; STORE BUFFER ADDRESS 170$: INC R1 ; INCREMENT COUNTER TSTB (R0)+ ; IS THIS THE LAST BYTE? BNE 170$ ; NO. KEEP GOING MOV R1,QIODPB+Q.IOPL+2 ; STORE BYTE COUNT DIR$ #QIODPB RETURN .PAGE .SBTTL INTERCEPT CODE (IN THE NODE) ; ; START OF INTERCEPT CODE. ; CODST=. ; ; THIS IS THE CODE TO INTERCEPT A TASK REQUEST. THE FOLLOWING ; THINGS ARE DONE: ; ; 1. SEE IF THE TASK BEING REQUESTED IS IN THE ACCOUNT LIST. ; ; 2. IF YES, THEN INIT. ALL ACCUM. TIMES AND SET START TIME. ; ; 3. RESTORE REGISTERS, EXECUTE THE INTERCEPTED INSTRUCTION, AND RETURN ; SETSTT: MOV R0,-(SP) ; SAVE R0 MOV R1,-(SP) ; SAVE R1 MOV R2,-(SP) ; SAVE R2 CALL MATCH ; LOOK FOR A MATCHING TCB ADDRESS BEQ OUT1 ; IF = 0, THEN NO MATCH ADD #4,R1 ; POINT TO START TIME LOCATION ; MOV (SP),R2 ; GET UCB ADDRESS BIS #340,@#PS ; RAISE PRIORITY TO 7 ;>>>>>>>>>>>>TEMP CODE<<<<<<<<<< MOV @#$QIOCT+6,(R1)+;;; SET HIGH ORDER START TIME ;;; USE THIS BECAUSE NEED ABSOLUTE 2 WORD START TIME ;;; U.TIC ONLY OK, IF TASK RUNNING ON THAT TI: WITH ;;; NO NULL TIME. MOV @#$QIOCT+4,(R1)+;;; SET LOW ORDER START TIME ;>>>>>>>>>>>>>>>TEMP CODE<<<<<<<<<< CLRB @#PS ;;; DROP PRIORITY TO 0 .REPT 4 CLR (R1)+ ; CLEAR INITITIAL TIMES .ENDR CLR (R1)+ ; ZERO TOTAL QIO COUNTERS CLR (R1)+ ; ZERO TOTAL QIO COUNTERS OUT1: MOV (SP)+,R2 ; RESTORE R2 MOV (SP)+,R1 ; RESTORE R1 MOV (SP)+,R0 ; RESTORE R0 BIC 2(SP),(R3)+ ;*INTERCEPTED INSTRUCTION CLR 2(SP) ;*INTERCEPTED INSTRUCTION RETURN ; RETURN TO NORMAL CODE ; ; THIS INTERCEPT CODE IS ENTERED WHEN A TASK EXITS. ; IT DOES THE FOLLOWING: ; ; 1. CHECKS FOR A MATCHING TCB ADDRESS ; ; 2. ADDS IN THE REMAINING CPU TIME AND QIO'S ; ; 3. CALCULATES THE TOTAL RUN TIME AND GETS ACNT # ; ; 4. REMOVES ENTRY FORM ACCOUNTING LIST ; ; 5. QUEUES ENTRY TO TSKLOG'S RECEIVE LIST AND STARTS IT ; STPTIM: MOV R5,-(SP) ; SAVE R5 MOV R4,-(SP) ; SAVE R4 MOV R5,R0 ; COPY TCB ADDRESS CALL MATCH ; IS THERE A MATCH? BEQ OUT2 ; NOPE. FORGET IT CALL 203$ ; ADD IN REMAINING CPU TIME MOV T.UCB(R5),R4 ; GET UCB ADDRESS MOV U.ACN(R4),B.CPU1(R1) ; GET ACNT # BIS #340,@#PS ; RAISE PRIORITY TO 7 ; MOV @#$QIOCT+6,-(SP);;; SAVE HIGH ORDER STOP TIME ***TEMP ; MOV @#$QIOCT+4,R0 ;;; SAVE LOW ORDER STOP TIME ***TEMP MOV @#$TIMEX,R0 ;;; SAVE LOW ORDER TIME MOV @#$TIMEX+2,-(SP);;; SAVE HIGH ORDER TIME CLRB @#PS ;;; AND DROP PRIORITY SUB B.CLK1(R1),R0 ; SUBTRACT LOW ORDER TIME SBC (SP) ; AND DON'T FORGET THE CARRY MOV R0,B.CLK1(R1) ; STORE FINAL TIME SUB B.CLK2(R1),(SP) ; SUBTRACT HIGH ORDER TIME MOV (SP)+,B.CLK2(R1); STORE FINAL TIME MOV (R1),(R2) ; CLOSE UP LIST BNE 200$ ; IF NOT AT END THEN CONTINUE MOV R2,ACCHD+2 ; AT END SO CORRECT POINTER 200$: MOV ACCPTR,R0 ; GET TSKLOG TCB ADDRESS CALL @#$EXRQF ; QUEUE NODE AND START TSKLOG OUT2: MOV (SP)+,R4 ; RESTORE R4 MOV (SP)+,R5 ; AND R5 CALLR @#$DRCMT ;*INTERCEPTED INSTRUCTION ; ; THIS CODE INTERCEPTS A CONTEXT SWITCH. A CHECK IS DONE ON BOTH ; THE OLD AND THE NEW TASK. ; ; 1. IF OLD TASK MATCHES, THEN THE ELAPSED CPU TIME ; ; 2. IF NEW TASK MATCHES, THEN THE START TIME IS PLACED ; IN THE START CPU TIME SLOT. NOW IF IT IS A NEW TASK IT ; CAN BE A NEW TASK EITHER BECAUSE THE CONTEXT SWITCH ; WAS TO A NEW TASK, OR NO NEW TASK EXISTED BUT AN ; INSTRUCTION(QIOW ??) CAUSED THE EXECUTION TO SUSPEND FOR A ; WHILE AND THE EXEC. ENTERED THE IDLE LOOP. ; ; CNTSW: MOV R0,-(SP) ; SAVE R0 MOV R3,-(SP) ; AND ALSO R3 MOV @#$TKTCB,R0 ; GET CURRENT TCB ADDRESS CALL MATCH ; IS IT A MATCH? BEQ CONT1 ; NO. SO CONTINUE AND TRY THE NEW ONE CALL 203$ ; YES, ADD IN CPU TIME AND QIO'S ; ; NOW CHECK THE NEW TASK FOR A MATCH ; CONT1: MOV R5,R0 ; COPY NEW TCB ADDRESS TO R0 CALL MATCH ; IS IT A MATCH? BEQ CONT2 ; NOPE. OH WELL. MOV T.UCB(R5),R0 ; YES, GET UCB ADDRESS BIS #340,@#PS ; RAISE PRIORITY TO 7 MOV U.TIC2(R0),B.CPU2(R1);;; STORE HIGH ORDER TIME MOV U.TIC1(R0),B.CPU1(R1);;; AND LOW ORDER TIME CLRB @#PS ;;; AND DROP IT AGAIN CONT2: ; MOV (SP)+,R3 ; RESTORE R3 MOV (SP)+,R0 ; AND R0 MOV R5,@#$TKTCB ;*INTERCEPTED INSTRUCTION RETURN ; BACK TO NORMAL CODE ; ; THIS ROUTINE CALCULATES THE ELAPSED CPU TIME ; AND ADDS IN QIO'S ISSUED SINCE LAST TIME COUNTER'S ZEROED. ; ON EXIT QIO COUNTERS ARE AGAIN ZEROED ; 203$: ; MOV T.UCB(R0),R3 ; GET UCB ADDRESS BIS #340,@#PS ; SET PRIORITY TO 7 MOV U.TIC2(R3),-(SP);;; STORE HIGH ORDER TIME MOV U.TIC1(R3),R0 ;;; AND GET LOW ORDER CLRB @#PS ;;; AND DROP PRIORITY SUB B.CPU1(R1),R0 ; CALCULATE ELAPSED CPU TIME (LOW) SBC (SP) ; AND REMEMBER THE CARRY ADD R0,B.TOT1(R1) ; ADD IT TO TOTAL ADC B.TOT2(R1) ; AND THE CARRY SUB B.CPU2(R1),(SP) ; THE HIGH ORDER ADD (SP)+,B.TOT2(R1); ADD IN THE HIGH ORDER RETURN ; AND RETURN ;+ ; -- MATCH ; THIS ROUTINE SEARCHES FOR A MATCH IN THE ACCOUNTING LIST ; ; INPUTS: ; ; R0 -- CONTAINS TCB ADDRESS TO SCAN FOR ; ; PRINTS: ; ; Z=1 -- NO ENTRY FOUND ; ; Z=0 -- FOUND ENTRY ; R0 -- TCB ADDRESS ; R1 -- ACCOUNTING BLOCK ADDRESS ; R2 -- PREVIOUS ENTRY IN LIST ; ;- MATCH: MOV PC,R2 ; GET CURRENT PC (BECAUSE WE ARE PIC CODE) ADD #ACCHD-MATCH-2,R2 ; CALCULATE ACTUAL ADDRESS 210$: MOV (R2),R1 ; GET NEXT ENTRY ADDRESS BEQ 230$ ; IF = 0, THEN NO MATCH CMP R0,2(R1) ; DOES THIS ONE MATCH? BEQ 220$ ; YES. GIVE IT BACK TO USER MOV R1,R2 ; NO. CONTINUE LOOKING BR 210$ ; TRY AGAIN 220$: CLZ ; LET USER KNOW THAT WE GOT ONE 230$: RETURN ; AND RETURN ; ; DATA BASES ; ACCHD: .WORD 0 ; ACCOUNTING LISTHEAD .WORD .-2 ; ACCPTR: .WORD 0 ; TSKLOG TCB ADDRESS ; TIME: .WORD 0,0 ; TIME FROM START OF TSKLOG ; ; END OF CODE (IN NODE) ; CODEN=. ; ; SIZE OF ALL CODE ; CODSIZ=CODEN-CODST .PAGE .SBTTL OFFSETS TO INTERCEPTS ; ; OFFSET IN REQSB FOR INTERCEPT ; .IF NDF M$$MUP STOFF=19.*2 .IFF STOFF=25.*2 .ENDC ; ; OFFSET IN SYSXT FOR INTERCEPT OFFSET ; CSOFF=11.*2 .IF DF L$$DRV&M$$MGE CSOFF=CSOFF+<4.*2> .IFTF CSOFF=CSOFF+<3.*2> .IFT CSOFF=CSOFF+<2*2> .ENDC CSOFF=CSOFF+<11.*2> .IF NDF M$$MGE CSOFF=CSOFF+<12.*2> ; THIS VALUE WRONG??? .ENDC CSOFF=CSOFF+<9.*2> .IF DF C$$CKP&T$$BUF!A$$TRP CSOFF=CSOFF+<9.*2> .IFTF CSOFF=CSOFF+<16.*2> .IF DF S$$TOP CSOFF=CSOFF+<10.*2> .ENDC ; S$$TOP CSOFF=CSOFF+<10.*2> .IF DF P$$P45 CSOFF=CSOFF+<10.*2> .ENDC CSOFF=CSOFF+<9.*2> .IF DF G$$EFN CSOFF=CSOFF+<2.*2> .ENDC ;G$$EFN CSOFF=CSOFF+<2.*2> .IF DF S$$TOP CSOFF=CSOFF+<4.*2> .ENDC ; S$$TOP .IFT CSOFF=CSOFF+<1*2> .ENDC CSOFF=CSOFF+<20.*2> .IF DF M$$MGE CSOFF=CSOFF+<6*2> .IFF .IF DF E$$EAE CSOFF=CSOFF+<9.*2> .ENDC .IFTF CSOFF=CSOFF+<2*2> .IF DF F$$LPP CSOFF=CSOFF+<3*2> .IF DF M$$MGE CSOFF=CSOFF+<7*2> .IF DF P$$LAS CSOFF=CSOFF+<3*2> .ENDC .ENDC CSOFF=CSOFF+<10.*2> .ENDC .ENDC ; ; END OF OFFSETS ; .PAGE .LIST BEX ; .END START