hhpc icon indicating copy to clipboard operation
hhpc copied to clipboard

Sometimes hhpc is so much hungry that it eats my pointer

Open LemonBoy opened this issue 9 years ago • 9 comments

I couldn't find anything about the nutritional values of a pointer but I guess it's not much healthy for hhpc. It just happens randomly, I can get it back after killing hhpc :(

LemonBoy avatar Dec 19 '14 16:12 LemonBoy

That's definitely not good at all. Could you run hhpc verbosely with the -v switch and see what it prints out?

aktau avatar Dec 19 '14 21:12 aktau

I've finally managed to catch it :dart:

hhpc: draining event
hhpc: succesfully grabbed mouse pointer
hhpc: event received, ungrabbing and sleeping
hhpc: draining event
hhpc: succesfully grabbed mouse pointer
hhpc: event received, ungrabbing and sleeping
hhpc: draining event
hhpc: succesfully grabbed mouse pointer
hhpc: event received, ungrabbing and sleeping
hhpc: draining event
hhpc: succesfully grabbed mouse pointer
hhpc: event received, ungrabbing and sleeping
hhpc: draining event
hhpc: XGrabPointer: already grabbed mouse pointer, retrying with delay
hhpc: XGrabPointer: already grabbed mouse pointer, retrying with delay
hhpc: XGrabPointer: already grabbed mouse pointer, retrying with delay
hhpc: XGrabPointer: already grabbed mouse pointer, retrying with delay
hhpc: XGrabPointer: already grabbed mouse pointer, retrying with delay
hhpc: XGrabPointer: already grabbed mouse pointer, retrying with delay
hhpc: succesfully grabbed mouse pointer

LemonBoy avatar Jan 19 '15 12:01 LemonBoy

This seems related to the nanosleep() returning earlier (EINTR) in the delay() function.

If nanosleep is interupted it will return early with a return value of -1. Since you don't use rmtp (NULL) nanosleep won't return the time remaining.

From there you set the global state of working to 0 and the main while loop here:

while (working && grabPointer(dpy, win, emptyCursor, mask)) {

always fails.

This is speculation though, I have experienced this as well but didn't think to fire up perf or gdb to investigate.

Earnestly avatar Jun 10 '15 11:06 Earnestly

As a follow up, I can manually set working to 0 in gdb and replicate this behaviour. The program never recovers from this and the cursor stays hidden indefinately.

Earnestly avatar Jun 10 '15 11:06 Earnestly

Here is an untested potential fix for this, it basically just continues after being interupted. It does not handle EINVAL. It may be better to just crash instead of setting working to 0 though.

[Edit: I could make this a Pull Request if you wish.]

diff --git a/hhpc.c b/hhpc.c
index f106f7f..54e5dc8 100644
--- a/hhpc.c
+++ b/hhpc.c
@@ -38,6 +38,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>

 static int gIdleTimeout = 1;
 static int gVerbose     = 0;
@@ -90,8 +91,11 @@ static void delay(time_t sec, long msec) {
     sleep.tv_sec  = sec;
     sleep.tv_nsec = (msec % 1000) * 1000 * 1000;

-    if (nanosleep(&sleep, NULL) == -1) {
-        signalHandler(0);
+    while (nanosleep(&sleep, &sleep) != 0) {
+        if (errno == EINTR)
+            continue;
+        else
+            signalHandler(0);
     }
 }

Earnestly avatar Jun 10 '15 11:06 Earnestly

Hm, this may not be the cause as I suspected, although it does fix one error case.

It seems to get stuck in select() sometimes and never returns.

Earnestly avatar Jun 10 '15 22:06 Earnestly

This might be a CANTFIX issue. Either way here's some gdb output after catching it fail:

Attaching to process 26362
Reading symbols from /usr/bin/hhpc...done.
Reading symbols from /usr/lib/libX11.so.6...(no debugging symbols found)...done.
Reading symbols from /usr/lib/libc.so.6...(no debugging symbols found)...done.
Reading symbols from /usr/lib/libxcb.so.1...(no debugging symbols found)...done.
Reading symbols from /usr/lib/libdl.so.2...(no debugging symbols found)...done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Reading symbols from /usr/lib/libXau.so.6...(no debugging symbols found)...done.
Reading symbols from /usr/lib/libXdmcp.so.6...(no debugging symbols found)...done.
Reading symbols from /usr/lib/libXcursor.so.1...(no debugging symbols found)...done.
Reading symbols from /usr/lib/libXrender.so.1...(no debugging symbols found)...done.
Reading symbols from /usr/lib/libXfixes.so.3...(no debugging symbols found)...done.
0x00007fc2b2c69ae3 in __select_nocancel () from /usr/lib/libc.so.6
(gdb) l
warning: Source file is more recent than executable.
234         switch (option) {
235             case 'i': gIdleTimeout = atoi(optarg); break;
236             case 'v': gVerbose = 1; break;
237             default: return 0;
238         }
239     }
240 
241     return 1;
242 }
243 
(gdb) p working
$1 = 1
(gdb) bt
#0  0x00007fc2b2c69ae3 in __select_nocancel () from /usr/lib/libc.so.6
#1  0x000000000040135a in waitForMotion (dpy=dpy@entry=0xdd6010, win=win@entry=197, timeout=1) at hhpc.c:200
#2  0x00000000004014a3 in main (argc=<optimized out>, argv=<optimized out>) at hhpc.c:274
(gdb) bt full
#0  0x00007fc2b2c69ae3 in __select_nocancel () from /usr/lib/libc.so.6
No symbol table info available.
#1  0x000000000040135a in waitForMotion (dpy=dpy@entry=0xdd6010, win=win@entry=197, timeout=1) at hhpc.c:200
        ready = <optimized out>
        xfd = 3
        fds = {__fds_bits = {8, 0 <repeats 15 times>}}
        event = {type = 6, xany = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, window = 197}, xkey = {type = 6, serial = 6368, send_event = 0, 
            display = 0xdd6010, window = 197, root = 197, subwindow = 6294090, time = 242038321, x = 504, y = 1041, x_root = 504, y_root = 1041, state = 0, keycode = 0, 
            same_screen = 1}, xbutton = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, window = 197, root = 197, subwindow = 6294090, time = 242038321, 
            x = 504, y = 1041, x_root = 504, y_root = 1041, state = 0, button = 0, same_screen = 1}, xmotion = {type = 6, serial = 6368, send_event = 0, 
            display = 0xdd6010, window = 197, root = 197, subwindow = 6294090, time = 242038321, x = 504, y = 1041, x_root = 504, y_root = 1041, state = 0, 
            is_hint = 0 '\000', same_screen = 1}, xcrossing = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, window = 197, root = 197, 
            subwindow = 6294090, time = 242038321, x = 504, y = 1041, x_root = 504, y_root = 1041, mode = 0, detail = 0, same_screen = 1, focus = 32706, state = 465}, 
          xfocus = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, window = 197, mode = 197, detail = 0}, xexpose = {type = 6, serial = 6368, 
            send_event = 0, display = 0xdd6010, window = 197, x = 197, y = 0, width = 6294090, height = 0, count = 242038321}, xgraphicsexpose = {type = 6, 
            serial = 6368, send_event = 0, display = 0xdd6010, drawable = 197, x = 197, y = 0, width = 6294090, height = 0, count = 242038321, major_code = 0, 
            minor_code = 504}, xnoexpose = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, drawable = 197, major_code = 197, minor_code = 0}, 
          xvisibility = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, window = 197, state = 197}, xcreatewindow = {type = 6, serial = 6368, 
            send_event = 0, display = 0xdd6010, parent = 197, window = 197, x = 6294090, y = 0, width = 242038321, height = 0, border_width = 504, 
            override_redirect = 1041}, xdestroywindow = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, event = 197, window = 197}, xunmap = {type = 6, 
            serial = 6368, send_event = 0, display = 0xdd6010, event = 197, window = 197, from_configure = 6294090}, xmap = {type = 6, serial = 6368, send_event = 0, 
            display = 0xdd6010, event = 197, window = 197, override_redirect = 6294090}, xmaprequest = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, 
            parent = 197, window = 197}, xreparent = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, event = 197, window = 197, parent = 6294090, 
            x = 242038321, y = 0, override_redirect = 504}, xconfigure = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, event = 197, window = 197, 
            x = 6294090, y = 0, width = 242038321, height = 0, border_width = 504, above = 4471060955640, override_redirect = 0}, xgravity = {type = 6, serial = 6368, 
            send_event = 0, display = 0xdd6010, event = 197, window = 197, x = 6294090, y = 0}, xresizerequest = {type = 6, serial = 6368, send_event = 0, 
            display = 0xdd6010, window = 197, width = 197, height = 0}, xconfigurerequest = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, parent = 197, 
            window = 197, x = 6294090, y = 0, width = 242038321, height = 0, border_width = 504, above = 4471060955640, detail = 0, value_mask = 140471200382977}, 
          xcirculate = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, event = 197, window = 197, place = 6294090}, xcirculaterequest = {type = 6, 
            serial = 6368, send_event = 0, display = 0xdd6010, parent = 197, window = 197, place = 6294090}, xproperty = {type = 6, serial = 6368, send_event = 0, 
            display = 0xdd6010, window = 197, atom = 197, time = 6294090, state = 242038321}, xselectionclear = {type = 6, serial = 6368, send_event = 0, 
            display = 0xdd6010, window = 197, selection = 197, time = 6294090}, xselectionrequest = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, 
            owner = 197, requestor = 197, selection = 6294090, target = 242038321, property = 4471060955640, time = 4471060955640}, xselection = {type = 6, 
            serial = 6368, send_event = 0, display = 0xdd6010, requestor = 197, selection = 197, target = 6294090, property = 242038321, time = 4471060955640}, 
          xcolormap = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, window = 197, colormap = 197, new = 6294090, state = 0}, xclient = {type = 6, 
            serial = 6368, send_event = 0, display = 0xdd6010, window = 197, message_type = 197, format = 6294090, data = {
              b = "16m\016\000\000\000\000\370\001\000\000\021\004\000\000\370\001\000", s = {13873, 3693, 0, 0, 504, 0, 1041, 0, 504, 0}, l = {242038321, 
                4471060955640, 4471060955640, 0, 140471200382977}}}, xmapping = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, window = 197, 
            request = 197, first_keycode = 0, count = 6294090}, xerror = {type = 6, display = 0x18e0, resourceid = 17732945007607808, serial = 14508048, 
            error_code = 197 '\305', request_code = 0 '\000', minor_code = 0 '\000'}, xkeymap = {type = 6, serial = 6368, send_event = 0, display = 0xdd6010, 
            window = 197, key_vector = "\305\000\000\000\000\000\000\000J\n`\000\000\000\000\000\061\066m\016\000\000\000\000\370\001\000\000\021\004\000"}, xgeneric = {
            type = 6, serial = 6368, send_event = 0, display = 0xdd6010, extension = 197, evtype = 0}, xcookie = {type = 6, serial = 6368, send_event = 0, 
            display = 0xdd6010, extension = 197, evtype = 0, cookie = 197, data = 0x600a4a}, pad = {140471200382982, 6368, 17732945007607808, 14508048, 197, 197, 
            6294090, 242038321, 4471060955640, 4471060955640, 0, 140471200382977, 465, 140474202610552, 140474202610552, 35188667056187, 287948944191717396, 
            844553846194176, 257698037760, 140474202604096, 401, 140474202610552, 140474202610552, 287948944191717376}}
        emptyCursor = 4194307
