[tipc] Rework how IPC chan handles gets destroyed

Stop registering shutdown callback for ports and channels.
Instead invoke corresponding shutdown code when last
reference to handle goes away. This way, handle_close is
effectively just decrements handle ref. Stop using handle_close
in favor of handle_decref where appropriate.

Change-Id: I8dff9182bc886f1187cb43c8320ae2c5400eeaee
diff --git a/lib/trusty/include/lib/trusty/ipc.h b/lib/trusty/include/lib/trusty/ipc.h
index 3d25f83..9947ee2 100644
--- a/lib/trusty/include/lib/trusty/ipc.h
+++ b/lib/trusty/include/lib/trusty/ipc.h
@@ -39,7 +39,6 @@
 enum {
 	IPC_PORT_STATE_INVALID		= 0,
 	IPC_PORT_STATE_LISTENING	= 1,
-	IPC_PORT_STATE_CLOSING		= 2,
 };
 
 enum {
diff --git a/lib/trusty/ipc.c b/lib/trusty/ipc.c
index 59fe72a..816f58a 100644
--- a/lib/trusty/ipc.c
+++ b/lib/trusty/ipc.c
@@ -60,7 +60,6 @@
 static void port_handle_destroy(handle_t *handle);
 
 static uint32_t chan_poll(handle_t *handle, uint32_t emask, bool finalize);
-static void chan_shutdown(handle_t *handle);
 static void chan_handle_destroy(handle_t *handle);
 
 static ipc_port_t *port_find_locked(const char *path);
@@ -71,13 +70,11 @@
 
 static struct handle_ops ipc_port_handle_ops = {
 	.poll		= port_poll,
-	.shutdown	= port_shutdown,
 	.destroy	= port_handle_destroy,
 };
 
 static struct handle_ops ipc_chan_handle_ops = {
 	.poll		= chan_poll,
-	.shutdown	= chan_shutdown,
 	.destroy	= chan_handle_destroy,
 };
 
@@ -174,13 +171,9 @@
 
 	LTRACEF("shutting down port %p\n", port);
 
-	/* change status to closing  */
-	port->state = IPC_PORT_STATE_CLOSING;
-
 	/* detach it from global list if it is in the list */
 	if (list_in_list(&port->node)) {
 		list_delete(&port->node);
-		handle_decref(phandle);
 	}
 
 	/* tear down pending connections */
@@ -195,11 +188,6 @@
 		/* remove connection from the list */
 		list_delete(&server->node);
 		chan_del_ref(server, &server->node_ref); /* drop list ref */
-
-		/* decrement usage count on port as pending connection
-		   is gone
-		 */
-		handle_decref(phandle);
 	}
 
 	mutex_release(&ipc_lock);
@@ -215,6 +203,9 @@
 	ASSERT(phandle);
 	ASSERT(ipc_is_port(phandle));
 
+	/* invoke port shutdown first */
+	port_shutdown(phandle);
+
 	ipc_port_t *port = containerof(phandle, ipc_port_t, handle);
 
 	/* pending list should be empty and
@@ -250,7 +241,6 @@
 	} else {
 		port->state = IPC_PORT_STATE_LISTENING;
 		list_add_tail(&ipc_port_list, &port->node);
-		handle_incref(&port->handle); /* and inc usage count */
 
 		/* go through pending connection list and pick those we can handle */
 		ipc_chan_t *client, *temp;
@@ -489,29 +479,16 @@
 	}
 }
 
-/*
- *  Called when caller closes handle.
- */
-static void chan_shutdown(handle_t *chandle)
-{
-	DEBUG_ASSERT(chandle);
-	DEBUG_ASSERT(ipc_is_channel(chandle));
-
-	mutex_acquire(&ipc_lock);
-
-	ipc_chan_t *chan = containerof(chandle, ipc_chan_t, handle);
-
-	chan_shutdown_locked(chan);
-
-	mutex_release(&ipc_lock);
-}
-
 static void chan_handle_destroy(handle_t *chandle)
 {
 	DEBUG_ASSERT(chandle);
 	DEBUG_ASSERT(ipc_is_channel(chandle));
 
 	ipc_chan_t *chan = containerof(chandle, ipc_chan_t, handle);
+
+	mutex_acquire(&ipc_lock);
+	chan_shutdown_locked(chan);
+	mutex_release(&ipc_lock);
 	chan_del_ref(chan, &chan->handle_ref);
 }
 
