From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 29-SEP-1990 00:35:35.92
To:	MRGATE::"ARISIA::EVERHART"
CC:	
Subj:	Re: Finding the idle time of a terminal

Received:  by crdgw1.ge.com (5.57/GE 1.73)
	 id AA28691; Sat, 29 Sep 90 00:17:45 EDT
Received: From TGV.COM by CRVAX.SRI.COM with TCP; Fri, 28 SEP 90 17:17:56 PDT
Date:     Fri, 28 Sep 90 16:44:53 PDT
From: adelman@TGV.COM (Kenneth Adelman)
Reply-To: Adelman@TGV.COM (Kenneth Adelman)
Message-Id: <900928164453.21c002f0@TGV.COM>
Subject:  Re: Finding the idle time of a terminal
To: midway!iitmax!ed@handies.ucar.edu
Cc: info-vax@sri.com

> I was looking around in the VMS "Device Support Manual" hoping to find
> a clue as to how to find out how much time has elapsed since a character
> was typed to or from a terminal.  Apparently its not as easy as checking a
> "Time of last use" field in the terminals UCB data structures.  Drat.
> I came up empty.  Hence this post.

    If the VMS terminal port driver does not set the TTY$M_PC_NOTIME
bit in the terminal UCB field UCB$W_TT_PRTCTL then the VMS terminal
class driver updates the field UCB$L_DUETIM to be the system-absolute
time at which the sanity timer is due to expire.  In general, if this
time is in the future it means I/O is in progress, if in the past it
is an indication of how long it has been since some I/O took place, and if
it is zero it means the terminal doesn't keep track of the due time.

    Here is a code fragment to retrieve the idle time in seconds. The
first argument is the address of a descriptor to the terminal name and
the second an address of a longword to return the idle time in seconds to.

							Ken


	.entry	idletime,^m<>
	pushal	(ap)
	pushaw	b^idletime_k
	calls	#2,g^sys$cmkrnl
	ret

	.entry	idletime_k,^m<r2,r3,r4>
	ifnord	#8,@4(ap),accvio	; make sure we can read descriptor
	ifnowrt #4,@8(ap),accvio	; and write the return address
	jsb	g^sch$iolockr		; lock I/O database for read
					;; we are now at IPL 2 (ASTDEL)
	movl	4(ap),r1		; search for device UCB
	jsb	g^ioc$searchdev
	blbc	r0,20$			; not found

	tstl	w^ucb$l_duetim(r1)
	bneq	9$
	mnegl	#1,@8(ap)
	brb	20$
9$:	subl3	w^ucb$l_duetim(r1),g^exe$gl_abstim,r1
	bgeq	10$
	clrl	r1
10$:	movl	r1,@8(ap)
20$:	pushl	r0
	jsb	g^sch$iounlock
	setipl	#0
	popr	#^M<r0>
	ret

accvio: movzwl	s^#ss$_accvio,r0
	ret

	.end

    The following code is a hack which causes the terminal driver
to update the DUETIM field for all terminals. You run this ONCE per boot
and it patches the terminal driver on-the-fly:

	.Title	Install-Idle-Monitor
;
;	This loads code into system space and patches into the
;	terminal port/class interface to update UCB$L_ABSTIM whenever
;	a character is sent or received. This allows us to keep
;	track of 'idletime' on non-TIMED devices.
;

	.library /SYS$LIBRARY:LIB/
	$CXBDEF
	$DDTDEF
	$DPTDEF
	$DYNDEF
	$TTYUCBDEF
	$TTYVECDEF
	$UCBDEF

	.Entry	Install_Idle_Monitor,^m<>
	$CMKRNL_S   $$Install_Idle_Monitor
	Ret


	.Entry	$$Install_Idle_Monitor,^m<r2,r3,r4,r5,r6,r7>

	;
	;   See if we have an RTA0 device installed.
	;

	Clrl	R7			; Assume no RTDRIVER DDT to patch
	Jsb	G^Sch$IOLockR		; Lock the I/O database

	MovAQ	RT_DEVICE,R1
	Jsb	G^IOC$SearchDev		; Search for RTA0
	Blbc	R0,1$
	Movl	UCB$L_DDT(R1),R7