#2  0x00000000004014a3 in main (argc=<optimized out>, argv=<optimized out>) at hhpc.c:274
        displayName = <optimized out>
        dpy = 0xdd6010
        scr = <optimized out>
        rootwin = 197

Earnestly avatar Jun 13 '15 21:06 Earnestly

Okay, well I seem to have "fixed" this by simply adding a timeout on the select(). This is not really very satisfactory.

diff --git a/hhpc.c b/hhpc.c
index f106f7f..84f6cc0 100644
--- a/hhpc.c
+++ b/hhpc.c
@@ -193,7 +193,15 @@ static void waitForMotion(Display *dpy, Window win, int timeout) {
          * is interruptible by signals, which allows ctrl+c to work. If we
          * were to just use XNextEvent() (which blocks), ctrl+c would not
          * work. */
-        ready = select(xfd + 1, &fds, NULL, NULL, NULL);
+        struct timeval tv = {5, 0}; /* waits 5 seconds */
+
+        if ((ready = select(xfd + 1, &fds, NULL, NULL, &tv)) == -1) {
+            if (working) perror("hhpc: error while select()'ing");
+        }
+
+        if (ready == 0) {
+            if (gVerbose) fprintf(stderr, "hhpc: timeout\n");
+        }

         if (ready > 0) {
             if (gVerbose) fprintf(stderr, "hhpc: event received, ungrabbing and sleeping\n");
@@ -211,12 +219,6 @@ static void waitForMotion(Display *dpy, Window win, int timeout) {

             delay(timeout, 0);
         }
-        else if (ready == 0) {
-            if (gVerbose) fprintf(stderr, "hhpc: timeout\n");
-        }
-        else {
-            if (working) perror("hhpc: error while select()'ing");
-        }
     }

     XUngrabPointer(dpy, CurrentTime);

I placed a 5 second timeout and this is the result after experiencing a lockout:

hhpc: succesfully grabbed mouse pointer
hhpc: event received, ungrabbing and sleeping
hhpc: draining event
hhpc: draining event
hhpc: draining event
[ ... ] About 100 of these events
hhpc: draining event
hhpc: draining event
hhpc: draining event
hhpc: succesfully grabbed mouse pointer
hhpc: event received, ungrabbing and sleeping

Earnestly avatar Jun 13 '15 22:06 Earnestly

can confirm this happens for me too. i am currently working around it manually by running killall hhpc; hhpc & disown in a terminal

rudyon avatar Jun 04 '23 12:06 rudyon