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 | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <time.h> | ||||
| #include "wayland-util.h" | ||||
| #include "wayland-version.h" | ||||
| 
 | ||||
|  | @ -250,6 +251,11 @@ int | |||
| 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); | ||||
|  |  | |||
|  | @ -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); | ||||
| 	ret = wl_display_dispatch_queue_timeout(display, queue, NULL); | ||||
| 	assert(ret == -1 || ret > 0); | ||||
| 
 | ||||
| 	while (true) { | ||||
| 		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); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /** Dispatch pending events in an event queue
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Sebastian Wick
						Sebastian Wick