;;;-*-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,-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+- ;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* ;;; 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 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==&<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