From 8a191daa297088133b9452a5fda7f2b3f207b2ba Mon Sep 17 00:00:00 2001
From: Jakob Bornecrantz <jakob@collabora.com>
Date: Tue, 27 Apr 2021 20:16:09 +0100
Subject: [PATCH] ipc: Add session_destroy to handle session destruction

---
 src/xrt/ipc/client/ipc_client_compositor.c    |  4 ++
 src/xrt/ipc/server/ipc_server.h               |  7 +++
 src/xrt/ipc/server/ipc_server_handler.c       | 18 ++++++++
 .../ipc/server/ipc_server_per_client_thread.c | 43 ++++++++++++-------
 src/xrt/ipc/shared/proto.json                 |  2 +
 5 files changed, 58 insertions(+), 16 deletions(-)

diff --git a/src/xrt/ipc/client/ipc_client_compositor.c b/src/xrt/ipc/client/ipc_client_compositor.c
index 136b62ae5..2cd3d916b 100644
--- a/src/xrt/ipc/client/ipc_client_compositor.c
+++ b/src/xrt/ipc/client/ipc_client_compositor.c
@@ -662,6 +662,10 @@ ipc_compositor_destroy(struct xrt_compositor *xc)
 
 	assert(icc->compositor_created);
 
+	IPC_ERROR(icc->ipc_c, "Called");
+
+	IPC_CALL_CHK(ipc_call_session_destroy(icc->ipc_c));
+
 	icc->compositor_created = false;
 }
 
diff --git a/src/xrt/ipc/server/ipc_server.h b/src/xrt/ipc/server/ipc_server.h
index 422f9640e..f5296533a 100644
--- a/src/xrt/ipc/server/ipc_server.h
+++ b/src/xrt/ipc/server/ipc_server.h
@@ -374,6 +374,13 @@ ipc_server_update_state(struct ipc_server *s);
 void *
 ipc_server_client_thread(void *_cs);
 
+/*!
+ * This destroyes the native compositor for this client and any extra objects
+ * created from it, like all of the swapchains.
+ */
+void
+ipc_server_client_destroy_compositor(volatile struct ipc_client_state *ics);
+
 /*!
  * @defgroup ipc_server_internals Server Internals
  * @brief These are only called by the platform-specific mainloop polling code.
diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c
index 2ce9f94fb..5b3e786dc 100644
--- a/src/xrt/ipc/server/ipc_server_handler.c
+++ b/src/xrt/ipc/server/ipc_server_handler.c
@@ -103,6 +103,10 @@ ipc_handle_session_create(volatile struct ipc_client_state *ics, const struct xr
 
 	struct xrt_compositor_native *xcn = NULL;
 
+	if (ics->xc != NULL) {
+		return XRT_ERROR_IPC_SESSION_ALREADY_CREATED;
+	}
+
 	xrt_result_t xret = xrt_syscomp_create_native_compositor(ics->server->xsysc, xsi, &xcn);
 	if (xret != XRT_SUCCESS) {
 		return xret;
@@ -144,6 +148,20 @@ ipc_handle_session_end(volatile struct ipc_client_state *ics)
 	return xrt_comp_end_session(ics->xc);
 }
 
+xrt_result_t
+ipc_handle_session_destroy(volatile struct ipc_client_state *ics)
+{
+	IPC_TRACE_MARKER();
+
+	if (ics->xc == NULL) {
+		return XRT_ERROR_IPC_SESSION_NOT_CREATED;
+	}
+
+	ipc_server_client_destroy_compositor(ics);
+
+	return XRT_SUCCESS;
+}
+
 xrt_result_t
 ipc_handle_compositor_get_info(volatile struct ipc_client_state *ics, struct xrt_compositor_info *out_info)
 {
diff --git a/src/xrt/ipc/server/ipc_server_per_client_thread.c b/src/xrt/ipc/server/ipc_server_per_client_thread.c
index 047641ed0..adafec590 100644
--- a/src/xrt/ipc/server/ipc_server_per_client_thread.c
+++ b/src/xrt/ipc/server/ipc_server_per_client_thread.c
@@ -124,12 +124,37 @@ client_loop(volatile struct ipc_client_state *ics)
 
 	ipc_message_channel_close((struct ipc_message_channel *)&ics->imc);
 
-	ics->num_swapchains = 0;
-
 	ics->server->threads[ics->server_thread_index].state = IPC_THREAD_STOPPING;
 	ics->server_thread_index = -1;
 	memset((void *)&ics->client_state, 0, sizeof(struct ipc_app_state));
 
+	os_mutex_unlock(&ics->server->global_state.lock);
+
+	ipc_server_client_destroy_compositor(ics);
+
+	// Should we stop the server when a client disconnects?
+	if (ics->server->exit_on_disconnect) {
+		ics->server->running = false;
+	}
+
+	ipc_server_deactivate_session(ics);
+}
+
+
+/*
+ *
+ * 'Exported' functions.
+ *
+ */
+
+void
+ipc_server_client_destroy_compositor(volatile struct ipc_client_state *ics)
+{
+	// Multiple threads might be looking at these fields.
+	os_mutex_lock(&ics->server->global_state.lock);
+
+	ics->num_swapchains = 0;
+
 	// Destroy all swapchains now.
 	for (uint32_t j = 0; j < IPC_MAX_CLIENT_SWAPCHAINS; j++) {
 		// Drop our reference, does NULL checking. Cast away volatile.
@@ -142,22 +167,8 @@ client_loop(volatile struct ipc_client_state *ics)
 
 	// Cast away volatile.
 	xrt_comp_destroy((struct xrt_compositor **)&ics->xc);
-
-	// Should we stop the server when a client disconnects?
-	if (ics->server->exit_on_disconnect) {
-		ics->server->running = false;
-	}
-
-	ipc_server_deactivate_session(ics);
 }
 
-
-/*
- *
- * Entry point.
- *
- */
-
 void *
 ipc_server_client_thread(void *_ics)
 {
diff --git a/src/xrt/ipc/shared/proto.json b/src/xrt/ipc/shared/proto.json
index d069e39cd..8b27e7415 100644
--- a/src/xrt/ipc/shared/proto.json
+++ b/src/xrt/ipc/shared/proto.json
@@ -66,6 +66,8 @@
 
 	"session_end": {},
 
+	"session_destroy": {},
+
 	"compositor_get_info": {
 		"out": [
 			{"name": "info", "type": "struct xrt_compositor_info"}