[PATCH wayland v4 08/11] client: Replace the singleton zombie with bespoke zombies

Daniel Stone daniels at collabora.com
Thu Dec 28 19:53:54 UTC 2017


From: Derek Foreman <derekf at osg.samsung.com>

Using the singleton zombie object doesn't allow us to posthumously retain
object interface information, which makes it difficult to properly inter
future events destined for the recently deceased proxy.

Notably, this makes it impossible for zombie proxy destined file
descriptors to be properly consumed.

When we create a proxy, we now create a zombie-state object to hold
information about the file descriptors in events it can receive. This
will allow us, in a future patch, to close those FDs.

[daniels: Split Derek's patch into a few smaller ones.]

Signed-off-by: Derek Foreman <derekf at osg.samsung.com>
Reviewed-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Daniel Stone <daniels at collabora.com>
---
 src/wayland-client.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 78 insertions(+), 4 deletions(-)

diff --git a/src/wayland-client.c b/src/wayland-client.c
index 987418a1..62d4f222 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -55,6 +55,11 @@ enum wl_proxy_flag {
 	WL_PROXY_FLAG_WRAPPER = (1 << 2),
 };
 
+struct wl_zombie {
+	int event_count;
+	int *fd_count;
+};
+
 struct wl_proxy {
 	struct wl_object object;
 	struct wl_display *display;
@@ -350,6 +355,66 @@ wl_display_create_queue(struct wl_display *display)
 	return queue;
 }
 
+static int
+message_count_fds(const char *signature)
+{
+	unsigned int count, i, fds = 0;
+	struct argument_details arg;
+
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+		if (arg.type == 'h')
+			fds++;
+	}
+
+	return fds;
+}
+
+static struct wl_zombie *
+prepare_zombie(struct wl_proxy *proxy)
+{
+	const struct wl_interface *interface = proxy->object.interface;
+	const struct wl_message *message;
+	int i, count;
+	struct wl_zombie *zombie = NULL;
+
+	/* If we hit an event with an FD, ensure we have a zombie object and
+	 * fill the fd_count slot for that event with the number of FDs for
+	 * that event. Interfaces with no events containing FDs will not have
+	 * zombie objects created. */
+	for (i = 0; i < interface->event_count; i++) {
+		message = &interface->events[i];
+		count = message_count_fds(message->signature);
+
+		if (!count)
+			continue;
+
+		if (!zombie) {
+			zombie = zalloc(sizeof(*zombie) +
+				        (interface->event_count * sizeof(int)));
+			if (!zombie)
+				return NULL;
+
+			zombie->event_count = interface->event_count;
+			zombie->fd_count = (int *) &zombie[1];
+		}
+
+		zombie->fd_count[i] = count;
+	}
+
+	return zombie;
+}
+
+static enum wl_iterator_result
+free_zombies(void *element, void *data, uint32_t flags)
+{
+	if (flags & WL_MAP_ENTRY_ZOMBIE)
+		free(element);
+
+	return WL_ITERATOR_CONTINUE;
+}
+
 static struct wl_proxy *
 proxy_create(struct wl_proxy *factory, const struct wl_interface *interface,
 	     uint32_t version)
@@ -434,10 +499,14 @@ proxy_destroy(struct wl_proxy *proxy)
 	if (proxy->flags & WL_PROXY_FLAG_ID_DELETED) {
 		wl_map_remove(&proxy->display->objects, proxy->object.id);
 	} else if (proxy->object.id < WL_SERVER_ID_START) {
+		struct wl_zombie *zombie = prepare_zombie(proxy);
+
+		/* The map now contains the zombie entry, until the delete_id
+		 * event arrives. */
 		wl_map_insert_at(&proxy->display->objects,
 				 WL_MAP_ENTRY_ZOMBIE,
 				 proxy->object.id,
-				 NULL);
+				 zombie);
 	} else {
 		wl_map_insert_at(&proxy->display->objects, 0,
 				 proxy->object.id, NULL);
@@ -860,12 +929,16 @@ display_handle_delete_id(void *data, struct wl_display *display, uint32_t id)
 
 	proxy = wl_map_lookup(&display->objects, id);
 
-	if (wl_object_is_zombie(&display->objects, id))
+	if (wl_object_is_zombie(&display->objects, id)) {
+		/* For zombie objects, the 'proxy' is actually the zombie
+		 * event-information structure, which we can free. */
+		free(proxy);
 		wl_map_remove(&display->objects, id);
-	else if (proxy)
+	} else if (proxy) {
 		proxy->flags |= WL_PROXY_FLAG_ID_DELETED;
-	else
+	} else {
 		wl_log("error: received delete_id for unknown id (%u)\n", id);
+	}
 
 	pthread_mutex_unlock(&display->mutex);
 }
@@ -1087,6 +1160,7 @@ WL_EXPORT void
 wl_display_disconnect(struct wl_display *display)
 {
 	wl_connection_destroy(display->connection);
+	wl_map_for_each(&display->objects, free_zombies, NULL);
 	wl_map_release(&display->objects);
 	wl_event_queue_release(&display->default_queue);
 	wl_event_queue_release(&display->display_queue);
-- 
2.14.3



More information about the wayland-devel mailing list