<div dir="ltr"><div><div><div>Hmm, thinking about that... Maybe this is not the right solution. Programmer should probably do something like:<br><br></div>do {<br>  ret = wl_display_read_events(display);<br>} while (ret == 0 && errno == EAGAIN);<br>
<br></div>to be sure he read the events (or got an error). This patch would force him to re-run wl_display_prepare_read again<br></div>in all threads.<br></div><div class="gmail_extra"><br><br><div class="gmail_quote">On 28 August 2014 11:32, Marek Chalupa <span dir="ltr"><<a href="mailto:mchqwerty@gmail.com" target="_blank">mchqwerty@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">In the first place, create a function display_wakeup_threads that<br>
contains always-repeated pattern: broadcast + increase serial.<br>
<br>
Replace the pattern with this function and call this function also<br>
on return from read_events when wl_connection_read fails with<br>
EAGAIN (this solves the bug from the test from previous commit).<br>
<br>
Now all return paths from read_events are safe and wake up the threads.<br>
There's a path in wl_display_read_events that do not wake up<br>
threads - this is the case when last_error is set. But on this<br>
path are the threads always awake, because every function that can<br>
set last_error sets it via display_fatal_error (which calls<br>
display_wakeup_threads).<br>
<br>
Signed-off-by: Marek Chalupa <<a href="mailto:mchqwerty@gmail.com">mchqwerty@gmail.com</a>><br>
---<br>
 src/wayland-client.c | 42 +++++++++++++++++++++++++++++-------------<br>
 1 file changed, 29 insertions(+), 13 deletions(-)<br>
<br>
diff --git a/src/wayland-client.c b/src/wayland-client.c<br>
index 9159ee0..9574cf7 100644<br>
--- a/src/wayland-client.c<br>
+++ b/src/wayland-client.c<br>
@@ -110,6 +110,27 @@ struct wl_display {<br>
 static int debug_client = 0;<br>
<br>
 /**<br>
+ * This helper function wakes up all threads that are<br>
+ * waiting for display->reader_cond (i. e. when reading is done<br>
+ * canceled, or an error occured)<br>
+ *<br>
+ * NOTE: must be called with display->mutex locked<br>
+ */<br>
+static void<br>
+display_wakeup_threads(struct wl_display *display)<br>
+{<br>
+       pthread_cond_broadcast(&display->reader_cond);<br>
+<br>
+       /* Thread can get sleeping only in read_events() and if we're<br>
+       * waking it up, it means that the read processed or was<br>
+       * canceled, so we must increase the read_serial.<br>
+       * This prevents from indefinite looping in read_events()<br>
+       * (when calling pthread_cond_wait under condition<br>
+       * display->read_serial == serial). */<br>
+       ++display->read_serial;<br>
+}<br>
+<br>
+/**<br>
  * This function is called for local errors (no memory, server hung up)<br>
  *<br>
  * \param display<br>
@@ -128,11 +149,7 @@ display_fatal_error(struct wl_display *display, int error)<br>
<br>
        display->last_error = error;<br>
<br>
-       pthread_cond_broadcast(&display->reader_cond);<br>
-       /* prevent from indefinite looping in read_events()<br>
-       * (when calling pthread_cond_wait under condition<br>
-       * display->read_serial == serial) */<br>
-       ++display->read_serial;<br>
+       display_wakeup_threads(display);<br>
 }<br>
<br>
 /**<br>
@@ -182,7 +199,7 @@ display_protocol_error(struct wl_display *display, uint32_t code,<br>
        display->protocol_error.interface = intf;<br>
<br>
        /*<br>
-        * here it is not necessary to broadcast reader's cond like in<br>
+        * here it is not necessary to wake up threads like in<br>
         * display_fatal_error, because this function is called from<br>
         * an event handler and that means that read_events() is done<br>
         * and woke up all threads. Since wl_display_prepare_read()<br>
@@ -1138,8 +1155,10 @@ read_events(struct wl_display *display)<br>
        if (display->reader_count == 0) {<br>
                total = wl_connection_read(display->connection);<br>
                if (total == -1) {<br>
-                       if (errno == EAGAIN)<br>
+                       if (errno == EAGAIN) {<br>
+                               display_wakeup_threads(display);<br>
                                return 0;<br>
+                       }<br>
<br>
                        display_fatal_error(display, errno);<br>
                        return -1;<br>
@@ -1162,8 +1181,7 @@ read_events(struct wl_display *display)<br>
                        }<br>
                }<br>
<br>
-               display->read_serial++;<br>
-               pthread_cond_broadcast(&display->reader_cond);<br>
+               display_wakeup_threads(display);<br>
        } else {<br>
                serial = display->read_serial;<br>
                while (display->read_serial == serial)<br>
@@ -1348,10 +1366,8 @@ wl_display_cancel_read(struct wl_display *display)<br>
        pthread_mutex_lock(&display->mutex);<br>
<br>
        display->reader_count--;<br>
-       if (display->reader_count == 0) {<br>
-               display->read_serial++;<br>
-               pthread_cond_broadcast(&display->reader_cond);<br>
-       }<br>
+       if (display->reader_count == 0)<br>
+               display_wakeup_threads(display);<br>
<br>
        pthread_mutex_unlock(&display->mutex);<br>
 }<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.9.3<br>
<br>
</font></span></blockquote></div><br></div>