[PATCH wayland 1/2] doc: Clarify documentation about dispatching event queues

Ander Conselvan de Oliveira ander.conselvan.de.oliveira at intel.com
Fri Oct 19 05:30:25 PDT 2012


Clarify on what cases each of the dispatching functions may block, what
is the main thread and add some real world examples.
---

Hi Kristian,

Hopefully I got it right this time. The documentation for
wl_display_dispatch_pending() is pretty much a reword of your answer
to my previous patch.

Feel free to amend any changes you see necessary.

Thanks,
Ander

 src/wayland-client.c |   58 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/wayland-client.h |   52 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 96 insertions(+), 14 deletions(-)

diff --git a/src/wayland-client.c b/src/wayland-client.c
index ccf8174..7e50b40 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 if there are no events to dispatch. If calling from
+ * the main thread, it will block reading data 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,14 +838,25 @@ 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.
  *
- * \sa wl_display_dispatch_queue()
+ * If the main event queue is empty, 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 It is not possible to check if there are events on the main queue
+ * or not. For dispatching main queue events without blocking, see \ref
+ * wl_display_dispatch_pending().
+ *
+ * \note Calling this makes the current thread the main one.
+ *
+ * \sa wl_display_dispatch_pending(), wl_display_dispatch_queue()
  *
  * \memberof wl_display
  */
@@ -852,6 +868,44 @@ 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, i.e., it doesn't block.
+ *
+ * This is necessary when a client's main loop wakes up on some fd other
+ * than the display fd (network socket, timer fd, etc) and calls \ref
+ * wl_display_dispatch_queue() from that callback. This may queue up
+ * events in the main queue while reading all data from the display fd.
+ * When the main thread returns to the main loop to block, the display fd
+ * no longer has data, causing a call to \em poll(2) (or similar
+ * functions) to block indefinitely, even though there are events ready
+ * to dispatch.
+ *
+ * To proper integrate the wayland display fd into a main loop, the
+ * client should always call \ref wl_display_dispatch_pending() and then
+ * \ref wl_display_flush() prior to going back to sleep. At that point,
+ * the fd typically doesn't have data so attempting I/O could block, but
+ * events queued up on the main queue should be dispatched.
+ *
+ * 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 eventually 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..71fe450 100644
--- a/src/wayland-client.h
+++ b/src/wayland-client.h
@@ -66,18 +66,46 @@ struct wl_proxy;
  * representation to the display's write buffer. The data is sent to the
  * 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.
- *
+ * Incoming data is handled in two steps: queueing and dispatching. In the
+ * queue step, the data coming from the display fd is interpreted and
+ * added to a queue. On the dispatch step, the handler for the incoming
+ * event set by the client on the corresponding \ref wl_proxy is called.
+ *
+ * A \ref wl_display has at least one event queue, called the <em>main
+ * queue</em>. Clients can create additional event queues with \ref
+ * wl_display_create_queue() and assign \ref wl_proxy's to it. Events
+ * occurring in a particular proxy are always queued in its assigned queue.
+ * A client can ensure that a certain assumption, such as holding a lock
+ * or running from a given thread, is true when a proxy event handler is
+ * called by assigning that proxy to an event queue and making sure that
+ * this queue is only dispatched when the assumption holds.
+ *
+ * The main queue is dispatched by calling \ref wl_display_dispatch().
+ * This will dispatch any events queued on the main queue and attempt
+ * to read from the display fd if its empty. Events read are then queued
+ * on the appropriate queues according to the proxy assignment. Calling
+ * that function makes the calling thread the <em>main thread</em>.
+ *
+ * A user created queue is dispatched with \ref wl_display_dispatch_queue().
+ * If there are no events to dispatch this function will block. If this
+ * is called by the main thread, this will attempt to read data from the
+ * display fd and queue any events on the appropriate queues. If calling
+ * from any other thread, the function will block until the main thread
+ * queues an event on the queue being dispatched.
+ *
+ * A real world example of event queue usage is Mesa's implementation of
+ * eglSwapBuffers() for the Wayland platform. This function might need
+ * to block until a frame callback is received, but dispatching the main
+ * queue could cause an event handler on the client to start drawing
+ * again. This problem is solved using another event queue, so that only
+ * the events handled by the EGL code are dispatched during the block.
+ *
+ * This creates a problem where the main thread dispatches a non-main
+ * queue, reading all the data from the display fd. If the application
+ * would call \em poll(2) after that it would block, even though there
+ * might be events queued on the main queue. Those events should be
+ * dispatched with \ref wl_display_dispatch_pending() before
+ * flushing and blocking.
  */
 struct wl_display;
 
-- 
1.7.9.5



More information about the wayland-devel mailing list