[Xcb] [PATCH v3:libxcb 2/2] Test case for reading the same reply multiple times.

Rami Ylimäki rami.ylimaki at vincit.fi
Wed Oct 13 07:48:14 PDT 2010


Signed-off-by: Rami Ylimäki <rami.ylimaki at vincit.fi>
---
 tests/test-ev-rep-deadlock2.c |  145 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 145 insertions(+), 0 deletions(-)
 create mode 100644 tests/test-ev-rep-deadlock2.c

diff --git a/tests/test-ev-rep-deadlock2.c b/tests/test-ev-rep-deadlock2.c
new file mode 100644
index 0000000..f1a10fa
--- /dev/null
+++ b/tests/test-ev-rep-deadlock2.c
@@ -0,0 +1,145 @@
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <xcb/xcb.h>
+
+static xcb_connection_t *c = NULL;
+static int event_reader_done = 0;
+static int request_invoker_done = 0;
+static int server_pid = 0;
+
+static void stop_server(pid_t pid)
+{
+    printf("Stopping X server pid(%d).\n", pid);
+    kill(server_pid, SIGSTOP);
+}
+
+static void cont_server(pid_t pid)
+{
+    printf("Letting X server continue %d.\n", pid);
+    kill(server_pid, SIGCONT);
+}
+
+static void *event_reader(void *arg)
+{
+    xcb_generic_event_t *event;
+
+    printf("Reading events.\n");
+    event = xcb_wait_for_event(c);
+    printf("Received events.\n");
+
+    event_reader_done = 1;
+    return NULL;
+}
+
+static void *request_invoker(void *arg)
+{
+    xcb_get_input_focus_cookie_t cookie1;
+    xcb_get_input_focus_cookie_t cookie2;
+    xcb_get_input_focus_reply_t *reply = NULL;
+
+    printf("Executing request.\n");
+    cookie1 = xcb_get_input_focus(c);
+    reply = xcb_get_input_focus_reply(c, cookie1, NULL);
+    printf("Received reply.\n");
+
+    printf("Executing new request.\n");
+    stop_server(server_pid);
+    cookie2 = xcb_get_input_focus(c);
+    xcb_flush(c);
+    reply = xcb_get_input_focus_reply(c, cookie1, NULL);
+    printf("Found out that previous reply has been already handled.\n");
+    reply = xcb_get_input_focus_reply(c, cookie2, NULL);
+    printf("Received new reply.\n");
+
+    request_invoker_done = 1;
+    return NULL;
+}
+
+int main(int argc, char **argv)
+{
+    pthread_t event_thread;
+    pthread_t request_thread;
+    int status = 0;
+
+    if (argc != 2)
+    {
+        printf("usage: %s pid-of-x-server\n", argv[0]);
+        return 1;
+    }
+    server_pid = atoi(argv[1]);
+
+    if (!(c = xcb_connect(NULL, NULL)))
+    {
+        printf("Can't connect to X server.\n");
+        return 1;
+    }
+
+    if (pthread_create(&event_thread, NULL, event_reader, NULL))
+    {
+        printf("Can't create event reader thread.\n");
+        return 1;
+    }
+    /* Wait until xcb_wait_for_event starts to block. */
+    sleep(3);
+
+    if (pthread_create(&request_thread, NULL, request_invoker, NULL))
+    {
+        printf("Can't create request invoker thread.\n");
+        return 1;
+    }
+    /* Wait until sync has received reply from xcb_get_input_focus. */
+    sleep(3);
+
+    cont_server(server_pid);
+    /* Wait until sync has received second reply. */
+    sleep(3);
+    
+    /* Expected result is that event reader thread blocked forever but
+     * didn't prevent request invoker from finishing. */
+    status = (!event_reader_done && request_invoker_done);
+
+    /* Event reader thread should be still waiting on a pthread
+     * condition. Closing the connection without any cleanup would
+     * freeze this main thread because doing so would destroy pthread
+     * objects that are still in use. That leads to undefined
+     * behaviour and for example phtread_cond_destroy called from
+     * xcb_disconnect could make the thread hang indefinitely.
+     *
+     * We will let the event reader exit cleanly by sending it an
+     * exposure event.
+     */
+    if (!event_reader_done)
+    {
+        const xcb_setup_t *setup = xcb_get_setup(c);
+        xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
+        xcb_screen_t *screen = iter.data;
+        xcb_window_t window = xcb_generate_id(c);
+        uint32_t mask = XCB_CW_EVENT_MASK;
+        uint32_t values[1] = { XCB_EVENT_MASK_EXPOSURE };
+        xcb_void_cookie_t cookie = xcb_create_window(c,                             /* Connection           */
+                                                     XCB_COPY_FROM_PARENT,          /* depth (same as root) */
+                                                     window,                        /* window Id            */
+                                                     screen->root,                  /* parent window        */
+                                                     0, 0,                          /* x, y                 */
+                                                     150, 150,                      /* width, height        */
+                                                     10,                            /* border_width         */
+                                                     XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class                */
+                                                     screen->root_visual,           /* visual               */
+                                                     mask, values);                 /* masks                */
+        cookie = xcb_map_window(c, window);
+        printf("Sending exposure event to self.\n");
+        xcb_flush(c);
+    }
+    
+    xcb_disconnect(c);
+
+    if (status)
+        printf("Test passed.\n");
+    else
+        printf("Test failed.\n");
+
+    return !status;
+}
-- 
1.6.3.3



More information about the Xcb mailing list