From ce1f4c29ab9d5c2a34335ef252a1d0ad977df636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Thu, 4 Oct 2012 17:34:18 -0400 Subject: [PATCH] client: Split event handling into demarshal and dispatch steps This lets us demarshal with a mutex held and then do dispatching after releasing the mutex. --- src/wayland-client.c | 68 ++++++++++++++++++++++++++++++------------- src/wayland-private.h | 1 + 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 9283985f..2265ed6b 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -499,22 +499,29 @@ create_proxies(struct wl_display *display, struct wl_closure *closure) return 0; } -static void -handle_event(struct wl_display *display, - uint32_t id, uint32_t opcode, uint32_t size) +static int +queue_event(struct wl_display *display, int len, struct wl_list *list) { + uint32_t p[2], id; + int opcode, size; struct wl_proxy *proxy; struct wl_closure *closure; const struct wl_message *message; - proxy = wl_map_lookup(&display->objects, id); + wl_connection_copy(display->connection, p, sizeof p); + id = p[0]; + opcode = p[1] & 0xffff; + size = p[1] >> 16; + if (len < size) + return 0; + proxy = wl_map_lookup(&display->objects, id); if (proxy == WL_ZOMBIE_OBJECT) { wl_connection_consume(display->connection, size); - return; + return size; } else if (proxy == NULL || proxy->object.implementation == NULL) { wl_connection_consume(display->connection, size); - return; + return size; } message = &proxy->object.interface->events[opcode]; @@ -529,40 +536,61 @@ handle_event(struct wl_display *display, abort(); } + wl_list_insert(list->prev, &closure->link); + + return size; +} + +static void +dispatch_event(struct wl_display *display, struct wl_closure *closure) +{ + struct wl_proxy *proxy; + uint32_t id; + int opcode; + + wl_list_remove(&closure->link); + id = closure->buffer[0]; + opcode = closure->buffer[1] & 0xffff; + + proxy = wl_map_lookup(&display->objects, id); + if (proxy == WL_ZOMBIE_OBJECT) + goto skip; + wl_closure_invoke(closure, &proxy->object, proxy->object.implementation[opcode], proxy->user_data); - + skip: wl_closure_destroy(closure); } WL_EXPORT int wl_display_dispatch(struct wl_display *display) { - uint32_t p[2], object; - int len, opcode, size; + struct wl_list list; + struct wl_closure *closure; + int len, size; /* FIXME: Handle flush errors, EAGAIN... */ wl_display_flush(display); /* FIXME: Shouldn't always read here... */ len = wl_connection_read(display->connection); + if (len == -1) + return -1; - while (len > 0) { - if ((size_t) len < sizeof p) + wl_list_init(&list); + while (len >= 8) { + size = queue_event(display, len, &list); + if (size == 0) break; - - wl_connection_copy(display->connection, p, sizeof p); - object = p[0]; - opcode = p[1] & 0xffff; - size = p[1] >> 16; - if (len < size) - break; - - handle_event(display, object, opcode, size); len -= size; } + while (!wl_list_empty(&list)) { + closure = container_of(list.next, struct wl_closure, link); + dispatch_event(display, closure); + } + return len; } diff --git a/src/wayland-private.h b/src/wayland-private.h index 15e4bd02..9c743e40 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -73,6 +73,7 @@ struct wl_closure { ffi_cif cif; void *args[20]; uint32_t *start; + struct wl_list link; uint32_t buffer[0]; };