aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@googlemail.com>2012-10-11 23:37:53 +0200
committerKristian Høgsberg <krh@bitplanet.net>2012-10-15 19:23:40 -0400
commit33b7637b4500a682018b503837b8aca9afae36f2 (patch)
tree8b124afc61f6212eb9b815c547093de5e5fd8875 /src
parentwayland: Take ownership of fd in wl_display_connect_to_fd() (diff)
downloadwayland-33b7637b4500a682018b503837b8aca9afae36f2.tar
wayland-33b7637b4500a682018b503837b8aca9afae36f2.tar.gz
wayland-33b7637b4500a682018b503837b8aca9afae36f2.tar.bz2
wayland-33b7637b4500a682018b503837b8aca9afae36f2.tar.lz
wayland-33b7637b4500a682018b503837b8aca9afae36f2.tar.xz
wayland-33b7637b4500a682018b503837b8aca9afae36f2.tar.zst
wayland-33b7637b4500a682018b503837b8aca9afae36f2.zip
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>
Diffstat (limited to 'src')
-rw-r--r--src/wayland-client.c99
-rw-r--r--src/wayland-client.h2
2 files changed, 81 insertions, 20 deletions
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 4013277..471abf3 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -84,6 +84,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_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
wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display)
{
wl_list_init(&queue->event_list);
@@ -358,9 +385,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
@@ -549,7 +574,8 @@ wl_display_disconnect(struct wl_display *display)
wl_map_release(&display->objects);
wl_event_queue_release(&display->queue);
pthread_mutex_destroy(&display->mutex);
- close(display->fd);
+ if (display->fd > 0)
+ close(display->fd);
free(display);
}
@@ -592,17 +618,19 @@ static const struct wl_callback_listener sync_listener = {
*
* \memberof wl_display
*/
-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
@@ -668,10 +696,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))
@@ -724,36 +754,60 @@ static int
dispatch_queue(struct wl_display *display,
struct wl_event_queue *queue, int block)
{
- int len, size, count;
+ int len, size, count, 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 (block && 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 (block && wl_list_empty(&queue->event_list)) {
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);
+ if (display->last_error)
+ goto err_unlock;
+ }
pthread_mutex_unlock(&display->mutex);
return count;
+
+err_unlock:
+ errno = display->last_error;
+ pthread_mutex_unlock(&display->mutex);
+
+ return -1;
}
/** Dispatch events in an event queue
@@ -834,7 +888,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 82e7cc9..fb9c952 100644
--- a/src/wayland-client.h
+++ b/src/wayland-client.h
@@ -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_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);