1$:

;
;	Allocate a buffer to hold the code the be loaded into
;	nonpaged pool
;

	MovL	#CodeLen+12,R1		; Skip 12 bytes for pool header
	TstL	R7
	BEql	2$
	AddW2	DDT$W_FDTSIZE(R7),R1	; Room for old FDT
	AddW2	#3*4,R1			; Room for the new FDT entry
2$:

	Jsb	G^Exe$AllocBuf
	Blbs	R0,10$
	Pushl	R0
	Brb	Done
10$:

;
;	Copy the code into the pool
;

	MovAB	12(R2),R6		    ; Address of start of code
	MovC3	#CodeLen,W^Code,(R6)	    ; Copy code into pool

;
;	Link the code into the class interface to TTDRIVER.
;

	MovL	G^TTY$GL_DPT,R1		    ; Get TTDRIVER DPT
	MovZWL	DPT$W_VECTOR(R1),R0	    ; Offset to CLASS VECTOR
	AddL2	R0,R1			    ; Address of CLASS VECTOR

	MovL	CLASS_GETNXT(R1),B^V1_Jump-Code(R6)
	MovL	CLASS_PUTNXT(R1),B^V2_Jump-Code(R6)
	MovAB	B^V1-Code(R6),CLASS_GETNXT(R1)
	MovAB	B^V2-Code(R6),CLASS_PUTNXT(R1)

;
;	Build a new FDT routine for RTTDRIVER.
;
	Tstl	R7
	Beql	20$
	Addl3	S^#Patched_RT_FDT-Code,R6,R0; Pointer to start of new FDT
	Movl	DDT$L_FDT(R7),R1	    ; Pointer to start of old FDT
	MovQ	(R1)+,(R0)+		    ; Copy the supported I/O mask
	MovQ	(R1)+,(R0)+		    ; Copy the buffered I/O mask
	MovQ	-16(R1),(R0)+		    ; Copy the supported into the new entry
	MovAB	B^RTT_Fix-Code(R6),(R0)+    ; New FDT code address
	MovZWL	DDT$W_FDTSIZE(R7),R2
	SubL2	#16,R2			    ; Calculate size of remaining FDT
	MovC3	R2,(R1),(R0)		    ; Move it
	MovAL	B^Patched_RT_FDT-Code(R6),DDT$L_FDT(R7)
	AddW2	#12,DDT$W_FDTSIZE(R7)	    ; Update the pointers to the new FDT
20$:
;
;	Exit
;
	Pushl	#SS$_NORMAL
Done:	Movl	G^CTL$GL_PCB,R4
	Jsb	G^SCH$IoUnLock
	PopL	R0
	Ret


RT_DEVICE:
	.Ascid	/_RTA0:/

;
;   This code sits in between the port/class interface for each
;   terminal and updates the "DUETIM" field when each I/O occurs
;   It *Must* be PIC.
;
Code:
V1:	BBC	#TTY$V_PC_NOTIME,UCB$W_TT_PRTCTL(R5),10$
	MovL	@#EXE$GL_ABSTIM,UCB$L_DUETIM(R5)
10$:	Jmp	@I^#00000000
V1_Jump = .-4


V2:	BBC	#TTY$V_PC_NOTIME,UCB$W_TT_PRTCTL(R5),10$
	MovL	@#EXE$GL_ABSTIM,UCB$L_DUETIM(R5)
10$:	Jmp	@I^#00000000
V2_Jump = .-4

Rtt_Fix:MovL	@#EXE$GL_ABSTIM,UCB$L_DUETIM(R5)
	Rsb

CodeLen = .-Code

Patched_RT_FDT:

	.End	Install_Idle_Monitor

