aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Wick <sebastian.wick@redhat.com>2024-02-07 19:00:46 +0100
committerDerek Foreman <derek.foreman@collabora.com>2025-02-04 14:09:51 +0000
commitddd348da7ea0889056843cf252729185d306b7b8 (patch)
tree5b0983c130fc4555f3ce2f89affed8d67db76677
parentevent-loop: Use timespec utils instead of hand-rolling our own (diff)
downloadwayland-ddd348da7ea0889056843cf252729185d306b7b8.tar
wayland-ddd348da7ea0889056843cf252729185d306b7b8.tar.gz
wayland-ddd348da7ea0889056843cf252729185d306b7b8.tar.bz2
wayland-ddd348da7ea0889056843cf252729185d306b7b8.tar.lz
wayland-ddd348da7ea0889056843cf252729185d306b7b8.tar.xz
wayland-ddd348da7ea0889056843cf252729185d306b7b8.tar.zst
wayland-ddd348da7ea0889056843cf252729185d306b7b8.zip
client: Add wl_display_dispatch_queue_timeout
For dispatching messages on a queue with a timeout. This slightly changes the samantics of wl_display_dispatch. Previously it was possible for it to return even though there wasn't a single dispatched event. The function correctly returned 0 in this case but it is now used to indicate a timeout. Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
-rw-r--r--src/wayland-client-core.h6
-rw-r--r--src/wayland-client.c155
2 files changed, 127 insertions, 34 deletions
diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h
index a4ca4e5..6d45dc0 100644
--- a/src/wayland-client-core.h
+++ b/src/wayland-client-core.h
@@ -27,6 +27,7 @@
#define WAYLAND_CLIENT_CORE_H
#include <stdint.h>
+#include <time.h>
#include "wayland-util.h"
#include "wayland-version.h"
@@ -251,6 +252,11 @@ wl_display_dispatch_queue(struct wl_display *display,
struct wl_event_queue *queue);
int
+wl_display_dispatch_queue_timeout(struct wl_display *display,
+ struct wl_event_queue *queue,
+ const struct timespec *timeout);
+
+int
wl_display_dispatch_queue_pending(struct wl_display *display,
struct wl_event_queue *queue);
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 2f6e00c..a60e567 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -45,6 +45,7 @@
#include "wayland-os.h"
#include "wayland-client.h"
#include "wayland-private.h"
+#include "timespec-util.h"
/** \cond */
@@ -1953,20 +1954,133 @@ wl_display_cancel_read(struct wl_display *display)
}
static int
-wl_display_poll(struct wl_display *display, short int events)
+wl_display_poll(struct wl_display *display,
+ short int events,
+ const struct timespec *timeout)
{
int ret;
struct pollfd pfd[1];
+ struct timespec now;
+ struct timespec deadline = {0};
+ struct timespec result;
+ struct timespec *remaining_timeout = NULL;
+
+ if (timeout) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ timespec_add(&deadline, &now, timeout);
+ }
pfd[0].fd = display->fd;
pfd[0].events = events;
do {
- ret = poll(pfd, 1, -1);
+ if (timeout) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ timespec_sub_saturate(&result, &deadline, &now);
+ remaining_timeout = &result;
+ }
+ ret = ppoll(pfd, 1, remaining_timeout, NULL);
} while (ret == -1 && errno == EINTR);
return ret;
}
+/** Dispatch events in an event queue with a timeout
+ *
+ * \param display The display context object
+ * \param queue The event queue to dispatch
+ * \param timeout A timeout describing how long the call should block trying to
+ * dispatch events
+ * \return The number of dispatched events on success, -1 on failure
+ *
+ * This function behaves identical to wl_display_dispatch_queue() except
+ * that it also takes a timeout and returns 0 if the timeout elapsed.
+ *
+ * Passing NULL as a timeout means an infinite timeout. An empty timespec
+ * causes wl_display_dispatch_queue_timeout() to return immediately even if no
+ * events have been dispatched.
+ *
+ * If a timeout is passed to wl_display_dispatch_queue_timeout() it is updated
+ * to the remaining time.
+ *
+ * \sa wl_display_dispatch_queue()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_dispatch_queue_timeout(struct wl_display *display,
+ struct wl_event_queue *queue,
+ const struct timespec *timeout)
+{
+ int ret;
+ struct timespec now;
+ struct timespec deadline = {0};
+ struct timespec result;
+ struct timespec *remaining_timeout = NULL;
+
+ if (timeout) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ timespec_add(&deadline, &now, timeout);
+ }
+
+ if (wl_display_prepare_read_queue(display, queue) == -1)
+ return wl_display_dispatch_queue_pending(display, queue);
+
+ while (true) {
+ ret = wl_display_flush(display);
+
+ if (ret != -1 || errno != EAGAIN)
+ break;
+
+ if (timeout) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ timespec_sub_saturate(&result, &deadline, &now);
+ remaining_timeout = &result;
+ }
+ ret = wl_display_poll(display, POLLOUT, remaining_timeout);
+
+ if (ret <= 0) {
+ wl_display_cancel_read(display);
+ return ret;
+ }
+ }
+
+ /* Don't stop if flushing hits an EPIPE; continue so we can read any
+ * protocol error that may have triggered it. */
+ if (ret < 0 && errno != EPIPE) {
+ wl_display_cancel_read(display);
+ return -1;
+ }
+
+ while (true) {
+ if (timeout) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ timespec_sub_saturate(&result, &deadline, &now);
+ remaining_timeout = &result;
+ }
+
+ ret = wl_display_poll(display, POLLIN, remaining_timeout);
+ if (ret <= 0) {
+ wl_display_cancel_read(display);
+ break;
+ }
+
+ ret = wl_display_read_events(display);
+ if (ret == -1)
+ break;
+
+ ret = wl_display_dispatch_queue_pending(display, queue);
+ if (ret != 0)
+ break;
+
+ /* We managed to read data from the display but there is no
+ * complete event to dispatch yet. Try reading again. */
+ if (wl_display_prepare_read_queue(display, queue) == -1)
+ return wl_display_dispatch_queue_pending(display, queue);
+ }
+
+ return ret;
+}
+
/** Dispatch events in an event queue
*
* \param display The display context object
@@ -1998,8 +2112,8 @@ wl_display_poll(struct wl_display *display, short int events)
* \note Since Wayland 1.5 the display has an extra queue
* for its own events (i. e. delete_id). This queue is dispatched always,
* no matter what queue we passed as an argument to this function.
- * That means that this function can return non-0 value even when it
- * haven't dispatched any event for the given queue.
+ * That means that this function can return even when it has not dispatched any
+ * event for the given queue.
*
* \sa wl_display_dispatch(), wl_display_dispatch_pending(),
* wl_display_dispatch_queue_pending(), wl_display_prepare_read_queue()
@@ -2012,37 +2126,10 @@ wl_display_dispatch_queue(struct wl_display *display,
{
int ret;
- if (wl_display_prepare_read_queue(display, queue) == -1)
- return wl_display_dispatch_queue_pending(display, queue);
-
- while (true) {
- ret = wl_display_flush(display);
-
- if (ret != -1 || errno != EAGAIN)
- break;
+ ret = wl_display_dispatch_queue_timeout(display, queue, NULL);
+ assert(ret == -1 || ret > 0);
- if (wl_display_poll(display, POLLOUT) == -1) {
- wl_display_cancel_read(display);
- return -1;
- }
- }
-
- /* Don't stop if flushing hits an EPIPE; continue so we can read any
- * protocol error that may have triggered it. */
- if (ret < 0 && errno != EPIPE) {
- wl_display_cancel_read(display);
- return -1;
- }
-
- if (wl_display_poll(display, POLLIN) == -1) {
- wl_display_cancel_read(display);
- return -1;
- }
-
- if (wl_display_read_events(display) == -1)
- return -1;
-
- return wl_display_dispatch_queue_pending(display, queue);
+ return ret;
}
/** Dispatch pending events in an event queue