.TITLE ACCOUNT - RECORD TASK ACTIVITY STATISTICS .IDENT /V03.00/ ; ; TO ASSEMBLE THIS PROGRAM, USE... ; ">MAC ACCOUNT=[200,200]RSXMC/PA:1,[1,1]EXEMC/ML,[6,10]ACCOUNT" ; (WITH VARIATIONS AS APPROPRIATE). ; ; REVISED 24-NOV-79 (SGD) : V02.00 ; ; INCLUDED LOGIC FOR "PSEUDO-TASKS" REPRESENTING TT: SIGNON TIME. ; THESE PSEUDO-TASKS SHOW UP IN THE LOG RECORD OUTPUT WITH NAME ; "LOG$nn", WHERE 'nn' IS THE UNIT NUMBER OF THE TT: DEVICE LOGGED ; ON. THE LISTED PRIORITY, MEMORY, AND ALL SAMPLE TIMES EXCEPT ; ELAPSED ARE RECORDED AS ZERO. (THE '$' INSURES THAT NO TASK CAN ; HAVE AN IDENTICAL NAME). ; ; REVISED 4-SEP-82 P. KURJAN V03.00 ; ; Take V02.00 from RSX SIG tape [370,120] with thanks to SGD ; for a job well done. ; ; V03.00 modifications (for use in G. Waychunas X-Ray Lab, ; Stanford University) include: ; ; -Add logic for conditional selection of "pseudo-tasks" only ; to allow logging of terminal connect time without logging of ; task execution statistics. ; ; -Add logic for conditional initialization from parameter file ; [6,10]ACCTLOG.PAR. Allows user to dynamically specify ; ; a. A list of account numbers which will not be logged. ; b. A list of tasknames which will not be logged. ; c. A minimum time threshhold (login time for pseudo-tasks; ; time active for tasks) below which logging will not occur. ; ; to assist in logging required information without burdensome ; log file sizes. For example ...PIP, ...F4P, ...TKB, ...MAC, ; etc. might not be logged if users are not being charged for ; program development. ; ; ACCTLOG.PAR is an ASCII file which is maintained by the user ; with any text editor. ; .PAGE ; THIS PROGRAM IS DESIGNED TO RECORD TASK ACTIVITY UNDER A PDP11 MAPPED ; RSX11M SYSTEM. IT WORKS BY SAMPLING ALL ACTIVE TASKS EVERY "TPSMPL" ; CLOCK TICKS. ON EACH SAMPLE, TASKS WHICH ARE NOT IN THE PROCESS OF ; BEING RECORDED ARE ASSUMED TO BE NEW, AND TASKS WHICH ARE NOT ON THE ; ACTIVE TASK LIST ARE ASSUMED TO HAVE TERMINATED, AND A "LOG RECORD" ; OF THEIR ACTIVITY IS WRITTEN OUT. THUS, IN GENERAL, ONE LOG RECORD ; CORRESPONDS TO ONE TASK EXECUTION, UNLESS THE TASK TERMINATES AND ; RESTARTS (WITH THE SAME TASK NAME) WITHIN ONE SAMPLE WINDOW. TO STOP ; THE PROGRAM, A "RESUME" COMMAND SHOULD BE GIVEN FOR THE TASK WHICH WILL ; CAUSE IT TO FLUSH OUT THE RECORDS FOR ALL TASKS CURRENTLY BEING RECORDED, ; AND THEN EXIT. A TASK'S LOG RECORD WILL ALSO BE FLUSHED IF THE NUMBER ; OF SAMPLES FOR IT GETS TO 65535 (UNSIGNED 16 BIT QUANTITY). THIS ; CORRESPONDS TO ABOUT 9 HOURS OF EXECUTION AT ONE SAMPLE EVERY 500MS. ; NOTE THAT THE ABOVE TWO FEATURES WILL ALSO CAUSE A LOG RECORD NOT TO ; CORRESPOND EXACTLY WITH A TASK'S EXECUTION, HOWEVER, BOTH ARE EASY ENOUGH ; TO DETECT/PREVENT IF DESIRED. ; ; THE FORMAT OF THE TASK RECORD WRITTEN OUT IS AS FOLLOWS: ; ; WORD ITEM ; ---- ---- ; 1 INTERNAL LINK WORD - IGNORE ; 2 FLAGS WORD - NO FLAGS PRESENTLY IN USE ; 3 START TIME - YEAR (EG 79=1979) ; 4 START TIME - MONTH ; 5 START TIME - DAY ; 6 START TIME - HOUR ; 7 START TIME - MINUTE ; 8 START TIME - SECOND ; 9 START TIME - CLOCK TICKS PAST SECOND ; 10 NUMBER OF CLOCK TICKS PER SECOND (60 FOR U.S. SYSTEMS) ; 11 NUMBER OF CLOCK TICKS PER SAMPLE PERIOD (TPSMPL) ; 12-13 TASK NAME IN RAD50 ; 14 TASK "CURRENT" UIC ; 15 TASK PRIORITY (AT TASK START) ; 16 TASK MEMORY IN 64 BYTE BLOCKS (AT START) ; 17 NUMBER OF SAMPLES TAKEN FOR TASK ; 18 # OF SAMPLES IN WHICH TASK WAS SUSPENDED ; 19 # OF SAMPLES IN WHICH TASK WAS IN WAITFOR (ANY REASON) ; 20 # OF SAMPLES IN WHICH TASK WAS CHECKPOINTED. ; 21 # OF SAMPLES IN WHICH TASK WAS STOPPED. ; 22 # OF SAMPLES IN WHICH TASK HAD CONTROL OF CPU ; 23 # OF SAMPLES FOR WHICH TASK HAD I/O CHARGED TO LP: ; 24 # SAMPLES FOR WHICH TASK HAD DISK I/O ACTIVE. ; ; SAMPLE TIMES SHOULD BE ON THE ORDER OF A SECOND FOR MOST APPLICATIONS. ; IT IS SET WITH THE GLOBAL SYMBOL "TPSMPL" (SEE BELOW). THE SYSTEM USES A ; HASHING SCHEME BASED ON THE TASK NAME, SO SAMPLES ARE REASONABLY FAST ; OPERATIONS. IF SMPPRV IS DEFINED, THEN PRIVILEGED TASKS WILL BE SAMPLED, ; OTHERWISE THEY WILL BE IGNORED. .PAGE ; TWO LOGICAL UNITS ARE USED: ; ; LU1: A FILE (SY:[6,10]ACCTLOG.DAT) WHERE ACCOUNTING DATA ; WILL RESIDE. THIS FILE WILL BE CREATED IF IT DOES NOT ; EXIST, OTHERWISE IT WILL BE APPENDED. ; LU2: SHOULD BE TI: - FOR TERMINATION MESSAGES. ; ; ; STEVEN G. DUFF FOR SANTA FE ENGINEERING SERVICES R&D 1979. ; 505 SOUTH MAIN ST. ; ORANGE, CAL. 92668 USA ; (714) 558-1300 ; ; THIS SOFTWARE IS UNLICENCED AND UNCOPYRIGHTED AND PERMISSION IS HEREBY ; GRANTED BY THE AUTHOR TO ANYONE TO MAKE USE OF IT IN ANY MANNER. HOWEVER, ; NO CLAIM OR WARRANTY, EXPRESS OR IMPLIED, IS MADE AS TO ITS FITNESS OR ; MERCHANTABILITY FOR ANY PARTICULAR PURPOSE OR USE. NEITHER THE AUTHOR, ; NOR SFES ASSUME ANY LIABILITY FOR CONSEQUENCES ARISING OUT OF THE USE ; OF THIS SOFTWARE. THE AUTHOR REQUESTS THAT ANY SUCH USE RETAIN ; THE ABOVE IDENTIFICATION AND DISCLAIMER IN THE SOURCE. .PAGE .PSECT .SBTTL GLOBAL DEFINITIONS ; ; MAXTSK DEFINES THE MAXIMUM NUMBER OF SIMULTANEOUS TASKS THAT ACTLOG ; IS ABLE TO MAINTAIN. IT DETERMINES THE SIZE OF THE LOG RECORD AREA. ; THIS INCLUDES THE SIGNON-TIME PSEUDO TASKS IF SGNRCD IS DEFINED (BELOW). ; MAXTSK == 30. ; ; NBUCKS DEFINES THE NUMBER OF HASH BUCKETS. IT SHOULD BE A PRIME #. ; LARGER NUMBERS WILL SPEED UP THE PROGRAM SOMEWHAT; A GOOD CHOICE IS ; A NUMBER IN THE VICINITY OF MAXTSK. IT CAUSES ONE WORD TO BE ALLOCATED ; FOR EACH BUCKET. ; NBUCKS == 51. ; ; NUCBS DEFINES THE NUMBER OF UCBS THAT WILL BE EXAMINED FOR ; CHARGING I/O DATA. TWO WORDS ARE USED FOR EACH UCB IN THE UCBTBL. ; NUCBS == 7. ; ; INIALC AND EXTALC DEFINE THE INITIAL AND EXTENSION BLOCK QUANTITIES ; FOR THE LOG FILE. THEY SHOULD BOTH BE >= ABOUT 50. ; INIALC == 50. EXTALC == 50. ; ; TPSMPL IS THE NUMBER OF CLOCK TICKS BETWEEN SAMPLES. IT SHOULD BE AROUND ; ONE SECOND'S WORTH, HOWEVER, MUCH LARGER OR SMALLER VALUES ARE NOT OUT ; OF THE QUESTION DEPENDING ON THE ACCURACY DESIRED, AND THE AMOUNT OF ; OVERHEAD THAT CAN BE TOLERATED. ; TPSMPL == 45. ; ; SPC DEFINES THE NUMBER OF SECONDS BEWEEN CLOSING AND RE-OPENING ; THE LOG FILE. THE PURPOSE IS TO PREVENT LOSS OF ANY MORE DATA THAN ; NECESSARY IN THE EVENT OF A SYSTEM CRASH. OF COURSE, ACCOUNTING FOR ; TASKS OUTSTANDING AT THE TIME OF THE CRASH WILL BE LOST, AND IN ALL ; CASES SOME DATA WILL BE LOST, BUT EVERY FEW MINUTES IS A GOOD NUMBER ; SPC == 500. ; ; SMPPRV, IF DEFINED, CAUSES SAMPLING OF PRIVILEGED TASKS (if TSKRCD ; is defined) AND PRIVILEGED LOGINS (if SGNRCD is defined). ; SMPPRV == 1 .PAGE ; ; DEFINE SGNRCD TO INCLUDE SIGNON TIME LOGGING. SIGNON TIME SHOWS UP ; IN THE OUTPUT AS A "PSEUDO-TASK" WITH THE NAME "LOG$nn" WHERE 'nn' ; IS THE NUMBER OF THE TT: DEVICE BEING LOGGED. ONLY ELAPSED TIME IS ; INDICATED FOR THIS TASK. INCLUDING THIS FEATURE INCREASES THE SIZE ; OF THE PROGRAM BY A FEW HUNDRED WORDS. ; SGNRCD == 1 ; ; Define TSKRCD to include task logging (e.g. logging of non-pseudo tasks). ; To avoid disturbing V02.00 logic more than necessary task statistics ; are always maintained internally; they are written to ACCTLOG.DAT only ; if TSKRCD is defined. ; ; NOTE that if neither SGNRCD nor TSKRCDis defined nothing will be output ; to ACCTLOG.DAT! ; TSKRCD == 1 ; .IF DF SGNRCD!TSKRCK .IFF .ERROR ;Conditionals selected disable all logging! .ENDC ; ; THE SYMBOL LOGUIC CONTROLS HOW UICS ARE DETERMINED. IF IT IS DEFINED, ; THEN THE DEFAULT UIC FOR TASKS AND THE LOGIN UIC FOR PSEUDO-TASKS IS ; USED AS THE CHARGING UIC IN THE LOG RECORD FOR THOSE TASKS. IT IS ; (IN THEORY) NOT POSSIBLE FOR AN UNPRIVILEGED USER TO ALTER THESE UICS ; BY A "SET /UIC..." OR A "RUN JOB/UIC=...". THE UIC WRITTEN OUT TO THE ; ACCOUNTING FILE WILL STILL BE THE ONE SET A LOGIN TIME. IF THE SITE ; WANTS THE CONVERSE, THAT IS, USERS CAN VOLUNTARILY ALTER THE BILLING ; UIC, THEN LOGUIC SHOULD BE LEFT UNDEFINED. ; LOGUIC == 1 .IIF DF LOGUIC HUIC=H.CUIC .IIF NDF LOGUIC HUIC=H.DUIC .IIF DF LOGUIC UUIC=U.LUIC .IIF NDF LOGUIC UUIC=U.UIC ; ; IF SGNRCD HAS BEEN DEFINED, THEN TTSIZE SHOULD GIVE THE HIGHEST ; UNIT NUMBER OF THE TT: DEVICE YOU WANT TO HAVE LOGGED. ; TTSIZE == 7 ; ; ADDRESS OF LINE FREQ. CLOCK INTERRUPT VECTOR (FOR STEALING INTERRUPT) ; CLKVEC == 100 ; ; Define PARAMS to enable dynamic parameter specification from ASCII ; file [6,10]ACCTLOG.PAR. Parameters allow the user to specify: ; ; -A list of account numbers which will not be logged. ; -A list of installed tasknames which will not be logged. ; -A minimum time threshhold for logging of logins (connect time) ; and tasks (active time). ; ; to minimize logging file storage requirements. (For compatibility with ; V02.00 dynamic parameter specification does not prevent internal ; sampling; it merely disables writing sampled data to output file ; ACCTLOG.DAT.) ; ; ACCTLOG.PAR is an ASCII file; records must not span block boundaries. ; Column 1 of each line designates the parameter type; the parameter field ; begins in column 3. One or more spaces or tabs separate the parameter ; field from the comment field. Parameter types are: ; ; A Account. Specified as [g,m]. Do not log activity in this account. ; T Task. Specified in ASCII (right fill with spaces if .LT. 6 characters). ; Do not log activity for this task. ; M Minimum Seconds; range 0-1000. Do not log activity (signon connect ; Time time or task active time) below this threshhold. ; If more than one M entry appears in ACCTLOG.PAR the final ; entry is the only one that matters! ; E End. Last line of parameter file to be read (anything following ; is treated as comments). ; C Comment. Entire line is treated as a comment. ; ; A typical ACCTLOG.PAR might read: ; ;C Parameter file for G. Waychunas X-Ray Lab Chargeback Accounting ;C ;M 15. Don't log activity unless duration exceeds 15 seconds. ;A [6,12] Don't log Kurjan's account ;A [300,300] Or Waychunas's ;T ...TKB Or program development utilities ;T ...MAC ;T ...PIP ;T ...F4P ;E ; PARAMS == 1. ; .IF DF PARAMS ; ; MXTSKD defines the maximum number of tasks ("T" entries) contained in ; parameter file [6,10]ACCTLOG.PAR. Any entries in excess of MXTSKD ; are ignored. ; MXTSKD == 40. ; ; MXACCD defines the maximum number of accounts ("A" entries) contained in ; parameter file [6,10]ACCTLOG.PAR. Any entries in excess of MXACCD ; are ignored. ; MXACCD == 20. ; .ENDC ; .PAGE .SBTTL MCALL AND SYSTEM STRUCTURE DEFINITIONS .MCALL CLOSE$,OFID$A,CMKT$S,QIOW$S .MCALL FSRSZ$,FDBDF$,FDAT$R,FDOP$A,OPEN$A,OPEN$W .MCALL MRKT$C,ASTX$S,PUT$,SPND$S,EXIT$S,GTIM$S .MCALL OPEN$R,FDOP$R,GET$S ; ; SYSTEM DATA STRUCTURE OFFSETS ; .MCALL TCBDF$,PCBDF$,HDRDF$,DCBDF$,UCBDF$,SCBDF$,PKTDF$ .MCALL FCSBT$ TCBDF$ PCBDF$ ,,1 HDRDF$ DCBDF$ ;DEVICE CONTROL BLOCK OFFSETS UCBDF$ ;UNIT CONTROL BLOCK OFFSETS SCBDF$ ;STATUS CONTROL BLOCK OFFSETS PKTDF$ ;I/O PACKET OFFSETS FCSBT$ ;FCS BIT DEFINITIONS .PAGE .SBTTL TERMINATION MESSAGES AND CONSTANTS ; ; MESSAGE IMAGES USED BY THE ER$XXX BRANCH POINTS UPON TERMINATION ARE ; DEFINED HERE. ; SPACE = ^O40 ;DEFINE A BLANK ERACCM: .ASCII /ACCOUNTING TERMINATED BY OPERATOR/ ERACCL = .-ERACCM ERCOFM: .ASCII /CAN'T OPEN ACCOUNTING FILE./ ERCOFL = .-ERCOFM ERMERM: .ASCII /TOO MANY TASKS FOR ACCOUNTING/ ERMERL = .-ERMERM ERCWFM: .ASCII /CAN'T WRITE TO ACCOUNTING FILE./ ERCWFL = .-ERCWFM .PAGE ERNESM: .ASCII /NO EXEC. POOL SPACE FOR ACCOUNTING/ ERNESL = .-ERNESM EREXTM: .ASCII /ACCOUNTING TERMINATED./ EREXTL = .-EREXTM ; .IF DF PARAMS ERPARM: .ASCII/ACCTLOG.PAR FILE READ ERROR/ ERPARL = .-ERPARM ; .ENDC ; .PAGE .SBTTL OUTPUT AND LOG FILE DEFINITIONS AND DATA AREAS. .EVEN ; .IF DF PARAMS .IFF ; DSD =LOGDSD ;If no parameter file FACC ==FO.APD ;initial open for append ; .IFT ;If parameter file ; DSD =PARDSD FACC ==FO.RD ;initial open for read .ENDC ; FSRSZ$ 1. ;ONE IO BUFFER (shared between .PAR and .DAT) LOGFDB: FDBDF$ ;FDB FOR ACCOUNTING LOG FILES FDOP$A 1.,DSD,,FACC ; ; SET UP THE DATA SET DESCRIPTORS FOR THE LOG FILE .EVEN LOGDVS::.ASCII /LB0:/ LOGDVL= .-LOGDVS .EVEN LOGDIS::.ASCII /[6,10]/ ;UIC STRING LOGDIL= .-LOGDIS ;UIC STRING LENGTH .EVEN LOGNMS::.ASCII /ACCTLOG.DAT/ ;FILENAME LOGNML= .-LOGNMS ;FILENAME STRING LENGTH ; .IF DF PARAMS .EVEN PARNMS: .ASCII /ACCTLOG.PAR/ PARNML = .-PARNMS .ENDC ; ; DATASET DESCRIPTORS ; .EVEN LOGDSD: .WORD LOGDVL,LOGDVS,LOGDIL,LOGDIS,LOGNML,LOGNMS ; .IF DF PARAMS PARDSD: .WORD LOGDVL,LOGDVS,LOGDIL,LOGDIS,PARNML,PARNMS ; ACCDSD: .WORD 1,PARBUF+2 ;DIRECTORY SET DESCR FOR .ASCPP CALL ; .ENDC ; .PAGE .SBTTL DATA STRUCTURE DEFINITIONS ; ; LOG RECORD STRUCTURE DEFINITIONS. THESE ALL BEGIN WITH "L.", FOLLOWED ; BY THREE LETTERS DESCRIBING THE FIELD, AND ENDING WITH "O" FOR AN OFFSET ; OR A "L" FOR LENGTH. ALL FIELDS HAVE BOTH L AND O DEFINITIONS. ; L.PNTO = 0. ;POINTER WORD (MUST BE AT OFFSET 0) L.PNTL = 2. ;POINTER WORD LENGTH L.FLGO = L.PNTO+L.PNTL ;FLAG WORD OFFSET L.FLGL = 2. ;FLAG WORD LENGTH L.TIMO = L.FLGO+L.FLGL ;TIME FIELD OFFSET L.TIML = 16. ;TIME FIELD LENGTH (YR-MO-DA-HR-MN-SEC-TIC-T/S) L.TPSO = L.TIMO+L.TIML ;TICKS PER SAMPLE L.TPSL = 2. ;TICKS PER SAMPLE LENGTH L.TNMO = L.TPSO+L.TPSL ;TASKNAME OFFSET L.TNML = 4. ;TASKNAME LENGTH (RAD50) L.UICO = L.TNMO+L.TNML ;UIC OF TASK L.UICL = 2. ;UIC FIELD LENGTH L.PRIO = L.UICO+L.UICL ;PRIORITY OF TASK L.PRIL = 2. ;PRIORITY LENGTH L.MEMO = L.PRIO+L.PRIL ;MEMORY ALLOCATED TO TASK L.MEML = 2. ;MEMORY FIELD LENGTH (64-BYTE BLOCKS) L.SMPO = L.MEMO+L.MEML ;TICKED EACH SAMPLE L.SMPL = 2. ;TICK FIELD OFFSET L.SPNO = L.SMPO+L.SMPL ;TICKED IF TASK SUSPENDED L.SPNL = 2. ;ONE WORD L.WFRO = L.SPNO+L.SPNL ;TICKED IF TASK IN WAITFOR L.WFRL = 2. ;ONE WORD L.CKPO = L.WFRO+L.WFRL ;TICKED IF TASK CHECKPOINTED L.CKPL = 2. ;ONE WORD L.STPO = L.CKPO+L.CKPL ;TICKED IF TASK IS STOPPED L.STPL = 2. ;ONE WORD L.CPUO = L.STPO+L.STPL ;TICKED FOR TASK IN CNTRL OF CPU L.CPUL = 2. ;ONE WORD L.LPCO = L.CPUO+L.CPUL ;TICKED FOR LP: OUTPUT BUSY L.LPCL = 2. ;ONE WORD L.D$CO = L.LPCO+L.LPCL ;TICKED FOR DP: OR DK: I/O BUSY L.D$CL = 2. ;ONE WORD LOGLEN == L.D$CL+L.D$CO ;LENGTH OF ONE LOG RECORD ; ; BIT OFFSETS FOR FLAG WORD (L.FLG*) ; FL.MRK = 1 ;MARK BIT FOR TICK AND FLUSH SCANS. .PAGE .SBTTL DATA AREAS ; ; LOG RECORD AREA. HERE IS WHERE THE ACTUAL ACCOUNTING LOGS ARE KEPT ; AND UPDATED. RECORDS ARE CHAINED THROUGH THEIR POINTER FIELDS. IF ; THE RECORD IS NOT ATTACHED TO A TASK, THEN IT IS CHAINED ON THE "FREE" ; POINTER LIST AND AVAILABLE FOR USE. OTHERWISE, IT IS BEING TICKED BY ; THE PRESENCE OF A PARTICULAR TASK (NAME/UIC), AND IS CHAINED BY THE HASH ; VALUE OF THE NAME/UIC ON A CHAIN THAT BEGINS AT THE CORRESPONDING HASH ; BUCKET (BELOW). A LOG RECORD IS ALLOCATED FROM THE FREE LIST TO A ; HASH CHAIN WHEN A TASK NAME IS SEEN FOR WHICH NO RECORD EXISTS. A LOG ; RECORD IS FLUSHED TO THE FILE AND FREED UP WHEN THE TASK NAME TO WHICH ; IT IS LOGICALLY CONNECTED IS NOT FOUND ON A PASS THROUGH THE ACTIVE TASK ; LIST (A MARK BIT IN THE FLAGS FIELD OF THE LOG RECORD IS USED FOR THIS). ; .EVEN LOGRCS::.BLKB LOGLEN*MAXTSK ENDRCS == . ;END OF LOG RECORD AREA FREE:: .BLKW 1. ; ; HASH BUCKETS. ; BUCKTS::.BLKW NBUCKS ENDBUC == . ; ; THIS IS THE UNIT-CONTROL-BLOCK TABLE THAT IS SET UP AT INITIALIZATION TIME. ; THE FORMAT IS TWO WORD ENTRIES OF THE FORM {UCB-ADDR, LOG-REC-OFFSET}. ; ONE SUCH PAIR IS DEFINED IN THE INITIALIZATION FOR ANY UCB THAT IS TO ; BE EXAMINED ON EACH WAKEUP SCAN. THE CORRESPONDING LOG-REC-OFFSET DEFINES ; THE OFFSET OF THE FIELD IN THE LOG RECORD THAT IS TO BE INCREMENTED WHEN ; THE UCB IS FOUND TO BE ACTIVE WITH I/O FOR A GIVEN TASK. ON EACH WAKEUP ; SCAN, THE PROGRAM MAKES A PASS OVER ALL UCBS DEFINED IN THIS TABLE. IF ; THE UCB/SCB IS BUSY WITH I/O FOR A TASK WITH AN ACTIVE LOG RECORD, THEN ; IT IS CHARGED TO THAT TASK BY INCREMENTING THE INDICATED FIELD IN THE LOG ; RECORD. THE TABLE END IS MARKED BY A PAIR OF ZERO WORDS. ; UCBTBL::.BLKW *2. .PAGE ; ; THESE ARE THE DATA AREAS FOR THE LFC INTERRUPT PROCESSING. IT INCLUDES ; A BLOCK OF CODE WHICH IS COPIED (DURING INITIALIZATION) INTO AN EXECUTIVE ; POOL TO INTERCEPT THE LFC INTERRUPT AND RECORD THE CURRENTLY ACTIVE TASK. ; FROM THIS, IT IS POSSIBLE TO DETERMINE THE TASK WHICH HAD CONTROL OF ; THE CPU JUST PRIOR TO THE CLOCK TICK WHICH CAUSED THIS TASK TO WAKE UP. ; ACTADR: .BLKW 1 ;GETS ADDRESS OF "PTSK" IN EXEC. BUFFER ACTTCB: .BLKW 1 ;GETS PTSK ON EACH WAKEUP BEFORE IT'S DSTRY'D PRIADR: .BLKW 1 ;GETS ADDRESS OF "PPRI" IN EXEC BUFFER. PRIACT: .BLKW 1 ;GETS "PPRI" ON EACH WAKEUP (ONLY 1 BYTE USED) IBADDR: .WORD 0 ;ADDRESS OF EXECUTIVE SPACE FOR INT. CODE INTBLK: ;START OF INTERCEPT CODE MOV CTSK,PTSK ;;;MAKE CURRENT TASK PREVIOUS TASK MOV @#$TKTCB,CTSK ;;;RECORD CURRENT TCB IN CASE ANOTHER TICK MOVB CPRI,PPRI ;;;ROTATE PRIORITY (FOR CHECKING IDLE) MOVB @#$CURPR,CPRI ;;;MOVE IN CURRENT TASK PRIORITY JMP @INTCON ;;;CONTINUE WITH INTERRUPT CTSK: .BLKW 1 ; TCB OF TASK LAST IN CONTROL OF CPU PTSK: .BLKW 1 ; TCB IN CONTROL AT LFC INT. BEFORE THAT. INTCON: .BLKW 1 ; GETS ADDRESS OF INTERRUPT CONTINUATION CPRI: .BLKB 1 ; PRIORITY OF TASK LAST EXECUTING PPRI: .BLKB 1 ; PRIORITY OF TASK EXECUTING BEFORE THAT. IBLEN = .-INTBLK ;LENGTH OF THE INTERRUPT BLOCK .IF DF SGNRCD .PAGE ; ; THIS IS THE TT: UCB TABLE SET UP DURING INITIALIZATION. THE iTH ENTRY ; IS SET TO POINT TO THE UCB FOR TTi:. A ZERO ENTRY INDICATES NO UCB. ; TTUTBL:: .BLKW TTSIZE+1 ENDTTU == . ; ; THIS IS A SECONDARY TABLE WHICH IS INITIALIZED WITH THE "$nn" PART ; OF THE PSEUDO TASK NAME FOR THE nnTH ENTRY. IT SAVES RECOMPUTING IT ; EACH TIME IT IS LOGGED. ; TTUNM2:: .BLKW TTSIZE ENDTNM == . ; ; THIS IS A BOGUS TCB/PCB/HDR SET THAT IS GIVEN TO THE "FIND" ROUTINE ; TO ALLOW IT TO LOOK UP PSEUDO TASKS IN ITS NORMAL FASHION. SINCE ; ONLY CERTAIN FIELDS ARE USED, THESE BLOCKS OVERLAP. CONSIDERABLE ; CARE SHOULD BE TAKEN WHEN ALTERING ANY LOGIC WHICH MIGHT EXAMINE THEM. ; .EVEN TTUTCB::.BLKB T.PCB ;ONLY USE PART OF TCB UP TO PCB PNTR TTPPTR: .WORD TTUPCB ;POINT PSEUDO-TASK PCB AS TTUPCB TTUPCB == .-P.HDR ;DON'T NEED PCB UP TO HDR LINK, OVERLAP IT .BLKW 1 ;HEADER IS TTUHDR (SET UP LATER) TTUHDR = .-HUIC ;DONT NEED PART UP TO UIC, OVERLAP IT. .BLKW 1 ;ONE WORD FOR UIC .ENDC ; ; This is a table listing RAD50 names of installed tasks ; whose logged data is not written to ACCTLOG.DAT. The table must ; be terminated by a zero word. ; .IF DF PARAMS ; TSKTBL:: .REPT 2*MXTSKD .WORD 0 .ENDM ENDTSK == . ; .WORD 0 ;Ensure zero word at end ; ; This is a table listing account numbers (high byte=g; low byte=m) whose ; logged data is not written to ACCTLOG.DAT. The table must be ; terminated by a zero word. ; ACCTBL:: .REPT MXACCD .WORD 0 .ENDM ENDACC == . ; .WORD 0 ;Ensure zero word at end ; ; This is a table listing minimum time threshhold for writing logged ; data to ACCTLOG.DAT (connect time for logins; active time for tasks). ; TIMTBL: .WORD 0 ; PARBUF: .BLKB 12. ;Input buffer for ACCTLOG.PAR ENDPAR == . ; .ENDC ; .IF NDF TSKRCD ; TSKBUF: .BLKW 2 ;Temporary storage for R50/ASCII conversion ; .ENDC ; .PAGE .SBTTL INITIALIZATION OF LOG RECORDS AND HASH TABLE ACCT:: MOV #LOGRCS,FREE ;SET FREE LIST TO FIRST LOG RECORD MOV #MAXTSK-1,R0 ;SET CNTR FOR LOOP TO INIT PNTR FIELDS MOV #LOGRCS,R1 ;R1 IS "NEXT" POINTER VALUE ; ; LOOP HERE INITIALIZING EACH POINTER FIELD OF EACH LOG RECORD IN TURN ; INIT01: ADD #LOGLEN,R1 ;POINT TO "NEXT" REC MOV R1,-LOGLEN(R1) ;MOVE IT INTO THE APPROPRIATE POINTER FIELD SOB R0,INIT01 ;BACK FOR MORE IF NOT DONE CLR @R1 ;ZERO FINAL LOG REC. ; ; NOW INITIALIZE THE HASH BUCKETS TO ZERO (SIGNIFYING EMPTY) ; MOV #BUCKTS,R1 ;POINT TO FIRST BUCKET INIT02: CLR (R1)+ ;ZAP IT CMP #ENDBUC,R1 ;LAST ONE? BHI INIT02 ;BACK IF NOT .IF DF SGNRCD .PAGE .SBTTL INITIALIZATION OF TT: TABLES ; ; INITIALIZE THE TTUTBL ENTRIES TO ZERO MOV #TTUTBL,R1 ;R1 IS TTUTBL POINTER ; ; LOOP HERE CLEARING SUCCESSIVE ENTRIES ; IN0201: CLR (R1)+ CMP #ENDTTU,R1 BHIS IN0201 ; ; NOW CHAIN DOWN THE DCBS, LOOKING FOR TT: DEVICES ; MOV $DEVHD,R0 ;R0 POINTS TO CURRENT DCB ON CHAIN ; ; LOOP HERE ON DCBS LOOKING FOR ONES FOR TT: ; IN0202: CMP D.NAM(R0),#"TT ;IS THIS A TT: DEVICE? BNE IN0204 ;IF NOT, SKIP IT. MOVB D.UNIT(R0),R3 ;GOT ONE. GET LOW UNIT # IN R3 TO START MOV D.UCB(R0),R2 ;R2 POINTS TO CURRENT UCB. ; ; LOOP HERE ON UCBS FOR THIS DCB, STUFFING THE UCB ADDRESS INTO THE ; APPROPRIATE SLOT OF THE TTUTBL. ; IN0203: CMP #TTSIZE,R3 ;CHECK FOR OUT OF RANGE OF TABLE BLT IN0204 ;ABORT THIS DCB IF SO. MOV R3,R1 ;ELSE OK - GET OFFSET IN TTUTBL ASL R1 ;OFFSET IN R1 MOV R2,TTUTBL(R1) ;MOVE IT IN ADD D.UCBL(R0),R2 ;POINT TO NEXT UCB INC R3 ;BUMP UNIT # BY ONE. CMPB D.UNIT+1(R0),R3 ;WAS THIS THE LAST ONE? BHIS IN0203 ;LOOP IF NOT. ; ; MERGE HERE TO MOVE TO NEXT DCB ON CHAIN. ; IN0204: MOV D.LNK(R0),R0 ;NEXT DCB BNE IN0202 ;LOOP IF THERE IS ONE. .PAGE ; ; NOW SET UP THE TASK NAMES (PRECOMPUTED IN TTUNM2) ; MOV #TTUHDR,TTUPCB+P.HDR ;POINT PCB OF TTUTCB AT TTUHDR AS HEADER ; MOV #^RLOG,T.NAM+TTUTCB ;SET INVARIANT PART OF PSEUDO TASK NAME CLR R0 ;R0 HOLDS UNIT # ; ; LOOP HERE ON SUCCESSIVE TT: UNITS (UP THROUGH TTSIZE) TO COMPUTE THE ; VARIABLE PART OF THE PSEUDO TASK NAME TO WHICH THE UNIT CORRESPONDS. ; THIS MUST BE RAD50, SO IT IS NOT TOTALLY TRIVIAL. THE PURPOSE OF ; PRE-COMPUTING THE NAMES IS TO SAVE TIME DURING SAMPLING. ; IN0205: MOV #^R$,R1 ;START FORMNG IN R1 WITH "$" TO BEGIN MOV R0,R2 ;GET UNIT # BIC #7,R2 ;MASK OUT LOW-ORDER DIGIT ADD #360,R2 ;BIAS HIGH-ORDER DIGIT TO RAD50 ADD R2,R1 ;ADD IN RAD50 DIGIT*10 (SINCE HIGH ORD ALREADY) ASL R2 ;DIGIT*2 ASL R2 ;AND AGAIN ADD R2,R1 ;+(*10) +(*40) = *50 MOV R0,R2 ;NOW DO LOW ORDER DIGIT BIC #70,R2 ;CLEAR OUT HIGH ORDER DIGIT ADD #36,R2 ;BIAS AS RAD50 DIGIT ADD R2,R1 ;ADD IN FOR FINAL RESULT MOV R0,R2 ;GET TABLE INDEX ASL R2 ;CONVERT TO OFFSET MOV R1,TTUNM2(R2) ;MOVE IN THE VAR. PART OF NAME JUST COMPUTED INC R0 ;BUMP UNIT # CMP R0,#TTSIZE ;CHECK AGAINST END BLE IN0205 ;JUMP BACK IF MORE TO DO. .ENDC .PAGE .SBTTL INITIALIZATION OF UCB TABLE ; ; HERE IS WHERE THE UCBTBL ENTRIES ARE ESTABLISHED. THE FOLLOWING CODE ; CAN BE ALTERED TO INCLUDE OTHER DEVICE TYPES OF INTEREST. ; INI02A: MOV #UCBTBL,R3 ;R3 POINTS TO CURRENT ENTRY IN UCBTBL MOV $DEVHD,R0 ;R0 IS CURRENT DCB POINTER ; ; LOOP HERE ON THE SYSTEM DCB CHAIN. IF THE DCB IS A DEVICE TYPE OF ; INTEREST FOR CHARGING TASKS, THEN GO RECORD THE UCB-ADDR/LOG-OFFSET ; PAIRS IN THE TABLE. OTHERWISE SKIP IT AND GO ON TO THE NEXT DCB. ; INI02B: MOV #L.LPCO,R1 ;SET OFFSET FOR LP: DEVICE CMP D.NAM(R0),#"LP ;IS IT LP:? BEQ INI02C ;IF YES THEN DO IT. ; MOV #L.D$CO,R1 ;ASSUME OFFSET FOR DISK DEVICE CMP D.NAM(R0),#"DL ;IS IT DL:? BEQ INI02C ;IF YES THEN DO IT. CMP D.NAM(R0),#"DY ;IS IT DY:? BEQ INI02C ;IF YES THEN DO IT. ; BR INI02E ;ELSE FORGET THIS DCB, TRY NEXT. ; ; BRANCH HERE WITH A DCB POINTER OF INTEREST IN R0 TO STORE THE UCBTBL ; ENTRIES FOR IT. R3 POINTS TO THE NEXT AVAILABLE SLOT IN UCBTBL. ; INI02C: MOV D.UCB(R0),R2 ;R2 IS UCB POINTER MOVB D.UNIT+1(R0),R4 ;GET HIGH UNIT NUMBER MOVB D.UNIT(R0),R5 ;GET LOW UNIT NUMBER FOR THIS DCB SUB R5,R4 ;GET NUMBER OF UNITS (UCB'S) BIC #^O177400,R4 ;MASK OUT POSSIBLE HIGH ORDER JUNK ; ; LOOP HERE ON EACH UCB FOR THIS DCB, STORING THE ENTRY IN UCBTBL. ; R2 POINTS TO THE UCB, R1 IS THE LOG RECORD OFFSET, AND R3 IS THE ; NEXT AVAILABLE SLOT IN THE UCBTBL. ; INI02D: MOV R2,(R3)+ ;MOVE IN UCB POINTER MOV R1,(R3)+ ;MOVE IN THE LOG REC. OFFSET FOR IT. ADD D.UCBL(R0),R2 ;POINT AT NEXT UCB DEC R4 ;BUMP DOWN THE LOOP COUNTER BPL INI02D ;DO MORE AS LONG AS IT ISNT NEGATIVE. ; ; MERGE HERE TO MOVE TO THE NEXT DCB ON THE SYSTEM CHAIN (IF ANY). ; INI02E: MOV D.LNK(R0),R0 ;LOAD NEXT DCB POINTER BNE INI02B ;LOOP IF NON-ZERO MOV #0,(R3)+ ;STORE ZERO MARK WORD MOV #0,(R3)+ ;ANOTHER TO COMPLETE ENTRY. .PAGE .SBTTL INITIALIZE LFC INTERCEPTION FOR CPU TRACKING ; ; THIS CODE SETS UP THE LINE FREQ. CLOCK INTERRUPT INTERCEPTION. ON EACH ; CLOCK TICK, THIS CODE IS ENTERED, AND RECORDS THE ACTIVE TCB'S FOR THE ; CURRENT AND IMMEDIATELY PRECEEDING CLOCK TICKS. THIS INFORMATION CAN ; BE USED TO CHARGE TASKS WITH CPU TIME. ; MOV #IBLEN,R1 ;LENGTH OF EXEC. POOL SPACE NEEDED FOR CODE EMT 376 ;SWITCH TO SYSTEM STATE (NO TASK SWITCHING) .WORD INI02G ;(RETURN POINT FOR USER STATE) JSR PC,$ALOCB ;TRY TO GET THE HUNK OF POOL SPACE BCS INI02F ;EXIT IF NO-GO MOV R0,IBADDR ;ELSE MOVE IN ADDRESS OF HUNK ; ; MERGE HERE TO RETURN TO USER STACK ; INI02F: RTS PC ;RETURN TO USER STATE ; ; BACK IN USER STATE ; INI02G: MOV @#CLKVEC,INTCON ;SET CONTINUATION ADDRESS FOR LFC INTERRUPT MOV IBADDR,R0 ;GET ADDRESS OF CORE HUNK BNE INI02H ;CONTINUE IF O-K. JMP ER$NES ;ELSE ERROR OUT - NO EXECUTIVE SPACE ; ; HERE WHEN EXEC. POOL CHUNK IS OK TO MOVE IN CODE ; INI02H: MOV #IBLEN,R1 ;LENGTH OF CODE TO MOVE IN ASR R1 ;CONVERT TO WORDS FOR LOOP COUNT MOV #INTBLK,R2 ;WHERE WE ARE MOVING TO ; ; LOOP HERE TO MOVE IN SUCCESSIVE WORDS OF CODE ; INI02I: MOV (R2)+,(R0)+ ;MOVE IN NEXT WORD AND INC. POINTERS SOB R1,INI02I ;AGAIN IF MORE MOV IBADDR,R0 ;ELSE LOOP DONE, RE-GET ADDR OF CORE BLOCK MOV #PTSK-INTBLK,R1 ;OFFSET IN BLOCK OF PTSK WORD ADD R0,R1 ;COMPUTE ABS. ADDRESS OF PTSK MOV R1,ACTADR ;SET AS POINTER. MOV #PPRI-INTBLK,R1 ;OFFSET IN BLOCK OF PPRI ADD R0,R1 ;GET ABS ADDR. OF IT MOV R1,PRIADR ;SAVE IT MOV R0,@#CLKVEC ;SPLICE IN THE INTERRUPT INTERCEPT .PAGE .SBTTL FILE OPEN AND INITIALIZATION ; ; Now we (conditionally) open and read the parameter file ACCTLOG.PAR; and ; initialize TSKTBL, ACCTBL, and TIMTBL. ; .IF DF PARAMS ; OPEN$R #LOGFDB ;OPEN FOR READ (LOCATE MODE) BCC 5$ ;BRANCH IF ALL IS RIGHT JMP ER$PAR ;DIAGNOSTIC ABEND - CANNOT OPEN FILE ; 5$: MOV #ACCTBL,R4 ;R4-->Next ACCTBL addr to write MOV #TSKTBL,R5 ;R5-->Next TSKTBL addr to write 10$: GET$S #LOGFDB,#PARBUF,#12. ;GET NEXT PARAMETER RECORD BCC 15$ ;IF CARRY CLEAR ALL IS OK CMPB #IE.RBG,F.ERR(R0) ;IGNORE RECORD LENGTH ERROR ;(only 1st 12 bytes matter) BEQ 15$ CMPB #IE.EOF,F.ERR(R0) ;TREATE END-OF-FILE ERROR BEQ 50$ ;AS NORMAL TERMINATOR JMP ER$PAR ;ELSE TELL OPERATOR TO FIX ACCTLOG.PAR ; 15$: CMPB @F.NRBD+2(R0),#'E ;1ST CHARACTER IN RECORD "E"? BEQ 50$ ;IF SO WE'RE DONE READING FILE-CLOSE IT CMPB @F.NRBD+2(R0),#'A ;1ST CHARACTER IN RECORD "A"? BNE 20$ CALL DELACC ;IF SO ENTER ACCT # IN ACCTBL BR 10$ ;AND GET NEXT RECORD FROM PARAM FILE 20$: CMPB @F.NRBD+2(R0),#'T ;1ST CHARACTER IN RECORD "T"? BNE 30$ CALL DELTSK ;IF SO ENTER RAD50 TASKNAME IN TSKTBL BR 10$ ;AND GET NEXT RECORD 30$: CMPB @F.NRBD+2(R0),#'M ;1ST CHARACTER IN RECORD "M" BNE 10$ ;IF NOT ASSUME COMMENT - IGNORE CALL DELTIM ;IF SO ENTER TIME THRESHHOLD IN TIMTBL BR 10$ ;AND GET NEXT RECORD ; 50$: CLOSE$ #LOGFDB ;CLOSE PARAMETER FILE FDOP$R #LOGFDB,,#LOGDSD,,#FO.APD ;REUSE FDB FOR OUTPUT FILE ACCTLOG.OUT .ENDC ; ; NOW WE OPEN THE OUTPUT FILE. FIRST WE TRY TO OPEN AN EXISTING FILE FOR ; APPEND, AND IF THAT DOESN'T WORK, WE TRY TO OPEN A NEW ONE FOR ; WRITE. IF THAT DOESN'T WORK, THEN WE GIVE UP AND ABEND. ; OPEN$A #LOGFDB ;OPEN FOR APPEND BCC INIT03 ;BRANCH IF ALL OK FDAT$R #LOGFDB,#R.FIX,#FD.BLK,#LOGLEN,#-INIALC,#-EXTALC ;SET FILE PARMS OPEN$W #LOGFDB ;OPEN NEW FILE FOR WRITE BCC INIT03 ;BRANCH IF ALL OK. JMP ER$COF ;ABEND - CAN'T OPEN FILE .PAGE ; ; BRANCH HERE WHEN FILE IS OPEN TO ISSUE THE INITIAL MARK TIME REQUEST, ; AND GO TO SLEEP. A RESUME COMMAND ISSUED TO THE TASK WHILE IT IS SLEEPING ; WILL CAUSE IT TO EXIT. ; INIT03: MRKT$C ,SPC,2,CHKPNT ;CHECKPOINT INTERVAL MRKT$C ,5.,1,INTURP ;START IN 5 TICKS (TICK OR TWO TO SETTLE DOWN). SPND$S ;Z-Z-Z-Z-Z-Z-Z CMKT$S ;NO MORE MARK TIMES PLEASE JSR PC,FLUSH ;CLOSE OUT THE OUTSTANDING TASKS JMP ER$ACC ;RESUME ISSUED. ACCOUNTING COMPLETED. ; .IF DF PARAMS ; .PAGE .SBTTL DELETE - INITIALIZE ACCTBL, TSKTBL, TIMTBL DELETE LISTS ; ; This routine is called to convert a [g,m] account read from ACCTLOG.PAR ; to binary format and enter it into ACCTBL ; DELACC:: CMP R4,#ENDACC ;ANY ROOM LEFT IN ACCTBL? BNE 10$ ;IF SO PROCEED WITH NEW ENTRY RETURN ;IF NOT IGNORE NEW ENTRY ; 10$: MOV R4,R3 ;SETUP FOR OUTPUT BUFFER FOR FCS .ASCPP CALL MOV #1,ACCDSD ;INITIALIZE LENGTH OF DIRECTORY STRING MOV #PARBUF+2,R2 ;POINT TO START OF DIRECTORY STRING 12$: CMPB (R2)+,#'] ;LOOK FOR END OF STRING BEQ 15$ ;FOUND IT CMP R2,#ENDPAR ;HAVE WE REACHED END OF INPUT BUFFER? BEQ 20$ ;YES - INVALID DIRECTORY STRING. IGNORE. INC ACCDSD ;HAVEN'T REACHED END. INCREMENT LENGTH BR 12$ ;AND CHECK NEXT CHARACTER 15$: MOV #ACCDSD,R2 ;SETUP INPUT DSD FOR .ASCPP CALL CALL .ASCPP ;CONVERT IT TO BINARY BCS 20$ ;CHECK FOR VALID CONVERSION TST (R4)+ ;IF OK STEP PTR TO NEXT ACCTBL LOCATION 20$: RETURN ; ; This routine is called to convert an ASCII 6-character taskname (right ; space filled if necessary) from ACCTLOG.PAR to RAD50 format and enter ; it in TSKTBL ; DELTSK:: CMP R5,#ENDTSK ;ANY ROOM LEFT IN TSKTBL? BNE 10$ ;IF SO PROCEED WITH NEW ENTRY. RETURN ;IF NOT IGNORE NEW ENTRY. ; 10$: MOV F.NRBD+2(R0),R0 ;SET UP INPUT BUFFER FOR $CAT5B CALL TST (R0)+ ;TASKNAME BEGINS IN 3RD CHARACTER MOV #1,R1 ;ALLOW PERIODS AS RAD50 CHARACTERS CALL $CAT5B ;CONVERT 1ST 3 CHARACTERS MOV R1,(R5)+ ;MOVE THEM INTO TSKTBL MOV #1,R1 ;SETUP FOR 2ND $CAT5B CALL CALL $CAT5B ;CONVERT LAST 3 CHARACTERS MOV R1,(R5)+ ;THEY BELONG IN TSKTBL, TOO. RETURN ;YOU DESERVE A REST. ; ; This routine is called to read an ASCII time magnitude (seconds) from ; ACCTLOG.PAR, convert it to sampling period units, and store it in ; TIMTBL. Any value in TIMTBL is overwritten. ; ; Since single-precision multiply is used the maximum ASCII input value ; is (65531/system clock frequency) = approx 1000 seconds. This routine ; does not detect overflow. ; DELTIM:: MOV F.NRBD+2(R0),R0 ;SETUP INPUT TO $CTDB TST (R0)+ ;ASCII MAGNITUDE BEGINS IN 3RD CHARACTER CALL $CDTB ;CONVERT TO BINARY-RESULT IN R1 MOV #H$$RTZ,R0 ;MOVE SYSTEM CLOCK FREQUENCY INTO R0 CALL $MUL ;MULTIPLY-USE ONLY LOW-ORDER RESULT IN R1 MOV R1,R0 ;MOVE LOW-ORDER INTO R0 MOV #TPSMPL,R1 ;MOVE TICKS/SAMPLE INTO R1 CALL $DIV ;DIVIDE - RESULT IS THRESHHOLD IN SAMPLE PDS MOV R0,TIMTBL ;WHICH BELONGS IN TIMTBL RETURN ;WELL DONE! ; .ENDC ; .PAGE .SBTTL ALONEW - ALLOCATE & INIT. A LOG RECORD FOR A NEW TASK. ; ; THIS ROUTINE IS CALLED TO CAUSE A NEW LOG RECORD TO BE ALLOCATED, ; AND THE APPROPRIATE FIELDS INITIALIZED FOR A NEWLY SEEN TASK CONTROL ; BLOCK. ; ; (R0) -> TCB FOR TASK ; (R1) -> END OF HASH CHAIN FOR THIS TASK NAME ; JSR PC,ALONEW ; (R0) -> NEW LOG RECORD FOR TASK ; R1 DESTROYED. ; ALONEW:: MOV R2,-(SP) ;SAVE R2 FOR EXIT. TST FREE ;BE SURE THERE IS A FREE LOG REC BEQ ALON01 ;IF NOT, ABEND MOV FREE,@R1 ;POINT END OF CHAIN AT NEW BLOCK MOV @FREE,FREE ;POINT FREE AT NEXT BLOCK ON FREE LIST MOV @R1,R1 ;POINT AT NEW BLOCK CLR L.PNTO(R1) ;SET NEW END-OF-HASH-CHAIN CLR L.FLGO(R1) ;CLEAR THE FLAGS WORD MOV R1,R2 ;FORM ADDRESS... ADD #L.TIMO,R2 ;...FOR GET TIME ROUTINE GTIM$S R2 ;FILL IN THE START TIME MOV #TPSMPL,L.TPSO(R1) ;SET NUMBER OF TICKS/SAMPLE MOV T.NAM(R0),L.TNMO(R1) ;FILL IN TASK NAME - 1ST WORD MOV T.NAM+2(R0),L.TNMO+2(R1) ;2ND WORD MOV T.PCB(R0),R2 ;GET PARTITION CNTL BLK FOR TASK MOV P.BLKS(R2),L.MEMO(R1) ;SET MEMORY OCCUPIED BY TASK MOV P.HDR(R2),R2 ;GET TASK HEADER MOV HUIC(R2),L.UICO(R1) ;SET UIC OF TASK CLRB L.PRIO+1(R1) ;ZERO UPPER BYTE OF PRIORITY WORD (UNUSED) MOVB T.PRI(R0),L.PRIO(R1) ;TASK PRIORITY CLR L.SMPO(R1) ;ZERO NUMBER OF SAMPLES CLR L.SPNO(R1) ;ZERO SUSPEND COUNT CLR L.WFRO(R1) ;ZERO WAITFOR COUNT CLR L.CKPO(R1) ;ZERO CHECKPOINT COUNT CLR L.STPO(R1) ;ZERO STOPPED COUNT CLR L.CPUO(R1) ;ZERO CPU SAMPLE COUNT CLR L.LPCO(R1) ;ZERO LP: OUTPUT SAMPLE COUNT CLR L.D$CO(R1) ;ZERO DISK I/O SAMPLE COUNT MOV (SP)+,R2 ;RESTORE R2 MOV R1,R0 ;SET ADDR. OF LOG REC. IN R0 AS ADVERTISED RTS PC ;BACK WE GO. ; ; BRANCH HERE IF NO MORE LOG RECORDS ARE AVAILABLE. NOTE THAT THIS DOES ; NOT ABSOLUTELY MEAN THAT THE NUMBER OF ACTIVE TASKS MAXIMUM HAS BEEN ; EXCEEDED, SINCE SOME TASKS MAY HAVE ENDED SINCE THE LAST SAMPLE, BUT THEIR ; LOG RECORDS WILL NOT BE FREED UNTIL THE FLUSH PASS. HOWEVER, IT IS PRETTY ; DAMN CLOSE. ; ALON01: JMP ER$MRE ;MAX. LOG RECS. EXCEEDED .PAGE .SBTTL CHGCPU - CHARGE LAST ACTIVE TCB FOR CPU ACCESS ; ; THIS MODULE USES THE "PTSK" TCB POINTER RECORDED BY THE LFC INTERCEPT ; CODE TO LOOK UP THE TASK IN THE LOG RECORD AREA, AND INCREMENT ITS ; CPU SAMPLE COUNT FIELD (IF IT IS THERE). ; CHGCPU:: MOVB PRIACT,R0 ;CHECK PRIORITY OF TASK (=0 => IDLE STATE) BEQ CHGC01 ;EXIT IF IDLE MOV ACTTCB,R0 ;GET TCB POINTER JSR PC,FIND ;LOOK IT UP TST R0 ;FOUND? BEQ CHGC01 ;IF NOT, THEN JUST EXIT INC L.CPUO(R0) ;ELSE BUMP CPU COUNT FOR TASK ; ; MERGE HERE TO EXIT ; CHGC01: RTS PC ;EXIT! .PAGE .SBTTL CHKPNT - CHECKPOINT THE FILE AT SPC INTERVAL ; ; ASYNCH. ENTRY POINT TO PROCESS MARK TIME INTERRUPT FOR CHECKPOINTING ; FILE. FILE IS RE-OPENED BY ID TO KEEP THE TIME DOWN. ; CHKPNT: MOV R0,-(SP) ;SAVE R0 FOR EXIT MOV R1,-(SP) ;SAVE R1 FOR EXIT ; ; FIRST, STACK THE CURRENT FNAME BLOCK FOR OFID$A LATER (THIS IS STUPID, BUT HAS ; TO BE DONE). ; MOV #LOGFDB+F.FNB,R1 ;START AT BEGINNING OF FNAME BLOCK CHKP01: MOV (R1)+,-(SP); ;STACK A WORD CMP #LOGFDB+F.FNB+S.FNB,R1 ;CHECK FOR END OF FNAME BLOCK BHI CHKP01 ;NO? THEN BACK, SLAVE. CLOSE$ #LOGFDB ;CLOSE THE FILE (ZAPS THE FDB) ; ; LOOP HERE TO RESTORE THE FDB FOR THE OPEN BY I.D. NOTE THAT R1 MUST POINT ; TO THE WORD ADDRESS IMMEDIATELY AFTER THE LAST WORD OF THE FNAME BLOCK. ; CHKP02: MOV (SP)+,-(R1) ;MOVE IN BACKWARDS CMP #LOGFDB+F.FNB,R1 ;GOTTEN BACK TO THE BEGINNING? BLO CHKP02 ;NO? THEN MORE! OFID$A #LOGFDB ;RE-OPEN FOR APPEND. BCC CHKP03 ;DID OPEN WORK? JMP ER$COF ;NO. ABEND ; ; FILE RE-OPENED. NOW EXIT OUT. ; CHKP03: MOV (SP)+,R1 ;RESTORE R1 MOV (SP)+,R0 ;RESTORE R0 MRKT$C ,SPC,2,CHKPNT ;RE-ISSUE FOR NEXT GO-ROUND TST (SP)+ ;POP MARK TIME JUNK WORD ASTX$S ;BYE, Y'ALL .PAGE .SBTTL FIND - LOCATE LOG RECORD FOR A TASK ; ; THIS FIND ROUTINE SEARCHES THE LOG RECORD AREA FOR AN ENTRY OF A TASK ; WITH A GIVEN NAME. IT GIVES BACK BOTH A POINTER TO THE LOG RECORD FOUND ; AND THE PREVIOUS LOG RECORD ON THAT HASH CHAIN, SO THAT INSERTIONS OR ; DELETIONS CAN BE MADE. ; ; (R0) -> TCB FOR TASK TO BE SEARCHED FOR. ; JSR PC,FIND ; (R0) -> POINTS TO LOG RECORD BLOCK FOUND, OR 0 IF NONE FOUND. ; (R1) -> POINTS TO PREVIOUS ON CHAIN (OR HASH BUCKET IF FIRST). ; IF NONE FOUND, POINTS TO PREVIOUS ON CHAIN. ; (R2,R4) DESTROYED ; FIND:: MOV R3,-(SP) ;SAVE R3 FOR EXIT MOV T.NAM(R0),R3 ;GET FIRST WORD OF NAME ADD T.NAM+2(R0),R3 ;ADD IN 2ND WORD FOR HASH MOV T.PCB(R0),R4 ;GO FIND... MOV P.HDR(R4),R4 ;...CURRENT UIC... MOV HUIC(R4),R4 ;...AND HANG ONTO IT. ADD R4,R3 ;BUT STIR IT IN TO THE HASH STEW TOO. CLR R2 ;GET SET FOR DIVIDE (HASH MOD BUCKETS) DIV #NBUCKS,R2 ;GET THE MODULO ASL R3 ;CONV. REMDR INTO BYTE OFFSET FOR BUCKETS MOV R3,R1 ;GET ADDR. OF THE... ADD #BUCKTS,R1 ;...RIGHT BUCKET INTO "PREV" POINTER. MOV R0,R3 ;COPY TCB POINTER TO FREE UP R0 MOV (R1),R0 ;GET POINTER TO FIRST LOG BLOCK ON CHAIN. ; ; LOOP HERE, RUNNING DOWN THE HASH CHAIN, SEARCHING FOR THE DESIGNATED ; NAME. EXIT WHEN IT IS FOUND, OR THE END OF THE CHAIN IS REACHED. ; FIND01: BEQ FIND03 ;EXIT IF R0=0 (END OF CHAIN) CMP L.UICO(R0),R4 ;UIC'S MATCH? BNE FIND02 ;NO? THEN SKIP THIS ONE. CMP L.TNMO(R0),T.NAM(R3) ;ELSE CHECK NAME FOR A MATCH BNE FIND02 ;SKIP IT IF FIRST WORD IS NO GO. CMP L.TNMO+2(R0),T.NAM+2(R3) ;CHECK SECOND WORD BEQ FIND03 ;BRANCH IF FOUND ; ; NOT FOUND. TRY NEXT ON CHAIN ; FIND02: MOV R0,R1 ;MAKE PREVIOUS INTO CURRENT MOV @R0,R0 ;GET NEXT CURRENT BR FIND01 ;GO BACK FOR IT ; ; LOOP IS DONE. RETURN TO CALLER ; FIND03: MOV (SP)+,R3 ;RESTORE R3 RTS PC ;BACK TO CALLER .PAGE .SBTTL FLUSH - EMIT A LOG RECORD TO FILE AND DELETE IT. ; ; THE PURPOSE OF THIS ROUTINE IS TO SCAN ALL ACTIVE LOG RECORDS (THOSE ; NOT ON THE FREE LIST), AND TO EMIT AND DEACTIVATE THOSE WHICH HAVE ; THEIR MARK BIT IN THE FLAGS WORD CLEAR. THIS MEANS THAT THEY WERE NOT ; TICKED ON THE LAST PASS THROUGH THE ACTIVE TASK LIST; HENCE THE ; PRESUMPTION IS THAT THE TASK THEY REPRESENT IS NO LONGER ACTIVE. ; ALL MARK BITS ARE CLEARED BY THIS ROUTINE (RESET FOR THE NEXT PASS). ; ; JSR PC,FLUSH ; (R0,R1,R2) - DESTROYED FLUSH:: ; ; LOOP ON ALL HASH BUCKETS, EXAMINING THEIR CHAINS. R0 POINTS TO THE ; CURRENT HASH BUCKET, R1 IS USED TO POINT TO THE "PREVIOUS" ELEMENT ; ON THE CHAIN (IN CASE "CURRENT" NEEDS TO BE SPLICED OUT AND RETURNED ; TO THE FREE CHAIN), AND R2 POINTS TO THE "CURRENT" OF THE CHAIN. ; MOV #BUCKTS,R0 ;SET BUCKET PTR TO FIRST BUCKET. FLSH01: MOV R0,R1 ;BUCKET LOOP. SET PREVIOUS AS BUCKET. ; ; LOOP HERE ON EACH ELEMENT OF THE CURRENT BUCKET'S CHAIN. ; FLSH02: MOV @R1,R2 ;POINT TO NEXT CURRENT BEQ FLSH05 ;NEXT BUCKET IF NO MORE BIT #FL.MRK,L.FLGO(R2) ;CHECK MARK BIT OF THIS LOG RECORD BNE FLSH03 ;DONT DISTURB IF SET MOV R0,-(SP) ;SAVE R0 AROUND TESTS AND PUT$ ; ; If TSKRCD is not defined, write only pseudo-tasks (identified by $ as ; 4th character in taskname) to output file. ; .IF NDF TSKRCD ; MOV R2,-(SP) ;SAVE R2 MOV R1,-(SP) ;ALSO R1 MOV #TSKBUF,R0 ;OUTPUT BUFFER FOR $C5TA CALL MOV L.TNMO+2(R2),R1 ;INPUT BUFFER-TASK NAME OF LOG RECORD (WORD 2) CALL $C5TA ;CONVERT TO ASCII MOV (SP)+,R1 ;RESTORE REGISTERS MOV (SP)+,R2 CMPB TSKBUF,#'$ ;IS 4TH CHARACTER "$" (TASKNAME "LOG$nn"?). BNE FLS02A ;IF NOT ITS A TASK - DON'T OUTPUT IT!! ; .ENDC ; ; if PARAMS is defined, ensure: ; -Taskname is not in TSKTBL ; -Account number is not in ACCTBL ; -And elapsed time is above TIMTBL threshhold ; before writing record to output file! ; .IF DF PARAMS ; MOV #TSKTBL,R0 ;R0 POINTS TO CURRENT TSKTBL ENTRY 10$: TST (R0) ;END OF TABLE? BEQ 20$ ;YES - TASKNAME NOT IN TSKTBL CMP L.TNMO(R2),(R0)+ ;DOES 1ST WORD OF TASKNAME MATCH TABLE ENTRY? BNE 15$ ;NO - CHECK NEXT TABLE ENTRY CMP L.TNMO+2(R2),(R0)+ ;YES-CHECK 2ND WORD BNE 10$ ;NO MATCH - CHECK NEXT TABLE ENTRY BR FLS02A ;MATCH FOUND - DON'T WRITE RECORD ; 15$: TST (R0)+ ;SKIP 2ND WORD BR 10$ ;AND CHECK NEXT ENTRY. ; ; This task is not in TSKTBL...but we're not home free yet! ; 20$: MOV #ACCTBL,R0 ;R0 POINTS TO CURRENT ACTTBL ENTRY 25$: TST (R0) ;END OF TABLE? BEQ 30$ ;YES - ACCOUNT NOT IN ACCTBL CMP L.UICO(R2),(R0)+ ;COMPARE LOG ACCOUNT WITH TABLE ENTRY BNE 25$ ;NO MATCH - CHECK NEXT TABLE ENTRY. BR FLS02A ;MATCH FOUND - DON'T PUT THIS RECORD ANYWHERE! ; ; The record is not in ACCTBL either. . .one more hurdle! ; 30$: CMP L.SMPO(R2),TIMTBL ;IS SAMPLE TIME AT OR ABOVE THRSHHOLD? BLO FLS02A ;NO - SO DON'T WASTE FILE SPACE ; .ENDC ; PUT$ #LOGFDB,R2,#LOGLEN ;ELSE WRITE IT TO THE FILE BCC FLS02A ;OK IF CARRY BIT CLEAR JMP ER$CWF ;ELSE ABEND (CANT WRITE) FLS02A: MOV (SP)+,R0 ;RESTORE BUCKET POINTER MOV @R2,@R1 ;SPLICE OVER IT MOV FREE,@R2 ;POINT IT AT CURRENT HEAD OF FREE LIST MOV R2,FREE ;MAKE IT NEW CURRENT HEAD BR FLSH04 ;DONE WITH IT. .PAGE ; ; COME HERE FOR A LOG RECORD THAT IS STILL ACTIVE TO RESET THE MARK BIT ; AND UPDATE THE PREVIOUS POINTER. ; FLSH03: BIC #FL.MRK,L.FLGO(R2) ;RESET THE MARK BIT MOV R2,R1 ;SET NEW PREVIOUS TO CURRENT ; ; MERGE HERE TO LOOP BACK FOR THE NEXT ITEM ON THE CHAIN. NOTE THAT ; PREVIOUS (R1) MUST BE SET PROPERLY FOR THE NEXT ITERATION. ; FLSH04: BR FLSH02 ;BACK FOR NEXT ONE. ; ; BRANCH HERE WHEN DONE WITH CURRENT HASH CHAIN (R0) TO MOVE TO THE ; NEXT ONE. ; FLSH05: ADD #2,R0 ;MOVE TO THE NEXT BUCKET CMP R0,#ENDBUC ;WAS THIS THE LAST ONE? BLO FLSH01 ;BACK IF NOT RTS PC ;ELSE BACK TO CALLER .PAGE .SBTTL INTURP - PROCESS MARK TIME AST ; ; THIS MODULE IS ENTERED AS AN ASYNCH. SERVICE ROUTINE TRAP FROM ; THE PRIOR MARK TIME REQUEST. IT PROCEEDS BY PERFORMING A TWO PASS ; OPERATION. PASS ONE IS IN THREE PARTS. THE FIRST PERFORMS A SCAN ; OF ALL ACTIVE TASKS IN THE SYSTEM'S ACTIVE TASK LIST, AND RECORDS THE ; APPROPRIATE SAMPLES IN THEIR CORRESPONDING LOG RECORD BLOCKS. ; TASKS WHICH HAVE NO LOG RECORD BLOCK (AND IF SMPPRV IS NOT DEFINED ; ARE NON-PRIVILEGED) ARE ASSUMED TO HAVE BECOME ACTIVE SINCE THE ; LAST SAMPLE, AND A LOG RECORD IS ALLOCATED FOR THEM. ; THE SECOND PART IS A LOOKUP OF THE TASK WHICH HAD ACTIVE CONTROL OF ; THE CPU PRIOR TO THE CURRENT WAKEUP. IF IT HAS AN ACTIVE LOG RECORD, ; THE CPU-TIME FIELD IN BUMPED. ; THE THIRD PART IS A SCAN OF ALL UCB'S IN THE UCBTBL TO FIND OUT ; IF ANY OF THE TASKS WITH ACTIVE LOG RECORDS HAVE I/O THAT SHOULD BE ; CHARGED TO THEM. ; THE SECOND PASS FLUSHES OUT ALL ACCOUNTING LOG RECORDS FOR TASKS ; WHICH WERE NOT SEEN ON PASS ONE, AS THEY ARE ASSUMED TO HAVE TERMINATED. ; INTURP:: MOV @ACTADR,ACTTCB ;SAVE LAST ACTIVE TCB BEFORE IT IS MESSED UP MOVB @PRIADR,PRIACT ;SAVE PRIORITY TOO (MAY HAVE BEEN IDLE). MRKT$C ,TPSMPL,1.,INTURP ;REISSUE ANOTHER MARK TIME. JSR PC,SAMPIT ;PASS ONE, SAMPLE ALL ACTIVE TASKS .IIF DF,SGNRCD, JSR PC,SMPSGN ;SAMPLE SIGNONS AS PSEUDO TASKS JSR PC,CHGCPU ;CHARGE CPU AGAINST TASK JSR PC,IOSAMP ;CHECK ACTIVE I/O JSR PC,FLUSH ;PASS TWO, FLUSH ANY MORIBUND TASK LOGS. TST (SP)+ ;POP EFN FOR AST EXIT ASTX$S ;RETURN FROM AST AND WAIT FOR NEXT SAMPLE .PAGE .SBTTL IOSAMP - SAMPLE ACTIVE I/O ; ; THIS ROUTINE RUNS DOWN THE UCB'S CORRESPONDING TO THE UCBTBL ENTRIES, ; CHARGING TASKS WHICH HAVE ACTIVE LOG RECORDS FOR THEIR I/O. ; ; JSR PC,IOSAMP ; (R0,R1,R2,R3,R4,R5) DESTROYED ; IOSAMP:: MOV #UCBTBL,R3 ;POINTS TO NEXT UCBTBL ENTRY TO BE PROCESSED ; ; LOOP HERE TO EXAMINE EACH UCB IN THE UCBTBL. R3 POINTS TO NEXT ENTRY. ; IOSM01: MOV (R3)+,R0 ;LOAD UP R0 WITH UCB POINTER BEQ IOSM02 ;EXIT IF UCB ADDR = 0 (END OF TABLE). MOV (R3)+,R5 ;LOAD R5 WITH LOG-REC OFFSET TO BE CHARGED JSR PC,IOCHRG ;ATTEMPT TO FIND ACTIVE TASK TO CHARGE BR IOSM01 ;LOOP FOR ANOTHER ; ; HERE TO EXIT ; IOSM02: RTS PC ;BACK WE GO! .PAGE .PAGE .SBTTL IOCHRG - CHARGE TASK FOR ACTIVE I/O ; ; THIS MODULE IS CALLED TO SEE IF A GIVEN UCB/SCB IS ACTIVE WITH I/O, AND ; IF SO, TO CHARGE THE LOG RECORD BELONGING TO THE REQUESTING TASK IF ; IT HAS A LOG RECORD EXTANT IN THE LOG RECORD AREA. ; ; (R0) -> UCB TO BE EXAMINED ; (R5) -> LOG RECORD OFFSET OF FIELD TO BE CHARGED ; JSR PC,IOCHRG ; (R0,R1,R2,R4) - DESTROYED. ; IOCHRG:: BITB #US.BSY,U.STS(R0) ;IS DEVICE/UNIT BUSY? BEQ IOCH01 ;EXIT IF SO. MOV U.SCB(R0),R2 ;GET STATUS CNTRL BLOCK PTR. TSTB S.STS(R2) ;IS CONTROLLER BUSY? BEQ IOCH01 ;IF NOT, THEN EXIT. MOV S.PKT(R2),R2 ;GET POINTER TO I/O PACKET FOR THIS I/O OP. MOV I.TCB(R2),R0 ;GET ADDR OF TCB FOR THIS I/O OP. JSR PC,FIND ;LOCATE LOG REC FOR IT TST R0 ;ANYTHING FOUND BEQ IOCH01 ;EXIT IF NOT ADD R5,R0 ;ELSE GET ADDR OF WORD TO BE TICKED. INC @R0 ;AND TICK IT. ; ; MERGE HERE TO EXIT ; IOCH01: RTS PC ;SAYONNARA. .PAGE .SBTTL SAMPIT - SAMPLE ALL ACTIVE TASKS ; ; THIS MODULE LOOPS ON THE ACTIVE TASK LIST RECORDING EACH TASK ; PRESENT. IF A TCB IS SEEN FOR THE FIRST TIME (NO LOG RECORD EXISTS), ; THEN A LOG RECORD IS CREATED AND INITIALIZED FOR IT FIRST. ; NON-PRIVILEGED TASKS ARE NOT LOGGED. ; ; JSR PC,SAMPIT ; (R0,R1,R3,R4) DESTROYED ; SAMPIT:: MOV $ACTHD,R3 ;GET POINTER TO FIRST TCB ; ; LOOP HERE ON TCB'S ON ACTIVE CHAIN. R3 POINTS TO CURRENT TCB ; SAMP01: TST T.ACTL(R3) ;IS THIS THE NULL TASK? BEQ SAMP04 ;DONE IF SO. .IF NDF SMPPRV ;SIFT OUT PRIV. TASKS UNLESS SMPPRV DEFINED BIT #T3.PRV,T.ST3(R3) ;TASK IS PRIVILEGED? BNE SAMP03 ;SKIP IT IF SO. .ENDC MOV R3,R0 ;POINT TO TCB FOR TASK JSR PC,FIND ;LOOK FOR IT IN LOG REC. AREA TST R0 ;WAS IT FOUND? BNE SAMP02 ;BRANCH IF SO. MOV R3,R0 ;NEW TASK. JSR PC,ALONEW ;SET UP A LOG REC. FOR IT ; ; MERGE HERE WITH R0 -> LOG REC, R3 -> TCB ; SAMP02: BIS #FL.MRK,L.FLGO(R0) ;SET MARK BIT FOR FLUSH PASS INC L.SMPO(R0) ;BUMP THE SAMPLE COUNT. CMP L.SMPO(R0),#^O177777 ;HAVE WE REACHED SAMPLE LIMIT? BNE SMP02C ;OK IF SO. BIC #FL.MRK,L.FLGO(R0) ;ELSE CLEAR MARK BIT TO GET IT OUT. .PAGE ; ; MERGE TO CHECK FOR SUSPEND BIT ; SMP02C: BIT #T2.SPN,T.ST2(R3) ;TASK SUSPENDED? BEQ SMP02D ;SKIP IF NO INC L.SPNO(R0) ;ELSE BUMP COUNT ; ; MERGE HERE TO CHECK WAITFOR BIT ; SMP02D: BIT #T2.WFR,T.ST2(R3) ;TASK IN WAITFOR? BEQ SMP02E ;SKIP IF NO INC L.WFRO(R0) ;ELSE BUMP COUNT ; ; CHECK CHECKPOINT BIT ; SMP02E: BIT #TS.OUT,T.STAT(R3) ;OUT OF MEMORY? BEQ SMP02F ;BRANCH IF SO INC L.CKPO(R0) ;ELSE BUMP COUNT ; ; CHECK STOPPED BIT ; SMP02F: BIT #T2.STP,T.ST2(R3) ;TASK STOPPED? BEQ SAMP03 ;SKIP IF NOT INC L.STPO(R0) ;ELSE BUMP STOPPED COUNT ; ; MERGE HERE TO MOVE TO NEXT TASK ON ACTIVE LIST ; SAMP03: MOV T.ACTL(R3),R3 ;POINT TO NEXT TCB BR SAMP01 ;LOOP. ; ; DONE WITH TASKS. RETURN .IF DF SGNRCD SAMP04: RTS PC .PAGE .SBTTL SMPSGN - SAMPLE SIGNED ON TERMINALS (PSEUDO-TASKS) ; ; THIS MODULE IS CALLED TO EXAMINE THE TT: DEVICES FOR SIGNED ON TERMINALS, ; AND RECORD THE ELAPSED TIME AS A PSEUDO-TASK "LOG$nn" (nn IS THE TERMINAL ; UNIT NUMBER. ; ; JSR PC,SMPSGN ; (R0,R1,R2,R4) - DESTROYED ; SMPSGN:: CLR R0 ;R0 IS TT: UNIT NUMBER BEING EXAMINED ; ; LOOP HERE ON SUCCESSIVE TTUTBL ENTRIES TO EXAMINE THEIR UCBS. ; SSGN01: MOV R0,R1 ;MAKE UNIT # INTO... ASL R1 ;...TABLE OFFSET IN R1 MOV TTUTBL(R1),R2 ;GET UCB POINTER IN R2 BEQ SSGN03 ;SKIP IF ENTRY IS ZERO BIT #U2.LOG,U.CW2(R2) ;IS TERMINAL LOGGED ON AT PRESENT? BNE SSGN03 ;SKIP IT IF NOT (0=YES) .IF NDF SMPPRV BIT #U2.PRV,U.CW2(R2) ;IS TERMINAL PRIVILEGED? BNE SSGN03 ;SKIP IF YES (1=YES) .ENDC MOV TTUNM2(R1),T.NAM+2+TTUTCB ;STUFF NAME INTO BOGUS TCB FOR FIND MOV UUIC(R2),HUIC+TTUHDR ;SET UIC ALSO MOV R0,-(SP) ;HANG ONTO UNIT # ACROSS CALL MOV #TTUTCB,R0 ;POINT AT TCB FOR CALL JSR PC,FIND ;FIND IT IF IT IS THERE TST R0 ;FOUND? BNE SSGN02 ;UPDATE IT IF SO. MOV #TTUTCB,R0 ;ELSE NEW SIGNON. POINT AT BOGUS TCB AGAIN JSR PC,ALONEW ;ALLOCATE NEW LOG RECORD CLR L.PRIO(R0) ;PRIORITY IS JUNK FOR PSEUDO-TASK. ZAP IT. CLR L.MEMO(R0) ;DITTO FOR MEMORY ALLOCATION ; ; MERGE HERE TO UPDATE THE PSEUDO TASK'S LOG RECORD ; SSGN02: BIS #FL.MRK,L.FLGO(R0) ;SET MARK BIT FOR FLUSH PASS INC L.SMPO(R0) ;UPDATE ELAPSED TIME SAMPLES CMP L.SMPO(R0),#^O177777 ;REACHED LIMIT? BNE SSG02A ;OK IF NO. BIC #FL.MRK,L.FLGO(R0) ;ELSE CLEAR MARK BIT TO GET IT OUT. ; ; MERGE HERE TO RESTORE UNIT # TO R0 ; SSG02A: MOV (SP)+,R0 ;UNLOAD UNIT NUMBER TO R0 ; ; MERGE HERE TO MOVE TO NEXT UCB IN TABLE ; SSGN03: INC R0 ;NEXT UNIT # (TABLE ENTRY) CMP R0,#TTSIZE ;LIMIT? BLE SSGN01 ;IF NO, THEN LOOP FOR NEXT ENTRY. RTS PC ;ELSE BACK TO CALLER .ENDC .PAGE .SBTTL ERROR HANDLERS ; ; THESE LABELS ER$XXX REPRESENT JMP POINTS FOR ABENDING THE ACCOUNTING. ; NOTE THAT THEY ARE NOT CALLED. ; ER$ACC: ;ACCOUNTING COMPLETE (NORMAL TERMINATION) MOV #ERACCM,R1 ;"CANCELLED BY OPERATOR" MOV #ERACCL,R2 ;LENGTH OF MESSAGE BR EREXIT ;GO PRINT AND EXIT ER$COF: MOV #ERCOFM,R1 ;CAN'T OPEN FILE MESSAGE MOV #ERCOFL,R2 ;(LENGTH) BR EREXIT ER$MRE: MOV #ERMERM,R1 ;MAX. RECORDS EXCEEDED MOV #ERMERL,R2 ;(LENGTH) BR EREXIT ER$CWF: MOV #ERCWFM,R1 ;CAN'T WRITE TO FILE MOV #ERCWFL,R2 ;(LENGTH) BR EREXIT ER$NES: MOV #ERNESM,R1 ;NO EXECUTIVE POOL SPACE MOV #ERNESL,R2 ;(LENGTH) BR EREXIT ; .IF DF PARAMS ER$PAR: MOV #ERPARM,R1 ;ERROR OPENING OR READING PARAMETER FILE MOV #ERPARL,R2 ;(LENGTH) BR EREXIT ; .ENDC ; ; MERGE HERE FROM ONE OF THE ABOVE ER$... CASES TO PRINT THE MESSAGE ; AND STOP THE PROGRAM ; EREXIT: CMKT$S ;NO INTERRUPTIONS ALLOWED QIOW$S #IO.WBT,#2.,#1.,,,, ;PRINT EXIT MESSAGE QIOW$S #IO.WBT,#2.,#1.,,,,<#EREXTM,#EREXTL,#SPACE> ;TERM. MSG ; ; NOW WE HAVE TO FREE UP THE EXECUTIVE POOL BLOCK AND RESTORE THE ; INTERRUPT PROPERLY ; MOV IBADDR,R0 ;GET ADDRESS OF CORE BLOCK BEQ ERXT01 ;SKIP IF NONE EVER ALLOCATED. MOV INTCON,@#CLKVEC ;SPLICE OUT THE INTERRUPT INTERCEPT MOV #IBLEN,R1 ;GET THE LENGTH OF THE BLOCK EMT 376 ;SWITCH TO SYSTEM STACK .WORD ERXT01 ;RETURN POINT FOR USER STACK JSR PC,$DEACB ;FREE UP THE BLOCK RTS PC ;BACK TO USER ; ; MERGE HERE AFTER CORE BLOCK WORRIES ARE OVER ; ERXT01: CLOSE$ #LOGFDB ;CLOSE THE LOG FILE NEATLY. EXIT$S ;B-DICKA, B-DICKA THATS ALL FOLKS. .END ACCT