[PATCH 1/2] doc: Clarify the interaction of dispatch{, _queue, _pending}()

Kristian Høgsberg hoegsberg at gmail.com
Wed Oct 17 14:28:33 PDT 2012


On Wed, Oct 17, 2012 at 09:26:08PM +0300, Ander Conselvan de Oliveira wrote:
> From: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira at intel.com>
> 
> Clarify on what cases each of the dispatching functions may block and
> also clarify what is the main thread.
> ---
>  src/wayland-client.c |   40 ++++++++++++++++++++++++++++++++++++++--
>  src/wayland-client.h |   30 +++++++++++++++++++-----------
>  2 files changed, 57 insertions(+), 13 deletions(-)
> 
> diff --git a/src/wayland-client.c b/src/wayland-client.c
> index 9ac4edb..89df3ba 100644
> --- a/src/wayland-client.c
> +++ b/src/wayland-client.c
> @@ -824,6 +824,11 @@ err_unlock:
>   * Dispatch all incoming events for objects assigned to the given
>   * event queue. On failure -1 is returned and errno set appropriately.
>   *
> + * This function blocks until there are events to dispatch. If calling from

It dispatches events immdiately (without reading or blocking) if there
are already events in the queue and doesn't block in that case.

> + * the main thread, this will cause data to be read from the display fd. For
> + * other threads this will block until the main thread queues events on the
> + * queue passed as argument.
> + *
>   * \memberof wl_display
>   */
>  WL_EXPORT int
> @@ -833,12 +838,20 @@ wl_display_dispatch_queue(struct wl_display *display,
>  	return dispatch_queue(display, queue, 1);
>  }
>  
> -/** Dispatch a display's main event queue
> +/** Process incoming events
>   *
>   * \param display The display context object
>   * \return The number of dispatched events on success or -1 on failure
>   *
> - * Dispatch the display's main event queue.
> + * This function blocks until there are events to be read from the display
> + * fd. Events are read and queued on the appropriate event queues. Finally,
> + * events on the main event queue are dispatched.
> + *
> + * \note This function may block even if there are events queued on the main
> + * queue. See \ref wl_display and \ref wl_display_dispatch_pending() for
> + * details.

It actually never blocks if there are events in the main queue, but
there's no way to know that, which is why we have the _pending()
variant, which never blocks.

> + * \note Calling this makes the current thread the main one.
>   *
>   * \sa wl_display_dispatch_queue()
>   *
> @@ -852,6 +865,29 @@ wl_display_dispatch(struct wl_display *display)
>  	return dispatch_queue(display, &display->queue, 1);
>  }
>  
> +/** Dispatch main queue events without reading from the display fd
> + *
> + * \param display The display context object
> + * \return The number of dispatched events or -1 on failure
> + *
> + * This function dispatches events on the main event queue. It does not
> + * attempt to read the display fd and simply returns zero if the main
> + * queue is empty.
> + *
> + * This may be necessary if the main thread explicit calls
> + * \ref wl_display_dispatch_queue(). In that case, that call may queue
> + * events on the main thread without dispatching them. Calling \ref
> + * wl_display_dispatch() again could block indefinitely trying to read
> + * from the connection, so, in that scenario, clients should call this
> + * function before flushing and blocking.

The case where wl_display_dispatch_pending() is necessary is when the
main loop wakes up on some other fd (network socket, timer fd, but not
the wayland fd) and ends up calling wl_display_dispatch_queue() for a
different queue from that callback.  This may queue up events in the
main queue while reading all data from the fd.  When the main thread
returns to the main loop to block in poll(2), the wayland fd no longer
has data and we'll block indefinitely, even though we have events
ready to dispatch.  The idea is that an application main thread should
always call wl_display_dispatch_pending() and then wl_display_flush()
prior to going back to sleep.  At that point, the fd typically doesn't
have data and we don't want to attempt I/O, but we do want to dispatch
any events that may have queued up.

The point about the call to wl_display_dispatch_queue() happening from
another source than the wayland socket fd is that if we end up calling
wl_display_dispatch_queue() from a wl_display_dispatch() callback, we
always return with an empty main event queue.  So this only happens if
we wake up on some other fd and calls wl_display_dispatch_queue() for
something other than the main queue.

A real-world example is a main loop that wakes up on a timerfd (or a
sound card fd becoming writable, for example in a video player), which
then triggers GL rendering and eventuall eglSwapBuffers.
eglSwapBuffers() may call wl_display_dispatch_queue() if it didn't
receive the frame event for the previous frame, and as such queue
events in the main queue.

> + * \note Calling this makes the current thread the main one.
> + *
> + * \sa wl_display_dispatch(), wl_display_dispatch_queue(),
> + *  wl_display_flush()
> + *
> + * \memberof wl_display
> + */
>  WL_EXPORT int
>  wl_display_dispatch_pending(struct wl_display *display)
>  {
> diff --git a/src/wayland-client.h b/src/wayland-client.h
> index fb9c952..f1604f6 100644
> --- a/src/wayland-client.h
> +++ b/src/wayland-client.h
> @@ -67,17 +67,25 @@ struct wl_proxy;
>   * compositor when the client calls \ref wl_display_flush().
>   *
>   * Event handling is done in a thread-safe manner using event queues. The
> - * display has a \em main event queue where initially all the events are
> - * queued. The listeners for the events queued in it are called when the
> - * client calls \ref wl_display_dispatch().
> - *
> - * The client can create additional event queues with \ref
> - * wl_display_create_queue() and assign different \ref wl_proxy objects to it.
> - * The events for a proxy are always queued only on its assign queue, that can
> - * be dispatched by a different thread with \ref wl_display_dispatch_queue().
> - *
> - * All the \ref wl_display's functions are thread-safe.
> - *
> + * display has a \em main event queue where events processed by the main
> + * thread are queued. Additional threads may have their own event queues,
> + * to which certain \ref wl_proxy's are assigned. A proxy's event is
> + * always queued in its assigned queue.

It's a little hard to explain, but the queue isn't necessarily a
per-thread thing.  It's more like a locking domain... access to a
queue must be serialized, for example by only accessing it from one
specific thread or by taking a lock before accessing it.  So for
example, the event queue used by the mesa EGL implementation is
protected by the mesa EGL mutex.  Any thread can access the event
queue (including the main thread) as long as they take that EGL mutex
(the EGL mutex is taken by the code EGL code, doesn't happen in
platfom_wayland.c)

> + *
> + * Calling \ref wl_display_dispatch() reads data from the display fd and
> + * makes the calling thread the main thread. Events are queued on the
> + * appropriate queues. This funcion will also dispatch the events on the
> + * main queue, i.e., the listeners for those events will be called from the
> + * main thread. Other threads dispatch the events on their queue using \ref
> + * wl_display_dispatch_queue(), causing the event handlers to be called on
> + * that thread.
> + *
> + * Calling \ref wl_display_dispatch_queue() from the main thread will also
> + * read data from the display fd, but events on the main queue won't be
> + * dispatched. In that case, those events can be dispatched without
> + * attempting to read the display fd and potentially blocking by calling
> + * \ref wl_display_dispatch_pending(). The latter function will also
> + * make the current thread the main one.
>   */
>  struct wl_display;
>  
> -- 
> 1.7.9.5
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list