Linux idle time detection broken

Moderators: Site Moderators, FAHC Science Team

Post Reply
MrBurritoTaco
Posts: 2
Joined: Tue Apr 21, 2020 1:29 am

Linux idle time detection broken

Post by MrBurritoTaco »

The idle detection algorithm seems to be broken in Linux, even though X Server provides this information in it's API see this

Code: Select all

https://github.com/gpolitis/xidle/blob/master/xidle.c or 
https://github.com/g0hl1n/xprintidle/blob/master/xprintidle.c
xidle is show below

Code: Select all

#include <stdio.h>
#include <X11/extensions/scrnsaver.h>

main() {
  XScreenSaverInfo *info = XScreenSaverAllocInfo();
  Display *display = XOpenDisplay(0);

  XScreenSaverQueryInfo(display, DefaultRootWindow(display), info);
  printf("%u ms\n", info->idle);
}
This code upon testing produces segfaults when the info or display pointers are NULL and is therefore unsafe for use, it however does show what is needed at a minimum to get idle time in milliseconds.
xprintidle is a safer approach as it contains error checking and a workarounds for some systems. (See workaroundCreepyXServer in xprintidle link).

This will only work on systems with an xserver running, which will still leave headless systems with broken idle time detection. You could use the 'w' command and awk something useful out of it, or possibly grab the source here

Code: Select all

https://gitlab.com/procps-ng/procps/-/blob/master/w.c
as a baseline to derive what's needed.
MrBurritoTaco
Posts: 2
Joined: Tue Apr 21, 2020 1:29 am

Re: Linux idle time detection broken

Post by MrBurritoTaco »

For those looking for a workaround, here's a simple python script I made. Ensure that While I'm Working is checked and that you have 'xprintidle' installed, on ubuntu sudo apt install xprintidle should do.

Code: Select all

#!/usr/bin/env python
from sys import argv
from time import sleep
from subprocess import Popen, PIPE

interval = 10 #Number of checks a minute
idle_minutes = 3 if len(argv) == 1 else float(argv[1]) #default to 3 min
paused = False #Assume running, will send a paused signal right away

while True:

  idle_time = int(Popen(["env", "DISPLAY=:0.0", "xprintidle"], stdout=PIPE).stdout.read())
  if idle_time > idle_minutes * 60000 and paused:
    Popen(["FAHClient", "--send-unpause"], stdout=PIPE)
    print "resume"
    paused = False
  if idle_time < idle_minutes * 60000 and not paused:
    Popen(["FAHClient", "--send-pause"], stdout=PIPE)
    print "pause"
    paused = True

  sleep(60 / interval)
Post Reply