+
+/*
+ * Delete session from the given hash table.
+ *
+ * Return lttng ht del error code being 0 on success and 1 on failure.
+ */
+int session_delete(struct lttng_ht *ht, struct relay_session *session)
+{
+ struct lttng_ht_iter iter;
+
+ assert(ht);
+ assert(session);
+
+ iter.iter.node = &session->session_n.node;
+ return lttng_ht_del(ht, &iter);
+}
+
+/*
+ * The caller MUST be from the viewer thread since the viewer refcount is
+ * decremented. With this calue down to 0, it will try to destroy the session.
+ */
+void session_viewer_try_destroy(struct lttng_ht *ht,
+ struct relay_session *session)
+{
+ unsigned long ret_ref;
+
+ assert(session);
+
+ ret_ref = uatomic_add_return(&session->viewer_refcount, -1);
+ if (ret_ref == 0) {
+ session_try_destroy(ht, session);
+ }
+}
+
+/*
+ * Should only be called from the main streaming thread since it does not touch
+ * the viewer refcount. If this refcount is down to 0, destroy the session only
+ * and only if the session deletion succeeds. This is done because the viewer
+ * *and* the streaming thread can both concurently try to destroy the session
+ * thus the first come first serve.
+ */
+void session_try_destroy(struct lttng_ht *ht, struct relay_session *session)
+{
+ int ret = 0;
+ unsigned long ret_ref;
+
+ assert(session);
+
+ ret_ref = uatomic_read(&session->viewer_refcount);
+ if (ret_ref == 0 && session->close_flag) {
+ if (ht) {
+ ret = session_delete(ht, session);
+ }
+ if (!ret) {
+ /* Only destroy the session if the deletion was successful. */
+ session_destroy(session);
+ }
+ }
+}
+
+/*
+ * Destroy a session object.
+ *
+ * This function must *NOT* be called with an RCU read lock held since
+ * the session's ctf_traces_ht is destroyed.
+ */
+void session_destroy(struct relay_session *session)
+{
+ struct ctf_trace *ctf_trace;
+ struct lttng_ht_iter iter;
+
+ assert(session);
+
+ DBG("Relay destroying session %" PRIu64, session->id);
+
+ /*
+ * Empty the ctf trace hash table which will destroy the stream contained
+ * in that table.
+ */
+ rcu_read_lock();
+ cds_lfht_for_each_entry(session->ctf_traces_ht->ht, &iter.iter, ctf_trace,
+ node.node) {
+ ctf_trace_delete(session->ctf_traces_ht, ctf_trace);
+ ctf_trace_destroy(ctf_trace);
+ }
+ rcu_read_unlock();
+ lttng_ht_destroy(session->ctf_traces_ht);
+
+ call_rcu(&session->rcu_node, rcu_destroy_session);
+}