@@ -651,9 +628,6 @@
 	chan_add_ref(server, &server->node_ref);
 	list_add_tail(&port->pending_list, &server->node);
 
-	/* bump a ref to the port while there's a pending connection */
-	handle_incref(&port->handle);
-
 	/* Notify port that there is a pending connection */
 	handle_notify(&port->handle);
 
@@ -790,21 +764,21 @@
 
 		if (ret < 0) {
 			/* timeout or other error */
-			handle_close(chandle);
+			handle_decref(chandle);
 			return ret;
 		}
 
 		if ((event & IPC_HANDLE_POLL_HUP) &&
 		    !(event & IPC_HANDLE_POLL_MSG)) {
 			/* hangup and no pending messages */
-			handle_close(chandle);
+			handle_decref(chandle);
 			return ERR_CHANNEL_CLOSED;
 		}
 
 		if (!(event & IPC_HANDLE_POLL_READY)) {
 			/* not connected */
 			TRACEF("Unexpected channel state: event = 0x%x\n", event);
-			handle_close(chandle);
+			handle_decref(chandle);
 			return ERR_NOT_READY;
 		}
 	}
@@ -812,7 +786,7 @@
 	ret = uctx_handle_install(ctx, chandle, &handle_id);
 	if (ret != NO_ERROR) {
 		/* Failed to install handle into user context */
-		handle_close(chandle);
+		handle_decref(chandle);
 		return (long) ret;
 	}
 
@@ -868,9 +842,6 @@
 	chan_add_ref(server, &tmp_server_ref);  /* add local ref */
 	chan_del_ref(server, &server->node_ref);  /* drop list ref */
 
-	/* drop the ref to port we took in connect() */
-	handle_decref(&port->handle);
-
 	client = server->peer;
 
 	/* there must be a client, it must be in CONNECTING state and
@@ -941,7 +912,7 @@
 err_uuid_copy:
 	uctx_handle_remove(ctx, new_id, NULL);
 err_install:
-	handle_close(chandle);
+	handle_decref(chandle);
 err_accept:
 	handle_decref(phandle);
 	return (long) ret;
diff --git a/lib/trusty/tipc_dev.c b/lib/trusty/tipc_dev.c
index 91bcff3..2e60a0c 100644
--- a/lib/trusty/tipc_dev.c
+++ b/lib/trusty/tipc_dev.c
@@ -308,7 +308,7 @@
 		local = alloc_local_addr(dev, remote, chan);
 		if (local == 0) {
 			LTRACEF("failed to alloc local address\n");
-			handle_close(chan);
+			handle_decref(chan);
 			chan = NULL;
 		}
 		mutex_release(&dev->ept_lock);
@@ -371,7 +371,7 @@
 			handle_set_cookie(chan, NULL);
 
 			/* close handle */
-			handle_close(chan);
+			handle_decref(chan);
 		}
 
 		free_local_addr(dev, ept_to_addr(dev, ept));
@@ -672,7 +672,7 @@
 		handle_set_cookie(chan, NULL);
 
 		/* close it */
-		handle_close(chan);
+		handle_decref(chan);
 
 		/* free_local_address */
 		free_local_addr(dev, local);
@@ -810,7 +810,7 @@
 
 		handle_list_del(&dev->handle_list, ept->chan);
 		handle_set_cookie(ept->chan, NULL);
-		handle_close(ept->chan);
+		handle_decref(ept->chan);
 		free_local_addr(dev, ept_to_addr(dev, ept));
 	}
 	mutex_release(&dev->ept_lock);