mirror of
				https://gitlab.freedesktop.org/wayland/wayland.git
				synced 2025-10-29 05:40:16 -04:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									ff8b885523
								
							
						
					
					
						commit
						ddd348da7e
					
				
					 2 changed files with 127 additions and 34 deletions
				
			
		|  | @ -27,6 +27,7 @@ | ||||||
| #define WAYLAND_CLIENT_CORE_H | #define WAYLAND_CLIENT_CORE_H | ||||||
| 
 | 
 | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
|  | #include <time.h> | ||||||
| #include "wayland-util.h" | #include "wayland-util.h" | ||||||
| #include "wayland-version.h" | #include "wayland-version.h" | ||||||
| 
 | 
 | ||||||
|  | @ -250,6 +251,11 @@ int | ||||||
| wl_display_dispatch_queue(struct wl_display *display, | wl_display_dispatch_queue(struct wl_display *display, | ||||||
| 			  struct wl_event_queue *queue); | 			  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 | int | ||||||
| wl_display_dispatch_queue_pending(struct wl_display *display, | wl_display_dispatch_queue_pending(struct wl_display *display, | ||||||
| 				  struct wl_event_queue *queue); | 				  struct wl_event_queue *queue); | ||||||
|  |  | ||||||
|  | @ -45,6 +45,7 @@ | ||||||
| #include "wayland-os.h" | #include "wayland-os.h" | ||||||
| #include "wayland-client.h" | #include "wayland-client.h" | ||||||
| #include "wayland-private.h" | #include "wayland-private.h" | ||||||
|  | #include "timespec-util.h" | ||||||
| 
 | 
 | ||||||
| /** \cond */ | /** \cond */ | ||||||
| 
 | 
 | ||||||
|  | @ -1953,20 +1954,133 @@ wl_display_cancel_read(struct wl_display *display) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | 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; | 	int ret; | ||||||
| 	struct pollfd pfd[1]; | 	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].fd = display->fd; | ||||||
| 	pfd[0].events = events; | 	pfd[0].events = events; | ||||||
| 	do { | 	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); | 	} while (ret == -1 && errno == EINTR); | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	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
 | /** Dispatch events in an event queue
 | ||||||
|  * |  * | ||||||
|  * \param display The display context object |  * \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 |  * \note Since Wayland 1.5 the display has an extra queue | ||||||
|  * for its own events (i. e. delete_id). This queue is dispatched always, |  * 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. |  * 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 |  * That means that this function can return even when it has not dispatched any | ||||||
|  * haven't dispatched any event for the given queue. |  * event for the given queue. | ||||||
|  * |  * | ||||||
|  * \sa wl_display_dispatch(), wl_display_dispatch_pending(), |  * \sa wl_display_dispatch(), wl_display_dispatch_pending(), | ||||||
|  * wl_display_dispatch_queue_pending(), wl_display_prepare_read_queue() |  * wl_display_dispatch_queue_pending(), wl_display_prepare_read_queue() | ||||||
|  | @ -2012,37 +2126,10 @@ wl_display_dispatch_queue(struct wl_display *display, | ||||||
| { | { | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (wl_display_prepare_read_queue(display, queue) == -1) | 	ret = wl_display_dispatch_queue_timeout(display, queue, NULL); | ||||||
| 		return wl_display_dispatch_queue_pending(display, queue); | 	assert(ret == -1 || ret > 0); | ||||||
| 
 | 
 | ||||||
| 	while (true) { | 	return ret; | ||||||
| 		ret = wl_display_flush(display); |  | ||||||
| 
 |  | ||||||
| 		if (ret != -1 || errno != EAGAIN) |  | ||||||
| 			break; |  | ||||||
| 
 |  | ||||||
| 		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); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Dispatch pending events in an event queue
 | /** Dispatch pending events in an event queue
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Sebastian Wick
						Sebastian Wick