Commit 266427723a649f02348e252ef82079d0f45792cc

Pierre Le Marre 2023-09-18T13:17:31

Test: Catch SIGUSR1 from Xvfb for X11 tests Based on the work done by Peter Hutterer. Original commit message: If SIGUSR1 is set to SIG_IGN, X servers (all of them, including Xvfb) will send that signal to the parent process when they're ready to accept connections. We can use that instead of a hardcoded sleep which brings the wait down to ~37ms on my box.

diff --git a/test/xvfb-wrapper.c b/test/xvfb-wrapper.c
index d9fa0a7..38d159b 100644
--- a/test/xvfb-wrapper.c
+++ b/test/xvfb-wrapper.c
@@ -35,17 +35,28 @@
 #include "xvfb-wrapper.h"
 #include "xkbcommon/xkbcommon-x11.h"
 
+static bool xvfb_is_ready;
+
+static void
+sigusr1_handler(int signal)
+{
+    xvfb_is_ready = true;
+}
+
 int
 xvfb_wrapper(int (*test_func)(char* display))
 {
     int ret = 0;
     FILE * display_fd;
     char display_fd_string[32];
+    sigset_t mask;
+    struct sigaction sa;
     char *xvfb_argv[] = {
         (char *) "Xvfb", (char *) "-displayfd", display_fd_string, NULL
     };
     char *envp[] = { NULL };
     pid_t xvfb_pid = 0;
+    size_t counter = 0;
     char display[32] = ":";
     size_t length;
 
@@ -57,6 +68,18 @@ xvfb_wrapper(int (*test_func)(char* display))
     }
     snprintf(display_fd_string, sizeof(display_fd_string), "%d", fileno(display_fd));
 
+    /* Set SIGUSR1 to SIG_IGN so Xvfb will send us that signal
+     * when it's ready to accept connections */
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGUSR1);
+    sigprocmask(SIG_BLOCK, &mask, NULL);
+    sa.sa_handler = SIG_IGN;
+    sa.sa_flags = 0;
+    sigemptyset(&sa.sa_mask);
+    sigaction(SIGUSR1, &sa, NULL);
+
+    xvfb_is_ready = false;
+
     /*
      * Xvfb command: let the server find an available display.
      *
@@ -71,8 +94,21 @@ xvfb_wrapper(int (*test_func)(char* display))
         goto err_xvfd;
     }
 
-    /* Wait for Xvfb fully waking up to accept a connection from a client. */
-    sleep(1);
+    sa.sa_handler = SIG_DFL;
+    sa.sa_flags = 0;
+    sigemptyset(&sa.sa_mask);
+    sigaction(SIGUSR1, &sa, NULL);
+    signal(SIGUSR1, sigusr1_handler);
+    sigprocmask (SIG_UNBLOCK, &mask, NULL);
+
+    /* Now wait for the SIGUSR1 signal that Xvfb is ready */
+    while (!xvfb_is_ready) {
+        usleep(1000);
+        if (++counter >= 3000) /* 3 seconds max wait */
+            break;
+    }
+
+    signal(SIGUSR1, SIG_DFL);
 
     /* Retrieve the display number: Xvfd writes the display number as a newline-
      * terminated string; copy this number to form a proper display string. */