When using select() to poll for the XChangeProperty event that clientmessage_response() generates, there is a race condition where the select() may start after clientmessage_response() has already called XChangeProperty(). In this case, the event is already on the X event queue, so select() never sees a change on the fd being watched. This causes xscreensaver-command to report that it didn't receive a response.
In place of using select(), XCheckIfEvent() is called using the new is_xscreensaver_command_event predicate to see if the event we're waiting for is already in the X event queue. If it isn't, we emulate the same timeout as before by sleep()ing one second for a maximum of 10 XCheckIfEvent() calls. In testing both the original xscreensaver-command and the patched version using the following loop, every call to the patched version returned successfully. The original version reported "no response to command" in 21 of the 30 calls even though the xscreensaver daemon saw the command every time. for i in $(seq 30); do xscreensaver-command -deactivate; done --- driver/remote.c | 206 +++++++++++++++++++++++++------------------------------ 1 files changed, 94 insertions(+), 112 deletions(-) diff --git a/driver/remote.c b/driver/remote.c index 507da6b..246e1d6 100644 --- a/driver/remote.c +++ b/driver/remote.c @@ -357,132 +357,114 @@ send_xscreensaver_command (Display *dpy, Atom command, long arg, } +static Bool +is_xscreensaver_command_event (Display *dpy, XEvent *event, XPointer arg) +{ + return event->xany.type == PropertyNotify && + event->xproperty.state == PropertyNewValue && + event->xproperty.atom == XA_SCREENSAVER_RESPONSE; +} + + static int xscreensaver_command_response (Display *dpy, Window window, Bool verbose_p, Bool exiting_p, char **error_ret) { - int fd = ConnectionNumber (dpy); - int timeout = 10; - int status; - fd_set fds; - struct timeval tv; + int sleep_count = 0; char err[2048]; + XEvent event; + Bool got_event = False; - while (1) + while (!(got_event = XCheckIfEvent(dpy, &event, + &is_xscreensaver_command_event, 0)) && + sleep_count++ < 10) + { + sleep(1); + } + if (!got_event) { - FD_ZERO(&fds); - FD_SET(fd, &fds); - memset(&tv, 0, sizeof(tv)); - tv.tv_sec = timeout; - status = select (fd+1, &fds, 0, &fds, &tv); + sprintf (err, "no response to command."); + if (error_ret) + *error_ret = strdup (err); + else + fprintf (stderr, "%s: %s\n", progname, err); + return -1; + } + else + { + Status st2; + Atom type; + int format; + unsigned long nitems, bytesafter; + unsigned char *msg = 0; - if (status < 0) - { - char buf[1024]; - if (error_ret) - { - sprintf (buf, "error waiting for reply"); - *error_ret = strdup (buf); - } - else - { - sprintf (buf, "%s: error waiting for reply", progname); - perror (buf); - } - return status; - } - else if (status == 0) + XSync (dpy, False); + if (old_handler) abort(); + old_handler = XSetErrorHandler (BadWindow_ehandler); + st2 = XGetWindowProperty (dpy, window, + XA_SCREENSAVER_RESPONSE, + 0, 1024, True, + AnyPropertyType, + &type, &format, &nitems, &bytesafter, + &msg); + XSync (dpy, False); + XSetErrorHandler (old_handler); + old_handler = 0; + + if (got_badwindow) { - sprintf (err, "no response to command."); - if (error_ret) - *error_ret = strdup (err); - else - fprintf (stderr, "%s: %s\n", progname, err); + if (exiting_p) + return 0; + + sprintf (err, "xscreensaver window unexpectedly deleted."); + + if (error_ret) + *error_ret = strdup (err); + else + fprintf (stderr, "%s: %s\n", progname, err); + return -1; } - else + + if (st2 == Success && type != None) { - XEvent event; - XNextEvent (dpy, &event); - if (event.xany.type == PropertyNotify && - event.xproperty.state == PropertyNewValue && - event.xproperty.atom == XA_SCREENSAVER_RESPONSE) + if (type != XA_STRING || format != 8) { - Status st2; - Atom type; - int format; - unsigned long nitems, bytesafter; - unsigned char *msg = 0; - - XSync (dpy, False); - if (old_handler) abort(); - old_handler = XSetErrorHandler (BadWindow_ehandler); - st2 = XGetWindowProperty (dpy, window, - XA_SCREENSAVER_RESPONSE, - 0, 1024, True, - AnyPropertyType, - &type, &format, &nitems, &bytesafter, - &msg); - XSync (dpy, False); - XSetErrorHandler (old_handler); - old_handler = 0; - - if (got_badwindow) - { - if (exiting_p) - return 0; + sprintf (err, "unrecognized response property."); - sprintf (err, "xscreensaver window unexpectedly deleted."); + if (error_ret) + *error_ret = strdup (err); + else + fprintf (stderr, "%s: %s\n", progname, err); - if (error_ret) - *error_ret = strdup (err); - else - fprintf (stderr, "%s: %s\n", progname, err); + if (msg) XFree (msg); + return -1; + } + else if (!msg || (msg[0] != '+' && msg[0] != '-')) + { + sprintf (err, "unrecognized response message."); - return -1; - } + if (error_ret) + *error_ret = strdup (err); + else + fprintf (stderr, "%s: %s\n", progname, err); - if (st2 == Success && type != None) - { - if (type != XA_STRING || format != 8) - { - sprintf (err, "unrecognized response property."); - - if (error_ret) - *error_ret = strdup (err); - else - fprintf (stderr, "%s: %s\n", progname, err); - - if (msg) XFree (msg); - return -1; - } - else if (!msg || (msg[0] != '+' && msg[0] != '-')) - { - sprintf (err, "unrecognized response message."); - - if (error_ret) - *error_ret = strdup (err); - else - fprintf (stderr, "%s: %s\n", progname, err); - - if (msg) XFree (msg); - return -1; - } - else - { - int ret = (msg[0] == '+' ? 0 : -1); - sprintf (err, "%s: %s\n", progname, (char *) msg+1); - - if (error_ret) - *error_ret = strdup (err); - else if (verbose_p || ret != 0) - fprintf ((ret < 0 ? stderr : stdout), "%s\n", err); - - XFree (msg); - return ret; - } - } + if (msg) XFree (msg); + return -1; + } + else + { + int ret = (msg[0] == '+' ? 0 : -1); + sprintf (err, "%s: %s\n", progname, (char *) msg+1); + + if (error_ret) + *error_ret = strdup (err); + else if (verbose_p || ret != 0) + fprintf ((ret < 0 ? stderr : stdout), "%s\n", err); + + XFree (msg); + return ret; } } } -- 1.6.3.3 -- James GPG Key: 1024D/61326D40 2003-09-02 James Vega <james...@debian.org>
signature.asc
Description: Digital signature