1
0
mirror of https://github.com/PDP-10/its.git synced 2026-01-22 10:32:13 +00:00
Eric Swenson 336bbaa979 Added channa and dragon directories, and added sources for netime,
dmpcpy, fsdefs, modems, netwrk, and pft.
2016-11-18 19:27:06 +01:00

3679 lines
91 KiB
Plaintext
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;;-*-Midas-*-
TITLE PFTHMG DRAGON II
define setf text,flg
ifdef flg,.stop
.tag foobar
printc "text
flg="
.ttymac flag
.ttyflg==.ttyflg+1
printx/flag
/
.ttyflg==.ttyflg-1
ifse flag,YES,flg==1
ifse flag,NO,flg==0
ifse flag,Y,flg==1
ifse flag,N,flg==0
ifndef flg,flg==flag
termin
ifndef flg,.go foobar
termin
setf [Macsyma and decimal time features for MC KL10]$$mcp
;setf [Puff internal stats collection (say yes)]$$stat
;$$MCP==1 ;non-zero if for MC
$$STAT==1 ;non-zero for PUFF internal stats collection
A=1
B=2
C=3
D=4
E=5
T=6
TT=7
H=10
I=11
J=12
Q=13
R=14
P=17
ERRCH==0
CLICH==1
DMPCH==2
maxch==3
batusr==4 ;See BATCH
batdsk==5 ;Same Bat time, same Bat channel!
INCH=15
OUCH=16
define syscal oper,args
.call [setz ? sixbit /oper/ ? args ((setz))] termin
busrc==100000 ;user control bit in USTP
EDITF: 0 ;NONZERO => WAITING FOR EDITING
IFN EDITF-100, .ERR EDITF MUST BE LOCATION 100
SNAME: sixbit /DRAGON/ ;DIRECTORY TO USE
LOTSNM: sixbit /CHANNA/ ;DIRECTORY FOR LOGOUT TIMES FILE
MALSNM: sixbit /.MAIL./ ;DIRECTORY FOR SENDING MAIL
DEBUG: -1 ;NONZERO => EXTRA CHECKS, .VALUES, ETC.
FIXIND: 0 ;NONZERO => FIX INDENTATION TO STANDARD VALUES
PDL: -120,,.
BLOCK 122
DEFINE INSIRP INS,VALS
IRPS VAL,,[VALS]
INS,VAL
TERMIN
TERMIN
ZZ==.
LOC 40
FORTY: 0
JSR UUOH
-intlen,,TSINT
LOC ZZ
;UUOS
WCHI=1000,, ;WRITE-CHAR-IMMEDIATE
XBUGCH=62000,, ;BUGCHK MACRO - MUST BE MUUO SO NO CLOBBER JPC
XCLBFI=3000,, ;CLBFIL MACRO
;Give bug message if debugging, and continue
DEFINE BUGCHK MESS/
XBUGCH [ASCIZ:MESS

]
TERMIN
;Give clobbered file message, pop AC times, and jump to GVLFLS to flush rest of line.
DEFINE CLBFIL AC,MESS/
XCLBFI AC,[ASCIZMESS]
TERMIN
SUBTTL How it works
;Accounting information is saved in the DRAGON HOARD file, which is a printable
;ascii file. At the end of the month, this file becomes the monthly report, and
;a new file is started by zeroing all the useages.
;Accounting information is obtained from the system by looking for "dmn-push"
;messages. The system has a circular buffer which can hold several of these
;messages. When it is idle, the daemon hangs waiting for the count of the
;number of messages pushed to change. It then copies out the messages.
;While it is updating the file, the daemon also checks the dmn-push buffer
;every 1/2 second to try to avoid missing any messages.
;The system pushes these messages when a user logs in or out, and when
;a job tree's name changes e.g. due to detach or attach. In future it may
;also do it spontaneously every fifteen minutes or so to keep the
;accounting up to date.
;The daemon generates two tables from the dmn-push messages. The logged-in
;tree table has an entry for each job tree that it saw log in to the system.
;The table is indexed by the user-index of the top-level job of the tree.
;This table simply remembers the information from the login message until
;logout time. The cruft table is a sequence of "pieces of cruft." Each
;piece of cruft contains the accounting information for one user session.
;When it comes time to update the accounting file, the pieces of cruft
;are matched against the accounting entries. When a match occurs, the
;usage in the piece of cruft is added to the usage in the accounting file
;for that user.
;Editing the accounting file.
;It is necessary to lock out updates of the file while it is being
;edited. The TS GEORGE program does this. The dragon remembers any
;dmn-push messages that happen while updating is locked out, so no
;information is lost. GEORGE should also be run just before shooting down
;the dragon to put up a new one, to insure that the file gets updated.
;The format of the accounting file is as follows:
;It is processed a line at a time.
;A line that begins with white space (actually, space or any control character)
;is a comment, which is not processed by this program. This is used to insert
;headings, page throws (^L), etc.
;Various special markers are indicated by a whole mess of dashes surrounding
;a keyword. The following keywords exist:
; TOTALS - the next line is for the "TOTALS" user whose usage is the sum of all
; the usage in the file.
; PAGE SUBTOTALS - the next line is for the "TOTALS" user whose usage
; is the sum of all the usage on the same page.
; RANDOMS - the remainder of the page containing this line is for
; "random users". Users not otherwise accounted for
; will be automatically inserted at the bottom of the page.
; Random users who don't log in for a month will be automatically
; deleted.
;^L is considered to separate pages. The only difference this makes is
;that "page subtotals" are reset by ^L. Also, ^L ends the randoms section.
;All other lines are accounting entries. Each accounting entry starts
;with a uname spec, which says what user or set of users will be accounted
;for on this line. It can be further narrowed down through the use of
;JOB, ACCT, and/or HOURS specs. (See below.) The remainder of the line
;contains usage informations, separated by spaces and tabs. These are, in
;order from left to right: the connect-time, the run-time, the swap-in count,
;the logout-date, and the logout-time. Times are in the form dd!hh:mm:ss.
;The swap-in count is just a decimal number. The logout date is in the
;form yy.mm.dd.
;The uname, job, and acct specs are, in the simplest case, just a sixbit
;name. Legal characters are letters (A-Z and a-z), numbers (0-9),
;underscore (_), and dot (.).
;If any other character is required it should be preceded by a slash (/).
;It is also possible to make a spec that matches a class of names, by use
;of the wild-card characters star (*) and sharp (#). Sharp matches any
;numeric digit. Star matches any character (even space). As a special
;case, a spec consisting of just a star matches anything (normally it would
;just match any one-character name.)
;The uname spec is matched against the XUNAME (what the user logged in as.)
;The job spec, which is optional and written as "JOB=spec", matches against
;the JNAME of the top-level job. This could be used to separate HACTRNs
;from HACTROs, account separately for job-device jobs ("JOB=JOB.##"), or
;hack daemons. The account spec, which is optional and written as "ACCT=spec",
;matches against the account-name logged in to. [There is currently no
;way for a user to log in to an account name, however.] This is used by
;users who want to split up their usage into several categories.
;The hours spec, which is optional and written as "HOURS=m-n", is used
;to account only for usage between certain hours (currently, it goes
;by the time of login.) E.g. "HOURS=9-5".
;When initially setting up a file, it is necessary to list all the
;users on the system who should be accounted for, dividing them up
;into pages by groups. Then there should be a page containing just
;-randoms-, and finally a page starting with -totals-, and containing
;a line TOTALS 0.0 0.0 0 0.0 0.0 76.08.01 on MC or
;a line TOTALS 0 0 0 76.08.01 00:00:00
;(or whatever date is appropriate.)
;If special jobnames, (e.g. job devices) or daemons are to be accounted
;for, they should go at the front.
;The following files are used by this program:
;
; DRAGON HOARD current accounting file
; DRAGON SAVE previous accounting file
; DRAGON YESTER yesterday's accounting file
; _DRGN_ BUFFER temporary name for output file
; month REPORT completed accounting file for that month
; LOGOUT TIMES old style logout-times file.
;
; It also sends mail to MAGIC-DRAGON-KEEPER and to the last
; person who edited the accounting file if it runs into
; any problems.
;blah blah
SUBTTL Program starts here
GO: .CLOSE 1,
.SUSET [.RSUPPRO,,T]
JUMPGE T,GO1 ;I prefer GO1, changing the directory to ZZ
SETZM DEBUG ;top level => running as daemon
.SUSET [.SXUNAME,,['PFTHMG]]
.SUSET [.SXJNAME,,['DRAGON]]
.SUSET [.SUNAME,,['PFTHMG]] ;UNAME first since TARAKA DRAGON may exist
.SUSET [.SJNAME,,['DRAGON]]
.suset [.shsname,,['DRAGON]] ; for the sake of file authors
JRST GO1
GO0: SETZM SNAME ;use debugger's directory.
SETZM LOTSNM
GO1: MOVE P,PDL
GO2: .RDATIM T, ;Wait until ITS thinks it knows the time
IOR T,TT
JUMPGE T,GO3
MOVEI T,5*30.
.SLEEP T,
JRST GO2
GO3: .suset [.ruind,,RUIND]
MOVE T,[SQUOZE 0,LIOBLK]
.EVAL T,
.LOSE
HRLOI T,-1(T)
EQVI T,SYCORE_-10.
SETZ TT,
.CALL [ SETZ ;Map in system core
'CORBLK
MOVEI %CBRED+%CBNDR
MOVEI %JSELF
MOVE T
MOVEI %JSABS
SETZ TT ]
.LOSE 1000
IRPS SYM,RELOC,[DMNBC+DMNBD+DMNBF+DMNBFE+DMNBEL DEDTIM+USRHI+LUBLK
UNAME#XUNAME#JNAME#USTP#UTRNTM#USIPRQ#TRUNTM#TSIPRQ#
SUPPRO#TIME+SYSMPT+SYSMLNG SYSMBF+]
MOVE T,[SQUOZE 0,SYM] ;Evaluate necessary system symbols
.EVAL T,
.LOSE
IFSE RELOC,+, ADDI T,SYCORE ;reloc address to system core
IFSE RELOC,#, ADD T,[SYCORE(R)] ;also index by user index in R
MOVEM T,SYM
TERMIN
MOVE T,DMNBFE
SUB T,DMNBF
IDIV T,DMNBEL
MOVEM T,DMNBSZ
IFN $$MCP, pushj p,maxget ;get a page of MACSYMA
;; Don't set %OPLIV until we are fairly certain we will live
.SUSET [.ROPTION,,T]
TLO T,%opopc+%opliv+%opint
.SUSET [.SOPTION,,T]
move t,[%rlfls\%rlset,,rltinv]
.realt t, ;give ourself periodic interrupts
JRST IDLE ;Go enter idle loop
SUBTTL UUO Handler
UUOH: 0 ;PC stored here
PUSH P,UUOH ;this must be first instruction, see TSINT
PUSH P,T ;UUOs shouldn't clobber any ACs.
LDB T,[331100,,FORTY]
CAIN T,WCHI_-33
JRST UWCHI
CAIN T,XCLBFI_-33
JRST UCLBFI
CAIE T,XBUGCH_-33
.VALUE
.SUSET [.RJPC,,BUGJPC]
JRST UBUGCH
UWCHI: HRRZ T,FORTY
PUSHJ P,WCH
UUORET: POP P,T
POPJ P,
;BUGCHK message in debug mode returns to DDT, in non-debug PDUMPs and continues
UBUGCH: SKIPE DEBUG
JRST UBUGC1
MOVEM 0,BUGACS ;saves ACs (already saved JPC)
MOVE 0,[1,,BUGACS+1]
BLT 0,BUGACS+17
MOVE 0,BUGACS
.CALL [ SETZ ;save core image
SIXBIT/OPEN/
[.UIO,,DMPCH]
['DSK,,]
['DRAGON]
[SIXBIT/>/]
SETZ [SIXBIT/CRASH/] ]
JRST UUORET ;tough noogies, more important to keep running
SETZ T,
.CALL [ SETZ
SIXBIT/PDUMP/
MOVEI %JSELF
MOVEI DMPCH
SETZ T ]
JRST UUORET ;tough noogies, more important to keep running
.IOT DMPCH,[JUMPA BUGHAK]
.IOT DMPCH,[JUMPA BUGHAK]
.CLOSE DMPCH,
UBUGCX: JRST UUORET
BUGHAK: .SUSET [.SJPC,,BUGJPC] ;here restore state so can look at dump
MOVSI 17,BUGACS
BLT 17,17
.VALUE [ASCIZ\:SL CHANNA;RAKASH PFTHMG
P\]
UBUGC1: POP P,T
.VALUE @FORTY
POPJ P,
;CLBFIL message in debug mode returns to DDT, in non-debug mode generates mail.
UCLBFI: SKIPE DEBUG
.VALUE [ASCIZ\: CLBFIL 
\]
AOS C,NERRS ;save message and line number in buffer
CAILE C,LERRBF
JRST UCLBF2
SOS C
HRRZ T,FORTY
MOVEM T,ERRBFZ(C)
MOVE T,LINENO
MOVEM T,ERRBFL(C)
MOVE T,UNAMEA
MOVEM T,ERRBFA(C)
MOVE T,UNAMEB
MOVEM T,ERRBFB(C)
MOVE T,UNAMEC
MOVEM T,ERRBFC(C)
UCLBF2: LDB T,[270400,,FORTY] ;flush pdl
CAIN T,17
JRST UUORET
ADDI T,2
HRLS T
SUB P,T
JRST GVLFL1 ;flush rest of input line
SUBTTL Routines to gobble dmn-push messages
;Procedure to gobble any dmn-push messages available from the system.
;Clobbers pretty much all ACs.
DMNPOP: MOVE Q,LDMNBD ;last message processed
CAML Q,@DMNBD
POPJ P, ;buffer empty
ADD Q,DMNBSZ
CAML Q,@DMNBC
JRST DMNPO1 ;jump if haven't missed any
;Following 2 lines commented out. We're never going to get rid of
;these and I'm tired of deleting the crash files. 11/30/77
; SKIPE LDMNBD ;if just started up, mumble this always happens
; BUGCHK Missed dmn-push message.
MOVE Q,@DMNBC ;get as many as we can
SUB Q,DMNBSZ
MOVEM Q,LDMNBD
DMNPO1: AOS Q,LDMNBD ;take next one after previous
SUBI Q,1 ;fudge (DMNBD=1 after msg 0 pushed).
IDIV Q,DMNBSZ ;mod size of buffer
MOVE Q,R
IMUL Q,DMNBEL
ADD Q,DMNBF ;now Q -> the dmn-push message
HRLZ T,Q ;save the message in case of a BUGCHK
HRRI T,BUGMSG
BLT T,BUGMSG+7
MOVE T,LI.IDX(Q) ;figure out what type of message it is
TLNE T,LI%COD
JRST DMNPO2
TLNE T,LO%COD
JRST DMNPO3
BUGCHK Unknown dmn-push message.
JRST DMNPOP ;try for more messages
DMNPO2: PUSHJ P,LOGIN
JRST DMNPOP ;try for more messages
DMNPO3: PUSHJ P,LOGOUT
JRST DMNPOP ;try for more messages
;Procedure to process dmn-push message for log in.
;Q -> the message. The logged-in tree table is updated.
;Uses T, TT, I, J, A, B.
LOGIN: MOVE I,LI.IDX(Q) ;get user index of top job of tree
TLZE I,LI%COD ;check that it's really a login.
TLNE I,-1
BUGCHK Message-type not Login.
IDIV I,LUBLK
CAIL I,NTREES ;make sure logged in trees table is big enough
.LOSE
SKIPN TR.UNM(I) ;make sure table entry not already in use
JRST LOGIN0
HLRO TT,TR.UNM(I) ;but watch out for wierd screw in ITS.
MOVE T,TR.JNM(I) ;where not logged in job sets its jname
CAMN T,LI.JNM(Q) ;(causing an accounting update) then logs in
AOJE TT,LOGIN0 ;(causing log in of already logged in job).
; ;Following line commented out until bugs in ATTACH/DETACH fixed up.
; BUGCHK That user index already logged in.
LOGIN0: MOVE T,LI.UNM(Q) ;fill in the table entry
MOVEM T,TR.UNM(I)
MOVE T,LI.JNM(Q)
MOVEM T,TR.JNM(I)
MOVE T,LI.TNM(Q)
MOVEM T,TR.TNM(I)
MOVE TT,LI.TIM(Q)
MOVEM TT,TR.TIM(I)
; MOVE T,LI.XUN(Q)
MOVE T,LI.UNM(Q) ; XUNAME not pushed by sys, screw around
MOVEM T,TR.XUN(I) ; Guess that UNAME is correct
MOVE TT,[-6,,[ SIXBIT /XUNAME/ ? MOVEM T
SIXBIT /UNAME/ ? MOVEM A
SIXBIT /JNAME/ ? MOVEM B ]]
SYSCALL USRVAR,[MOVEI %JSNUM(I) ? MOVE TT]
POPJ P, ; Gone? Give up.
CAMN A,TR.UNM(I)
CAME B,TR.JNM(I)
POPJ P, ; Not the same job? Give up.
TLC T,-1
TLCE T,-1
MOVEM T,TR.XUN(I) ; Logged in? Use it!
POPJ P,
;Procedure to process dmn-push message for log out.
;Q -> the message. Corresponding entry in logged-in tree table
;is found, and cruft is pushed. Later the file will be updated
;from the cruft.
;Uses T, TT, H, I, J, A, B, C.
LOGOUT: MOVE I,LO.IDX(Q) ;get user index of top job of tree
TLZE I,LO%COD ;check that it's really a logout.
TLNE I,-1
BUGCHK Message-type not Logout.
IDIV I,LUBLK
CAIL I,NTREES ;make sure logged in trees table is big enough
.LOSE
SETZB A,C ;no connect time nor trmnam if missed log in.
MOVE B,LO.UNM(Q) ;no xuname if missed log in.
MOVEI TT,9 ;no hour if missed log in.
SKIPN TR.UNM(I)
JRST LOGOU0 ;jump if missed log in.
MOVE TT,LO.UNM(Q) ;make some checks
CAME TT,TR.UNM(I)
JRST LOGOU3
MOVE TT,LO.JNM(Q)
CAME TT,TR.JNM(I)
JRST LOGOU3
MOVE A,LO.TIM(Q) ;get connect time
SUB A,TR.TIM(I)
JUMPL A,[ BUGCHK Negative connect time.
MOVEI A,0
JRST .+1 ]
MOVE B,TR.XUN(I) ;get XUNAME
MOVE C,TR.TNM(I) ;get TRMNAM
SETZM TR.UNM(I) ;guy is now logged out
.CALL [ SETZ ;compute hour of login in TT
'RQDATE
MOVEM T
SETZM T ] ;QDATE system came up
SETO T,
MOVEI TT,9 ;9 AM is default if
AOJE T,LOGOU0 ; sys doesn't know time
MOVEI T,-1(T)
IMULI T,15. ;30ths since midnight when system came up
ADD T,TR.TIM(I) ;30ths since midnight of login
IDIVI T,3600.*30. ;hours since midnight of login
IDIVI T,24. ;modulo 24 in case system up more than one day
ifn $$STAT,aos crftys ;count this for statistical purposes
logou0: pushj p,getcor ;allocate one crufty
popj p, ; no core.
MOVEM A,CF.CTM(H)
MOVEM B,CF.UNM(H)
MOVEM C,CF.TNM(H)
MOVEM TT,CF.HOR(H)
MOVE T,LO.JNM(Q)
MOVEM T,CF.JNM(H)
MOVE T,LO.RTM(Q) ;HLRZ if still had old 4.069 usec clock
addi t,4166. ;round,
idivi t,8333. ;converting to seconds*30.
MOVEM T,CF.RTM(H)
MOVE T,LO.SWI(Q)
MOVEM T,CF.SWI(H)
ifn $$mcp,[
setzm cf.mct(h) ;MACSYMA type is counted elsewhen
setzm cf.mrt(h)
];mcp
PUSHJ P,RDATIM ;TT gets date, T gets time
MOVEM TT,CF.DAT(H)
MOVEM T,CF.TIM(H)
SETOM CF.VAL(H)
POPJ P,
;This BUGCHK commented out due to ITS lossage....8/9/76
LOGOU3: ;BUGCHK Logout Tree doesn't match logged-in tree.
SETZM TR.UNM(I)
JRST LOGOU0
getcor: MOVEI H,CF.LEN ;push onto end of cruft table
ADDB H,CRUFTP
getc1a: CAMG H,CRUFTE
jrst getcr1
ifn $$STAT,aos coraos ;count how often we
MOVE T,CRUFTE ;need more core
LSH T,-10.
CAIL T,<SYCORE_-10.>-3
.LOSE ;URK
.CALL [ SETZ
'CORBLK
MOVEI %CBRED+%CBWRT+%CBNDR+%CBNDW
MOVEI %JSELF
MOVEI (T)
SETZI %JSNEW ]
JRST [ MOVEI TT,5*30. ;CAN'T GET CORE, WAIT 5 SEC
.SLEEP TT,
XCT .-1 ;TRY AGAIN
JRST getcrb ;STILL LOSING, BARF
JRST .+1 ] ;WON AFTER ALL
MOVEI T,1_10.
ADDM T,CRUFTE
JRST getc1a
getcrb: BUGCHK Can't get core to expand cruft table.
MOVEI H,10.*30. ;WAIT 10 SECONDS BEFORE TRYING ANYTHING
.SLEEP H,
MOVNI H,CF.LEN
ADDM H,CRUFTP
POPJ P,
getcr1: cail h,cruftz+<crfsiz*2000>-<crfmrg*cf.len> ;is it getting big?
jrst [setom dmpcnt ; yes, request dump soon
.suset [.sipirqc,,[%pirlt]] ;And speed things up a bit
jrst .+1]
subi h,cf.len ;h -> new cruft.
jrst popj1 ;return
;Defensive routine to find out the date and time.
;TT gets date, T gets time, nothing clobbered.
;Sets stuff to -1 if it wouldn't have done for the duke.
RDATIM: .RDATIM T,
PUSH P,A
PUSH P,B
PUSHJ P,RDATI1
EXCH T,TT
PUSHJ P,RDATI1
EXCH T,TT
POP P,B
POP P,A
POPJ P,
;Subroutine to fix T
RDATI1: JUMPLE T,RDATI9 ;ITS knows it's losing
MOVE B,[440600,,T]
RDATI2: ILDB A,B ;Check for garbage characters
CAIL A,'0
CAILE A,'9
JRST RDATI9
TLNE B,770000
JRST RDATI2 ;Needn't check for wrong year, month 13, etc.
POPJ P, ;since dragon doesn't flame at those anyway.
RDATI9: SETOB T,TT ;lossage, don't trust any of it
POPJ P,
SUBTTL Idle Loop
;This is where we sit when there's nothing to do.
;.HANG on the daemon buffer.
;Also, every 15 minutes do a file-update.
;If system goes down, wait for full down-ness then log out self, sys, and
;core and perform final file-update.
IDLE: PUSHJ P,DSKLOG ;Log disk errors.
MOVE T,@TIME ;Check for need to run hourly daemon kludge
SUB T,RYGTIM
CAIGE T,3600.*30.
JRST IDLE01
move a,[sixbit /hourly/]
pushj p,batch
IDLE1B: MOVE T,@TIME
MOVEM T,RYGTIM'
IDLE01: move t,dmpinv ;15 minutes (unless sys going down)
movem t,dmpcnt ; from now do update
.SUSET [.SMASK,,[%PIRLT+%PICLI+%PIDWN+%PIPDL]]
IDLE00: MOVE T,LDMNBD
IDLE0: CAMN T,@DMNBD ; PC will be IDLE0
IDLE1: .HANG ; or IDLE1 if interrupt out
SHUTD0: PUSHJ P,DMNPOP ;gobble down any daemon messages
SKIPL @DEDTIM ;unless ITS is down,
JRST IDLE00 ;wait more.
MOVE T,@TIME ;save time that system went down.
SKIPN DWNTIM
MOVEM T,DWNTIM
SUB T,DWNTIM ;# 30ths since shutdown
CAIL T,5*30. ;wait at most 5 seconds for other daemons to logout.
JRST SHUTD2
MOVE R,@USRHI ;see how many jobs are still on the system
SETZ A,
SHUTD1: SUB R,LUBLK
SKIPE @UNAME
AOS A
JUMPG R,SHUTD1
CAILE A,3
JRST IDLE00 ;some OPTLIV daemon hasn't logged out yet.
SHUTD2: MOVE R,@USRHI ;Time to go.
SHUTD3: SUB R,LUBLK ;Log out the jobs that are left (sys, core, us).
SKIPE @UNAME
SKIPL @SUPPRO
JRST SHUTD4
MOVEI Q,FAKMSG ;fake up the dmn-push message
HRRM R,LO.IDX(Q) ;see DMNPLO and LOGUSE in ITS.
MOVE T,@TIME
MOVEM T,LO.TIM(Q)
MOVE T,@UNAME
MOVEM T,LO.UNM(Q)
MOVE T,@JNAME
MOVEM T,LO.JNM(Q)
MOVE TT,@UTRNTM
ADD TT,@TRUNTM
MOVE T,@USIPRQ
ADD T,@TSIPRQ
MOVEM TT,LO.RTM(Q)
MOVEM T,LO.SWI(Q)
PUSHJ P,LOGOUT ;gobble down this fake message
SHUTD4: JUMPG R,SHUTD3
JRST FILEUP ;Do final FILEUP and .LOGOUT
SUBTTL Interrupt handler
TSINT: setz p ;push the .JPC and .SUUOH and miscellany ...
%piioc ? 0 ? -1 ? -1 ? iocint ;IOC errors
%pidwn ? 0 ? 0 ? 0 ? dwnint ;only sets flags, don't defer anything
;%PIRLT and %PICLK defer each other to prevent
;contention for pushing cruft
;%PIRLT's get delayed if they happen while not
;idle, so there can be no contention from
;%PIRLT's vs. MP cruft pushes.
%piclk ? 0 ? %piclk\%pirlt\%picli ? 0 ? clkint ;finish up first
%pirlt ? 0 ? %pirlt\%picli\%pidwn\%piclk ? 0 ? rltint ;time-critical
%picli ? 0 ? %pirlt\%picli ? 0 ? cliint ;defer %PIRLT so handler exits
;before getting %PIRLT it gives itself.
intlen==.-tsint
;Here on system-going-down interrupt
DWNINT: PUSH P,T
SKIPE T,@DEDTIM
JRST DWNIN1
SETZM DWNTIM ;ITS revived.
movni t,31 ;back to normal intervals
movem t,dmpinv
setom maxinv ;count out once per clock tick.
setom maxcnt
movei t,60.*3600./100. ;interval under normalcy
movem t,rltinv
jrst dismst ;return
DWNIN1: CAIL T,2*60.*60. ;Going down in less than two minutes?
jrst dismst ;No, don't panic.
movni t,4 ;Yes, start checking world every 2 seconds.
came t,dmpinv ;is it already schedualled sooner?
movem t,dmpcnt ; no, schedual it sooner
movem t,dmpinv ;and make rest of world use this interval
movni t,18. ;every 18 ticks (36 secs) do the MACSYMA update
came t,maxinv ;so they don't happen at our accelerated rate.
movem t,maxcnt
movni t,60.*2. ;2. seconds,
movem t,maxinv ;set the interval
move t,[%rlfls\%rlset,,rltinv] ;spead up the clock
.realt t,
jrst dismst
;Here on real-time interrupt
RLTINT: PUSH P,T
hrrz t,-4(p) ;get the PC we interrupted from. Idle?
CAIE T,IDLE0
CAIN T,IDLE1
JRST RLTIN0
MOVE T,[%rlfls\%rlset,,[60.]] ;no, check again in a second
.REALT T,
jrst dismst ;dismis from the interrupt
RLTIN0: move t,[%rlfls\%rlset,,rltinv] ;and hack it for that interval
.realt t,
ifn $$mcp,[
aosl maxcnt ;if this is a for-real interrupt
pushj p,maxscn ; update MACSYMA's
];mcp
pop p,t ;restore T
syscal dismis,[%clbit,,(setz) ;dismis to our hack
p
%climm,,rlthak] ;hack our from directly.
.lose %lssys
rlthak: aosge dmpcnt ;time to update the file?
jrst idle00 ; nope, just go hack them some more
SKIPE T,@DEDTIM ;system down or going down soon?
CAIL T,2*60.*60. ; i.e. 2 minutes
jrst FILEUP ; no, run file update generator
jrst shutd0 ;yes, do shutdown checks
;Here on slow-clock interrupt. While we aren't idle, every 1/2
;second we check for dmn messages this way, to avoid losing any.
CLKINT: INSIRP PUSH P,A B C D E T TT H I J Q R FORTY UUOH
PUSHJ P,DMNPOP
INSIRP POP P,UUOH FORTY R Q J I H TT T E D C B A
jrst dismis ;return
;Here on IOCER interrupt. If device full, wait ten seconds then try
;again. If anything else, we're screwed.
IOCINT: PUSH P,T
.SUSET [.RBCHN,,T]
MOVSI T,.RIOS(T)
HRRI T,T
.SUSET T
LDB T,[.BP (37000),T] ; Get IOCER code
CAIE T,11 ; DEVICE FULL?
jrst [ move t,-4(p) ; No, dismis and instantly .LOSE
hrlm t,losadr ; RH has 1+.LZ %PIIOC
pop p,t
syscal dismis,[movsi (setz) ? move p
move -3(p) ; Restore PC
move -5(p) ; Restore DF1
move -4(p) ; Restore DF2
move losadr] ; Do .LOSE
.lose %lssys]
MOVEI T,10.*30.
.SLEEP T,
hrrz t,-4(p) ;get the PC off the stack
CAIL T,UBUGCH
CAILE T,UBUGCX
jrst dismst ;retry the failing instruction.
MOVEI T,UUORET ;disk full while dumping crash file, give up!
movem t,-4(p)
.CLOSE DMPCH,
dismst: pop p,t ;restore T
dismis: syscal dismis,[%clbit,,(setz) ? p]
.lose %lssys
losadr: 0,,1+.lz %piioc
;Here on CLI interrupt. Someone wants to edit the accounting file.
;Latch onto the job in question, do a file update, tell the job
;to proceed, and wait for it to go away.
CLIINT: .OPEN CLICH,[.UII,,'CLA]
JRST CLIINL
.IOT CLICH,UPDATR
.IOT CLICH,UPDATJ
.CALL [ SETZ
SIXBIT/OPEN/
[10,,CLICH]
['USR,,]
UPDATR
SETZ UPDATJ ]
JRST CLIINL
.CALL [ SETZ
'CORBLK
MOVEI %CBRED+%CBNDR
MOVEI %JSELF
MOVEI CMPAGE_-10.
MOVEI CLICH
SETZI 0 ]
JRST CLIINL
SETOM CLIFLG ;cause it to hang up
setom dmpcnt ;make next real-time int cause file update
.suset [.sipirqc,,[%pirlt]] ;cause immediate real-time interrupt
CAIA
CLIINL: BUGCHK CLI Lossage.
.CLOSE CLICH,
jrst dismis
SUBTTL File update generator
FILEUP:
ifn $$mcp,[
pushj p,maxget ;re-map MACSYMA in case it has changed
pushj p,maxlog ;first, log all the MACSYMA's up to now.
];mcp
MOVE Q,CRUFTP
MOVEM Q,CRUFTF ;all cruft to here will be gobbled, more may come in
SUBI Q,CRUFT ;now sort the cruft table by uname
SKIPN CHKALL ;do anyway if need to check file syntax.
SKIPE CLIFLG ;or if hacking CLI
CAIA
JUMPE Q,IDLE ;well, not much to do here
.SUSET [.SMASK,,[%PICLK+%PIIOC+%PIDWN+%PICLI+%PIPDL]]
FILEU1: MOVEI A,CRUFT ;Start a sort pass
SETZ R, ;this used to be a shell sort, but now it's a bubble.
FILEU2: MOVE B,A ;next step of pass ;maybe it will work.
ADDI B,CF.LEN
CAML B,CRUFTF
JRST FILEU5 ;pass done
MOVE T,CF.UNM(A) ;compare two crufties
CAMG T,CF.UNM(B)
JRST FILEU4
HRLI A,-CF.LEN ;out of order, exchange
FILEU3: MOVE T,(A)
EXCH T,(B)
MOVEM T,(A)
AOS B
AOBJN A,FILEU3
AOJA R,FILEU2
FILEU4: ADDI A,CF.LEN
JRST FILEU2
FILEU5: JUMPG R,FILEU1 ;if exchanged any, do another pass
MOVEI A,CRUFT ;should now be sorted, but I feel insecure...
FILEU6: MOVEI B,CF.LEN(A)
CAML B,CRUFTF
JRST FILEU7
MOVE T,CF.UNM(A)
CAMLE T,CF.UNM(B)
.VALUE
ADDI A,CF.LEN
JRST FILEU6
;Open input and output files
FILEU7: .SUSET [.SSNAME,,SNAME]
.OPEN INCH,[.BAI,,'DSK ? 'DRAGON ? SIXBIT/HOARD/]
.LOSE 1400
.OPEN OUCH,[.BAO,,'DSK ? SIXBIT/_DRGN_/ ? SIXBIT/BUFFER/]
.LOSE 1400
SETZM INBC
SETOM BBC
SETOM OUTBC
SETZM NERRS
SETZM LINENO
IRPS FIG,,STCTIM STRTIM STSWAP STLODT STLOTM
SETZM FIG ;reset subtotals since starting a page
TERMIN
IRPS FIG,,GTCTIM GTRTIM GTSWAP
SETZM FIG ;reset grand totals since starting a page
TERMIN
ifn $$mcp,[
IRPS FIG,,STMCTM STMRTM GTMCTM GTMRTM
SETZM FIG
TERMIN
];mcp
PUSHJ P,GROVEL
;drops through
;drops in
;Here on EOF. Finish up and return to the idle loop.
FILFIN: SKIPGE TOTLF
CLBFIL 17,Totals section does not contain TOTALS line.
SETZM TOTLF
SKIPE STOTLF
CLBFIL 17,Sub-total screw.
SETZM STOTLF
SKIPE RANDF
CLBFIL 17,Randoms section doesn't end, probably no Totals section.
SETZM RANDF
SETZM DRANDF
PUSHJ P,WBUF ;dump out the last buffer
.CALL [ SETZ ;and close the output file
'RENMWO
MOVEI OUCH
[SIXBIT/DRAGON/]
SETZ [SIXBIT/HOARD/] ]
.LOSE 1000
SKIPE MNTHLF
JRST MNTHL1
SKIPE NERRS
JRST FILEU8 ;jump if clobbered file to be saved and mail to be sent
.CALL [ SETZ ;save one version back of input file
'DELETE
[SIXBIT/DSK/]
[SIXBIT/DRAGON/]
SETZ [SIXBIT/SAVE/] ]
JFCL
.CALL [ SETZ
'RENMWO
MOVEI INCH
[SIXBIT/DRAGON/]
SETZ [SIXBIT/SAVE/] ]
BUGCHK Can't rename input file.
FILU8X: .CLOSE INCH, ;Here when file update complete.
.CLOSE OUCH,
PUSHJ P,LOTUP ;do the LOGOUT TIMES file.
HRRZS CHKALL ;delete program file-checking request
PUSHJ P,GOIDLE ;clean up cruft table
SKIPE YEARF ;perform periodic special processing
PUSHJ P,YEARLY
SKIPE MONTHF
PUSHJ P,MNTHLY
SKIPE DAYF
PUSHJ P,DAILY
SKIPGE @DEDTIM
.LOGOUT ;ka-zap. (finally)
SETZM EDITF ;any previous edits have now been gobbled down
SKIPL CLIFLG
JRST IDLE ;exit from file update stuff
.SUSET [.SIMASK,,[%PICLK]] ;going to hang up waiting for user to edit file.
MOVE T,CMPAGE+100 ;check user's "password"
CAME T,['GEORGE]
JRST FILU8Z
MOVNS CLIFLG ;initial file-update complete.
SETOM EDITF ;tell the user to go ahead.
SKIPE CMPAGE+100 ;wait for user to edit the file.
.HANG
FILU8Z: SETZM CLIFLG ;clear out interlocks
HRROS CHKALL ;check user's edits.
.CALL [ SETZ ;flush communications page.
'CORBLK
MOVEI 0
MOVEI %JSELF
SETZI CMPAGE_-10. ]
JFCL
JRST FILEUP ;gobble down edited file and check for errors,
;also file away cruft accumulated during editing.
;Call here to restore environment after doing a file-update.
;Clobber T, TT.
GOIDLE: .SUSET [.SAMASK,,[%PICLK]] ;no more 1/2 second breaks please
movei t,-25. ;reset back to time to wait for next update
movem t,dmpcnt
MOVE T,CRUFTP ;find amount of cruft pushed while updating
SUB T,CRUFTF
JUMPE T,GOIDL1
HRLZ TT,CRUFTF ;copy it down to beginning of cruft buffer
HRRI TT,CRUFT
BLT TT,CRUFT-1(T)
GOIDL1: MOVEM T,CRUFTP ;fix pointers
MOVEI T,CRUFT
MOVEM T,CRUFTF
ADDB T,CRUFTP
CAIL T,CRUFTZ-100 ;If there are unused
POPJ P,
MOVE T,CRUFTE ; excess cruft pages,
SUBI T,CRUFTZ ; flush them.
JUMPLE T,CPOPJ
LSH T,-10. ;number of such pages.
MOVNS T
MOVSS T
HRRI T,CRUFTZ_-10. ;aobjn pointer to pages
.CALL [ SETZ
'CORBLK
MOVEI 0
MOVEI %JSELF
SETZ T ]
.LOSE 1000 ;should never fail.
MOVEI T,CRUFTZ ;reset pointer to end of core
MOVEM T,CRUFTE
POPJ P,
;Yearly processing
YEARLY: SETZM YEARF
.SUSET [.SIMASK,,[%PICLK]]
move a,[sixbit /yearly/]
pushj p,batch
.CALL [ SETZ
SIXBIT/OPEN/
[.BAO,,OUCH]
[SIXBIT/DSK/]
[SIXBIT/MAIL/]
[SIXBIT/>/]
SETZ MALSNM ]
JRST YEARLX
SETOM OUTBC
MOVEI TT,[ASCIZFROM-JOB:DRAGON
SENT-BY:PFTHMG-DRAGON
RCPT:(MAGIC-DRAGON-KEEPER)
SUBJECT:Happy New Year
TEXT;-1
Well, I couldn't think of anything else that needed to be in the yearly processing.
]
PUSHJ P,ASZW
PUSHJ P,WBUF
YEARLX: .CLOSE OUCH,
.SUSET [.SAMASK,,[%PICLK]]
POPJ P,
FILEU8: .CALL [ SETZ
'RENMWO
MOVEI INCH
[SIXBIT/CLBFIL/]
SETZ [SIXBIT/>/] ]
.LOSE 1000
.CALL [ SETZ ;Send mail
SIXBIT/OPEN/
[.BAO,,OUCH]
[SIXBIT/DSK/]
[SIXBIT/MAIL/]
[SIXBIT/>/]
SETZ MALSNM ]
.LOSE 1400
SETOM OUTBC
SKIPN A,UPDATR
JRST FILU8E
MOVEI TT,[ASCIZTO:CM"]
PUSHJ P,ASZW
SETZB B,C
PUSHJ P,SIXW
WCHI 15
WCHI 12
FILU8E: MOVEI TT,[ASCIZFROM-JOB:DRAGON
SENT-BY:PFTHMG-DRAGON
RCPT:(MAGIC-DRAGON-KEEPER)
SUBJECT:Clobberage of accounting file
TEXT;-1
Bad syntax was detected in the accounting file. The offending lines
have been deleted. The bad file is saved as ]
PUSHJ P,ASZW
PUSHJ P,FLNMW
MOVEI TT,[ASCIZ
The errors encountered were:
]
PUSHJ P,ASZW
FILU8A: CAML C,NERRS
JRST FILU8C
CAIL C,LERRBF
JRST FILU8B
MOVE TT,ERRBFZ(C)
PUSHJ P,ASZW
MOVEI TT,[ASCIZ (Line ]
PUSHJ P,ASZW
MOVE A,ERRBFL(C)
PUSHJ P,NUMW
MOVE A,ERRBFA(C)
MOVE B,ERRBFB(C)
SKIPN ERRBFC(C)
JUMPE A,[ JUMPE B,FILU8D ? JRST .+1 ]
WCHI ",
WCHI 40
PUSH P,C
MOVE C,ERRBFC(C)
PUSHJ P,SIXW
POP P,C
FILU8D: MOVEI TT,[ASCIZ)
]
PUSHJ P,ASZW
AOJA C,FILU8A
FILU8B: MOVEI TT,[ASCIZetc ad nauseam]
PUSHJ P,ASZW
FILU8C: PUSHJ P,WBUF
JRST FILU8X
SUBTTL Daily processing
;Save the accounting file.
;Check for clobbered LOGOUT TIMES file.
;Maybe this should also sort the randoms?
DAILY: SETZM DAYF
HRROS CHKALL ;Check whole file once a day.
.SUSET [.SIMASK,,[%PICLK]]
move a,[sixbit /daily/]
pushj p,batch
.OPEN INCH,[.BAI,,'DSK ? 'DRAGON ? SIXBIT/SAVE/ ]
JRST DAILX
.OPEN OUCH,[.BAO,,'DSK ? 'DRAGON ? 'YESTER ]
JRST DAILX
DAILY1: MOVE T,[-OUTBFL,,OUTBUF]
.IOT INCH,T
HRLOI TT,-OUTBUF-1(T)
EQVI TT,OUTBUF
.IOT OUCH,TT
JUMPGE T,DAILY1
DAILX: .CLOSE INCH,
.CLOSE OUCH,
SETOM LOTCHF'
.CALL [ SETZ
SIXBIT/OPEN/
[.BAI,,INCH]
[SIXBIT/DSK/]
[SIXBIT/LOGOUT/]
[SIXBIT/TIMES/]
SETZ LOTSNM ]
JRST DAILX1
LOTCH1: MOVE T,[-5,,LOTOLD]
.IOT INCH,T
JUMPGE T,LOTCH2
CAMN T,[-5,,LOTOLD]
JRST DAILX1
PUSHJ P,LOTCH9
MOVEI TT,[ASCIZ\File length not a multiple of 5 words.
\]
PUSHJ P,ASZW
JRST DAILX1
LOTCH9: AOSE LOTCHF
POPJ P,
.CALL [ SETZ
SIXBIT/OPEN/
[.BAO,,OUCH]
[SIXBIT/DSK/]
[SIXBIT/MAIL/]
[SIXBIT/>/]
SETZ MALSNM]
.LOSE 1400
SETOM OUTBC
MOVEI TT,[ASCIZ\FROM-JOB:DRAGON
SENT-BY:PFTHMG-DRAGON
RCPT:(MAGIC-DRAGON-KEEPER)
TEXT;-1
The file \]
PUSHJ P,ASZW
PUSHJ P,FLNMW
MOVEI TT,[ASCIZ\ seems to be clobbered. Please check it.
The offensive material follows:
\]
PUSHJ P,ASZW
POPJ P,
LOTCH2: MOVE B,[440700,,LOTOLD]
MOVE C,[440700,,[ASCIZ\ZZZZZZ99/99/99 99:99:99
\]]
LOTCH3: ILDB T,B
ILDB TT,C
JUMPE TT,LOTCH1
CAIN TT,"Z
JRST [ CAIL T,40
CAIL T,140
JRST LOTCH4
JRST LOTCH3 ]
CAIN TT,"9
JRST [ CAIL T,"0
CAILE T,"9
JRST LOTCH4
JRST LOTCH3 ]
CAMN T,TT
JRST LOTCH3
LOTCH4: PUSHJ P,LOTCH9
MOVEI TT,LOTOLD
PUSHJ P,ASZW
MOVEI TT,[ASCIZ/
/]
PUSHJ P,ASZW
JRST LOTCH1
DAILX1: SKIPL LOTCHF
PUSHJ P,WBUF
.CLOSE INCH,
.CLOSE OUCH,
.SUSET [.SAMASK,,[%PICLK]]
POPJ P,
SUBTTL Monthly processing
;Save the accounting file as DRAGON lastmonth,
;and reset all the usages to zero.
MNTHLY: SETZM MONTHF
.SUSET [.SIMASK,,[%PICLK]]
move a,[sixbit /mnthly/]
pushj p,batch
SETOM MNTHLF ;Use regular grovel routines, almost...
HRROS CHKALL ; [this is needed to get all lines processed]
JRST FILEU7 ; upon completion, they will return to MNTHL1
;Trap here from GROVL9 for each line in the file.
MNTHL2: SKIPE DRANDF ;if random user with no usage last month,
SKIPE CTIME
JRST MNTHL3
SKIPN RTIME
SKIPE SWAPS
JRST MNTHL3
JRST GROVEL ;flush him completely
MNTHL3: SETZM CTIME ;reset usage
SETZM RTIME
SETZM SWAPS
ifn $$mcp,[
setzm mctime
setzm mrtime
];mcp
PUSHJ P,WBACK ;write it back out
SKIPN TOTLF ;unless this was final totals line
JRST GROVEL ;and go process more
ifn $$STAT,[
ifn $$MCP,[
MOVEI TT,[ASCIZ\
STATS fups crfts crftm core runt nomax normax newfls newcnt oldfls oldcnt
STATS 0 0 0 0 0.0 0.0 0.0 0 0 0 0
FUPS - # of file updates
CRFTYS - # of pieces of cruft pushed from logouts
CRFTYM - # of pieces of cruft pushed from MACSYMAs
CORE - # of times core has been grown. Core is flushed when file updated.
RUNT - runtime consumed by PFTHMG
NOMAX - amount of time during which there were no MACSYMA's on the machine
NORMAX - amount of time during which no one accrued MACSYMA connect time
NEWFLS - # of times new entries in MACSYMA table had to be invalidated
NEWCNT - # of entries so invalidated
OLDFLS - # of times all entries in MACSYMA table had to be invalidated
OLDCNT - # of entries so invalidated
This file is for period beginning \]
]; END IFN $$MPC,
IFE $$MCP,[
movei tt,[asciz /
STATS fups crfts core runt
STATS 0 0 0 0.0
FUPS - # of file updates
CRFTYS - # of pieces of cruft pushed from logouts
CORE - # of times core has been grown. Core is flushed when file updated.
RUNT - runtime consumed by PFTHMG
This file is for period beginning /]
]; END IFE $$MCP,
]; END IFN $$STAT,
ife $$stat,[
movei tt,[asciz /
This file is for period beginning /]
]; END IFE $$STAT
PUSHJ P,ASZW
MOVE A,LODAT
PUSHJ P,DATW
WCHI 40
.rtime a, ;gotta get the time from system
movem a,lotim ;and use it; we don't remember logout times
PUSHJ P,TIMW
MOVEI TT,[ASCIZ\
System Uptime Report
OK \]
MOVE D,LODAT
MOVEM D,OKDAT
MOVE D,LOTIM
MOVEM D,OKTIM
SETZM OKTMUP
MOVEI D,OKDAT
PUSHJ P,UPTRWW
SETZM TOTLF ;avoid screw at FILFIN
POPJ P, ;end file, return out of grovel
MNTHL1: SKIPE NERRS
.VALUE ;we really fucked-up somehow
LDB T,[141400,,LASDAT] ;rename the file to be last month's report
ANDI T,717
TRZE T,100
ADDI T,10.
CAIL T,1
CAILE T,12.
.VALUE ;random month
.CALL [ SETZ
'RENMWO
MOVEI INCH
MONTHS(T)
SETZ ['REPORT] ]
.LOSE 1000
.CALL [ SETZ
SIXBIT/OPEN/
[.BAO,,OUCH]
[SIXBIT/DSK/]
[SIXBIT/MAIL/]
[SIXBIT/>/]
SETZ MALSNM ]
JRST MNTHL7
SETOM OUTBC
MOVEI TT,[ASCIZFROM-JOB:DRAGON
SENT-BY:PFTHMG-DRAGON
RCPT:(MAGIC-DRAGON-KEEPER)
SUBJECT:That Time Again
TEXT;-1
Don't forget to print out the ]
PUSHJ P,ASZW
PUSHJ P,FLNMW
MOVEI TT,[ASCIZ file and
give it to the appropriate people.
- puff
]
PUSHJ P,ASZW
PUSHJ P,WBUF
MNTHL7: .CLOSE OUCH,
.CLOSE INCH,
SETZM MNTHLF
HRRZS CHKALL
.SUSET [.SAMASK,,[%PICLK]]
POPJ P, ;end of monthly processing
MONTHS: 'FOOBAR
SIXBIT/JAN/
SIXBIT/FEB/
SIXBIT/MARCH/
SIXBIT/APRIL/
SIXBIT/MAY/
SIXBIT/JUNE/
SIXBIT/JULY/
SIXBIT/AUGUST/
SIXBIT/SEP/
SIXBIT/OCT/
SIXBIT/NOV/
SIXBIT/DEC/
SUBTTL Hack the LOGOUT TIMES file
;For compatibility with old & name dragons.
LOTUP: MOVEI Q,CRUFT
CAML Q,CRUFTF
POPJ P,
LOTUP0: SKIPL CF.UNM(Q) ;old dragon used different sort, fix up
JRST LOTUP1 ;make Q point to lowest positive
ADDI Q,CF.LEN
CAMGE Q,CRUFTF
JRST LOTUP0
MOVE Q,CRUFTF
LOTUP1: MOVE R,Q ;save pntr to lowest positive
MOVE J,CRUFTF ;remember haven't done negatives yet
.CALL [ SETZ
SIXBIT/OPEN/
[.BAI,,INCH]
[SIXBIT/DSK/]
[SIXBIT/LOGOUT/]
[SIXBIT/TIMES/]
SETZ LOTSNM ]
POPJ P, ;tough rocks
.CALL [ SETZ
SIXBIT/OPEN/
[.BAO,,OUCH]
[SIXBIT/DSK/]
[SIXBIT/_DRGN_/]
[SIXBIT/TIMES/]
SETZ LOTSNM ]
.LOSE 1400
PUSHJ P,LOTFILL ;fill LOTNEW
LOTUP5: MOVE T,[-5,,LOTOLD] ;get entry from file
.IOT INCH,T
JUMPL T,LOTEOF
LOTUP4: MOVE A,LOTOLD ;quick compare
LSH A,-1
SUB A,LOTCMP
JUMPG A,LOTUP6 ;LOTNEW goes first
JUMPL A,LOTUP7 ;LOTOLD goes first
LDB A,[350700,,LOTOLD+1];hmm, check 6th char
LDB B,[350700,,LOTNEW+1]
CAMLE B,A
JRST LOTUP7 ;LOTOLD goes first
CAMN B,A
JRST LOTUP8 ;LOTNEW replaces LOTOLD
LOTUP6: MOVE T,[-5,,LOTNEW] ;Put LOTNEW first
.IOT OUCH,T
MOVE D,LOTCMP
LOTUP3: MOVE E,LOTNEW+1
PUSHJ P,LOTFILL ;get new LOTNEW
CAME D,LOTCMP
JRST LOTUP4
XOR E,LOTNEW+1
TLNN E,774000
JRST LOTUP3 ;this one the same, get another
JRST LOTUP4
LOTUP7: MOVE T,[-5,,LOTOLD] ;put LOTOLD first
.IOT OUCH,T
JRST LOTUP5 ;and get a new one
LOTUP8: MOVE T,[LOTNEW,,LOTOLD] ;LOTNEW replaces LOTOLD
BLT T,LOTOLD+4
PUSHJ P,LOTFILL ;get new LOTNEW
JRST LOTUP4
LOTEOF: MOVSI A,377777 ;EOF on old file
CAME A,LOTCMP ;See if EOF on new also
JRST LOTUP8 ;No, read through rest of new
.CLOSE INCH,
.CALL [ SETZ ;Install new version
'RENMWO
MOVEI OUCH
['LOGOUT]
SETZ [SIXBIT/TIMES/]]
.LOSE 1000
.CLOSE OUCH,
POPJ P,
LOTFILL:CAML Q,J
JRST LOTFL1 ;This section of cruft table exhausted
MOVE A,CF.JNM(Q)
CAME A,['HACTRN] ;Only do legitimate human users
JRST LOTFL4
HLRO A,CF.UNM(Q)
AOJE A,LOTFL4 ;Bastard
MOVE B,[440600,,CF.UNM(Q)]
MOVE C,[440700,,LOTNEW]
LOTFL0: ILDB A,B
ADDI A,40'
IDPB A,C
TLNE B,770000
JRST LOTFL0
MOVE A,CF.DAT(Q) ;MMDDYY
ROT A,14
MOVEM A,CF.DAT(Q)
MOVE B,[440600,,CF.DAT(Q)]
MOVEI TT,6+6
LOTFL3: ILDB A,B
ADDI A,40'
IDPB A,C
TRNE TT,1
IBP C
SOJG TT,LOTFL3
MOVE A,LOTNEW ;set up quick compare word
LSH A,-1
MOVEM A,LOTCMP'
ADDI Q,CF.LEN
POPJ P,
LOTFL1: JUMPE R,LOTFL2
MOVEI Q,CRUFT ;do negatives
MOVE J,R
MOVEI R,0
JRST LOTFILL
LOTFL2: MOVSI A,377777 ;make dummy entry
MOVEM A,LOTCMP
POPJ P,
LOTFL4: ADDI Q,CF.LEN ;next
JRST LOTFILL
SUBTTL Grovel over accounting file
;Grovel over the accounting file, updating according to the cruft table.
GROVEL: AOS LINENO ;starting a new line of input
SETZM UNAMEA ;haven't seen a uname yet
SETZM UNAMEB ;..
SETZM UNAMEC ;..
GROVL0: PUSHJ P,RCH ;get first character in line
CAILE T,40 ;skip if white space or eof
JRST GROVL1
CAIE T,^L ;formfeed is considered to end the randoms section...
JRST GVLCPY
IRPS FIG,,STCTIM STRTIM STSWAP STLODT STLOTM
SETZM FIG ;reset subtotals since ending a page
TERMIN
ifn $$mcp,[
SETZM STMCTM
SETZM STMRTM
];mcp
SKIPE RANDF ;if ending randoms section, add new randoms here
PUSHJ P,SPECR1
SETZM DRANDF
WCHI ^L
JRST GROVL0
GVLCPY: JUMPL T,CPOPJ ;return from GROVEL if EOF.
PUSHJ P,WCH ;copy the line over verbatim
CAIN T,12
JRST GROVEL
GVLCP1: PUSHJ P,RCH
JRST GVLCPY
GVLFL1: PUSHJ P,RCH
GVLFLS: JUMPL T,CPOPJ ;similar to GVLCPY but flush rest of line
CAIN T,12
JRST GROVEL
jrst gvlfl1
GROVL1: CAIN T,"- ;lines of dashes introduce special sections
JRST SPEC0
pushj p,untyi ;buffer back the first char of line
SETZM LVRBEG ;default unspecified stuff to 0
MOVE T,[LVRBEG,,LVRBEG+1]
BLT T,LVREND-1
PUSHJ P,SIXR ;get the uname spec of this line
pushj p,untyi ;buffer back delimiter
MOVEM A,UNAMEA
MOVEM B,UNAMEB
MOVEM C,UNAMEC
SKIPE TOTLF
JRST GRVL1T
SKIPE STOTLF
JRST GRVL1S
MOVE E,P
SKIPN CHKALL
PUSHJ P,UCRUFT ;see if this line's getting hacked
JRST GROVL2
GRVLNH: MOVE A,UNAMEA ;nope, just put out the uname
MOVE B,UNAMEB
MOVE C,UNAMEC
PUSHJ P,SIXW
JRST GVLCP1 ;and copy the rest verbatim
GROVL2: MOVE P,E ;this line's getting hacked, gobble it down
GROVL3: PUSHJ P,SIGCH
CAIG T,40
JRST GROVL9 ;end of line
CAIE T,"j
CAIN T,"J
JRST GROVL4
CAIE T,"a
CAIN T,"A
JRST GROVL5
CAIE T,"h
CAIN T,"H
JRST GROVL6
;drops through
;drops in
pushj p,untyi
move tt,column ;column before delimiter
movem tt,ctimep
pushj p,numf
clbfil 0,Garbage character where connect-time expected.
ifn $$MCP,pushj p,hread ;get connect time from hours.xx
ife $$MCP,pushj p,dhmsr ;get connect time from D!HH:MM:SS
movem a,ctime
pushj p,sigch
caig t,40
jrst grovl9 ;end of line
pushj p,untyi
move tt,column
movem tt,rtimep
pushj p,numf
clbfil 0,Garbage character where run-time expected.
ifn $$MCP,pushj p,hread ;get run time from HOURS.xxx
ife $$MCP,pushj p,dhmsr ;get run time from D!HH:MM:SS
movem a,rtime
pushj p,sigch
caig t,40
jrst grovl9 ;end of line
pushj p,untyi
move tt,column
movem tt,swapsp
pushj p,numf
clbfil 0,Garbage character where swap-in count expected.
pushj p,numr ;get number of swaps
movem a,swaps
pushj p,sigch
caig t,40
jrst grovl9 ;end of line
ifn $$MCP,[
pushj p,untyi
move tt,column
movem tt,mctimp ;remember where we found this
pushj p,numf ;check for bad char
clbfil 0,Garbage character where MACSYMA connect time expected.
pushj p,hread ;read the time
movem a,mctime ;and remember it
pushj p,sigch ;get next significant char
caig t,40 ;end of line?
jrst grovl9 ; yes
pushj p,untyi ;buffer it back
move tt,column
movem tt,mrtimp ;remember where we found this
pushj p,numf ;check it for bad
clbfil 0,Garbage character where MACSYMA run time expected.
pushj p,hread ;read the run time
movem a,mrtime ;remember it
pushj p,sigch ;and get the next significant char
caig t,40 ;end of line?
jrst grovl9 ; yes
] ; END IFN $$MCP,
pushj p,untyi ;buffer it back
move tt,column
movem tt,lodatp
pushj p,numf
clbfil 0,Garbage character where logout date expected.
pushj p,datr ;get logout date
movem a,lodat
pushj p,sigch
caig t,40
jrst grovl9 ;end of line
pushj p,untyi
move tt,column
movem tt,lotimp
pushj p,numf
clbfil 0,Garbage character where logout time expected.
pushj p,timr ;get logout time
movem a,lotim
grvl9a: pushj p,sigch ;get char that ends line
grovl9: caie t,15
clbfil 0,Garbage character.
pushj p,rch
caie t,12
pushj p,untyi
pushj p,coldef ;default columns of unspecified data.
SKIPE MNTHLF
JRST MNTHL2 ;if monthly processing, zero usage before writing back
SKIPE TOTLF
JRST SPECT2 ;This is totals line, go add in all crufts.
SKIPE STOTLF
JRST SPECS2 ;Process subtotals
MOVE A,UNAMEA
MOVE B,UNAMEB
MOVE C,UNAMEC
PUSHJ P,UCRUFT
UPDUSR ;update this line from cruft
PUSHJ P,WBACK ;write it back out
JRST GROVEL ;go do next line
;Skip if char in T is a numeric digit.
NUMF: CAIL T,"0
CAILE T,"9
POPJ P,
JRST POPJ1
GROVL4: pushj p,untyi
PUSHJ P,SIXR
CAMN A,[SIXBIT/JOB/]
CAIE T,"=
CLBFIL 0,Bad JOB= Spec.
PUSHJ P,SIXR
pushj p,untyi
MOVEM A,JNAMEA
MOVEM B,JNAMEB
MOVEM C,JNAMEC
SETOM JNAMEF
JUMPN A,GROVL3
JUMPN B,GROVL3
JUMPN C,GROVL3
CLBFIL 0,Null JOB= Spec.
GROVL5: pushj p,untyi
PUSHJ P,SIXR
CAMN A,[SIXBIT/ACCT/]
CAIE T,"=
CLBFIL 0,Bad ACCT= Spec.
PUSHJ P,SIXR
pushj p,untyi
MOVEM A,ACCNTA
MOVEM B,ACCNTB
MOVEM C,ACCNTC
SETOM ACCNTF
JUMPN A,GROVL3
JUMPN B,GROVL3
JUMPN C,GROVL3
CLBFIL 0,Null ACCT= Spec.
GROVL6: pushj p,untyi
PUSHJ P,SIXR
CAMN A,[SIXBIT/HOURS/]
CAIE T,"=
CLBFIL 0,Bad HOURS= Spec.
PUSHJ P,NUMR
MOVEM A,FHOUR
PUSHJ P,RCH
CAIE T,"-
CLBFIL 0,HOURS= Spec not followed by two numbers.
PUSHJ P,NUMR
MOVEM A,LHOUR
SETOM HOURSF
JRST GROVL3
;Default columns of unspecified items.
;Clobber T.
IFN $$MCP,[
COLDEF: MOVEI T,21. ;default starting places for unspecified fields
IRPS FIG,,[CTIMEP RTIMEP SWAPSP mctimp mrtimp LODATP
]WID,,[10. 11. 7. 10. 11. 10. ]
SKIPE FIXIND
SETZM FIG
SKIPE FIG
SKIPA T,FIG
MOVEM T,FIG
ADDI T,WID
TERMIN
POPJ P,
] ; END IFN $$MCP,
IFE $$MCP,[
COLDEF: MOVEI T,21. ;default starting places for unspecified fields
IRPS FIG,,[CTIMEP RTIMEP SWAPSP LODATP LOTIMP
]WID,,[13. 10. 7. 10. 10. ]
SKIPE FIXIND
SETZM FIG
SKIPE FIG
SKIPA T,FIG
MOVEM T,FIG
ADDI T,WID
TERMIN
POPJ P,
] ; END IFE $$MCP,
SUBTTL Write back a line
wback: setzm column
MOVE A,UNAMEA
jumpe a,cpopj ;don't write wild-care UNAMEs
MOVE B,UNAMEB
MOVE C,UNAMEC
PUSHJ P,SIXW
SKIPN JNAMEF
JRST WBACK1
MOVEI TT,[ASCIZ/ JOB=/]
PUSHJ P,ASZW
MOVE A,JNAMEA
MOVE B,JNAMEB
MOVE C,JNAMEC
PUSHJ P,SIXW
WBACK1: SKIPN ACCNTF
JRST WBACK2
MOVEI TT,[ASCIZ/ ACCT=/]
PUSHJ P,ASZW
MOVE A,ACCNTA
MOVE B,ACCNTB
MOVE C,ACCNTC
PUSHJ P,SIXW
WBACK2: SKIPN HOURSF
JRST WBACK3
MOVEI TT,[ASCIZ/ HOURS=/]
PUSHJ P,ASZW
MOVE A,FHOUR
PUSHJ P,NUMW
WCHI "-
MOVE A,LHOUR
PUSHJ P,NUMW
WBACK3: SKIPN CTIME ;if all 0, don't write any figures
SKIPE RTIME
JRST WBACK4
SKIPN LODAT
SKIPE LOTIM
JRST WBACK4
ifn $$mcp,[
skipn mctime
skipe mrtime
jrst wback4
];mcp
SKIPN SWAPS
JRST CRLF
wback4: move t,ctimep
PUSHJ P,COLADJ
MOVE A,CTIME
SKIPE CHKALL
ADDM A,STCTIM
ifn $$MCP,pushj p,hwrit2 ;connect time in hours.xx
ife $$MCP,pushj p,dhmsw ;connect time in D!HH:MM:SS
move t,rtimep
PUSHJ P,COLADJ
MOVE A,RTIME
SKIPE CHKALL
ADDM A,STRTIM
ifn $$MCP,pushj p,hwrit3 ;run time in hours.xx
ife $$MCP,pushj p,dhmsw ;run time in D!HH:MM:SS
move t,swapsp
PUSHJ P,COLADJ
MOVE A,SWAPS
SKIPE CHKALL
ADDM A,STSWAP
PUSHJ P,NUMW
ifn $$MCP,[
move t,mctimp ;get column to start MACSYMA connect time in
pushj p,coladj ;and adjust our position
move a,mctime ;get the user's MACSYMA connect time
skipe chkall ;if we're counting them
addm a,stmctm ; add it into the subtotal
pushj p,hwrit2 ;write it with 2 post-decimal digits
move t,mrtimp ;get column to start MACSYMA run time in
pushj p,coladj ;and adjust our posititon
move a,mrtime ;get the user's MACSYMA run time
skipe chkall ;if we're taking subtotals
addm a,stmrtm ; count this in the subtotal
pushj p,hwrit3 ;write it with 3 post-decimal digits
] ; END IFN $$MCP,
move t,lodatp
PUSHJ P,COLADJ
SKIPE A,LODAT
CAMN A,[-1]
JRST WBACK5
SKIPE CHKALL
MOVEM A,STLODT
PUSHJ P,DATW
WBACK5:
ife $$MCP,[
move t,lotimp
PUSHJ P,COLADJ
SKIPE A,LOTIM
CAMN A,[-1]
JRST CRLF
SKIPE CHKALL
MOVEM A,STLOTM
PUSHJ P,TIMW
] ;END IFE $$MCP,
CRLF: WCHI 15
WCHI 12
POPJ P,
SUBTTL Special sections
;Here from GROVEL when row of dashes encountered. Begin special section.
SPEC0: PUSHJ P,RCH ;find non-dash
CAIE T,40
CAIN T,"-
JRST SPEC0
MOVE Q,T ;save section type letter
CAIL Q,"a
SUBI Q,40
SKIPE TOTLF
CLBFIL 0,Totals section does not contain TOTALS line.
SKIPE STOTLF
CLBFIL 0,Subtotal screw.
SKIPE RANDF ;if ending randoms section, add new randoms
PUSHJ P,SPECR1
SETZM DRANDF
SPEC1: PUSHJ P,RCH ;gobble down rest of line
CAIE T,12
JUMPGE T,SPEC1
MOVSI I,-LSPECT ;look up section type in table
LDB T,[350700,,@SPECNM(I)]
CAME T,Q
AOBJN I,.-2
SKIPL I
CLBFIL 0,Row of dashes of unrecognized type.
MOVE TT,SPECNM(I) ;compute length of special name
HRLI TT,440700
MOVNI A,1 ;A will get (- (+ 2 length))
SPEC1A: ILDB T,TT
SOS A
JUMPN T,SPEC1A
ADDI A,68. ;number of dashes to fill in with
LSH A,-1
MOVE T,A ;copy dashes into output file
WCHI "-
SOJG T,.-1
WCHI 40
MOVE TT,SPECNM(I)
PUSHJ P,ASZW
WCHI 40
MOVE T,A
WCHI "-
SOJG T,.-1
WCHI 15
WCHI 12
SKIPN MNTHLF
JRST @SPECAD(I) ;dispatch to appropriate handler
JRST @SPECMO(I)
SPECNM: [ASCIZ/RANDOMS/] ;names of special sections
[ASCIZ/TOTALS/]
[ASCIZ/PAGE SUBTOTALS/]
LSPECT==.-SPECNM
SPECAD: SPECRN ;normal dispatch for special section
SPECTT
SPECST
IFN .-SPECAD-LSPECT, .ERR SPECAD DISAGREES WITH SPECNM
SPECMO: SPECMR ;dispatch for during monthly processing
SPECTT
GROVEL
IFN .-SPECMO-LSPECT, .ERR SPECMO DISAGREES WITH SPECNM
SPECMR: SETOM DRANDF ;delete useless randoms
JRST GROVEL
;Random users begin here. What we do is put any otherwise
;unaccounted for users at the END of this section.
SPECRN: SETOM RANDF
JRST GROVEL
;Call here when end of randoms section is reached. Preserves only Q.
SPECR1: PUSH P,Q
SETZM RANDF
JRST SPECR9
SPECR2: SKIPN CF.VAL(Q)
JRST SPECR7
SETZM LVRBEG ;Found a user not yet accounted for.
MOVE T,[LVRBEG,,LVRBEG+1]
BLT T,LVREND-1 ;So fake up an accounting entry for that user.
MOVE T,CF.UNM(Q)
MOVEM T,UNAMEA
MOVE T,CF.JNM(Q)
MOVEM T,JNAMEA
PUSHJ P,NRJNMP
SETOM JNAMEF ;unusual jname, record it
PUSHJ P,COLDEF ;using default columns
SPECR3: PUSHJ P,UPDUS3 ;update fake accounting from the data
SPECR4: ADDI Q,CF.LEN ;look for more cruft for the same user
CAML Q,CRUFTF
JRST SPECR8
MOVE T,CF.UNM(Q)
SKIPE CF.VAL(Q)
CAME T,UNAMEA
JRST SPECR4
MOVE T,CF.JNM(Q)
SKIPN JNAMEF
JRST [ PUSHJ P,NRJNMP
JRST SPECR4
JRST SPECR3 ]
CAME T,JNAMEA
JRST SPECR4
JRST SPECR3 ;found some, gobble it down too
SPECR8: PUSHJ P,WBACK ;write it out
SPECR9: MOVEI Q,CRUFT-CF.LEN ;Look for more randoms.
SPECR7: ADDI Q,CF.LEN
CAMGE Q,CRUFTF
JRST SPECR2
POP P,Q
POPJ P,
;Skip if T is a prosaic jname. Clobber T.
NRJNMP: CAMN T,['HACTRN]
JRST POPJ1
AND T,[777777,,767070]
CAMN T,['JOB.00]
JRST POPJ1
POPJ P,
;Here for page subtotals. Next line is like a totals line
;but only stuff on this page is updated into it.
SPECST: SETOM STOTLF ;tell groveler to process a little differently
JRST GROVEL
GRVL1S: CAME A,['TOTALS]
CLBFIL 0,TOTALS line missing after PAGE SUBTOTALS header.
JRST GROVL3
SPECS2:
ifn $$mcp,[
IRPS FIG1,OP,[CTIME+RTIME+SWAPS+MCTIME+MRTIME+LODAT LOTIM]FIG2,,[STCTIM STRTIM STSWAP STMCTM STMRTM STLODT STLOTM]
MOVE T,FIG2 ;increase page subtotals
SKIPE CHKALL
SETZM FIG1 ;recalculating
IFSE OP,+, ADDM T,FIG1
.ELSE [ SKIPE T
MOVEM T,FIG1 ]
TERMIN
];$$mcp
ife $$mcp,[
IRPS FIG1,OP,[CTIME+RTIME+SWAPS+LODAT LOTIM]FIG2,,[STCTIM STRTIM STSWAP STLODT STLOTM]
MOVE T,FIG2 ;increase page subtotals
SKIPE CHKALL
SETZM FIG1 ;recalculating
IFSE OP,+, ADDM T,FIG1
.ELSE [ SKIPE T
MOVEM T,FIG1 ]
TERMIN
];$$mcp
PUSHJ P,WBACK ;write it back out
ifn $$mcp,[
IRPS FIG1,,[GTCTIM GTRTIM GTSWAP GTMCTM GTMRTM]FIG2,,[CTIME RTIME SWAPS MCTIME MRTIME]
MOVE T,FIG2 ;update grand totals
ADDM T,FIG1
TERMIN
];mcp
ife $$mcp,[
IRPS FIG1,,[GTCTIM GTRTIM GTSWAP]FIG2,,[CTIME RTIME SWAPS]
MOVE T,FIG2 ;update grand totals
ADDM T,FIG1
TERMIN
];mcp
SETZM STOTLF ;end subtotal processing
JRST GROVEL ;continue normal grovelling
;Come here to generate totals section.
;First comes a line for user "TOTALS" which totals all the usage.
;then comes the STATS line which gets statistics on PUFF's operation,
;then the system uptime report
SPECTT: SETOM TOTLF ;flag for totals mode.
JRST GROVEL
GRVL1T: SKIPL TOTLF
JRST GRVL2T
CAME A,['TOTALS]
CLBFIL 0,Totals section does not begin with TOTALS line.
JRST GROVL3
SPECT2: MOVEI Q,CRUFT ;Returns here after gobbling existing totals.
MOVE T,LODAT ;Save date file last updated.
MOVEM T,LASDAT
SPECT3: CAML Q,CRUFTF
JRST SPECT4
PUSHJ P,UPDUS3 ;Add in this piece of cruft
ADDI Q,CF.LEN
JRST SPECT3
SPECT4: SKIPN CHKALL ;If recalculating total
JRST SPCT4A
MOVE T,GTCTIM
MOVEM T,CTIME
MOVE T,GTRTIM
MOVEM T,RTIME
MOVE T,GTSWAP
MOVEM T,SWAPS
ifn $$mcp,[
move t,gtmctm
movem t,mctime
move t,gtmrtm
movem t,mrtime
];$$mcp
SPCT4A: PUSHJ P,RDATIM ;T gets time, TT gets date
SKIPLE T
MOVEM T,LOTIM ;set date/time file last updated.
JUMPLE TT,SPECT5
MOVEM TT,LODAT
SKIPG T,LASDAT ;compare this date against previous
JRST SPECT5 ;if known
XOR T,TT ;see what differs
TLNE T,777700
SETOM YEARF
TDNE T,[77770000]
SETOM MONTHF
TRNE T,7777
SETOM DAYF
SPECT5: PUSHJ P,WBACK ;write it out
MOVNS TOTLF ;set TOTLF to 1 to process uptime cruft
JRST GROVEL
;Here for a line of uptime report. Should be UP, DOWN, or OK
GRVL2T: CAME A,[SIXBIT/UP/] ;UP and DOWN we just copy over
CAMN A,[SIXBIT/DOWN/]
JRST GRVLNH
ifn $$STAT,[
camn a,[sixbit /STATS/] ;PUFF's internal stats
jrst grvlst ; go handle them
]; END $$STAT,
CAME A,[SIXBIT/OK/]
CLBFIL 0,Word other than UP, DOWN, or OK in uptime report.
PUSHJ P,SIGCH
pushj p,untyi
PUSHJ P,DATR
MOVEM A,NOKDAT
PUSHJ P,SIGCH
pushj p,untyi
PUSHJ P,TIMR
MOVEM A,NOKTIM
PUSHJ P,SIGCH
pushj p,untyi
ifn $$MCP,pushj p,hread ;get run time from HOURS.xxx
ife $$MCP,pushj p,dhmsr ;get run time from D!HH:MM:SS
MOVEM A,NOKTMU
PUSHJ P,RDATIM ;TT gets date, T gets time
EXCH TT,OKDAT
EXCH T,OKTIM
CAMN T,NOKTIM
CAME TT,NOKDAT
JRST WASDWN
STILUP: .RDTIME T,
MOVEM T,OKTMUP
MOVEI TT,[ASCIZ/OK /]
MOVEI D,OKDAT
PUSHJ P,UPTRWW
JRST GVLFL1
WASDWN: MOVEI TT,[ASCIZ/DOWN /]
MOVEI D,NOKDAT
PUSHJ P,UPTRWW
MOVE D,NOKDAT
PUSHJ P,6DTCNV
MOVE B,A
MOVE D,OKDAT
PUSHJ P,6DTCNV
SUBM A,B ;B:=NUMBER OF DAYS DOWN
MOVE D,NOKTIM
PUSHJ P,6TMCNV
MOVE C,A
MOVE D,OKTIM
PUSHJ P,6TMCNV
SUB A,C ;A:=NUMBER OF SECONDS*30.
IMULI B,24.*60.*60.*30.
ADD A,B
MOVEM A,OKTMUP ;STORE LENGTH OF TIME DOWN
MOVEI TT,[ASCIZ/UP /]
MOVEI D,OKDAT
PUSHJ P,UPTRWW
JRST STILUP
UPTRWW: SETZM COLUMN
PUSHJ P,ASZW ;WRITE LINE TO UPTIME REPORT
MOVE A,OKDAT-OKDAT(D)
PUSHJ P,DATW
WCHI 40
MOVE A,OKTIM-OKDAT(D)
PUSHJ P,TIMW
WCHI 40
MOVE A,OKTMUP-OKDAT(D)
ifn $$MCP,pushj p,hwrit2 ;write out uptime as HOURS.xx
ife $$MCP,pushj p,dhmsw ;write out uptime as D!HH:MM:SS
MOVEI T,40. ;ALIGN FOR REASON
PUSHJ P,COLADJ
JRST CRLF
ifn $$STAT,[
;;; update STATS line
;;; STATS line looks like:
;STATS fups crftys[crftym]coraos runt[nomax normax newfls newcnt oldfls oldcnt]
;;; where items in [...]'s exist only if $$MCP is on
;;; FUPS is # of file updates
;;; CRFTYS is # of dmnpsh logout's processed (# therefore pushing cruft)
;;; CRFTYM is # of MACSYMA's cruft is pushed for
;;; RUNTIME is total runtime consumed by PUFF
;;; CORAOS is total times core has been grown
;;; NOMAX is total times no MACSYMA's seen
;;; NORMAX is total times no MACSYMA's seen running
;;; NEWFLS is total times NEWFLS is called
;;; NEWCNT is total jobs invalidated by NEWFLS
;;; OLDFLS is total times OLDFLS is called
;;; OLDCNT is total jobs invalidated by OLDFLS
grvlst: pushj p,sigch ;find significant char
pushj p,untyi ;buffer back the char
move t,column ;remember our column as well
movem t,updtcp ;so we can write it back in the same place
pushj p,numr ;get count of file updates
aos a ;count this update
movem a,updtct ;remember it
movei b,crftys ;# of crufties pushed by logouts
pushj p,addct0
ifn $$MCP,[
movei b,crftym ;count number of crufties pushed by MACSYMA's
pushj p,addct0
]; END ifn $$MCP,
movei b,coraos ;update the count of core growings
pushj p,addct0
move a,lrunt ;back up
movem a,orunt ;what we wrote out last time
pushj p,sigch ;next significant char
pushj p,untyi ;buffer it back
move t,column ;remember where we got it
movem t,lruntp
ifn $$MCP,pushj p,hread ;get run time from HOURS.xxx
ife $$MCP,pushj p,dhmsr ;get run time from D!HH:MM:SS
movem a,lrunt
ifn $$MCP,[
pushj p,sigch ;find next entry
pushj p,untyi ;buffer back the char
move t,column ;remember where we got it
movem t,nomaxp
pushj p,hread ;read the number
move b,nomax ;get the count
imuli b,60.*6.*3. ;convert to 1/100'ths of hours
add a,b
movem a,nomaxc ;add in the count
setzm nomax ;restart count
pushj p,sigch ;find next entry
pushj p,untyi ;buffer back the char
move t,column ;remember where on the line it was found
movem t,normxp
pushj p,hread ;read the number
move b,normax ;get the count
imuli b,60.*6.*3. ;convert to 1/100'ths of hours
add a,b ;add in the count
movem a,normxc ;remember the count for later
setzm normax ;restart count
movei b,flsnew ;update the count of NEWFLS's we've done
pushj p,addct0
movei b,cntnew ;update the count of MACSYMA's NEWFLS'ed
pushj p,addct0
movei b,flsold ;update the count of OLDFLS's we've done
pushj p,addct0
movei b,cntold ;update the count of MACSYMA's OLDFLS'ed
pushj p,addct0
]; end $$IFN $$MCP
setzm column ;start at the LHS
movei tt,[asciz /STATS/]
pushj p,aszw ;write it back out
move t,updtcp ;get where we got the info from
pushj p,coladj ;adjust our column to win
move a,updtct ;get our count of updates
pushj p,numw ;write out new count
movei b,crftys ;# of crufties pushed by logouts
pushj p,addct1
ifn $$MCP,[
movei b,crftym ;count number of crufties pushed by MACSYMA's
pushj p,addct1
]; END IFN $$MCP,
movei b,coraos ;update the count of core growings
pushj p,addct1
.suset [.rrunt,,a] ;get our runtime
sub a,orunt ;uncount the old
addi a,4166. ;round,
idivi a,8333. ;converting to seconds*30.
add a,lrunt ;count it in with what was there
move t,a ;get copy to round off
addi t,30.*1800./1000. ;round it off
idivi t,30.*3600./1000. ;just like printing and re-reading it will
imul t,[<30.*3600./1000.>*8333.] ;so that we don't accumulate error.
movem t,orunt
move t,lruntp ;get position to write this cruft in
pushj p,coladj
ifn $$MCP,pushj p,hwrit3 ;write with 3 decimal places precision
ife $$MCP,pushj p,dhmsw ;run time in D!HH:MM:SS
ifn $$MCP,[
move t,nomaxp
pushj p,coladj
move a,nomaxc ;no-macsyma connect-time count
pushj p,hwrit2 ;record updated count
move t,normxp
pushj p,coladj
move a,normxc ;no-macsyma run-time count
pushj p,hwrit2 ;record updated count
movei b,flsnew ;update the count of NEWFLS's we've done
pushj p,addct1
movei b,cntnew ;update the count of MACSYMA's NEWFLS'ed
pushj p,addct1
movei b,flsold ;update the count of OLDFLS's we've done
pushj p,addct1
movei b,cntold ;update the count of MACSYMA's OLDFLS'ed
pushj p,addct1
]; END IFN $$MCP,
pushj p,crlf ;terpri
jrst gvlfl1
addct0: pushj p,sigch ;find next entry
pushj p,untyi ;buffer back the char
move t,column
movem t,1(b) ;remember where to put it on the line
pushj p,numr ;read the number
addm a,(b) ;add in the count
popj p, ;return
addct1: move t,1(b) ;get column to hack
pushj p,coladj ;adjust the output column now
move a,(b) ;get the new count
setzm (b) ;restart count
jrst numw ;record updated count
]; END IFN $$STAT,
6DTCNV: PUSHJ P,6XXMNG ;DAYS SINCE 1 JAN 1901
SOS A,T
IMULI A,365.
IDIVI T,4
ADD A,T
PUSHJ P,6XXMNG
ADD A,(T)6DTMNL-1
PUSHJ P,6XXMNG
ADDI A,-1(T)
POPJ P,
6DTMNL: ZZ==0
IRPS L,,31 28 31 30 31 30 31 31 30 31 30 31
ZZ
ZZ==ZZ+.RADIX 10.,L
TERMIN
6TMCNV: PUSHJ P,6XXMNG ;SECONDS SINCE MIDNIGHT
MOVE A,T
IMULI A,60.
PUSHJ P,6XXMNG
ADD A,T
IMULI A,60.
PUSHJ P,6XXMNG
ADD A,T
POPJ P,
6XXMNG: LDB T,[360400,,D]
LDB TT,[300400,,D]
IMULI T,10.
ADD T,TT
LSH D,14
POPJ P,
SUBTTL Update user data
;Update user info from piece of cruft pointed to by Q.
UPDUSR: SKIPN CF.VAL(Q)
POPJ P, ;already accounted for
SKIPN JNAMEF
JRST UPDUS1
MOVE A,JNAMEA ;verify that JNAME matches
MOVE B,JNAMEB
MOVE C,JNAMEC
MOVE T,CF.JNM(Q)
PUSHJ P,MATCH
POPJ P, ;no match
UPDUS1: SKIPN ACCNTF
JRST UPDUS2
MOVE A,ACCNTA ;verify that account matches
MOVE B,ACCNTB
MOVE C,ACCNTC
MOVE T,CF.TNM(Q)
PUSHJ P,MATCH
POPJ P,
UPDUS2: SKIPN HOURSF
JRST UPDUS3
MOVE T,CF.HOR(Q) ;verify that hour matches
CAML T,FHOUR
CAMLE T,LHOUR
POPJ P,
UPDUS3: MOVE T,CF.CTM(Q) ;update the usage
ADDM T,CTIME
ADDM T,STCTIM ;also update page subtotals
MOVE T,CF.RTM(Q)
ADDM T,RTIME
ADDM T,STRTIM
MOVE T,CF.SWI(Q)
ADDM T,SWAPS
ADDM T,STSWAP
ifn $$mcp,[
move t,cf.mct(q) ;update the macsyma connect time
addm t,mctime
addm t,stmctm ;update the subtotal
move t,cf.mrt(q) ;update the macsyma run time
addm t,mrtime
addm t,stmrtm ;update the subtotal
];mcp
MOVE T,CF.DAT(Q)
MOVEM T,LODAT
MOVEM T,STLODT
MOVE T,CF.TIM(Q)
MOVEM T,LOTIM
MOVEM T,STLOTM
SETZM CF.VAL(Q) ;don't count this one again
POPJ P,
;Skip if sixbit in T matches spec in A, B, C. Clobbers A, B, C.
MATCH: ANDCB B,C ;mask for literally specd chars
XOR A,T ;xor the sixbits
TDNE A,B
POPJ P, ;simply spec'd chars don't match
JUMPE C,POPJ1 ;match!
AND C,T ;chars that gotta be digits or space
REPEAT 6,[
SETZ B,
LSHC B,6
JUMPE B,.+4
CAIL B,'0
CAILE B,'9
POPJ P, ;no match
]
JRST POPJ1 ;matches
SUBTTL Matching Routines
;Routine to match masked sixbit (in A, B, C) against cruft table.
;For each match, routine after call is called with Q -> piece of cruft.
;Clobbers A, B, Q, R, T, TT plus whatever that routine clobbers.
UCRUFT: JUMPN B,UCRUF0 ;has stars
JUMPN C,UCRUF0 ;has sharps
JRST FUSER ;easy case
UCRUF0: MOVEI Q,CRUFT ;Q -> pieces of cruft
ANDCB B,C ;mask for chars literally specd
MOVSI T,(@)
IORM T,(P)
INSIRP PUSH P,A B C Q
UCRUF1: MOVE A,-3(P)
XOR A,CF.UNM(Q)
TDNE A,-2(P)
JRST UCRUF4 ;simply spec'd chars don't match
SKIPN B,-1(P)
JRST UCRUF3 ;match!
AND B,CF.UNM(Q) ;chars that gotta be digits or space
REPEAT 6,[
SETZ A,
LSHC A,6
JUMPE A,.+4
CAIL A,'0
CAILE A,'9
JRST UCRUF4 ;no match
]
UCRUF3: PUSHJ P,@-4(P) ;matches, call spec'd routine
UCRUF4: MOVEI Q,CF.LEN ;advance to next piece of cruft
ADDB Q,(P)
CAMGE Q,CRUFTF
JRST UCRUF1
SUB P,[4,,4] ;done
JRST POPJ1
;Routine to do binary search of cruft table for uname in A.
;Calls routine after call with Q -> each matching piece of cruft.
;Clobbers Q, R, T, TT, plus whatever that routine clobbers.
FUSER: MOVEI T,CRUFT ;T lower limit
MOVE TT,CRUFTF ;TT upper limit
FUSER0: MOVE Q,TT ;Q pointer halfway between
SUB Q,T
JUMPE Q,POPJ1 ;not found
IDIVI Q,CF.LEN*2 ;ensure proper alignment (clobber R)
IMULI Q,CF.LEN
ADD Q,T
CAMN A,CF.UNM(Q)
JRST FUSER2 ;got it.
CAML A,CF.UNM(Q)
JRST FUSER1
MOVE TT,Q ;go down
JRST FUSER0
FUSER1: MOVEI T,CF.LEN(Q) ;go up
JRST FUSER0
FUSER2: CAIE Q,CRUFT ;Found one cruft entry for this user.
CAME A,CF.UNM-CF.LEN(Q) ;Look back to see if there are more.
JRST FUSER3
SUBI Q,CF.LEN
JRST FUSER2
FUSER3: MOVSI T,(@) ;Call spec'd routine for all entries for this user.
IORM T,(P)
PUSH P,A
PUSH P,Q
FUSER4: PUSHJ P,@-2(P)
MOVEI Q,CF.LEN
ADDB Q,(P)
CAML Q,CRUFTF
JRST FUSER5
MOVE A,-1(P)
CAMN A,CF.UNM(Q)
JRST FUSER4
FUSER5: SUB P,[2,,2]
POPJ1: AOS (P)
CPOPJ: POPJ P,
SUBTTL I/O Routines
;Read character into T. Returns -1 at EOF. Keeps track of column position.
; UNTYI unreads the last character, keeping track of column position
unrch:
untyi: movem t,bbc ;buffer back the character
move t,ocolum ;get the old column number
movem t,column ;it's current now.
move t,bbc ;just in case anyone expects the char to remain
popj p,
rch: move t,column ;remember this position in case of UNTYI's
movem t,ocolum
skipl t,bbc ;check for buffered back character
jrst [ setom bbc ? jrst rch3] ;get it
sosge inbc
jrst rch1 ;refill input buffer
rch2: ildb t,inbp
rch3: aos column
caie t,^M ;CR?
cain t,^J ;LF?
setzm column ; End of line
CAIE T,^I
POPJ P,
MOVEI T,7 ;tabs
ADD T,COLUMN
TRZ T,7
MOVEM T,COLUMN
MOVEI T,^I
POPJ P,
RCH1: MOVE T,[-INBFL,,INBUF]
.IOT INCH,T
MOVEI T,-INBUF(T) ;number of words read
IMULI T,5 ;number of characters
SOJL T,CPOPJ ;if read nothing, eof.
MOVEM T,INBC ;otherwise, set up count
MOVE T,[440700,,INBUF] ;and pointer
MOVEM T,INBP
JRST RCH2 ;and return first character
;Write character from T
WCH: SOSGE OUTBC
JRST WCH1 ;no room in output buffer
IDPB T,OUTBP
AOS COLUMN
caie t,^I ;tab?
popj p, ; no, that's all.
movei t,7 ;yes, add another 7 positions
add t,column ;to the position
trz t,7 ;and round down
movem t,column ;to nearest tab stop
movei t,^I ;in case someone really wants it.
popj p,
WCH1: PUSH P,T
AOSL OUTBC ;skip if no previous buffer
PUSHJ P,WBUF ;dump previous buffer
MOVEI T,5*OUTBFL
MOVEM T,OUTBC
MOVE T,[440700,,OUTBUF]
MOVEM T,OUTBP
POP P,T
JRST WCH
;Write out the output buffer. Clobbers T.
WBUF: MOVE T,OUTBP ;pad to end of word
TLNN T,760000
JRST WBUF1
MOVEI T,^C
PUSHJ P,WCH
JRST WBUF
WBUF1: HRLOI T,-OUTBUF(T)
EQVI T,OUTBUF
.IOT OUCH,T
POPJ P,
;Routine to read sixbit.
;A gets sixbit, B gets *-mask, C gets #-mask, T gets delimiter.
;Clobbers H, I, J.
SIXR: SETZB B,C
SETZ A,
MOVE H,[440600,,A]
MOVE I,[440600,,B]
MOVE J,[440600,,C]
SIXR0: PUSHJ P,RCH
CAIN T,"/
JRST SIXR1 ;slash quotes
CAIN T,"*
JRST SIXR2 ;star matches any
CAIN T,"#
JRST SIXR3 ;sharp matches digits
CAIE T,"_ ;otherwise only letters, digits, underscore, dot allowed
CAIN T,".
JRST SIXR4
CAIL T,"0
CAILE T,"z
JRST SIXR9
CAIL T,"a
JRST SIXR5
CAILE T,"Z
JRST SIXR9
CAILE T,"9
CAIL T,"A
JRST SIXR4
SIXR9: CAILE T,40
CAIN T,"=
CAIA
CLBFIL 1,Illegal character in sixbit name.
JUMPN A,CPOPJ ;check for just a star
JUMPN C,CPOPJ
CAMN B,[770000,,000000]
SETO B, ;which should be equivalent to six stars
POPJ P, ;done
SIXR1: PUSHJ P,RCH
SIXR4: SUBI T,40
SIXR5: TLNN H,770000
CLBFIL 1,Name longer than six characters.
IDPB T,H
IBP I
IBP J
JRST SIXR0
SIXR2: TLNN H,770000
CLBFIL 1,Name longer than six characters.
IBP H
SETO T,
IDPB T,I
IBP J
JRST SIXR0
SIXR3: TLNN H,770000
CLBFIL 1,Name longer than six characters.
IBP H
IBP I
SETO T,
IDPB T,J
JRST SIXR0
;Advance to next significant char, return it in T.
SIGCH: PUSHJ P,RCH
CAIE T,40
CAIN T,^I
JRST SIGCH
POPJ P,
;Write out from A, B, C. (Opposite of SIXR.)
;Clobbers H, I, J, T, TT.
SIXW: JUMPN A,SIXW0 ;check for lone star
JUMPN C,SIXW0
CAME B,[-1]
JRST SIXW0
WCHI "*
POPJ P,
SIXW0: MOVE H,[440600,,A]
MOVE I,[440600,,B]
MOVE J,[440600,,C]
SIXW1: TLNN H,770000
POPJ P,
ILDB T,I ;star?
JUMPN T,SIXW2
ILDB T,J ;sharp?
JUMPN T,SIXW3
ILDB T,H
JUMPE T,SIXW4 ;space, handle with char
ADDI T,40 ;ordinary character
CAIN T,"_ ;but maybe needs to be slashified
JRST SIXW6
CAIE T,".
CAIL T,"0
CAILE T,"Z
JRST SIXW5
CAILE T,"9
CAIL T,"A
JRST SIXW6
SIXW5: WCHI "/
SIXW6: PUSHJ P,WCH
JRST SIXW1
SIXW2: IBP H
IBP J
WCHI "*
JRST SIXW1
SIXW3: IBP H
WCHI "#
JRST SIXW1
SIXW4: LDB TT,[360600,,H] ;see if space is embedded or terminal
MOVEI T,1
LSH T,(TT)
SOS T ;mask for chars not yet processed
TDNE A,T
JRST SIXW7 ;embedded because of ordinary chars to right
TDNN B,T
TDNE C,T
JRST SIXW7 ;embedded because of magic chars to right
POPJ P, ;terminal
SIXW7: MOVEI T,40 ;embedded space
JRST SIXW5
FLNMW: .CALL [ SETZ ;Write filename of input file
'RFNAME ;Clobber A, B, C, H, I, J, T, TT
MOVEI INCH
MOVEM CLBDEV'
MOVEM CLBFN1'
MOVEM CLBFN2'
SETZM CLBSNM' ]
.LOSE 1000
SETZB B,C
IRPS NM,CH,[CLBDEV:CLBSNM;CLBFN1 CLBFN2]
MOVE A,NM
PUSHJ P,SIXW
IFSN [CH], WCHI "CH
TERMIN
POPJ P,
;Read decimal number into A. Buffer-back the delimiter. Clobber T.
NUMR: SETZ A,
NUMR0: PUSHJ P,RCH
CAIL T,"0
CAILE T,"9
JRST UNRCH
IMULI A,10.
ADDI A,-"0(T)
JRST NUMR0
;Write decimal number from A. Clobber A, B, T.
NUMW: MOVMS A ;paranoia
IDIVI A,10.
HRLM B,(P)
SKIPE A
PUSHJ P,NUMW
HLRZ B,(P)
MOVEI T,"0(B)
JRST WCH
;Adjust to column specified in T, but give at least 2 spaces.
;Clobber T.
COLADJ: SUB T,COLUMN ;distance to go
CAIGE T,2
MOVEI T,2
ADD T,COLUMN ;where to go
PUSH P,T
TRO T,7
SUB T,COLUMN
LSH T,-3 ;number of tabs needed
JUMPE T,COLAD1
COLAD0: WCHI ^I
SOJG T,COLAD0
COLAD1: POP P,T
SUB T,COLUMN ;number of spaces needed
JUMPLE T,CPOPJ
COLAD2: WCHI 40
SOJG T,COLAD2
POPJ P,
;Write asciz from TT. Clobber T, TT.
ASZW: HRLI TT,440700
ASZW0: ILDB T,TT
JUMPE T,CPOPJ
PUSHJ P,WCH
JRST ASZW0
ifn $$MCP,[
;;; Read hours.xxx into A as 30'ths of a second. Clobbers T and A
hread: pushj p,numr ;A gets a number
imuli a,60.*60.*30. ;standard internal time units
pushj p,rch ;T gets delimiter
caig t,40 ;delimiter?
jrst unrch ; buffer it back, and return with no fraction
caie t,". ;had better be "."
clbfil 1,Non "." where decimal point expected in hours.xxx field
pushj p,getdig ;get a digit
popj p, ; delimiter, read no more
imuli t,60.*60.*3. ;first goes in 10'ths position
add a,t ;accumulate in A
pushj p,getdig ;get a digit
popj p, ; delimiter, just return
imuli t,60.*6.*3. ;goes in 100'th of hours position
add a,t
pushj p,getdig ;get a digit, this time
popj p, ; delimiter, just return
imuli t,3600.*30./1000. ;goes in 1000'ths of hours position
add a,t ;accumulate in A
pushj p,rch ;get a character
caig t,40 ;is it a delimiter?
popj p, ;yes, all OK.
clbfil 1,Number too long or garbage in hours.xxx field
getdig: pushj p,rch ;get another char
caig t,40 ;is it a delimiter?
popj p,
caige t,"0 ; legal digit?
cail t,"9
caia ; yes
clbfil 2,Garbage in hours.xxx field
subi t,"0 ;convert to number
aos (p) ;skip
popj p, ;return
;;; HWRIT2 writes time as n.xx Clobbers T, A, B, and C
;;; HWRIT3 writes time as n.xxx Clobbers T, A, B, and C
hwrit2: MOVMS A ;paranoia
addi a,180.*3. ;Round off correction.
movei c,3600.*30./100. ;smallest printing value, for 0 suppression
;falls through
hwrita: idivi a,60.*60.*30. ;convert 30'ths of seconds to hours
push p,b ;save remainder, since NUMW clobbers B
pushj p,numw ;write the number
wchi ". ;decimal point
pop p,a ;recover saved remainder
idivi a,60.*60.*3. ;separate off the big part
pushj p,putdig ;put it out
camge b,c ;Is it aproximately 0??
popj p, ; yes, don't print any more digits
move a,b ;let's hack the rest
idivi a,60.*6.*3. ;separate off the 100'ths hours
pushj p,putdig ;put out this digit
camge b,c ;is the rest effectively 0?
popj p, ; yes, don't print any more digits
move a,b ;B has last digit
idivi a,3600.*30./1000. ;final convertion to 1000'th of hour from secs
jrst putdig ;write out last digit
hwrit3: movms a ;paranoia, inherited from MOON
addi a,18.*3. ;round, don't truncate!
movei c,3600.*30./1000. ;smallest printing val for zero supression
jrst hwrita ;write out all but last digit
putdig: movei t,"0(a) ;turn A into ascii digit
jrst wch ;and write out the digit
] ;END IFN $$MCP,
IFE $$MCP,[
;Read DD!HH:MM:SS into A. Buffer-back delimiter. Clobber A, B, C, T.
DHMSR: SETZB B,C ;B seconds from HH:MM:SS, C days
DHMSR0: PUSHJ P,NUMR ;A gets a number
PUSHJ P,RCH ;T gets its delimiter
CAIN T,"!
JRST DHMSR1
CAIN T,":
JRST DHMSR2
PUSHJ P,UNRCH
IMULI C,24.*60.*60.
ADD A,C
IMULI B,60.
ADD A,B
imuli a,30. ;convert to seconds*30.
POPJ P,
DHMSR1: MOVE C,A
JRST DHMSR0
DHMSR2: IMULI B,60.
ADD B,A
JRST DHMSR0
;Write DD!HH:MM:SS from A. Clobber A, B, T.
DHMSW: MOVMS A ;paranoia
SETZM DHMSWF' ;frob-typed flag
idivi a,30. ;convert to seconds
IDIVI A,24.*60.*60. ;seperate days from HHMMSS
JUMPE A,DHMSW0 ;suppress days
PUSH P,B
PUSHJ P,NUMW
WCHI "!
POP P,B
SETOM DHMSWF
DHMSW0: MOVE A,B
IDIVI A,60.*60.
SKIPN DHMSWF
JUMPE A,DHMSW1
PUSH P,B
PUSHJ P,NUM2W
WCHI ":
POP P,B
SETOM DHMSWF
DHMSW1: MOVE A,B
IDIVI A,60.
SKIPN DHMSWF
JUMPE A,DHMSW2
PUSH P,B
PUSHJ P,NUM2W
WCHI ":
POP P,B
SETOM DHMSWF
DHMSW2: MOVE A,B
NUM2W: SKIPN DHMSWF ;If a frob already typed, write number with two digits.
JRST NUMW
IDIVI A,10.
WCHI "0(A)
WCHI "0(B)
POPJ P,
]; END IFE $$MCP,
;Read YY.MM.DD into A as SIXBIT/YYMMDD/. Clobber T, B, C. Buffer back delimiter.
DATR: SKIPA C,[".]
;Read HH:MM:SS into A as SIXBIT/HHMMSS/. Clobber T, B, C. Buffer back delimiter.
TIMR: MOVEI C,":
SETZ A,
MOVE B,[440600,,A]
TIMR0: PUSHJ P,RCH
CAMN T,C
JRST TIMR0
CAIL T,"0
CAILE T,"9
JRST TIMR1
SUBI T,40
TLNN B,770000
CLBFIL 1,Date/Time too long.
IDPB T,B
JRST TIMR0
TIMR1: MOVE B,A
AND B,[606060606060]
CAME B,[202020202020]
CLBFIL 1,Date/Time short or garbaged.
JRST UNRCH
;Write SIXBIT/YYMMDD/ in A as YY.MM.DD. Clobber T, B, C.
DATW: SKIPA C,[".]
;Write SIXBIT/HHMMSS/ in A as HH:MM:SS. Clobber T, B, C.
TIMW: MOVEI C,":
MOVE B,[440600,,A]
TIMW0: ILDB T,B
ADDI T,40
PUSHJ P,WCH
ILDB T,B
ADDI T,40
PUSHJ P,WCH
TLNN B,770000
POPJ P,
MOVE T,C
PUSHJ P,WCH
JRST TIMW0
SUBTTL System message logging
;This looks for SYSMSG messages starting with:
; "DSK: "
; "MEMORY: "
;and files them in the file DRAGON; SYSMSG LOG
;Clobbers all registers, uses OUCH
DSKLOG: SETOM DSKLGF ;Flag file not open yet
SETOM OUTBC ;Initialize output buffer routine
.SUSET [.SIDF1,,[%PIRLT]] ;Defer real-time ints
MOVEI TT,8 ;Compute number of words in SYSMBF
LSH TT,@SYSMLNG
MOVEM TT,SYSMBL
SUBI TT,1
MOVEM TT,SYSMBM
DSKLG0: MOVE TT,@SYSMPT ;Last message generated by system
CAMG TT,SYSMPU
JRST DSKLGX ;No new messages
SUB TT,SYSMBL
CAMLE TT,SYSMPU
MOVEM TT,SYSMPU ;Got behind, skip to catch up
MOVEI A,8
ADDB A,SYSMPU
AND A,SYSMBM ;Index in SYSMBF of message to do
ADD A,SYSMBF ;Address in system of message
HRRZ B,(A) ; Get pointer to ascii message
MOVE TT,SYCORE(B) ; Get first 5 characters
CAMN TT,[ASCII/DSK: /]
JRST DSKLGA ; Go log DSK: message
CAME TT,[ASCII/MEMOR/]
JRST DSKLG0 ; Not relevant, ignore
MOVE TT,SYCORE+1(B) ; Get next 5 characters
TRZ TT,77777 ; Reduce to next 3 characters
CAME TT,[ASCII/Y: /]
JRST DSKLG0 ; Not relevant, ignore
; Go log MEMORY: message
DSKLGA: AOSN DSKLGF ;Open file if necessary
PUSHJ P,DSKLGO
WCHI 15 ;crlf
WCHI 12
.RDATE TT, ;Time stamp
PUSHJ P,6BTW
WCHI 40
.RTIME TT,
PUSHJ P,6BTW
WCHI 40
WCHI 40
ADD B,[440700,,SYCORE] ;bp to asciz string to type
HLLZ D,(A) ;Get arg mode types
DSKLG1: ILDB T,B
JUMPE T,DSKLG2 ;end
CAIGE T,10
JRST DSKLG3 ;insert that many arguments
PUSHJ P,WCH
JRST DSKLG1
DSKLG2: WCHI 40
PUSHJ P,DSKLG4
JRST DSKLG0
JRST DSKLG2
DSKLG3: PUSH P,T ;Number of args to print
DSKL3A: PUSHJ P,DSKLG4
JFCL
WCHI 40 ;Space after each arg
SOSLE (P)
JRST DSKL3A
SUB P,[1,,1]
JRST DSKLG1
;Display next arg, using A and D.
DSKLG4: MOVEI C,0
LSHC C,3 ;Pull arg-type out of D
JUMPE C,CPOPJ ;No more args, return with no skip
AOS (P) ;Normally skips, i.e. more args exist
AOS A
MOVE TT,(A) ;Get arg
XCT .(C)
JRST DSKLG5 ;1 Octal
JRST DSKLG6 ;2 Decimal
JRST DSKLG6 ;3 Decimal with commas
POPJ P, ;4 crlf (ignore)
POPJ P, ;5 not used
JRST 6BTW ;6 Sixbit
JRST DSKLG7 ;7 Asciz
DSKLG7: ADDI TT,SYCORE
JRST ASZW
DSKLG5: TLNN TT,-1
JRST DSKLG9
PUSH P,TT
HLRZS TT
PUSHJ P,DSKLG9
WCHI ",
WCHI ",
POP P,TT
HRRZS TT
DSKLG9: SKIPA C,[8]
DSKLG6: MOVEI C,10.
MOVE T,TT
DSKLG8: IDIV T,C
HRLM TT,(P)
SKIPE T
PUSHJ P,DSKLG8
HLRZ T,(P)
ADDI T,"0
JRST WCH
;Routine to open the disk log file
DSKLGO: .CALL [ SETZ
SIXBIT/OPEN/
JFFO TT ;error code
[100000+.BAO,,OUCH] ;Write over
[SIXBIT/DSK/]
[SIXBIT/SYSMSG/]
[SIXBIT/LOG/]
SETZ SNAME ]
CAIA
JRST DKLGO1
CAIE TT,%ENSFL
JRST [ SUB P,[1,,1]
JRST DSKLGX ] ;Give it up
.CALL [ SETZ
SIXBIT/OPEN/
[.BAO,,OUCH]
[SIXBIT/DSK/]
[SIXBIT/SYSMSG/]
[SIXBIT/LOG/]
SETZ SNAME ]
JRST [ SUB P,[1,,1]
JRST DSKLGX ] ;Give it up
DKLGO1: .CALL [ SETZ ;Seek to eof
'FILLEN
MOVEI OUCH
SETZM TT ]
.LOSE %LSSYS
.ACCESS OUCH,TT
POPJ P,
;Print next arg
;Sixbit output from TT
6BTW: MOVEI T,0
LSHC T,6
ADDI T,40
PUSHJ P,WCH
JUMPN TT,6BTW
POPJ P,
;Exit from DSKLOG
DSKLGX: SKIPL OUTBC ;If any buffered output, send it
PUSHJ P,WBUF
.CLOSE OUCH,
.SUSET [.SADF1,,[%PIRLT]] ;Reenable real-time ints
POPJ P,
ifn $$MCP,[
;;; Access a shared page of MACSYMA
maxget: syscal open,[%CLBIT,,.uii ;access MACSYMA
%climm,,maxch ;on it's very own channel
[sixbit /SYS/]
[sixbit /TS/]
[sixbit /MACSYM/]]
.lose %lsfil
syscal corblk,[%clbit,,%cbndr
%climm,,0
%climm,,%jself
%climm,,maxpag
%climm,,maxch
%climm,,maxshr] ;maxshr is page of file shared with MACSYMA
.lose %lsfil
.close maxch,
popj p,
;;; find all MACSYMA's and account for them
;;; This should only be called with interrupts defered
MAXSCN: pushj p,maxmrk ;mark all the MACSYMA's
jrst maxswp ;scan and push all old macsymas
maxlog: movsi j,-ntrees
maxlg1: skipn mx.xun(j) ;is there one there?
jrst maxlg9 ; nope, nothing further to do
pushj p,mxpsh1 ;push the cruft, but don't reset it
setzm mx.ctm(j) ;don't count connect time twice
maxlg9: aobjn j,maxlg1 ;for all MACSYMA's
popj p, ;don't do anything yet
;;; This routine is called every 100'th of an hour and finds all jobs with
;;; a page sharing with our MAXPAG, and if that job is already under
;;; survelance, (as determined by the same XUNAME, and runtime >
;;; than previous runtime) AOS's the connect time, and updates the run time
;;; If the slot is filled with a different job, it is pushed onto cruft
;;; table. The flag half of MX.CTM is then set to -1 for new entries, and
;;; 1 for new entries, for the sake of detecting timing screws that leave
;;; you in another page's circular list. If this condition is detected,
;;; all new entries are purged in the sweep phase.
;;;
;;; The sweep routine, which is called after the mark phase, and clears
;;; LH(MX.CTM) and pushes cruft for MACSYMA's that have disappeared, and
;;; deletes entries not active.
MAXMRK: move j,ruind ;in ourself
syscal cortyp,[%climm,,%jsnum(j) ;start in our very own
%climmm,,maxpag ;MACSYMA page
%clout,,t ;ignore type of page
%clout,,j ;job
%clout,,i ;page# in job
%clout,,t] ;determines non-shared page
.lose %lssys ; FOOBAR
hrrz t,t ;flush left-half bits!
sosle t ;any sharers?
jrst markl1 ; yes, trace down that chain
ifn $$stat,aos nomax ;nope! Count this event!
popj p, ;but don't try to count MACSYMA's
marklp: syscal cortyp,[%climm,,%jsnum(j) ;job we are hacking
i ;page in job
%clout,,t ;Ignore type of page
%clout,,j ;job
%clout,,i ;page # in job
%clout,,t] ;determines non-shared page
jrst newfls ; lost chain somewhere, restart
hrrz t,t ;flush left-half bits!
sojle t,newfls ;if T is 1 or zero, no sharers, lost chain
markl1: camn j,ruind ;is it us?
popj p, ; yes, end of circle
jumpe j,newfls ;paranoia
movei r,(j) ;move pointer to R so we can hack abs addrs
imul r,lublk ;make absolute pointer
hlre tt,mx.ctm(j) ;have we already looked at this job?
jumpl tt,newfls ; YES! Invalidate new jobs!
jumpn tt,oldfls ; YES! Invalidate ALL jobs!!!!!! Lose!!!
pushj p,smjobp ;check to be sure it's the same job
jrst markn ; not same! or gone (0 -=> b)
movei tt,1 ;note that this job was already there
hrlm tt,mx.ctm(j) ;marked!
jrst marklp ;loop til no more jobs in chain
markn: jumpe b,newfls ;if b is 0, retry
hrros mx.ctm(j) ;mark this job as new
jrst marklp ;keep on marking
;; come here to flush all new entries and retry mark operation
newfls: movsi j,-ntrees ;for all trees
ifn $$STATS,aos flsnew ;count the number of times we do this
newfl1: hlre t,mx.ctm(j) ;get the flag
skipge t ;if it's new
pushj p,maxrst ; reset the entry
ifn $$STATS,[
skipge t ;if it's new
aos cntnew ; count this for our stats
]; END IFN $$STATS,
aobjn j,newfl1 ;for all trees
jrst maxmrk ;restart
;; come here to flush all entries and retry mark operation
oldfls: movsi j,-ntrees ;for all tress
ifn $$STATS,aos flsold ;count the number of times this gets done
oldfl1:
ifn $$STATS,[
skipn mx.xun ;if there's anything there
aos cntold ; count it as being flushed
]; END IFN $$STATS,
pushj p,maxrst ;reset the entry (always, out of paranoia)
aobjn j,oldfl1 ;play it again.
jrst maxmrk ;restart
;;;; the sweep phase. Pushes dead jobs, unmarks.
maxswp: movsi j,-ntrees ;for all MACSYMA's
ifn $$STAT,setzm rmaxfl ;flag to notice if there are no running maximas
maxsw0: hlre t,mx.ctm(j) ;Get the marking
hrrzs mx.ctm(j) ;unmark it
skipn tt,mx.xun(j) ;is there a MACSYMA in this slot?
jumpe t,maxsw9 ; no macsyma, no mark, ignore the slot
jumpe tt,maxsw4 ; no macsyma, marked. Initialize
jumpe t,maxsw6 ; MACSYMA, no mark, just push old MACSYMA.
jumpg t,maxsw4 ; MACSYMA, old MARK
pushj p,maxpsh ; MACSYMA, new marked. Push first.
maxsw4: movei r,(j) ;get pointer into system for this job.
imul r,lublk ;convert to system pointer
move t,@ustp ;get info on run/stopped state
pushj p,smjobp ;is this the same job? Get info
jumpn tt,maxsw6 ; no, don't hack this entry
jumpe b,maxsw5 ;job gone, don't hack this entry, push it
movem b,mx.xun(j) ;remember who you are
tlnn t,busrc ;Is it running?
aos mx.ctm(j) ; count this connect time
tlnn t,busrc ;is it running?
setom rmaxfl ; note that we found one
movem a,mx.rtm(j) ;save the runtime
movei tt,9. ;default hour is 9. am
syscal rqdate,[%clout,,t]
jrst [movem tt,mx.hor(j) ;system doesn't know time, assume 9
jrst maxsw9]
hrrs t
idivi t,2.*60.*60. ;convert to hour of day
movei tt,(t) ;get in TT
movem tt,mx.hor(j)
jrst maxsw9 ;already pushed entry, if any
maxsw5: skipe mx.xun(j) ;if there is a job in this slot
maxsw6: pushj p,maxpsh ; Push this entry
maxsw9: aobjn j,maxsw0 ;for all MACSYMA's
ifn $$stat,[
skipn rmaxfl ;were there any running MACSYMA's?
aos normax ; nope, count this event
]; end ifn $$stat,
popj p, ;return
;;; SMJOBP skips if job pointed to by J is the same one recorded earlier
;;; assumes R is already set to LUBLK*<J>
;;; as a side effect, it returns runtime in A and XUNAME in B.
;;; if the job is gone, it returns 0 in B
;;; Does not clobber T or TT !!
smjobp: move a,@utrntm ;get runtime for this user
skipn b,@xuname ;get XUNAME for this user
move b,@uname ; Or UNAME if no XUNAME
skipn @uname ;paranoia, has the job disapeared?
setz b, ; if UNAME is 0, XUNAME should be too!
jumpe b,cpopj ;Paranoid of timing screws
skipn mx.xun(j) ;Is there already a job in that slot?
popj p,
came b,mx.xun(j) ;is it this same job?
popj p, ; No, gotta push it first
camge a,mx.rtm(j) ;is it the same job?
popj p, ; No, gotta push it first
jrst popj1 ;same job!
;;; push the MACSYMA entry pointed to by J onto the cruft table and reset it.
maxpsh: pushj p,mxpsh1 ;push the cruft
maxrst: setzm mx.xun(j) ;clear out the XUNAME
setzm mx.ctm(j) ;and connect time
setzm mx.rtm(j) ;and runtime
setzm mx.ort(j) ;and old runtime
setzm mx.hor(j) ;he didn't log in at a time yet!
popj p, ;done, return
mxpsh1:
ifn $$STAT,aos crftym ;count number of times pushed these
pushj p,getcor ;allocate a crufty
popj p, ; no core
move t,mx.xun(j) ;get the name
movem t,cf.unm(h) ;and name the crufty
move t,[sixbit /HACTRN/] ;pretend it's a HACTRN
movem t,cf.jnm(h)
setzm cf.ctm(h) ;connect time is counted elsewhen
setzm cf.rtm(h) ;similarly the
setzm cf.swi(h) ;other tree-total resources.
setzm cf.tnm(h) ;similarly, since TRMNAM isn't used now.
hrrz t,mx.ctm(j) ;remember MACSYMA connect time
imuli t,30.*3600./100. ;units of 1/100'th of an hour to seconds*30.
movem t,cf.mct(h)
move t,mx.rtm(j) ;remember MACSYMA run time
sub t,mx.ort(j) ;this much has been counted already
addi t,4166. ;round,
idivi t,8333. ;converting to seconds*30.
movem t,cf.mrt(h) ;and put it into the cruft
addi t,30.*1800./1000. ;round it off
idivi t,30.*3600./1000. ;just like printing and re-reading it will
imul t,[<30.*3600./1000.>*8333.] ;so that we don't accumulate error.
addm t,mx.ort(j) ;remember we've counted this much
pushj p,rdatim ;TT gets date, T gets time
movem tt,cf.dat(h) ;remember date
movem t,cf.tim(h) ;time
setom cf.val(h) ;etc.
popj p, ;return
]; END IFN $$MCP,
SUBTTL batch job launcher
;;;Call this routine with a first file name in A. Checks for files on
;;;DRAGON with that first file name, which it then loads and launches.
if1, .insrt system;fsdefs
batdir: sixbit /dragon/ ;directory to check for batch jobs.
batch: syscal open,[[.bii,,batdsk] ? [sixbit /dsk/]
[sixbit /.file./] ? [sixbit /(dir)/] ? batdir]
.lose %lssys
move tt,[-2000,,batufd]
.iot batdsk,tt
.close batdsk,
move t,batufd+udnamp
batch1: cail t,2000
jrst batch3
came a,batufd+unfn1(t)
jrst batch2
syscal open,[[.uii,,batdsk] ? [sixbit /dsk/]
a ? batufd+unfn2(t) ? batdir]
jrst batch2
syscal open,[[.bio,,batusr] ? [sixbit /usr/]
movei 0 ? batufd+unfn2(t)]
jrst batch2
syscal load,[movei batusr ? movei batdsk]
jrst batch2
.iot batdsk,tt
hrrz tt,tt
.uset batusr,[.supc,,tt]
syscal disown,[%clbit,,5 ? movei batusr]
jfcl
batch2: addi t,lunblk
jrst batch1
batch3: .close batdsk,
.close batusr,
popj p,
SUBTTL Variables, etc.
VARIABLES
;Variables into which a line from accounting file is copied
LVRBEG::
UNAMEA: 0 ;sixbit of uname
UNAMEB: 0 ;* mask for uname
UNAMEC: 0 ;# mask for uname
JNAMEA: 0 ;sixbit of jname
JNAMEB: 0 ;* mask for jname
JNAMEC: 0 ;# mask for jname
JNAMEF: 0 ;jname present flag
ACCNTA: 0 ;sixbit of accnt
ACCNTB: 0 ;* mask for accnt
ACCNTC: 0 ;# mask for accnt
ACCNTF: 0 ;account present flag
FHOUR: 0 ;first hour
LHOUR: 0 ;last hour
HOURSF: 0 ;hours present flag
CTIME: 0 ;connect time in seconds*30.
CTIMEP: 0 ;column position of .. + 1
RTIME: 0 ;run time in seconds*30.
RTIMEP: 0 ;column position of .. + 1
SWAPS: 0 ;number of swap ins
SWAPSP: 0 ;column position of .. + 1
ifn $$MCP,[
mctime: 0 ;macsyma connect time in seconds*30.
mctimp: 0 ;column position of .. + 1
mrtime: 0 ;macsyma run time in seconds*30.
mrtimp: 0 ;column position of .. + 1
]; END IFN $$MCP,
LODAT: 0 ;logout date
LODATP: 0 ;column position of .. + 1
LOTIM: 0 ;logout time
LOTIMP: 0 ;column position of .. + 1
COLUMN: 0 ;current column position
OCOLUM: 0 ;previous column position (for sake of TAB's)
LVREND::
;I/O Routines' Variables
INBC: 0 ;input bytes available
INBP: 0 ;input byte pointer
OUTBC: 0 ;output bytes left in buffer
OUTBP: 0 ;output byte pointer
BBC: -1 ;.GE. 0 => buffered back character
INBFL==200
INBUF: BLOCK INBFL ;input buffer
OUTBFL==200
OUTBUF: BLOCK OUTBFL ;output buffer
;Variables for error routine
NERRS: 0 ;number of errors (index into ERRBFZ, ERRBFL)
LERRBF==40
ERRBFL: BLOCK LERRBF ;line number
ERRBFZ: BLOCK LERRBF ;asciz message
ERRBFA: BLOCK LERRBF ;uname being hacked
ERRBFB: BLOCK LERRBF ;..
ERRBFC: BLOCK LERRBF ;..
LINENO: 0 ;current line number
INTJPC: 0 ;JPC at TSINT
BUGJPC: 0 ;JPC at BUGCHK
BUGACS: BLOCK 20 ;ACs at BUGCHK
BUGMSG: BLOCK 10 ;DMNPOP copies each message into here for benefit of BUGCHK
;Variables for batch job launcher
batufd: block 2000 ;binary MFD of directory to search for batch jobs.
;Variables for file updater etc.
CHKALL: 1,, ;non-zero => check all lines for garbage, not just ones being updated.
;LH is modified by program; RH is a debugging switch.
;assembled non-zero so will check whole file when first starting up.
UPDATR: 0 ;name of person who last updated the file.
UPDATJ: 0 ;jname
CLIFLG: 0 ;0 normal, -1 do initial file update, 1 waiting for CLI completion.
DWNTIM: 0 ;time system went down.
DRANDF: 0 ;non-zero => delete useless randoms
RANDF: 0 ;non-zero => currently in random users section.
TOTLF: 0 ;non-zero => currently in totals section.
STOTLF: 0 ;non-zero => next line is subtotals.
LASDAT: 0 ;sixbit date file last updated
YEARF: 0 ;nonzero => year has just ticked over
MONTHF: 0 ;nonzero => month has just ticked over
DAYF: 0 ;nonzero => day has just ticked over
MNTHLF: 0 ;nonzero => doing monthly reset processing
STCTIM: 0 ;subtotal connect time
STRTIM: 0 ;subtotal run time
STSWAP: 0 ;subtotal swaps
IFN $$MCP,[
stmctm: 0 ;subtotal MACSYMA connect time
stmrtm: 0 ;subtotal MACSYMA run time
]; END IFN $$MCP,
STLODT: 0 ;subtotal logout date
STLOTM: 0 ;subtotal logout time
GTCTIM: 0 ;grand total connect time
GTRTIM: 0 ;grand total run time
GTSWAP: 0 ;grand total swaps
IFN $$MCP,[
gtmctm: 0 ;grand total MACSYMA connect time
gtmrtm: 0 ;grand total MACSYMA run time
]; END IFN $$MCP,
;don't change order of next 6 items
OKDAT: -1 ;sixbit date last seen this execution of dragon
OKTIM: -1 ;sixbit time ditto
OKTMUP: -1 ;seconds*30. of up-time
NOKDAT: 0 ;last date from file
NOKTIM: 0 ;..
NOKTMU: 0 ;..
LOTOLD: BLOCK 5 ;read from file into here
0
LOTNEW: ASCII\UNAME MM/DD/YY HH:MM:SS
\ ;build new in here
IFN .-LOTNEW-5, .ERR LOTNEW loses
;dmn-push message from system for login
LI.==,,-1
LI.TIM==0 ;FIRST WORD IS TIME IN 30THS
LI.IDX==1 ;RH USER INDEX
LI%COD==10000 ;LH IS THIS CODE
LI.UNM==2 ;UNAME
LI.JNM==3 ;JNAME
LI.TNM==4 ;TRMNAM
;dmn-push message from system for logout
LO.==,,-1
LO.TIM==0 ;FIRST WORD IS TIME IN 30THS
LO.IDX==1 ;RH USER INDEX
LO%COD==20000 ;LH IS THIS CODE
LO.UNM==2 ;UNAME
LO.JNM==3 ;JNAME
LO.RTM==4 ;RUN TIME IN 4.069 MICROSECOND UNITS
LO.SWI==5 ;SWAP-IN REQUESTS
;Fake logout message used at shutdown
FAKMSG:
0 ;LO.TIM
LO%COD,, ;LO.IDX
0 ;LO.UNM
0 ;LO.JNM
0 ;LO.RTM
0 ;LO.SWI
;All stuff referenced frequently by DMNPOP etc. should be after this point.
CONST.: CONSTANTS
;Cruft for each logged in tree
NTREES==171 ;SHOULD BE ENOUGH (BETTER BE MORE THAN MAXJ)
TR.UNM: BLOCK NTREES ;UNAME, 0 IF SLOT EMPTY
TR.JNM: BLOCK NTREES ;TOP JNAME
TR.TNM: BLOCK NTREES ;TRMNAM AT LOGIN
TR.XUN: BLOCK NTREES ;XUNAME
TR.TIM: BLOCK NTREES ;TIME AT LOGIN (FOR COMPUTING CONNECT)
;Unless we miss a dmn-push, nothing can go away or change
;its name without the system saying so. Trees can appear
;without the system saying so if they are created by disowning;
;in that case we just won't charge connect time.
IFN $$MCP,[
mx.xun: block ntrees ;UNAME, 0 if slot empty
mx.ctm: block ntrees ;<flag>,,<interval count> (flag is used to mark MACSYMAs
; found on given scan; the count -=> connect time)
mx.rtm: block ntrees ;runtime of this MACSYMA
mx.ort: block ntrees ;runtime of this MACSYMA which has already been recorded
mx.hor: block ntrees ;hour this MACSYMA was started, for HOURS=
]; END IFN $$MCP,
;Cruft pushed for logged out trees (at end of core)
CF.==,,-1
CF.UNM==0 ;XUNAME (0 MARKS END OF CRUFT)
CF.JNM==1 ;JNAME
CF.TNM==2 ;TRMNAM (ACCOUNT)
CF.HOR==3 ;HOUR OF THE DAY LOGGED IN (0-23.)
CF.CTM==4 ;CONNECT TIME IN SECONDS*30.
CF.RTM==5 ;RUN TIME IN SECONDS*30.
CF.SWI==6 ;# SWAPINS
ifn $$MCP,[
CF.MCT==7 ;# of times this MACSYMA was runable
CF.MRT==10 ;run time this MACSYMA observed to use
CF.DAT==11 ;SIXBIT DATE OF LOGOUT
CF.TIM==12 ;SIXBIT TIME OF LOGOUT
CF.VAL==13 ;VALID FLAG (0 => HAS BEEN PUT INTO ACCT FILE)
CF.LEN==14 ;# WDS/CRUFTY
]; END IFN $MCP,
ife $$MCP,[
CF.DAT==7 ;SIXBIT DATE OF LOGOUT
CF.TIM==10 ;SIXBIT TIME OF LOGOUT
CF.VAL==11 ;VALID FLAG (0 => HAS BEEN PUT INTO ACCT FILE)
CF.LEN==12 ;# WDS/CRUFTY
]; END IFE $MCP,
;data
ruind: 0 ;OUR user index
;timers
dmpcnt: -31 ;count till time to dump
dmpinv: -31 ;# of clock cycles between file updates (25. = 15 minutes)
maxcnt: -1 ;count till time to do acounting update on MACSYMAs
maxinv: -1 ;count of ticks per 36. second period
rltinv: 60.*36. ;36. seconds between ints, normally.
CRUFTP: CRUFT ;points at first unused entry in cruft table.
CRUFTF: CRUFT ;fence. stuff below this is getting updated into file.
CRUFTE: CRUFTZ ;points at highest loc+1 allocated for cruft table.
; which had better be a page boundary.
ifn $$STAT,[
;; internal statistics
updtct: 0 ;count of file updates
updtcp: 0 ;position of above on line
crftys: 0 ;# of pieces of cruft pushed by logout dmnpush
crftsp: 0 ;position of above on line
lrunt: 0 ;last recorded runtime
lruntp: 0 ;position of above on line
orunt: 0 ;runtime consumed so far in this job
coraos: 0 ;# of times we've grown core.
coraop: 0 ;position of above on line
ifn $$MCP,[
rmaxfl: 0 ;flag to notice no running MACSYMA's seen
crftym: 0 ;# of pieces of cruft pushed for MACSYMA's
crftmp: 0 ;position of above on line
nomax: 0 ;# of times no MACSYMA's seen
nomaxc: 0
nomaxp: 0 ;position of above on line
normax: 0 ;# of times no running MACSYMA's seen
normxc: 0
normxp: 0 ;position of above on line
flsnew: 0 ;# of times we've NEWFLS'd
flsnwp: 0 ;position of above on line
cntnew: 0 ;# of MACSYMA's we've NEWFLS'd
cntnwp: 0 ;position of above on line
flsold: 0 ;# of times we've OLDFLS'd
flsolp: 0 ;position of above on line
cntold: 0 ;# of MACSYMA's we've OLDFLS'd
cntolp: 0 ;position of above on line
]; END IFN $$MCP,
]; END IFN $$STAT,
;Pointers to relevant system symbols
DEDTIM: 0 ;<0 system down. 0 Up. Otherwise time till death.
TIME: 0 ;30ths since system up.
USRHI: 0 ;index of highest user +.
LUBLK: 0 ;length of user variables block.
UNAME: 0 ;user name.
XUNAME: 0 ;user's intended uname
JNAME: 0 ;job name.
SUPPRO: 0 ;superior pointer.
USTP: 0 ;run/stop flag
UTRNTM: 0 ;user run time.
USIPRQ: 0 ;user swapin requests.
TRUNTM: 0 ;run time of inferiors minus previously-logged.
TSIPRQ: 0 ;swapin requests of inferiors minus previously-logged.
DMNBC: 0 ;AOS'ed each time something is put in the buffer, before
DMNBD: 0 ;AOS'ed each time something is put in the buffer, after
DMNBF: 0 ;the buffer
DMNBFE: 0 ;the end of the buffer
DMNBEL: 0 ;# words per message
LDMNBD: 0 ;last value of DMNBD seen
DMNBSZ: 0 ;number of frobs that fit in the buffer
SYSMPT: 0 ;Pointer to index of message most recently inserted in SYSMBF
SYSMLNG:0 ;log(2) of number of 4-word entries in SYSMBF
SYSMBF: 0 ;Pointer to SYSMSG table in the system
SYSMBL: 0 ;Number of words in SYSMBF
SYSMBM: 0 ;That minus one (mask)
SYSMPU: 0 ;Index of last message processed
DSKLGF: 0 ;-1 means file not opened yet in DSKLOG
;Cruft Table Starts Here
CRUFT: -1
CRUFTZ==<CRUFT+1777>&<776000> ;address of first additional cruft page.
crfmrg==20. ;ask for update this many crufties from full
crfsiz==10. ;ten pages of cruft before panic dump
maxpag==176 ;page for sharing with MACSYMA
maxshr==60 ;page of SYS:TS MACSYM to share with
CMPAGE=376000 ;Communication page, see CLIINT.
SYCORE=400000 ;Upper Core is mapped into absolute.
END GO