<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On 26 November 2014 at 13:48, Pekka Paalanen <span dir="ltr"><<a href="mailto:ppaalanen@gmail.com" target="_blank">ppaalanen@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Fri, 21 Nov 2014 11:12:35 +0100<br>
Marek Chalupa <<a href="mailto:mchqwerty@gmail.com">mchqwerty@gmail.com</a>> wrote:<br>
<br>
> Remove out-dated documentation and add few more words<br>
> about this topic.<br>
><br>
> Signed-off-by: Marek Chalupa <<a href="mailto:mchqwerty@gmail.com">mchqwerty@gmail.com</a>><br>
> ---<br>
>  src/wayland-client.c | 106 ++++++++++++++++++++++++++++++++++++++++++---------<br>
>  1 file changed, 87 insertions(+), 19 deletions(-)<br>
><br>
> diff --git a/src/wayland-client.c b/src/wayland-client.c<br>
> index 41c49e9..b1a1fa0 100644<br>
> --- a/src/wayland-client.c<br>
> +++ b/src/wayland-client.c<br>
> @@ -909,6 +909,12 @@ static const struct wl_callback_listener sync_listener = {<br>
>   * Blocks until the server process all currently issued requests and<br>
>   * sends out pending events on the event queue.<br>
>   *<br>
> + * \note This function uses wl_display_dispatch_queue() internally. If you<br>
> + * are using wl_display_read_events() from more threads, don't use this function<br>
> + * (or make sure that calling wl_display_roundtrip_queue() doesn't interfere<br>
> + * with calling wl_display_prepare_read() and wl_display_read_events())<br>
> + *<br>
> + * \sa wl_display_roundtrip()<br>
>   * \memberof wl_display<br>
>   */<br>
>  WL_EXPORT int<br>
> @@ -940,6 +946,11 @@ wl_display_roundtrip_queue(struct wl_display *display, struct wl_event_queue *qu<br>
>   * Blocks until the server process all currently issued requests and<br>
>   * sends out pending events on the default event queue.<br>
>   *<br>
> + * \note This function uses wl_display_dispatch_queue() internally. If you<br>
> + * are using wl_display_read_events() from more threads, don't use this function<br>
> + * (or make sure that calling wl_display_roundtrip() doesn't interfere<br>
> + * with calling wl_display_prepare_read() and wl_display_read_events())<br>
> + *<br>
>   * \memberof wl_display<br>
>   */<br>
>  WL_EXPORT int<br>
> @@ -1211,14 +1222,55 @@ cancel_read(struct wl_display *display)<br>
>   *<br>
>   * This will read events from the file descriptor for the display.<br>
>   * This function does not dispatch events, it only reads and queues<br>
> - * events into their corresponding event queues.  If no data is<br>
> + * events into their corresponding event queues. If no data is<br>
>   * avilable on the file descriptor, wl_display_read_events() returns<br>
> - * immediately.  To dispatch events that may have been queued, call<br>
> - * wl_display_dispatch_pending() or<br>
> - * wl_display_dispatch_queue_pending().<br>
> + * immediately. To dispatch events that may have been queued, call<br>
> + * wl_display_dispatch_pending() or wl_display_dispatch_queue_pending().<br>
>   *<br>
>   * Before calling this function, wl_display_prepare_read() must be<br>
> - * called first.<br>
> + * called first. When running in more threads (which is the usual<br>
> + * case, since we'd use wl_display_dispatch() otherwise), every thread<br>
> + * must call wl_display_prepare_read() before calling this function.<br>
> + *<br>
> + * After calling wl_display_prepare_read() there can be some extra code<br>
> + * before calling wl_display_read_events(), for example poll() or alike.<br>
> + * Example of code in a thread:<br>
> + *<br>
> + * \code<br>
> + *<br>
> + *   while (wl_display_prepare_read(display) < 0)<br>
> + *           wl_display_dispatch_pending(display);<br>
> + *   wl_display_flush(display);<br>
> + *<br>
> + *   ... some code ...<br>
> + *<br>
> + *   fds[0].fd = wl_display_get_fd(display);<br>
> + *   fds[0].event = POLLIN | POLLHUP | POLLERR;<br>
> + *   poll(fds, 1, -1);<br>
> + *<br>
> + *   if (!everything_ok()) {<br>
> + *   wl_display_cancel_read(display);<br>
> + *   handle_error();<br>
> + *   }<br>
> + *<br>
> + *   if (wl_display_read_events(display) < 0)<br>
> + *   handle_error();<br>
> + *<br>
> + *   ...<br>
> + * \endcode<br>
> + *<br>
> + * The code should be as short as possible since other threads may<br>
> + * get sleeping until all threads called wl_display_read_events()<br>
> + * or wl_display_cancel_read().<br>
<br>
</div></div>Hi,<br>
<br>
this paragraph is a bit confusing, "short code" is not a clear term.<br>
There is also the poll() which may take an arbitary amount of time to<br>
return. I probably see what you are getting at, but it should be<br>
rephrased.<br>
<br>
How about something like:<br>
<br>
After wl_display_prepare_read() succeeds, other threads that enter<br>
wl_display_read_events() will sleep until the very last thread enters<br>
it too or cancels. Therefore when the display fd becomes (or already<br>
is) readable, wl_display_read_events() should be called as soon as<br>
possible to unblock all threads. If wl_display_read_events() will not<br>
be called, then wl_display_cancel_read() must be called<br>
posthaste instead to let the other threads continue.<br></blockquote><div><br></div><div>Yes, that's clearer :)<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<span class=""><br>
> + *<br>
> + * This function must not be called simultaneously with wl_display_dispatch().<br>
> + * It may lead to deadlock. If programmer wants, for some reason, use<br>
> + * wl_display_dispatch() in one thread and wl_display_read_events() in another,<br>
> + * extra care must be taken to serialize these calls, i. e. use mutexes or<br>
> + * similar.<br>
<br>
</span>Hmm, that mutex should protect not only wl_display_read_events() call,<br>
but the whole sequence between prepare_read and<br>
read_events/cancel_read, should it not?<br></blockquote><div><br></div><div>Yup<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> + *<br>
> + * \sa wl_display_prepare_read(), wl_display_cancel_read(),<br>
> + * wl_display_dispatch_pending(), wl_display_dispatch()<br>
>   *<br>
>   * \memberof wl_display<br>
>   */<br>
> @@ -1296,17 +1348,17 @@ wl_display_prepare_read_queue(struct wl_display *display,<br>
>       return ret;<br>
>  }<br>
><br>
> -/** Prepare to read events after polling file descriptor<br>
> +/** Prepare to read events from the display's file descriptor<br>
>   *<br>
>   * \param display The display context object<br>
>   * \return 0 on success or -1 if event queue was not empty<br>
>   *<br>
>   * This function must be called before reading from the file<br>
> - * descriptor using wl_display_read_events().  Calling<br>
> - * wl_display_prepare_read() announces the calling threads intention<br>
> + * descriptor using wl_display_read_events(). Calling<br>
> + * wl_display_prepare_read() announces the calling thread's intention<br>
>   * to read and ensures that until the thread is ready to read and<br>
>   * calls wl_display_read_events(), no other thread will read from the<br>
> - * file descriptor.  This only succeeds if the event queue is empty<br>
> + * file descriptor. This only succeeds if the event queue is empty<br>
>   * though, and if there are undispatched events in the queue, -1 is<br>
>   * returned and errno set to EAGAIN.<br>
>   *<br>
> @@ -1314,6 +1366,13 @@ wl_display_prepare_read_queue(struct wl_display *display,<br>
>   * either call wl_display_read_events() when it's ready or cancel the<br>
>   * read intention by calling wl_display_cancel_read().<br>
>   *<br>
> + * This function doesn't acquire exclusive access to the display's fd.<br>
> + * It only registers that the thread calling this function has intention to<br>
> + * read from fd. When all registered readers call wl_display_read_events(),<br>
> + * only one (at random) eventually reads and queues the events and the<br>
> + * others are sleeping meanwhile. This way we avoid races and still<br>
> + * can read from more threads.<br>
> + *<br>
>   * Use this function before polling on the display fd or to integrate<br>
>   * the fd into a toolkit event loop in a race-free way.  Typically, a<br>
>   * toolkit will call wl_display_dispatch_pending() before sleeping, to<br>
> @@ -1350,9 +1409,10 @@ wl_display_prepare_read_queue(struct wl_display *display,<br>
>   * Here we call wl_display_prepare_read(), which ensures that between<br>
>   * returning from that call and eventually calling<br>
>   * wl_display_read_events(), no other thread will read from the fd and<br>
> - * queue events in our queue.  If the call to<br>
> - * wl_display_prepare_read() fails, we dispatch the pending events and<br>
> - * try again until we're successful.<br>
> + * queue events in our queue. If the call to wl_display_prepare_read() fails,<br>
> + * we dispatch the pending events and try again until we're successful.<br>
> + *<br>
> + * \sa wl_display_cancel_read(), wl_display_read_events()<br>
>   *<br>
>   * \memberof wl_display<br>
>   */<br>
> @@ -1362,13 +1422,15 @@ wl_display_prepare_read(struct wl_display *display)<br>
>       return wl_display_prepare_read_queue(display, &display->default_queue);<br>
>  }<br>
><br>
> -/** Release exclusive access to display file descriptor<br>
> +/** Cancel read intention on display's fd<br>
>   *<br>
>   * \param display The display context object<br>
>   *<br>
> - * This releases the exclusive access.  Useful for canceling the lock<br>
> - * when a timed out poll returns fd not readable and we're not going<br>
> - * to read from the fd anytime soon.<br>
> + * After a thread successfully called wl_display_preapare_read() it must<br>
<br>
</div></div>Typo: preapare.<br>
<span class=""><br>
> + * either call wl_display_read_events() or wl_display_cancel_read().<br>
> + * If the threads do not follow this rule it will lead to deadlock.<br>
> + *<br>
> + * \sa wl_display_prepare_read(), wl_display_read_events()<br>
>   *<br>
>   * \memberof wl_display<br>
>   */<br>
> @@ -1396,6 +1458,9 @@ wl_display_cancel_read(struct wl_display *display)<br>
>   * threads this will block until the main thread queues events on the queue<br>
>   * passed as argument.<br>
>   *<br>
> + * For behaviour in multi-threaded environment see wl_display_read_events()<br>
> + * and wl_display_prepare_read()<br>
<br>
</span>Shouldn't we have the same warning here for wl_display_dispatch_queue()<br>
as we have below for wl_display_dispatch()?<br>
<br>
Only the *_pending() function are safe in a multithreaded app, right?<br>
<span class=""><br></span></blockquote><div><br></div><div>Yes, only the ones that do not attempt to read from the fd.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
> + *<br>
>   * \memberof wl_display<br>
>   */<br>
>  WL_EXPORT int<br>
> @@ -1502,10 +1567,13 @@ wl_display_dispatch_queue_pending(struct wl_display *display,<br>
>   * or not. For dispatching main queue events without blocking, see \ref<br>
>   * wl_display_dispatch_pending().<br>
>   *<br>
> - * \note Calling this will release the display file descriptor if this<br>
> - * thread acquired it using wl_display_acquire_fd().<br>
> + * In multi-threaded environment, programmer may want to use<br>
> + * wl_display_read_events(). However, use of wl_display_read_events()<br>
> + * must not be mixed with wl_display_dispatch(). See wl_display_read_events()<br>
> + * and wl_display_prepare_read() for more details.<br>
>   *<br>
> - * \sa wl_display_dispatch_pending(), wl_display_dispatch_queue()<br>
> + * \sa wl_display_dispatch_pending(), wl_display_dispatch_queue(),<br>
> + * wl_display_read_events()<br>
>   *<br>
>   * \memberof wl_display<br>
>   */<br>
<br>
</span>Meanwhile I have merged some patches that make this one need a rebase.<br>
<br>
Otherwise it looks ok to me.<br>
<br>
<br>
Thanks,<br>
pq<br></blockquote><div> </div></div><br></div><div class="gmail_extra">Thanks,<br></div><div class="gmail_extra">Marek<br></div><div class="gmail_extra"><br></div></div>