mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-11-04 13:29:51 -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,6 +574,7 @@ 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);
|
||||||
|
if (display->fd > 0)
|
||||||
close(display->fd);
|
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);
|
||||||
|
|
||||||
|
if (display->last_error) {
|
||||||
|
errno = display->last_error;
|
||||||
|
ret = -1;
|
||||||
|
} else {
|
||||||
ret = wl_connection_flush(display->connection);
|
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