[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