From 818bb399b040f9db5d6563cfbd9ec8da9131f30d Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Fri, 19 Oct 2012 15:30:25 +0300 Subject: [PATCH] doc: Clarify documentation about dispatching event queues Clarify on what cases each of the dispatching functions may block, what is the main thread and add some real world examples. --- 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 main + * queue. 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 main thread. + * + * 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; -- 2.7.4