objnam JOBMON.LIT ; Created 9-June-86, Last modified 29-Feb-88 ; by Irv Bromberg, Medic/OS Consultants, Toronto, CANADA radix 10 vedit=23 vminor=4 vmajor=3 vsub=0 vwho=1 if eq,1 Edit history: 29-Feb-88 3.4(23) Don't touch if terminal driver has TD$LDL!TD$NUL set (don't need to check for PSEUDO or NULL drivers anymore) 19-Feb-88 3.3(22) Don't touch if terminal does not have echo enabled. 3.2(21) Don't care if job not at monitor level, if meets other criteria. Always force ^C before logoff command, causes input buffer to be flushed and terminal to beep. 13-Mar-87 3.1(20) added prompt for logoff command on next input line Syntax: JOBMON {minutes} >logoff command ; here logoff command is entered at ">" prompt A typical example: JOBMON 10 ; 10-minute timeout >LOGOFF however the system operator has the option of setting any convenient logoff command (lowercase is supported), maximum length 80 characters. Leading whitespace in the logoff command is ignored. The default logoff command (if a blank line is entered at the ">" prompt) is: LOGOFF ; forced off by JOBMON Monitors all jobs on system for inactivity. Any job sitting inactive for the specified number of minutes (default=10 minutes) will be forced to LOGOFF, provided: - it is logged into an account - it is attached to a non-PSEUDO, non-FAKE terminal - its terminal driver is neither PSEUDO nor NULL - its terminal status is in line-input mode with echo enabled (i.e. T$DAT T$IMI T$LCL and T$ECS terminal status bits all OFF) Where a job has been inactive and meets all of the above criteria JOBMON will first force a Control-C to cause the input buffer to be flushed and the job's terminal to beep, and then will force the specified or default logoff command to the job. JOBMON is re-entrant and re-usable, and may be run logged-out. The minutes before timeout must be at least 1; if omitted or less than 1 the default timeout (10 minutes) will be used. endc search SYS J.ALC=1 ; undefined as of AMOS/L 1.3 search SYSSYM search TRM JCB=A0 Self=A1 Buffer=A2 IDV=A2 TDV=A2 Table=A3 WRK=A4 TCB=A5 Atemp=A6 Jobs=D0 ; number of jobs in job table Char=D1 CrtCmd=D1 Number=D1 Timeout=D2 ; minutes before logoff Count=D3 JobNum=D4 ; current job number * workspace ItemSize Dtemp=D6 IDVNAM=D7 TDVNAM=D7 ; Workspace format - for each job in job table: OFFCMD=82 ; size of space reserved for logoff command @WRK .ofini .ofdef CPUTIM,4 ; job's last observed CPU time .ofdef Idle,2 ; #minutes of idle inactivity .ofsiz ItemSize ; size of a workspace element DftTime=10 ; default to 10-minute timeout NULL=0 ETX=3 BEL=7 CR=13 TD$NUL=^H40 phdr -2,0,PH$REE!PH$REU ; re-entrant/usable, run logged-out mov JOBCUR,Self CntTbl: ; first check jobs table to find out how much memory worksp we need mov JOBTBL,Table ; index the jobs table clr Jobs ; pre-clear br 20$ ; enter at end of loop 10$: inc Jobs ; found one job, count it 20$: cmp (Table)+,#-1 ; end of table? bne 10$ ; no, loop back and count some more mov #DftTime,Timeout ; preset default value lin ; end of line? beq GetWRK gtdec ; get number of minutes for timeout tst Number beq GetWRK ; must be at least 1 mov Number,Timeout ; set specified timeout GetWRK: ; now get all the workspace we need as impure area mov Jobs,Dtemp ; calculate workspace size required mul Dtemp,#ItemSize ; multiply by size per element add #OFFCMD,Dtemp ; add space for logoff command push Dtemp push getmem @SP jne Abort pop WRK pop GetCMD: ; first input the logoff command into the workspace mov JOBTRM(Self),TCB ; get our own TCB orw #T$ILC,T.STS(TCB) ; allow lowercase input ttyi asciz ">" ; prompt for logoff command input even kbd ; set pointer to logoff command byp ; skip leading whitespace lin ; empty line? bne 5$ ; no, process the entry lea Buffer,LOGOFF ; yes, take the default 5$: mov WRK,Atemp ; point at storage for logoff command movw #OFFCMD-1,Dtemp ; set maximum size 10$: movb (Buffer)+,Char ; get next character of logoff command movb Char,(Atemp)+ ; save next char of logoff command cmpb Char,#CR ; terminate on CR dbeq Dtemp,10$ ; loop till done or full ; no need to terminate the line since WRK area cleared by GETMEM already ; The first time through the loop we initialize at the WRK items Loop: mov JOBTBL,Table ; check all jobs again clr JobNum ; pre-clear WRK offset register ChkTbl: mov (Table)+,Dtemp ; job assigned here? bpl ChkJob ; >0 =not end of table DidPass:sleep #600000 ; -1=end of table, sleep for 1 minute tstb JOBSTS(Self) ; were we killed? bpl Loop ; no, go back again Abort: typecr <%Aborted> ; aborted by Ctrl-C exit ChkJob: jeq NxtJob ; 0=job not assigned here mov Dtemp,JCB ; index this Job Control Block cmp JCB,Self ; exempt ourself jeq NxtJob ; (could never log self off) tstw JOBUSR(JCB) ; currently logged-in at all? jeq NotIdle ; no, exempt if not logged-in ChkJSTS:movw JOBSTS(JCB),Dtemp ; is it at monitor level? andw #^C,Dtemp ; anything besides TIW/MON on? jne NotIdle ; yes, can't touch this guy ChkATT: mov JOBTRM(JCB),Dtemp ; is job attached? beq NotIdle ; no, unattached jobs are exempt mov Dtemp,TCB ; index Terminal Control Block ChkIDV: mov T.IDV(TCB),IDV ; check that IDV not PSEUDO or FAKE mov -4(IDV),IDVNAM ; get this guy's IDV name lea Atemp,IDVs ; index list of exempt interface dvrs 10$: mov (Atemp)+,Dtemp ; get next exempt IDV name beq ChkTDV ; not an exempt IDV cmp IDVNAM,Dtemp ; is it an exempt IDV? bne 10$ ; not this IDV, go check next br NotIdle ; yes, this job is exempt ChkTDV: mov T.TDV(TCB),TDV ; check that TDV not PSEUDO or NULL movw TD.TYP(TDV),Dtemp ; check for TDV LCL or NULL bits andw #,Dtemp bne NotIdle ChkTSTS:movw T.STS(TCB),Dtemp ; is it in echo line input mode? andw #ECS!LCL!DAT!IMI,Dtemp ; check echo suppress and data mode bne NotIdle ChkTime:mov JOBCPU(JCB),Dtemp ; has CPU time changed? cmp Dtemp,OFFCMD+CPUTIM(WRK)[~JobNum] ; don't care what it is/was bne NotIdle ; only whether or not it has changed decw OFFCMD+Idle(WRK)[~JobNum] ; countdown the minutes bgt NxtJob ; and continue on to next job Kill: ; found an idle job, force him off movb #ETX,Char ; force ^C first to flush input buffer trmicp ; and kill if not at monitor level mov WRK,Buffer ; recall pointer to logoff command More: movb (Buffer)+,Char ; get next char (terminate at NULL) beq NotIdle trmicp ; force the character as input br More NotIdle:mov JOBCPU(JCB),OFFCMD+CPUTIM(WRK)[~JobNum] ; save CPU time movw Timeout,OFFCMD+Idle(WRK)[~JobNum] ; give him full timeout again NxtJob: addw #ItemSize,JobNum ; adjust WRK offset to next job jmp ChkTbl ; go back for more IDVs: rad50 "PSEUDO" ; list of exempted interface drivers rad50 "FAKE" ; <-- as published in AMUS.LOG rad50 "FLiP" ; AlphaBASE FLiP driver lword 0 LOGOFF: ascii "LOGOFF ; forced off by JOBMON" ; send LOGOFF command+comment byte CR,NULL ; CR, NULL to terminate even end .