+static
+void session_release(struct urcu_ref *ref)
+{
+ int ret;
+ struct ltt_ust_session *usess;
+ struct ltt_kernel_session *ksess;
+ struct ltt_session *session = container_of(ref, typeof(*session), ref);
+
+ usess = session->ust_session;
+ ksess = session->kernel_session;
+
+ /* Clean kernel session teardown */
+ kernel_destroy_session(ksess);
+
+ /* UST session teardown */
+ if (usess) {
+ /* Close any relayd session */
+ consumer_output_send_destroy_relayd(usess->consumer);
+
+ /* Destroy every UST application related to this session. */
+ ret = ust_app_destroy_trace_all(usess);
+ if (ret) {
+ ERR("Error in ust_app_destroy_trace_all");
+ }
+
+ /* Clean up the rest. */
+ trace_ust_destroy_session(usess);
+ }
+
+ /*
+ * Must notify the kernel thread here to update it's poll set in order to
+ * remove the channel(s)' fd just destroyed.
+ */
+ ret = notify_thread_pipe(kernel_poll_pipe[1]);
+ if (ret < 0) {
+ PERROR("write kernel poll pipe");
+ }
+
+ DBG("Destroying session %s (id %" PRIu64 ")", session->name, session->id);
+ pthread_mutex_destroy(&session->lock);
+
+ consumer_output_put(session->consumer);
+ snapshot_destroy(&session->snapshot);
+
+ ASSERT_LOCKED(ltt_session_list.lock);
+ del_session_list(session);
+ del_session_ht(session);
+ pthread_cond_broadcast(<t_session_list.removal_cond);
+ free(session);
+}
+
+/*
+ * Acquire a reference to a session.
+ * This function may fail (return false); its return value must be checked.
+ */
+bool session_get(struct ltt_session *session)
+{
+ return urcu_ref_get_unless_zero(&session->ref);
+}
+
+/*
+ * Release a reference to a session.
+ */
+void session_put(struct ltt_session *session)
+{
+ /*
+ * The session list lock must be held as any session_put()
+ * may cause the removal of the session from the session_list.
+ */
+ ASSERT_LOCKED(ltt_session_list.lock);
+ assert(session->ref.refcount);
+ urcu_ref_put(&session->ref, session_release);
+}
+
+/*
+ * Destroy a session.
+ *
+ * This method does not immediately release/free the session as other
+ * components may still hold a reference to the session. However,
+ * the session should no longer be presented to the user.
+ *
+ * Releases the session list's reference to the session
+ * and marks it as destroyed. Iterations on the session list should be
+ * mindful of the "destroyed" flag.
+ */
+void session_destroy(struct ltt_session *session)
+{
+ assert(!session->destroyed);
+ session->destroyed = true;
+ session_put(session);
+}
+