client: Split event handling into demarshal and dispatch steps
authorKristian Høgsberg <krh@bitplanet.net>
Thu, 4 Oct 2012 21:34:18 +0000 (17:34 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Thu, 11 Oct 2012 00:59:00 +0000 (20:59 -0400)
This lets us demarshal with a mutex held and then do dispatching after
releasing the mutex.

src/wayland-client.c
src/wayland-private.h

index 9283985..2265ed6 100644 (file)
@@ -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)
-                       break;
-               
-               wl_connection_copy(display->connection, p, sizeof p);
-               object = p[0];
-               opcode = p[1] & 0xffff;
-               size = p[1] >> 16;
-               if (len < size)
+       wl_list_init(&list);
+       while (len >= 8) {
+               size = queue_event(display, len, &list);
+               if (size == 0)
                        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;
 }
 
index 15e4bd0..9c743e4 100644 (file)
@@ -73,6 +73,7 @@ struct wl_closure {
        ffi_cif cif;
        void *args[20];
        uint32_t *start;
+       struct wl_list link;
        uint32_t buffer[0];
 };