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 <[email protected]> --- src/wayland-client.c | 106 +++++++++++++++++++++++++++++++++++++++++---------- src/wayland-client.h | 2 +- 2 files changed, 87 insertions(+), 21 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index cd2f508..4e8f85a 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -79,6 +79,33 @@ struct wl_display { 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_queues, 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 wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display) { wl_list_init(&queue->event_list); @@ -266,9 +293,7 @@ display_handle_error(void *data, break; } - pthread_mutex_lock(&display->mutex); - display->last_error = err; - pthread_mutex_unlock(&display->mutex); + wl_display_fatal_error(display, err); } static void @@ -430,14 +455,21 @@ wl_display_disconnect(struct wl_display *display) wl_connection_destroy(display->connection); wl_map_release(&display->objects); wl_event_queue_release(&display->queue); - close(display->fd); + if (display->fd >= 0) + close(display->fd); free(display); } WL_EXPORT int wl_display_get_fd(struct wl_display *display) { - return display->fd; + int fd; + + pthread_mutex_lock(&display->mutex); + fd = display->fd; + pthread_mutex_unlock(&display->mutex); + + return fd; } static void @@ -453,17 +485,19 @@ static const struct wl_callback_listener sync_listener = { sync_callback }; -WL_EXPORT void +WL_EXPORT int wl_display_roundtrip(struct wl_display *display) { struct wl_callback *callback; - int done; + int done, ret = 0; done = 0; callback = wl_display_sync(display); wl_callback_add_listener(callback, &sync_listener, &done); - while (!done) - wl_display_dispatch(display); + while (!done && !ret) + ret = wl_display_dispatch(display); + + return ret; } static int @@ -529,10 +563,12 @@ queue_event(struct wl_display *display, int len) message = &proxy->object.interface->events[opcode]; closure = wl_connection_demarshal(display->connection, size, &display->objects, message); + if (!closure) + return -1; - if (closure == NULL || create_proxies(proxy, closure) < 0) { - fprintf(stderr, "Error demarshalling event\n"); - abort(); + if (create_proxies(proxy, closure) < 0) { + wl_closure_destroy(closure); + return -1; } if (wl_list_empty(&proxy->queue->event_list)) @@ -585,36 +621,59 @@ WL_EXPORT int wl_display_dispatch_queue(struct wl_display *display, struct wl_event_queue *queue) { - int len, size; + int len, size, ret; pthread_mutex_lock(&display->mutex); - /* FIXME: Handle flush errors, EAGAIN... */ - wl_connection_flush(display->connection); + if (display->last_error) + goto err_unlock; + + ret = wl_connection_flush(display->connection); + if (ret < 0 && errno != EAGAIN) { + display_fatal_error(display, errno); + goto err_unlock; + } if (wl_list_empty(&queue->event_list) && pthread_equal(display->display_thread, pthread_self())) { len = wl_connection_read(display->connection); if (len == -1) { - pthread_mutex_unlock(&display->mutex); - return -1; + display_fatal_error(display, errno); + goto err_unlock; + } else if (len == 0) { + display_fatal_error(display, EPIPE); + goto err_unlock; } while (len >= 8) { size = queue_event(display, len); - if (size == 0) + if (size == -1) { + display_fatal_error(display, errno); + goto err_unlock; + } else if (size == 0) { break; + } len -= size; } } else if (wl_list_empty(&queue->event_list)) { pthread_cond_wait(&queue->cond, &display->mutex); + if (display->last_error) + goto err_unlock; } - while (!wl_list_empty(&queue->event_list)) + while (!wl_list_empty(&queue->event_list)) { dispatch_event(display, queue); + if (display->last_error) + goto err_unlock; + } pthread_mutex_unlock(&display->mutex); return 0; + +err_unlock: + errno = display->last_error; + pthread_mutex_unlock(&display->mutex); + return -1; } WL_EXPORT int @@ -646,7 +705,14 @@ wl_display_flush(struct wl_display *display) 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); diff --git a/src/wayland-client.h b/src/wayland-client.h index 6fae273..637094c 100644 --- a/src/wayland-client.h +++ b/src/wayland-client.h @@ -63,7 +63,7 @@ int wl_display_dispatch_queue(struct wl_display *display, int wl_display_get_error(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); void wl_log_set_handler_client(wl_log_func_t handler); -- 1.7.12.2 _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
