diff --git a/0054-Fix-a-thread-hang-with-xcb_wait_for_special_event.patch b/0054-Fix-a-thread-hang-with-xcb_wait_for_special_event.patch new file mode 100644 index 0000000..e310b7f --- /dev/null +++ b/0054-Fix-a-thread-hang-with-xcb_wait_for_special_event.patch @@ -0,0 +1,132 @@ +From 5b40681c887192307f3ae147d2158870aa79c05f Mon Sep 17 00:00:00 2001 +From: Uli Schlachter +Date: Fri, 12 Jun 2015 15:13:05 +0200 +Subject: [PATCH 54/54] Fix a thread hang with xcb_wait_for_special_event() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Consider the following: + +- Two threads are calling xcb_wait_for_special_event() and xcb_wait_for_reply() + concurrently. +- The thread doing xcb_wait_for_reply() wins the race and poll()s the socket for + readability. +- The other thread will be put to sleep on the special_event_cond of the special + event (this is done in _xcb_conn_wait() via the argument + xcb_wait_for_special_event() gives it). +- The first thread gets its reply, but does not yet receive any special event. + +In this case, the first thread will return to its caller. On its way out, it +will call _xcb_in_wake_up_next_reader(), but that function cannot wake up +anything since so far it did not handle xcb_wait_for_special_event(). + +Thus, the first thread stays blocked on the condition variable and no thread +tries to read from the socket. + +A test case demonstrating this problem is available at the bug report. + +Fix this similar to how we handle this with xcb_wait_for_reply(): + +The function wait_for_reply() adds an entry into a linked list of threads that +wait for a reply. Via this list, _xcb_in_wake_up_next_reader() can wake up this +thread so that it can call _xcb_conn_wait() again and then poll()s the socket. + +Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=84252 +Signed-off-by: Uli Schlachter +Tested-by: Michel Dänzer +--- + src/xcb_in.c | 32 ++++++++++++++++++++++++++++++++ + src/xcbint.h | 1 + + 2 files changed, 33 insertions(+) + +diff --git a/src/xcb_in.c b/src/xcb_in.c +index 322bed8..bab4bc7 100644 +--- a/src/xcb_in.c ++++ b/src/xcb_in.c +@@ -97,6 +97,11 @@ typedef struct reader_list { + struct reader_list *next; + } reader_list; + ++typedef struct special_list { ++ xcb_special_event_t *se; ++ struct special_list *next; ++} special_list; ++ + static void remove_finished_readers(reader_list **prev_reader, uint64_t completed) + { + while(*prev_reader && XCB_SEQUENCE_COMPARE((*prev_reader)->request, <=, completed)) +@@ -475,6 +480,26 @@ static void remove_reader(reader_list **prev_reader, reader_list *reader) + } + } + ++static void insert_special(special_list **prev_special, special_list *special, xcb_special_event_t *se) ++{ ++ special->se = se; ++ special->next = *prev_special; ++ *prev_special = special; ++} ++ ++static void remove_special(special_list **prev_special, special_list *special) ++{ ++ while(*prev_special) ++ { ++ if(*prev_special == special) ++ { ++ *prev_special = (*prev_special)->next; ++ break; ++ } ++ prev_special = &(*prev_special)->next; ++ } ++} ++ + static void *wait_for_reply(xcb_connection_t *c, uint64_t request, xcb_generic_error_t **e) + { + void *ret = 0; +@@ -750,17 +775,22 @@ xcb_generic_event_t *xcb_poll_for_special_event(xcb_connection_t *c, + xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c, + xcb_special_event_t *se) + { ++ special_list special; + xcb_generic_event_t *event; + + if(c->has_error) + return 0; + pthread_mutex_lock(&c->iolock); + ++ insert_special(&c->in.special_waiters, &special, se); ++ + /* get_special_event returns 0 on empty list. */ + while(!(event = get_special_event(c, se))) + if(!_xcb_conn_wait(c, &se->special_event_cond, 0, 0)) + break; + ++ remove_special(&c->in.special_waiters, &special); ++ + _xcb_in_wake_up_next_reader(c); + pthread_mutex_unlock(&c->iolock); + return event; +@@ -889,6 +919,8 @@ void _xcb_in_wake_up_next_reader(xcb_connection_t *c) + int pthreadret; + if(c->in.readers) + pthreadret = pthread_cond_signal(c->in.readers->data); ++ else if(c->in.special_waiters) ++ pthreadret = pthread_cond_signal(&c->in.special_waiters->se->special_event_cond); + else + pthreadret = pthread_cond_signal(&c->in.event_cond); + assert(pthreadret == 0); +diff --git a/src/xcbint.h b/src/xcbint.h +index f89deba..acce646 100644 +--- a/src/xcbint.h ++++ b/src/xcbint.h +@@ -142,6 +142,7 @@ typedef struct _xcb_in { + struct event_list *events; + struct event_list **events_tail; + struct reader_list *readers; ++ struct special_list *special_waiters; + + struct pending_reply *pending_replies; + struct pending_reply **pending_replies_tail; +-- +2.4.3 + diff --git a/libxcb.spec b/libxcb.spec index 6e37ed9..112edf3 100644 --- a/libxcb.spec +++ b/libxcb.spec @@ -2,7 +2,7 @@ Name: libxcb Version: 1.11 -Release: 7%{?dist} +Release: 8%{?dist} Summary: A C binding to the X11 protocol License: MIT URL: http://xcb.freedesktop.org/ @@ -17,6 +17,7 @@ Source1: pthread-stubs.pc.in ## upstream patches (post 1.11 tag commits) Patch53: 0053-Call-_xcb_wake_up_next_reader-from-xcb_wait_for_spec.patch +Patch54: 0054-Fix-a-thread-hang-with-xcb_wait_for_special_event.patch BuildRequires: doxygen BuildRequires: graphviz @@ -120,6 +121,9 @@ find $RPM_BUILD_ROOT -name '*.la' -delete %{_pkgdocdir} %changelog +* Thu Jun 25 2015 Rex Dieter 1.11-8 +- followup fix for thread deadlocks (#1193742, fdo#84252) + * Wed Jun 17 2015 Fedora Release Engineering - 1.11-7 - Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild