commit adbbaabc265e354b7986b48815ee556f1a07769b
Author: David Goulet <dgoulet@efficios.com>
Date:   Thu Jun 6 12:37:01 2013 -0400

    Fix: sanitize wait queue in the dispatch thread
    
    This is to avoid memory leaks when the notify socket is never received
    thus cleaning the wait node for command socket that are invalid.
    
    Acked-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
    Signed-off-by: David Goulet <dgoulet@efficios.com>

diff --git a/src/bin/lttng-sessiond/lttng-sessiond.h b/src/bin/lttng-sessiond/lttng-sessiond.h
index a0916c5..7338805 100644
--- a/src/bin/lttng-sessiond/lttng-sessiond.h
+++ b/src/bin/lttng-sessiond/lttng-sessiond.h
@@ -66,6 +66,15 @@ struct ust_cmd_queue {
 };
 
 /*
+ * Use by the dispatch registration to queue UST command socket to wait for the
+ * notify socket.
+ */
+struct ust_reg_wait_node {
+	struct ust_app *app;
+	struct cds_list_head head;
+};
+
+/*
  * This pipe is used to inform the thread managing application notify
  * communication that a command is queued and ready to be processed.
  */
diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c
index 4470afc..add3be8 100644
--- a/src/bin/lttng-sessiond/main.c
+++ b/src/bin/lttng-sessiond/main.c
@@ -1334,6 +1334,85 @@ error:
 }
 
 /*
+ * Sanitize the wait queue of the dispatch registration thread meaning removing
+ * invalid nodes from it. This is to avoid memory leaks for the case the UST
+ * notify socket is never received.
+ */
+void sanitize_wait_queue(struct cds_list_head *wait_queue)
+{
+	int ret, nb_fd = 0, i;
+	unsigned int fd_added = 0;
+	struct lttng_poll_event events;
+	struct ust_reg_wait_node *wait_node = NULL, *tmp_wait_node;
+
+	assert(wait_queue);
+
+	lttng_poll_init(&events);
+
+	ret = lttng_poll_create(&events, 1, LTTNG_CLOEXEC);
+	if (ret < 0) {
+		goto error_create;
+	}
+
+	cds_list_for_each_entry_safe(wait_node, tmp_wait_node,
+			wait_queue, head) {
+		assert(wait_node->app);
+		ret = lttng_poll_add(&events, wait_node->app->sock,
+				LPOLLHUP | LPOLLERR);
+		if (ret < 0) {
+			goto error;
+		}
+
+		fd_added = 1;
+	}
+
+	if (!fd_added) {
+		goto end;
+	}
+
+	/*
+	 * Poll but don't block so we can quickly identify the faulty events and
+	 * clean them afterwards from the wait queue.
+	 */
+	ret = lttng_poll_wait(&events, 0);
+	if (ret < 0) {
+		goto error;
+	}
+	nb_fd = ret;
+
+	for (i = 0; i < nb_fd; i++) {
+		/* Get faulty FD. */
+		uint32_t revents = LTTNG_POLL_GETEV(&events, i);
+		int pollfd = LTTNG_POLL_GETFD(&events, i);
+
+		cds_list_for_each_entry_safe(wait_node, tmp_wait_node,
+				wait_queue, head) {
+			if (pollfd == wait_node->app->sock &&
+					(revents & (LPOLLHUP | LPOLLERR))) {
+				cds_list_del(&wait_node->head);
+				ust_app_destroy(wait_node->app);
+				free(wait_node);
+				break;
+			}
+		}
+	}
+
+	if (nb_fd > 0) {
+		DBG("Wait queue sanitized, %d node were cleaned up", nb_fd);
+	}
+
+end:
+	lttng_poll_clean(&events);
+	return;
+
+error:
+	lttng_poll_clean(&events);
+error_create:
+	ERR("Unable to sanitize wait queue");
+	return;
+}
+
+/*
  * Dispatch request from the registration threads to the application
  * communication thread.
  */
@@ -1342,10 +1421,7 @@ static void *thread_dispatch_ust_registration(void *data)
 	int ret;
 	struct cds_wfq_node *node;
 	struct ust_command *ust_cmd = NULL;
-	struct {
-		struct ust_app *app;
-		struct cds_list_head head;
-	} *wait_node = NULL, *tmp_wait_node;
+	struct ust_reg_wait_node *wait_node = NULL, *tmp_wait_node;
 
 	CDS_LIST_HEAD(wait_queue);
 
@@ -1355,6 +1431,13 @@ static void *thread_dispatch_ust_registration(void *data)
 		/* Atomically prepare the queue futex */
 		futex_nto1_prepare(&ust_cmd_queue.futex);
 
+		/*
+		 * Make sure we don't have node(s) that have hung up before receiving
+		 * the notify socket. This is to clean the list in order to avoid
+		 * memory leaks from notify socket that are never seen.
+		 */
+		sanitize_wait_queue(&wait_queue);
+
 		do {
 			struct ust_app *app = NULL;
 			ust_cmd = NULL;
diff --git a/src/bin/lttng-sessiond/ust-app.c b/src/bin/lttng-sessiond/ust-app.c
index 396ca93..00f3bcb 100644
--- a/src/bin/lttng-sessiond/ust-app.c
+++ b/src/bin/lttng-sessiond/ust-app.c
@@ -4795,3 +4795,15 @@ close_socket:
 		call_rcu(&obj->head, close_notify_sock_rcu);
 	}
 }
+
+/*
+ * Destroy a ust app data structure and free its memory.
+ */
+void ust_app_destroy(struct ust_app *app)
+{
+	if (!app) {
+		return;
+	}
+
+	call_rcu(&app->pid_n.head, delete_ust_app_rcu);
+}
diff --git a/src/bin/lttng-sessiond/ust-app.h b/src/bin/lttng-sessiond/ust-app.h
index 6e6ff02..30835e0 100644
--- a/src/bin/lttng-sessiond/ust-app.h
+++ b/src/bin/lttng-sessiond/ust-app.h
@@ -305,6 +305,7 @@ struct ust_app *ust_app_create(struct ust_register_msg *msg, int sock);
 void ust_app_notify_sock_unregister(int sock);
 ssize_t ust_app_push_metadata(struct ust_registry_session *registry,
 		struct consumer_socket *socket, int send_zero_data);
+void ust_app_destroy(struct ust_app *app);
 
 #else /* HAVE_LIBLTTNG_UST_CTL */
 
@@ -497,6 +498,11 @@ ssize_t ust_app_push_metadata(struct ust_registry_session *registry,
 {
 	return 0;
 }
+static inline
+void ust_app_destroy(struct ust_app *app)
+{
+	return;
+}
 
 #endif /* HAVE_LIBLTTNG_UST_CTL */
 
