mirror of
				https://gitlab.freedesktop.org/wayland/wayland.git
				synced 2025-11-03 09:01:42 -05:00 
			
		
		
		
	wayland-client: forward fatal errors to caller
If any callback or helper function fails with a fatal error, we now set the last_error flag and prevent all further I/O on the wl_display. We wake up all sleeping event-queues and notify the caller that they should shutdown wl_display. Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
		
							parent
							
								
									edae4ffa37
								
							
						
					
					
						commit
						33b7637b45
					
				
					 2 changed files with 81 additions and 20 deletions
				
			
		| 
						 | 
					@ -83,6 +83,33 @@ struct wl_display {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int wl_debug = 0;
 | 
					static int wl_debug = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					display_fatal_error(struct wl_display *display, int error)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct wl_event_queue *iter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (display->last_error)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!error)
 | 
				
			||||||
 | 
							error = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						display->last_error = error;
 | 
				
			||||||
 | 
						close(display->fd);
 | 
				
			||||||
 | 
						display->fd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_list_for_each(iter, &display->event_queue_list, link)
 | 
				
			||||||
 | 
							pthread_cond_broadcast(&iter->cond);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					wl_display_fatal_error(struct wl_display *display, int error)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pthread_mutex_lock(&display->mutex);
 | 
				
			||||||
 | 
						display_fatal_error(display, error);
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&display->mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display)
 | 
					wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -358,9 +385,7 @@ display_handle_error(void *data,
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_lock(&display->mutex);
 | 
						wl_display_fatal_error(display, err);
 | 
				
			||||||
	display->last_error = err;
 | 
					 | 
				
			||||||
	pthread_mutex_unlock(&display->mutex);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -549,7 +574,8 @@ wl_display_disconnect(struct wl_display *display)
 | 
				
			||||||
	wl_map_release(&display->objects);
 | 
						wl_map_release(&display->objects);
 | 
				
			||||||
	wl_event_queue_release(&display->queue);
 | 
						wl_event_queue_release(&display->queue);
 | 
				
			||||||
	pthread_mutex_destroy(&display->mutex);
 | 
						pthread_mutex_destroy(&display->mutex);
 | 
				
			||||||
	close(display->fd);
 | 
						if (display->fd > 0)
 | 
				
			||||||
 | 
							close(display->fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(display);
 | 
						free(display);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -592,17 +618,19 @@ static const struct wl_callback_listener sync_listener = {
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * \memberof wl_display
 | 
					 * \memberof wl_display
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
WL_EXPORT void
 | 
					WL_EXPORT int
 | 
				
			||||||
wl_display_roundtrip(struct wl_display *display)
 | 
					wl_display_roundtrip(struct wl_display *display)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct wl_callback *callback;
 | 
						struct wl_callback *callback;
 | 
				
			||||||
	int done;
 | 
						int done, ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	done = 0;
 | 
						done = 0;
 | 
				
			||||||
	callback = wl_display_sync(display);
 | 
						callback = wl_display_sync(display);
 | 
				
			||||||
	wl_callback_add_listener(callback, &sync_listener, &done);
 | 
						wl_callback_add_listener(callback, &sync_listener, &done);
 | 
				
			||||||
	while (!done)
 | 
						while (!done && !ret)
 | 
				
			||||||
		wl_display_dispatch(display);
 | 
							ret = wl_display_dispatch(display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
| 
						 | 
					@ -668,10 +696,12 @@ queue_event(struct wl_display *display, int len)
 | 
				
			||||||
	message = &proxy->object.interface->events[opcode];
 | 
						message = &proxy->object.interface->events[opcode];
 | 
				
			||||||
	closure = wl_connection_demarshal(display->connection, size,
 | 
						closure = wl_connection_demarshal(display->connection, size,
 | 
				
			||||||
					  &display->objects, message);
 | 
										  &display->objects, message);
 | 
				
			||||||
 | 
						if (!closure)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (closure == NULL || create_proxies(proxy, closure) < 0) {
 | 
						if (create_proxies(proxy, closure) < 0) {
 | 
				
			||||||
		fprintf(stderr, "Error demarshalling event\n");
 | 
							wl_closure_destroy(closure);
 | 
				
			||||||
		abort();
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (wl_list_empty(&proxy->queue->event_list))
 | 
						if (wl_list_empty(&proxy->queue->event_list))
 | 
				
			||||||
| 
						 | 
					@ -724,36 +754,60 @@ static int
 | 
				
			||||||
dispatch_queue(struct wl_display *display,
 | 
					dispatch_queue(struct wl_display *display,
 | 
				
			||||||
	       struct wl_event_queue *queue, int block)
 | 
						       struct wl_event_queue *queue, int block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int len, size, count;
 | 
						int len, size, count, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_lock(&display->mutex);
 | 
						pthread_mutex_lock(&display->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: Handle flush errors, EAGAIN... */
 | 
						if (display->last_error)
 | 
				
			||||||
	wl_connection_flush(display->connection);
 | 
							goto err_unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = wl_connection_flush(display->connection);
 | 
				
			||||||
 | 
						if (ret < 0 && errno != EAGAIN) {
 | 
				
			||||||
 | 
							display_fatal_error(display, errno);
 | 
				
			||||||
 | 
							goto err_unlock;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (block && wl_list_empty(&queue->event_list) &&
 | 
						if (block && wl_list_empty(&queue->event_list) &&
 | 
				
			||||||
	    pthread_equal(display->display_thread, pthread_self())) {
 | 
						    pthread_equal(display->display_thread, pthread_self())) {
 | 
				
			||||||
		len = wl_connection_read(display->connection);
 | 
							len = wl_connection_read(display->connection);
 | 
				
			||||||
		if (len == -1) {
 | 
							if (len == -1) {
 | 
				
			||||||
			pthread_mutex_unlock(&display->mutex);
 | 
								display_fatal_error(display, errno);
 | 
				
			||||||
			return -1;
 | 
								goto err_unlock;
 | 
				
			||||||
 | 
							} else if (len == 0) {
 | 
				
			||||||
 | 
								display_fatal_error(display, EPIPE);
 | 
				
			||||||
 | 
								goto err_unlock;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		while (len >= 8) {
 | 
							while (len >= 8) {
 | 
				
			||||||
			size = queue_event(display, len);
 | 
								size = queue_event(display, len);
 | 
				
			||||||
			if (size == 0)
 | 
								if (size == -1) {
 | 
				
			||||||
 | 
									display_fatal_error(display, errno);
 | 
				
			||||||
 | 
									goto err_unlock;
 | 
				
			||||||
 | 
								} else if (size == 0) {
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			len -= size;
 | 
								len -= size;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (block && wl_list_empty(&queue->event_list)) {
 | 
						} else if (block && wl_list_empty(&queue->event_list)) {
 | 
				
			||||||
		pthread_cond_wait(&queue->cond, &display->mutex);
 | 
							pthread_cond_wait(&queue->cond, &display->mutex);
 | 
				
			||||||
 | 
							if (display->last_error)
 | 
				
			||||||
 | 
								goto err_unlock;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (count = 0; !wl_list_empty(&queue->event_list); count++)
 | 
						for (count = 0; !wl_list_empty(&queue->event_list); count++) {
 | 
				
			||||||
		dispatch_event(display, queue);
 | 
							dispatch_event(display, queue);
 | 
				
			||||||
 | 
							if (display->last_error)
 | 
				
			||||||
 | 
								goto err_unlock;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_unlock(&display->mutex);
 | 
						pthread_mutex_unlock(&display->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return count;
 | 
						return count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_unlock:
 | 
				
			||||||
 | 
						errno = display->last_error;
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&display->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Dispatch events in an event queue
 | 
					/** Dispatch events in an event queue
 | 
				
			||||||
| 
						 | 
					@ -834,7 +888,14 @@ wl_display_flush(struct wl_display *display)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_lock(&display->mutex);
 | 
						pthread_mutex_lock(&display->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = wl_connection_flush(display->connection);
 | 
						if (display->last_error) {
 | 
				
			||||||
 | 
							errno = display->last_error;
 | 
				
			||||||
 | 
							ret = -1;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ret = wl_connection_flush(display->connection);
 | 
				
			||||||
 | 
							if (ret < 0 && errno != EAGAIN)
 | 
				
			||||||
 | 
								display_fatal_error(display, errno);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_unlock(&display->mutex);
 | 
						pthread_mutex_unlock(&display->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -121,7 +121,7 @@ int wl_display_dispatch_pending(struct wl_display *display);
 | 
				
			||||||
int wl_display_get_error(struct wl_display *display);
 | 
					int wl_display_get_error(struct wl_display *display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int wl_display_flush(struct wl_display *display);
 | 
					int wl_display_flush(struct wl_display *display);
 | 
				
			||||||
void wl_display_roundtrip(struct wl_display *display);
 | 
					int wl_display_roundtrip(struct wl_display *display);
 | 
				
			||||||
struct wl_event_queue *wl_display_create_queue(struct wl_display *display);
 | 
					struct wl_event_queue *wl_display_create_queue(struct wl_display *display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wl_log_set_handler_client(wl_log_func_t handler);
 | 
					void wl_log_set_handler_client(wl_log_func_t handler);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue