News, tips, partners, and perspectives for the Oracle Solaris operating system

An idle hack

Alan Coopersmith
Senior Principal Software Engineer

An occasionally recurring question we get is how to tell how long an X session has been idle without having the xauth cookie to open a connection to the display. While thinking about this recently, I thought of a way to do it, if you have root access and can poke around in the X server process space.


Warning: The technique that follows is for educational & entertainment purposes only. It is not a supported interface, is subject to change or break at any time, and may not even work for you right now. Use at your own risk. Do not fold, spindle, or mutilate.


The X server keeps track internally of the time that it last saw an event from an input device such as a keyboard or mouse and uses this to determine when to blank the screen or remove power from the monitor, among other things. You can see these checks in the source code in Xserver/os/WaitFor.c (all the references here are to the open source Xorg code base - Xsun code in these areas is almost identical so it's close enough for reference). For instance, if you look at the function ScreenSaverTimeoutExpire, you'll see it calculate the time since the last event as:

    INT32 timeout = now - lastDeviceEventTime.milliseconds;
We simply need to duplicate this to determine the idle time of the current session.

The lastDeviceEventTime is a global variable, which means we can query it via the Solaris mdb debugger in a live process. It's defined as type TimeStamp which is:

typedef struct _TimeStamp {
    CARD32 months;      /* really ~49.7 days */
    CARD32 milliseconds;
}           TimeStamp;
CARD32 is an X type defined to be a 32-bit unsigned integer. So to get the value of lastDeviceEventTime.milliseconds we can use this mdb command which prints in decimal form the value of the 4-byte word that is 4 bytes after the address defined as lastDeviceEventTime:
# echo "lastDeviceEventTime+4/D" | mdb -p 5755
Xsun`lastDeviceEventTime+4:     1804124248
(5755 is the process id of the currently running Xsun process on this system.)

now represents the current time and is set earlier in WaitFor.c by calling GetTimeInMillis, which can be found in Xserver/os/utils.c, and is simply:

    struct timeval  tp;

    return(tp.tv_sec * 1000) + (tp.tv_usec / 1000);
We can replicate this in perl using the gettimeofday function provided in the Time::HiRes module provided in perl 5.8 (which means it's included in Solaris 10, but you need to provide it yourself for older versions). A perl one-liner that mimics the above function, including truncating to 32-bit (important when using a perl built with 64-bit integer support) is (formatted for readability - put this all on one line to run):
perl -MTime::HiRes -e '
	use integer;
	@t = Time::HiRes::gettimeofday(); 
	print ( ($t[0]*1000 + $t[1]/1000) % 0x100000000 ); 
	print "\n";'

Now we just need to subtract the lastEventDeviceTime we got from mdb with the current time we got from gettimeofday, which in a burst of barely readable perl code looks like:

echo "lastDeviceEventTime+4/D" | mdb -p process_id | perl -MTime::HiRes -n -e '
      use integer; 
      @t = Time::HiRes::gettimeofday(); 
      @l = split /\:/, $_; 
      $i = ((($t[0]*1000 + $t[1]/1000) % 0x100000000) - $l[1]); 
      print $i/1000 . " seconds since last device event \n";'


Running on the test system next to me:
# echo "lastDeviceEventTime+4/D" | mdb -p 5755 | perl -MTime::HiRes -n -e 'use integer; @t=Time::HiRes::gettimeofday(); @l=split /\:/, $_; $i = ((($t[0]*1000 + $t[1]/1000)%0x100000000) - $l[1]); print $i/1000 . " seconds since last device event \n";'
2212 seconds since last device event

[ hit a key on the keyboard and run again ]
# echo "lastDeviceEventTime+4/D" | mdb -p 5755 | perl -MTime::HiRes -n -e 'use integer; @t=Time::HiRes::gettimeofday(); @l=split /\:/, $_; $i = ((($t[0]*1000 + $t[1]/1000)%0x100000000) - $l[1]); print $i/1000 . " seconds since last device event \n";'
2 seconds since last device event

We have now picked the X server's brain and found out when it last heard from an input device. It's definitely messy, but scarily seems to work.

Join the discussion

Comments ( 3 )
  • Roland Mainz Wednesday, October 20, 2004
    Is there a variable/structure member which tracks the idle time of a single window or screen ?
  • Alan Coopersmith Wednesday, October 20, 2004
    Not that I'm aware of - as far as I know the X server just keeps track of the time since the last input event seen on any input device to the server.
  • Roland Mainz Thursday, October 21, 2004
    Is it possible to add a new variable to the server-internal |Window| structure to track such stuff or would that break the Xfree86/X.org DDX module ABI ?
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.