[PATCH 2/8] client: Split event handling into demarshal and dispatch steps

Kristian Høgsberg krh at bitplanet.net
Tue Oct 9 19:37:59 PDT 2012


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 9283985..2265ed6 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)
-			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;
 }
 
diff --git a/src/wayland-private.h b/src/wayland-private.h
index 15e4bd0..9c743e4 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];
 };
 
-- 
1.7.10.2



More information about the wayland-devel mailing list