#include #include #include #include #include #include static xcb_connection_t *conn; static xcb_screen_t *screen; static xcb_window_t win; static xcb_pixmap_t pix; static uint32_t present_event_type; static xcb_special_event_t *se; static pthread_barrier_t barrier; #define NUM_THREADS 2 static pthread_t start_thread(void *(*start_routine)(void *), void *arg) { pthread_t thread; int res; res = pthread_create(&thread, NULL, start_routine, arg); assert(res == 0); return thread; } static void check_no_pending_events(void) { xcb_generic_event_t *ev; ev = xcb_poll_for_event(conn); assert(ev == NULL); ev = xcb_poll_for_special_event(conn, se); assert(ev == NULL); } static void wait_event(void) { xcb_generic_event_t *ge; ge = xcb_wait_for_special_event(conn, se); printf("%p: Got special event\n", ge); free(ge); } static void *wait_event_thread(void *arg) { (void) arg; pthread_barrier_wait(&barrier); wait_event(); return NULL; } static void try_deadlock(void) { xcb_get_input_focus_cookie_t cookie; pthread_t thread; int res; thread = start_thread(wait_event_thread, NULL); /* No idea what this does, but it does give me special events for * xcb_wait_for_special_event(). */ xcb_present_pixmap(conn, win, pix, 0, XCB_NONE, XCB_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL); cookie = xcb_get_input_focus(conn); xcb_flush(conn); /* Create a race with the other thread at who recv()s on the socket */ pthread_barrier_wait(&barrier); /* Now actually call recv() */ free(xcb_get_input_focus_reply(conn, cookie, NULL)); puts("Got input focus"); res = pthread_join(thread, NULL); assert(res == 0); /* The above xcb_present_pixmap() causes two events to be send. Collect * the second one. */ wait_event(); check_no_pending_events(); } static void setup(void) { conn = xcb_connect(NULL, NULL); assert(!xcb_connection_has_error(conn)); screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; win = xcb_generate_id(conn); pix = xcb_generate_id(conn); present_event_type = xcb_generate_id(conn); xcb_create_window(conn, screen->root_depth, win, screen->root, 1, 1, 3, 3, 0, XCB_COPY_FROM_PARENT, screen->root_visual, XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, (const uint32_t[]) { 1, XCB_EVENT_MASK_PROPERTY_CHANGE }); xcb_create_pixmap(conn, screen->root_depth, pix, win, 3, 3); xcb_present_select_input(conn, present_event_type, win, XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY | XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY | XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY | XCB_PRESENT_EVENT_MASK_REDIRECT_NOTIFY); se = xcb_register_for_special_xge(conn, &xcb_present_id, present_event_type, NULL); assert(se); pthread_barrier_init(&barrier, NULL, NUM_THREADS); } int main() { setup(); while (1) { try_deadlock(); puts(""); } xcb_unregister_for_special_event(conn, se); xcb_disconnect(conn); return 0; }