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
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<J.TIW!J.MON!J.ALC>,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 #<TD$LCL!TD$NUL>,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