Use compiler-agnostic defines to silence warning
[lttng-tools.git] / src / bin / lttng-sessiond / session.cpp
index 1846024fcc60670d505a740db81125c7ec1e0aec..8d6bc5c37ed574a18ac6792b674e7337e39f8106 100644 (file)
@@ -6,6 +6,25 @@
  */
 
 #define _LGPL_SOURCE
  */
 
 #define _LGPL_SOURCE
+#include "buffer-registry.hpp"
+#include "cmd.hpp"
+#include "kernel.hpp"
+#include "lttng-sessiond.hpp"
+#include "session.hpp"
+#include "timer.hpp"
+#include "trace-ust.hpp"
+#include "ust-app.hpp"
+#include "utils.hpp"
+
+#include <common/common.hpp>
+#include <common/ctl/format.hpp>
+#include <common/sessiond-comm/sessiond-comm.hpp>
+#include <common/trace-chunk.hpp>
+#include <common/urcu.hpp>
+#include <common/utils.hpp>
+
+#include <lttng/location-internal.hpp>
+
 #include <dirent.h>
 #include <inttypes.h>
 #include <limits.h>
 #include <dirent.h>
 #include <inttypes.h>
 #include <limits.h>
 #include <sys/types.h>
 #include <urcu.h>
 
 #include <sys/types.h>
 #include <urcu.h>
 
-#include <common/common.hpp>
-#include <common/sessiond-comm/sessiond-comm.hpp>
-#include <common/trace-chunk.hpp>
-#include <common/urcu.hpp>
-#include <common/utils.hpp>
-
-#include "lttng-sessiond.hpp"
-#include <lttng/location-internal.hpp>
-
-#include "cmd.hpp"
-#include "kernel.hpp"
-#include "session.hpp"
-#include "timer.hpp"
-#include "trace-ust.hpp"
-#include "utils.hpp"
-
 namespace {
 struct ltt_session_destroy_notifier_element {
        ltt_session_destroy_notifier notifier;
 namespace {
 struct ltt_session_destroy_notifier_element {
        ltt_session_destroy_notifier notifier;
@@ -59,21 +62,77 @@ namespace ls = lttng::sessiond;
 const char *forbidden_name_chars = "/";
 
 /* Global hash table to keep the sessions, indexed by id. */
 const char *forbidden_name_chars = "/";
 
 /* Global hash table to keep the sessions, indexed by id. */
-struct lttng_ht *ltt_sessions_ht_by_id = NULL;
+struct lttng_ht *ltt_sessions_ht_by_id = nullptr;
 /* Global hash table to keep the sessions, indexed by name. */
 /* Global hash table to keep the sessions, indexed by name. */
-struct lttng_ht *ltt_sessions_ht_by_name = NULL;
+struct lttng_ht *ltt_sessions_ht_by_name = nullptr;
 
 /*
  * Init tracing session list.
  *
  * Please see session.h for more explanation and correct usage of the list.
  */
 
 /*
  * Init tracing session list.
  *
  * Please see session.h for more explanation and correct usage of the list.
  */
-struct ltt_session_list the_session_list = {
-       .lock = PTHREAD_MUTEX_INITIALIZER,
-       .removal_cond = PTHREAD_COND_INITIALIZER,
-       .next_uuid = 0,
-       .head = CDS_LIST_HEAD_INIT(the_session_list.head),
-};
+struct ltt_session_list the_session_list;
+
+/*
+ * Return a ltt_session structure ptr that matches name. If no session found,
+ * NULL is returned. This must be called with the session list lock held using
+ * session_lock_list and session_unlock_list.
+ * A reference to the session is implicitly acquired by this function.
+ */
+struct ltt_session *session_find_by_name(const char *name)
+{
+       struct ltt_session *session_to_return;
+
+       LTTNG_ASSERT(name);
+       ASSERT_SESSION_LIST_LOCKED();
+
+       DBG2("Trying to find session by name %s", name);
+
+       for (auto session : lttng::urcu::list_iteration_adapter<ltt_session, &ltt_session::list>(
+                    the_session_list.head)) {
+               if (!strncmp(session->name, name, NAME_MAX) && !session->destroyed) {
+                       session_to_return = session;
+                       goto found;
+               }
+       }
+
+       return nullptr;
+found:
+       return session_get(session_to_return) ? session_to_return : nullptr;
+}
+
+/*
+ * Return an ltt_session that matches the id. If no session is found,
+ * NULL is returned. This must be called with rcu_read_lock and
+ * session list lock held (to guarantee the lifetime of the session).
+ */
+struct ltt_session *session_find_by_id(uint64_t id)
+{
+       struct lttng_ht_node_u64 *node;
+       struct lttng_ht_iter iter;
+       struct ltt_session *ls;
+
+       ASSERT_RCU_READ_LOCKED();
+       ASSERT_SESSION_LIST_LOCKED();
+
+       if (!ltt_sessions_ht_by_id) {
+               goto end;
+       }
+
+       lttng_ht_lookup(ltt_sessions_ht_by_id, &id, &iter);
+       node = lttng_ht_iter_get_node<lttng_ht_node_u64>(&iter);
+       if (node == nullptr) {
+               goto end;
+       }
+       ls = lttng::utils::container_of(node, &ltt_session::node);
+
+       DBG3("Session %" PRIu64 " found by id.", id);
+       return session_get(ls) ? ls : nullptr;
+
+end:
+       DBG3("Session %" PRIu64 " NOT found by id", id);
+       return nullptr;
+}
 } /* namespace */
 
 /*
 } /* namespace */
 
 /*
@@ -138,7 +197,7 @@ static void del_session_list(struct ltt_session *ls)
 /*
  * Return a pointer to the session list.
  */
 /*
  * Return a pointer to the session list.
  */
-struct ltt_session_list *session_get_list(void)
+struct ltt_session_list *session_get_list()
 {
        return &the_session_list;
 }
 {
        return &the_session_list;
 }
@@ -146,72 +205,47 @@ struct ltt_session_list *session_get_list(void)
 /*
  * Returns once the session list is empty.
  */
 /*
  * Returns once the session list is empty.
  */
-void session_list_wait_empty(void)
+void session_list_wait_empty(std::unique_lock<std::mutex> list_lock)
 {
 {
-       pthread_mutex_lock(&the_session_list.lock);
-       while (!cds_list_empty(&the_session_list.head)) {
-               pthread_cond_wait(&the_session_list.removal_cond,
-                               &the_session_list.lock);
-       }
-       pthread_mutex_unlock(&the_session_list.lock);
-}
-
-/*
- * Acquire session list lock
- */
-void session_lock_list(void)
-{
-       pthread_mutex_lock(&the_session_list.lock);
+       /* Keep waiting until the session list is empty. */
+       the_session_list.removal_cond.wait(list_lock,
+                                          [] { return cds_list_empty(&the_session_list.head); });
 }
 
 /*
  * Try to acquire session list lock
  */
 }
 
 /*
  * Try to acquire session list lock
  */
-int session_trylock_list(void)
-{
-       return pthread_mutex_trylock(&the_session_list.lock);
-}
-
-/*
- * Release session list lock
- */
-void session_unlock_list(void)
+int session_trylock_list() noexcept
 {
 {
-       pthread_mutex_unlock(&the_session_list.lock);
+       /* Return 0 if successfully acquired. */
+       return the_session_list.lock.try_lock() ? 0 : 1;
 }
 
 /*
  * Get the session's consumer destination type.
 }
 
 /*
  * Get the session's consumer destination type.
- *
- * The caller must hold the session lock.
  */
  */
-enum consumer_dst_type session_get_consumer_destination_type(
-               const struct ltt_session *session)
+enum consumer_dst_type session_get_consumer_destination_type(const ltt_session::locked_ref& session)
 {
        /*
         * The output information is duplicated in both of those session types.
         * Hence, it doesn't matter from which it is retrieved. However, it is
         * possible for only one of them to be set.
         */
 {
        /*
         * The output information is duplicated in both of those session types.
         * Hence, it doesn't matter from which it is retrieved. However, it is
         * possible for only one of them to be set.
         */
-       return session->kernel_session ?
-                       session->kernel_session->consumer->type :
-                       session->ust_session->consumer->type;
+       return session->kernel_session ? session->kernel_session->consumer->type :
+                                        session->ust_session->consumer->type;
 }
 
 /*
  * Get the session's consumer network hostname.
  * The caller must ensure that the destination is of type "net".
 }
 
 /*
  * Get the session's consumer network hostname.
  * The caller must ensure that the destination is of type "net".
- *
- * The caller must hold the session lock.
  */
  */
-const char *session_get_net_consumer_hostname(const struct ltt_session *session)
+const char *session_get_net_consumer_hostname(const ltt_session::locked_ref& session)
 {
 {
-       const char *hostname = NULL;
+       const char *hostname = nullptr;
        const struct consumer_output *output;
 
        const struct consumer_output *output;
 
-       output = session->kernel_session ?
-                       session->kernel_session->consumer :
-                       session->ust_session->consumer;
+       output = session->kernel_session ? session->kernel_session->consumer :
+                                          session->ust_session->consumer;
 
        /*
         * hostname is assumed to be the same for both control and data
 
        /*
         * hostname is assumed to be the same for both control and data
@@ -233,49 +267,44 @@ const char *session_get_net_consumer_hostname(const struct ltt_session *session)
 /*
  * Get the session's consumer network control and data ports.
  * The caller must ensure that the destination is of type "net".
 /*
  * Get the session's consumer network control and data ports.
  * The caller must ensure that the destination is of type "net".
- *
- * The caller must hold the session lock.
  */
  */
-void session_get_net_consumer_ports(const struct ltt_session *session,
-               uint16_t *control_port, uint16_t *data_port)
+void session_get_net_consumer_ports(const ltt_session::locked_ref& session,
+                                   uint16_t *control_port,
+                                   uint16_t *data_port)
 {
        const struct consumer_output *output;
 
 {
        const struct consumer_output *output;
 
-       output = session->kernel_session ?
-                       session->kernel_session->consumer :
-                       session->ust_session->consumer;
+       output = session->kernel_session ? session->kernel_session->consumer :
+                                          session->ust_session->consumer;
        *control_port = output->dst.net.control.port;
        *data_port = output->dst.net.data.port;
 }
 
 /*
  * Get the location of the latest trace archive produced by a rotation.
        *control_port = output->dst.net.control.port;
        *data_port = output->dst.net.data.port;
 }
 
 /*
  * Get the location of the latest trace archive produced by a rotation.
- *
- * The caller must hold the session lock.
  */
  */
-struct lttng_trace_archive_location *session_get_trace_archive_location(
-               const struct ltt_session *session)
+struct lttng_trace_archive_location *
+session_get_trace_archive_location(const ltt_session::locked_ref& session)
 {
        int ret;
 {
        int ret;
-       struct lttng_trace_archive_location *location = NULL;
-       char *chunk_path = NULL;
+       struct lttng_trace_archive_location *location = nullptr;
+       char *chunk_path = nullptr;
 
        if (session->rotation_state != LTTNG_ROTATION_STATE_COMPLETED ||
 
        if (session->rotation_state != LTTNG_ROTATION_STATE_COMPLETED ||
-                       !session->last_archived_chunk_name) {
+           !session->last_archived_chunk_name) {
                goto end;
        }
 
        switch (session_get_consumer_destination_type(session)) {
        case CONSUMER_DST_LOCAL:
                ret = asprintf(&chunk_path,
                goto end;
        }
 
        switch (session_get_consumer_destination_type(session)) {
        case CONSUMER_DST_LOCAL:
                ret = asprintf(&chunk_path,
-                               "%s/" DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY "/%s",
-                               session_get_base_path(session),
-                               session->last_archived_chunk_name);
+                              "%s/" DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY "/%s",
+                              session_get_base_path(session),
+                              session->last_archived_chunk_name);
                if (ret == -1) {
                        goto end;
                }
                if (ret == -1) {
                        goto end;
                }
-               location = lttng_trace_archive_location_local_create(
-                               chunk_path);
+               location = lttng_trace_archive_location_local_create(chunk_path);
                break;
        case CONSUMER_DST_NET:
        {
                break;
        case CONSUMER_DST_NET:
        {
@@ -283,13 +312,13 @@ struct lttng_trace_archive_location *session_get_trace_archive_location(
                uint16_t control_port, data_port;
 
                hostname = session_get_net_consumer_hostname(session);
                uint16_t control_port, data_port;
 
                hostname = session_get_net_consumer_hostname(session);
-               session_get_net_consumer_ports(session,
-                               &control_port,
-                               &data_port);
+               session_get_net_consumer_ports(session, &control_port, &data_port);
                location = lttng_trace_archive_location_relay_create(
                location = lttng_trace_archive_location_relay_create(
-                               hostname,
-                               LTTNG_TRACE_ARCHIVE_LOCATION_RELAY_PROTOCOL_TYPE_TCP,
-                               control_port, data_port, session->last_chunk_path);
+                       hostname,
+                       LTTNG_TRACE_ARCHIVE_LOCATION_RELAY_PROTOCOL_TYPE_TCP,
+                       control_port,
+                       data_port,
+                       session->last_chunk_path);
                break;
        }
        default:
                break;
        }
        default:
@@ -305,7 +334,7 @@ end:
  *
  * The session list lock must be held.
  */
  *
  * The session list lock must be held.
  */
-static int ltt_sessions_ht_alloc(void)
+static int ltt_sessions_ht_alloc()
 {
        int ret = 0;
 
 {
        int ret = 0;
 
@@ -334,16 +363,16 @@ end:
  *
  * The session list lock must be held.
  */
  *
  * The session list lock must be held.
  */
-static void ltt_sessions_ht_destroy(void)
+static void ltt_sessions_ht_destroy()
 {
        if (ltt_sessions_ht_by_id) {
                lttng_ht_destroy(ltt_sessions_ht_by_id);
 {
        if (ltt_sessions_ht_by_id) {
                lttng_ht_destroy(ltt_sessions_ht_by_id);
-               ltt_sessions_ht_by_id = NULL;
+               ltt_sessions_ht_by_id = nullptr;
        }
 
        if (ltt_sessions_ht_by_name) {
                lttng_ht_destroy(ltt_sessions_ht_by_name);
        }
 
        if (ltt_sessions_ht_by_name) {
                lttng_ht_destroy(ltt_sessions_ht_by_name);
-               ltt_sessions_ht_by_name = NULL;
+               ltt_sessions_ht_by_name = nullptr;
        }
 
        return;
        }
 
        return;
@@ -386,7 +415,7 @@ end:
  * Return `false` if hash table objects are null.
  * The session list lock must be held.
  */
  * Return `false` if hash table objects are null.
  * The session list lock must be held.
  */
-static bool ltt_sessions_ht_empty(void)
+static bool ltt_sessions_ht_empty()
 {
        bool empty = false;
 
 {
        bool empty = false;
 
@@ -443,7 +472,7 @@ static void del_session_ht(struct ltt_session *ls)
        LTTNG_ASSERT(!ret);
 
        if (ltt_sessions_ht_empty()) {
        LTTNG_ASSERT(!ret);
 
        if (ltt_sessions_ht_empty()) {
-               DBG("Empty ltt_sessions_ht_by_id/name, destroying hast tables");
+               DBG("Empty ltt_sessions_ht_by_id/name, destroying hash tables");
                ltt_sessions_ht_destroy();
        }
 }
                ltt_sessions_ht_destroy();
        }
 }
@@ -451,52 +480,60 @@ static void del_session_ht(struct ltt_session *ls)
 /*
  * Acquire session lock
  */
 /*
  * Acquire session lock
  */
-void session_lock(struct ltt_session *session)
+void session_lock(const ltt_session *session)
 {
        LTTNG_ASSERT(session);
 {
        LTTNG_ASSERT(session);
+       session->lock();
+}
 
 
-       pthread_mutex_lock(&session->lock);
+void ltt_session::lock() const noexcept
+{
+       pthread_mutex_lock(&_lock);
+}
+
+void ltt_session::unlock() const noexcept
+{
+       ltt_session::_const_session_unlock(*this);
 }
 
 /*
  * Release session lock
  */
 }
 
 /*
  * Release session lock
  */
-void session_unlock(struct ltt_session *session)
+void session_unlock(const ltt_session *session)
 {
        LTTNG_ASSERT(session);
 {
        LTTNG_ASSERT(session);
+       session->unlock();
+}
 
 
-       pthread_mutex_unlock(&session->lock);
+void ltt_session::_const_session_unlock(const ltt_session& session)
+{
+       pthread_mutex_unlock(&session._lock);
 }
 
 }
 
-static
-int _session_set_trace_chunk_no_lock_check(struct ltt_session *session,
-               struct lttng_trace_chunk *new_trace_chunk,
-               struct lttng_trace_chunk **_current_trace_chunk)
+static int _session_set_trace_chunk_no_lock_check(const ltt_session::locked_ref& session,
+                                                 struct lttng_trace_chunk *new_trace_chunk,
+                                                 struct lttng_trace_chunk **_current_trace_chunk)
 {
        int ret = 0;
        unsigned int i, refs_to_acquire = 0, refs_acquired = 0, refs_to_release = 0;
 {
        int ret = 0;
        unsigned int i, refs_to_acquire = 0, refs_acquired = 0, refs_to_release = 0;
-       struct cds_lfht_iter iter;
-       struct consumer_socket *socket;
        struct lttng_trace_chunk *current_trace_chunk;
        uint64_t chunk_id;
        enum lttng_trace_chunk_status chunk_status;
 
        struct lttng_trace_chunk *current_trace_chunk;
        uint64_t chunk_id;
        enum lttng_trace_chunk_status chunk_status;
 
-       rcu_read_lock();
+       const lttng::urcu::read_lock_guard read_lock;
        /*
         * Ownership of current trace chunk is transferred to
         * `current_trace_chunk`.
         */
        current_trace_chunk = session->current_trace_chunk;
        /*
         * Ownership of current trace chunk is transferred to
         * `current_trace_chunk`.
         */
        current_trace_chunk = session->current_trace_chunk;
-       session->current_trace_chunk = NULL;
+       session->current_trace_chunk = nullptr;
        if (session->ust_session) {
        if (session->ust_session) {
-               lttng_trace_chunk_put(
-                               session->ust_session->current_trace_chunk);
-               session->ust_session->current_trace_chunk = NULL;
+               lttng_trace_chunk_put(session->ust_session->current_trace_chunk);
+               session->ust_session->current_trace_chunk = nullptr;
        }
        if (session->kernel_session) {
        }
        if (session->kernel_session) {
-               lttng_trace_chunk_put(
-                               session->kernel_session->current_trace_chunk);
-               session->kernel_session->current_trace_chunk = NULL;
+               lttng_trace_chunk_put(session->kernel_session->current_trace_chunk);
+               session->kernel_session->current_trace_chunk = nullptr;
        }
        if (!new_trace_chunk) {
                ret = 0;
        }
        if (!new_trace_chunk) {
                ret = 0;
@@ -509,71 +546,75 @@ int _session_set_trace_chunk_no_lock_check(struct ltt_session *session,
        refs_to_acquire += !!session->ust_session;
        refs_to_acquire += !!session->kernel_session;
 
        refs_to_acquire += !!session->ust_session;
        refs_to_acquire += !!session->kernel_session;
 
-       for (refs_acquired = 0; refs_acquired < refs_to_acquire;
-                       refs_acquired++) {
+       for (refs_acquired = 0; refs_acquired < refs_to_acquire; refs_acquired++) {
                if (!lttng_trace_chunk_get(new_trace_chunk)) {
                        ERR("Failed to acquire reference to new trace chunk of session \"%s\"",
                if (!lttng_trace_chunk_get(new_trace_chunk)) {
                        ERR("Failed to acquire reference to new trace chunk of session \"%s\"",
-                                       session->name);
+                           session->name);
                        goto error;
                }
        }
 
        if (session->ust_session) {
                        goto error;
                }
        }
 
        if (session->ust_session) {
-               const uint64_t relayd_id =
-                               session->ust_session->consumer->net_seq_index;
-               const bool is_local_trace =
-                               session->ust_session->consumer->type ==
-                               CONSUMER_DST_LOCAL;
+               const uint64_t relayd_id = session->ust_session->consumer->net_seq_index;
+               const bool is_local_trace = session->ust_session->consumer->type ==
+                       CONSUMER_DST_LOCAL;
 
                session->ust_session->current_trace_chunk = new_trace_chunk;
                if (is_local_trace) {
                        enum lttng_error_code ret_error_code;
 
 
                session->ust_session->current_trace_chunk = new_trace_chunk;
                if (is_local_trace) {
                        enum lttng_error_code ret_error_code;
 
-                       ret_error_code = ust_app_create_channel_subdirectories(
-                                       session->ust_session);
+                       ret_error_code =
+                               ust_app_create_channel_subdirectories(session->ust_session);
                        if (ret_error_code != LTTNG_OK) {
                                goto error;
                        }
                }
                        if (ret_error_code != LTTNG_OK) {
                                goto error;
                        }
                }
-               cds_lfht_for_each_entry(
-                               session->ust_session->consumer->socks->ht,
-                               &iter, socket, node.node) {
+
+               for (auto *socket :
+                    lttng::urcu::lfht_iteration_adapter<consumer_socket,
+                                                        decltype(consumer_socket::node),
+                                                        &consumer_socket::node>(
+                            *session->ust_session->consumer->socks->ht)) {
                        pthread_mutex_lock(socket->lock);
                        ret = consumer_create_trace_chunk(socket,
                        pthread_mutex_lock(socket->lock);
                        ret = consumer_create_trace_chunk(socket,
-                                       relayd_id,
-                                       session->id, new_trace_chunk,
-                                       DEFAULT_UST_TRACE_DIR);
+                                                         relayd_id,
+                                                         session->id,
+                                                         new_trace_chunk,
+                                                         DEFAULT_UST_TRACE_DIR);
                        pthread_mutex_unlock(socket->lock);
                        if (ret) {
                                goto error;
                        }
                }
        }
                        pthread_mutex_unlock(socket->lock);
                        if (ret) {
                                goto error;
                        }
                }
        }
+
        if (session->kernel_session) {
        if (session->kernel_session) {
-               const uint64_t relayd_id =
-                               session->kernel_session->consumer->net_seq_index;
-               const bool is_local_trace =
-                               session->kernel_session->consumer->type ==
-                               CONSUMER_DST_LOCAL;
+               const uint64_t relayd_id = session->kernel_session->consumer->net_seq_index;
+               const bool is_local_trace = session->kernel_session->consumer->type ==
+                       CONSUMER_DST_LOCAL;
 
                session->kernel_session->current_trace_chunk = new_trace_chunk;
                if (is_local_trace) {
                        enum lttng_error_code ret_error_code;
 
 
                session->kernel_session->current_trace_chunk = new_trace_chunk;
                if (is_local_trace) {
                        enum lttng_error_code ret_error_code;
 
-                       ret_error_code = kernel_create_channel_subdirectories(
-                                       session->kernel_session);
+                       ret_error_code =
+                               kernel_create_channel_subdirectories(session->kernel_session);
                        if (ret_error_code != LTTNG_OK) {
                                goto error;
                        }
                }
                        if (ret_error_code != LTTNG_OK) {
                                goto error;
                        }
                }
-               cds_lfht_for_each_entry(
-                               session->kernel_session->consumer->socks->ht,
-                               &iter, socket, node.node) {
+
+               for (auto *socket :
+                    lttng::urcu::lfht_iteration_adapter<consumer_socket,
+                                                        decltype(consumer_socket::node),
+                                                        &consumer_socket::node>(
+                            *session->kernel_session->consumer->socks->ht)) {
                        pthread_mutex_lock(socket->lock);
                        ret = consumer_create_trace_chunk(socket,
                        pthread_mutex_lock(socket->lock);
                        ret = consumer_create_trace_chunk(socket,
-                                       relayd_id,
-                                       session->id, new_trace_chunk,
-                                       DEFAULT_KERNEL_TRACE_DIR);
+                                                         relayd_id,
+                                                         session->id,
+                                                         new_trace_chunk,
+                                                         DEFAULT_KERNEL_TRACE_DIR);
                        pthread_mutex_unlock(socket->lock);
                        if (ret) {
                                goto error;
                        pthread_mutex_unlock(socket->lock);
                        if (ret) {
                                goto error;
@@ -590,18 +631,17 @@ int _session_set_trace_chunk_no_lock_check(struct ltt_session *session,
 end:
        if (_current_trace_chunk) {
                *_current_trace_chunk = current_trace_chunk;
 end:
        if (_current_trace_chunk) {
                *_current_trace_chunk = current_trace_chunk;
-               current_trace_chunk = NULL;
+               current_trace_chunk = nullptr;
        }
 end_no_move:
        }
 end_no_move:
-       rcu_read_unlock();
        lttng_trace_chunk_put(current_trace_chunk);
        return ret;
 error:
        if (session->ust_session) {
        lttng_trace_chunk_put(current_trace_chunk);
        return ret;
 error:
        if (session->ust_session) {
-               session->ust_session->current_trace_chunk = NULL;
+               session->ust_session->current_trace_chunk = nullptr;
        }
        if (session->kernel_session) {
        }
        if (session->kernel_session) {
-               session->kernel_session->current_trace_chunk = NULL;
+               session->kernel_session->current_trace_chunk = nullptr;
        }
        /*
         * Release references taken in the case where all references could not
        }
        /*
         * Release references taken in the case where all references could not
@@ -615,19 +655,19 @@ error:
        goto end_no_move;
 }
 
        goto end_no_move;
 }
 
-struct lttng_trace_chunk *session_create_new_trace_chunk(
-               const struct ltt_session *session,
-               const struct consumer_output *consumer_output_override,
-               const char *session_base_path_override,
-               const char *chunk_name_override)
+struct lttng_trace_chunk *
+session_create_new_trace_chunk(const ltt_session::locked_ref& session,
+                              const struct consumer_output *consumer_output_override,
+                              const char *session_base_path_override,
+                              const char *chunk_name_override)
 {
        int ret;
 {
        int ret;
-       struct lttng_trace_chunk *trace_chunk = NULL;
+       struct lttng_trace_chunk *trace_chunk = nullptr;
        enum lttng_trace_chunk_status chunk_status;
        enum lttng_trace_chunk_status chunk_status;
-       const time_t chunk_creation_ts = time(NULL);
+       const time_t chunk_creation_ts = time(nullptr);
        bool is_local_trace;
        const char *base_path;
        bool is_local_trace;
        const char *base_path;
-       struct lttng_directory_handle *session_output_directory = NULL;
+       struct lttng_directory_handle *session_output_directory = nullptr;
        const struct lttng_credentials session_credentials = {
                .uid = LTTNG_OPTIONAL_INIT_VALUE(session->uid),
                .gid = LTTNG_OPTIONAL_INIT_VALUE(session->gid),
        const struct lttng_credentials session_credentials = {
                .uid = LTTNG_OPTIONAL_INIT_VALUE(session->uid),
                .gid = LTTNG_OPTIONAL_INIT_VALUE(session->gid),
@@ -640,28 +680,26 @@ struct lttng_trace_chunk *session_create_new_trace_chunk(
                output = consumer_output_override;
        } else {
                LTTNG_ASSERT(session->ust_session || session->kernel_session);
                output = consumer_output_override;
        } else {
                LTTNG_ASSERT(session->ust_session || session->kernel_session);
-               output = session->ust_session ?
-                                        session->ust_session->consumer :
-                                        session->kernel_session->consumer;
+               output = session->ust_session ? session->ust_session->consumer :
+                                               session->kernel_session->consumer;
        }
 
        is_local_trace = output->type == CONSUMER_DST_LOCAL;
        }
 
        is_local_trace = output->type == CONSUMER_DST_LOCAL;
-       base_path = session_base_path_override ? :
-                       consumer_output_get_base_path(output);
+       base_path = session_base_path_override ?: consumer_output_get_base_path(output);
 
        if (chunk_creation_ts == (time_t) -1) {
                PERROR("Failed to sample time while creation session \"%s\" trace chunk",
 
        if (chunk_creation_ts == (time_t) -1) {
                PERROR("Failed to sample time while creation session \"%s\" trace chunk",
-                               session->name);
+                      session->name);
                goto error;
        }
 
                goto error;
        }
 
-       next_chunk_id = session->most_recent_chunk_id.is_set ?
-                       session->most_recent_chunk_id.value + 1 : 0;
+       next_chunk_id =
+               session->most_recent_chunk_id.is_set ? session->most_recent_chunk_id.value + 1 : 0;
 
        if (session->current_trace_chunk &&
 
        if (session->current_trace_chunk &&
-                       !lttng_trace_chunk_get_name_overridden(session->current_trace_chunk)) {
+           !lttng_trace_chunk_get_name_overridden(session->current_trace_chunk)) {
                chunk_status = lttng_trace_chunk_rename_path(session->current_trace_chunk,
                chunk_status = lttng_trace_chunk_rename_path(session->current_trace_chunk,
-                                       DEFAULT_CHUNK_TMP_OLD_DIRECTORY);
+                                                            DEFAULT_CHUNK_TMP_OLD_DIRECTORY);
                if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                        goto error;
                }
                if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                        goto error;
                }
@@ -670,21 +708,19 @@ struct lttng_trace_chunk *session_create_new_trace_chunk(
                if (!session->rotated) {
                        new_path = "";
                } else {
                if (!session->rotated) {
                        new_path = "";
                } else {
-                       new_path = NULL;
+                       new_path = nullptr;
                }
        } else {
                new_path = DEFAULT_CHUNK_TMP_NEW_DIRECTORY;
        }
 
                }
        } else {
                new_path = DEFAULT_CHUNK_TMP_NEW_DIRECTORY;
        }
 
-       trace_chunk = lttng_trace_chunk_create(next_chunk_id,
-                       chunk_creation_ts, new_path);
+       trace_chunk = lttng_trace_chunk_create(next_chunk_id, chunk_creation_ts, new_path);
        if (!trace_chunk) {
                goto error;
        }
 
        if (chunk_name_override) {
        if (!trace_chunk) {
                goto error;
        }
 
        if (chunk_name_override) {
-               chunk_status = lttng_trace_chunk_override_name(trace_chunk,
-                               chunk_name_override);
+               chunk_status = lttng_trace_chunk_override_name(trace_chunk, chunk_name_override);
                if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                        goto error;
                }
                if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                        goto error;
                }
@@ -698,16 +734,13 @@ struct lttng_trace_chunk *session_create_new_trace_chunk(
                goto end;
        }
 
                goto end;
        }
 
-       chunk_status = lttng_trace_chunk_set_credentials(trace_chunk,
-                       &session_credentials);
+       chunk_status = lttng_trace_chunk_set_credentials(trace_chunk, &session_credentials);
        if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                goto error;
        }
 
        if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                goto error;
        }
 
-       DBG("Creating base output directory of session \"%s\" at %s",
-                       session->name, base_path);
-       ret = utils_mkdir_recursive(base_path, S_IRWXU | S_IRWXG,
-                       session->uid, session->gid);
+       DBG("Creating base output directory of session \"%s\" at %s", session->name, base_path);
+       ret = utils_mkdir_recursive(base_path, S_IRWXU | S_IRWXG, session->uid, session->gid);
        if (ret) {
                goto error;
        }
        if (ret) {
                goto error;
        }
@@ -715,10 +748,9 @@ struct lttng_trace_chunk *session_create_new_trace_chunk(
        if (!session_output_directory) {
                goto error;
        }
        if (!session_output_directory) {
                goto error;
        }
-       chunk_status = lttng_trace_chunk_set_as_owner(trace_chunk,
-                       session_output_directory);
+       chunk_status = lttng_trace_chunk_set_as_owner(trace_chunk, session_output_directory);
        lttng_directory_handle_put(session_output_directory);
        lttng_directory_handle_put(session_output_directory);
-       session_output_directory = NULL;
+       session_output_directory = nullptr;
        if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                goto error;
        }
        if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                goto error;
        }
@@ -727,25 +759,22 @@ end:
 error:
        lttng_directory_handle_put(session_output_directory);
        lttng_trace_chunk_put(trace_chunk);
 error:
        lttng_directory_handle_put(session_output_directory);
        lttng_trace_chunk_put(trace_chunk);
-       trace_chunk = NULL;
+       trace_chunk = nullptr;
        goto end;
 }
 
        goto end;
 }
 
-int session_close_trace_chunk(struct ltt_session *session,
-               struct lttng_trace_chunk *trace_chunk,
-               enum lttng_trace_chunk_command_type close_command,
-               char *closed_trace_chunk_path)
+int session_close_trace_chunk(const ltt_session::locked_ref& session,
+                             struct lttng_trace_chunk *trace_chunk,
+                             enum lttng_trace_chunk_command_type close_command,
+                             char *closed_trace_chunk_path)
 {
        int ret = 0;
        bool error_occurred = false;
 {
        int ret = 0;
        bool error_occurred = false;
-       struct cds_lfht_iter iter;
-       struct consumer_socket *socket;
        enum lttng_trace_chunk_status chunk_status;
        enum lttng_trace_chunk_status chunk_status;
-       const time_t chunk_close_timestamp = time(NULL);
+       const time_t chunk_close_timestamp = time(nullptr);
        const char *new_path;
 
        const char *new_path;
 
-       chunk_status = lttng_trace_chunk_set_close_command(
-                       trace_chunk, close_command);
+       chunk_status = lttng_trace_chunk_set_close_command(trace_chunk, close_command);
        if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                ret = -1;
                goto end;
        if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                ret = -1;
                goto end;
@@ -753,7 +782,7 @@ int session_close_trace_chunk(struct ltt_session *session,
 
        if (chunk_close_timestamp == (time_t) -1) {
                ERR("Failed to sample the close timestamp of the current trace chunk of session \"%s\"",
 
        if (chunk_close_timestamp == (time_t) -1) {
                ERR("Failed to sample the close timestamp of the current trace chunk of session \"%s\"",
-                               session->name);
+                   session->name);
                ret = -1;
                goto end;
        }
                ret = -1;
                goto end;
        }
@@ -763,30 +792,29 @@ int session_close_trace_chunk(struct ltt_session *session,
                new_path = "";
        } else {
                /* Use chunk name for new chunk. */
                new_path = "";
        } else {
                /* Use chunk name for new chunk. */
-               new_path = NULL;
+               new_path = nullptr;
        }
        if (session->current_trace_chunk &&
        }
        if (session->current_trace_chunk &&
-                       !lttng_trace_chunk_get_name_overridden(session->current_trace_chunk)) {
+           !lttng_trace_chunk_get_name_overridden(session->current_trace_chunk)) {
                /* Rename new chunk path. */
                /* Rename new chunk path. */
-               chunk_status = lttng_trace_chunk_rename_path(session->current_trace_chunk,
-                                       new_path);
+               chunk_status =
+                       lttng_trace_chunk_rename_path(session->current_trace_chunk, new_path);
                if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                        ret = -1;
                        goto end;
                }
        }
        if (!lttng_trace_chunk_get_name_overridden(trace_chunk) &&
                if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                        ret = -1;
                        goto end;
                }
        }
        if (!lttng_trace_chunk_get_name_overridden(trace_chunk) &&
-                       close_command == LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION) {
+           close_command == LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION) {
                const char *old_path;
 
                if (!session->rotated) {
                        old_path = "";
                } else {
                const char *old_path;
 
                if (!session->rotated) {
                        old_path = "";
                } else {
-                       old_path = NULL;
+                       old_path = nullptr;
                }
                /* We need to move back the .tmp_old_chunk to its rightful place. */
                }
                /* We need to move back the .tmp_old_chunk to its rightful place. */
-               chunk_status = lttng_trace_chunk_rename_path(trace_chunk,
-                                       old_path);
+               chunk_status = lttng_trace_chunk_rename_path(trace_chunk, old_path);
                if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                        ret = -1;
                        goto end;
                if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                        ret = -1;
                        goto end;
@@ -795,27 +823,28 @@ int session_close_trace_chunk(struct ltt_session *session,
        if (close_command == LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED) {
                session->rotated = true;
        }
        if (close_command == LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED) {
                session->rotated = true;
        }
-       chunk_status = lttng_trace_chunk_set_close_timestamp(trace_chunk,
-                       chunk_close_timestamp);
+       chunk_status = lttng_trace_chunk_set_close_timestamp(trace_chunk, chunk_close_timestamp);
        if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                ERR("Failed to set the close timestamp of the current trace chunk of session \"%s\"",
        if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                ERR("Failed to set the close timestamp of the current trace chunk of session \"%s\"",
-                               session->name);
+                   session->name);
                ret = -1;
                goto end;
        }
 
        if (session->ust_session) {
                ret = -1;
                goto end;
        }
 
        if (session->ust_session) {
-               const uint64_t relayd_id =
-                               session->ust_session->consumer->net_seq_index;
+               const uint64_t relayd_id = session->ust_session->consumer->net_seq_index;
 
 
-               cds_lfht_for_each_entry(
-                               session->ust_session->consumer->socks->ht,
-                               &iter, socket, node.node) {
+               for (auto *socket :
+                    lttng::urcu::lfht_iteration_adapter<consumer_socket,
+                                                        decltype(consumer_socket::node),
+                                                        &consumer_socket::node>(
+                            *session->ust_session->consumer->socks->ht)) {
                        pthread_mutex_lock(socket->lock);
                        ret = consumer_close_trace_chunk(socket,
                        pthread_mutex_lock(socket->lock);
                        ret = consumer_close_trace_chunk(socket,
-                                       relayd_id,
-                                       session->id,
-                                       trace_chunk, closed_trace_chunk_path);
+                                                        relayd_id,
+                                                        session->id,
+                                                        trace_chunk,
+                                                        closed_trace_chunk_path);
                        pthread_mutex_unlock(socket->lock);
                        if (ret) {
                                ERR("Failed to close trace chunk on user space consumer");
                        pthread_mutex_unlock(socket->lock);
                        if (ret) {
                                ERR("Failed to close trace chunk on user space consumer");
@@ -824,17 +853,19 @@ int session_close_trace_chunk(struct ltt_session *session,
                }
        }
        if (session->kernel_session) {
                }
        }
        if (session->kernel_session) {
-               const uint64_t relayd_id =
-                               session->kernel_session->consumer->net_seq_index;
+               const uint64_t relayd_id = session->kernel_session->consumer->net_seq_index;
 
 
-               cds_lfht_for_each_entry(
-                               session->kernel_session->consumer->socks->ht,
-                               &iter, socket, node.node) {
+               for (auto *socket :
+                    lttng::urcu::lfht_iteration_adapter<consumer_socket,
+                                                        decltype(consumer_socket::node),
+                                                        &consumer_socket::node>(
+                            *session->kernel_session->consumer->socks->ht)) {
                        pthread_mutex_lock(socket->lock);
                        ret = consumer_close_trace_chunk(socket,
                        pthread_mutex_lock(socket->lock);
                        ret = consumer_close_trace_chunk(socket,
-                                       relayd_id,
-                                       session->id,
-                                       trace_chunk, closed_trace_chunk_path);
+                                                        relayd_id,
+                                                        session->id,
+                                                        trace_chunk,
+                                                        closed_trace_chunk_path);
                        pthread_mutex_unlock(socket->lock);
                        if (ret) {
                                ERR("Failed to close trace chunk on kernel consumer");
                        pthread_mutex_unlock(socket->lock);
                        if (ret) {
                                ERR("Failed to close trace chunk on kernel consumer");
@@ -863,28 +894,28 @@ end:
  * daemon as the same "offset" in a metadata stream will no longer point
  * to the same content.
  */
  * daemon as the same "offset" in a metadata stream will no longer point
  * to the same content.
  */
-static
-enum lttng_error_code session_kernel_open_packets(struct ltt_session *session)
+static enum lttng_error_code session_kernel_open_packets(const ltt_session::locked_ref& session)
 {
        enum lttng_error_code ret = LTTNG_OK;
 {
        enum lttng_error_code ret = LTTNG_OK;
-       struct consumer_socket *socket;
        struct lttng_ht_iter iter;
        struct cds_lfht_node *node;
        struct lttng_ht_iter iter;
        struct cds_lfht_node *node;
-       struct ltt_kernel_channel *chan;
 
 
-       rcu_read_lock();
+       const lttng::urcu::read_lock_guard read_lock;
 
        cds_lfht_first(session->kernel_session->consumer->socks->ht, &iter.iter);
        node = cds_lfht_iter_get_node(&iter.iter);
 
        cds_lfht_first(session->kernel_session->consumer->socks->ht, &iter.iter);
        node = cds_lfht_iter_get_node(&iter.iter);
-       socket = container_of(node, typeof(*socket), node.node);
+       auto *socket = lttng_ht_node_container_of(node, &consumer_socket::node);
 
 
-       cds_list_for_each_entry(chan,
-                       &session->kernel_session->channel_list.head, list) {
+       for (auto chan :
+            lttng::urcu::list_iteration_adapter<ltt_kernel_channel, &ltt_kernel_channel::list>(
+                    session->kernel_session->channel_list.head)) {
                int open_ret;
 
                DBG("Open packet of kernel channel: channel key = %" PRIu64
                int open_ret;
 
                DBG("Open packet of kernel channel: channel key = %" PRIu64
-                               ", session name = %s, session_id = %" PRIu64,
-                               chan->key, session->name, session->id);
+                   ", session name = %s, session_id = %" PRIu64,
+                   chan->key,
+                   session->name,
+                   session->id);
 
                open_ret = consumer_open_channel_packets(socket, chan->key);
                if (open_ret < 0) {
 
                open_ret = consumer_open_channel_packets(socket, chan->key);
                if (open_ret < 0) {
@@ -895,16 +926,16 @@ enum lttng_error_code session_kernel_open_packets(struct ltt_session *session)
        }
 
 end:
        }
 
 end:
-       rcu_read_unlock();
        return ret;
 }
 
        return ret;
 }
 
-enum lttng_error_code session_open_packets(struct ltt_session *session)
+enum lttng_error_code session_open_packets(const ltt_session::locked_ref& session)
 {
        enum lttng_error_code ret = LTTNG_OK;
 
        DBG("Opening packets of session channels: session name = %s, session id = %" PRIu64,
 {
        enum lttng_error_code ret = LTTNG_OK;
 
        DBG("Opening packets of session channels: session name = %s, session id = %" PRIu64,
-                       session->name, session->id);
+           session->name,
+           session->id);
 
        if (session->ust_session) {
                ret = ust_app_open_packets(session);
 
        if (session->ust_session) {
                ret = ust_app_open_packets(session);
@@ -929,26 +960,24 @@ end:
  *
  * Must be called with the session lock held.
  */
  *
  * Must be called with the session lock held.
  */
-int session_set_trace_chunk(struct ltt_session *session,
-               struct lttng_trace_chunk *new_trace_chunk,
-               struct lttng_trace_chunk **current_trace_chunk)
+int session_set_trace_chunk(const ltt_session::locked_ref& session,
+                           struct lttng_trace_chunk *new_trace_chunk,
+                           struct lttng_trace_chunk **current_trace_chunk)
 {
 {
-       ASSERT_LOCKED(session->lock);
-       return _session_set_trace_chunk_no_lock_check(session, new_trace_chunk,
-                       current_trace_chunk);
+       ASSERT_LOCKED(session->_lock);
+       return _session_set_trace_chunk_no_lock_check(
+               session, new_trace_chunk, current_trace_chunk);
 }
 
 }
 
-static
-void session_notify_destruction(const struct ltt_session *session)
+static void session_notify_destruction(const ltt_session::locked_ref& session)
 {
        size_t i;
 {
        size_t i;
-       const size_t count = lttng_dynamic_array_get_count(
-                       &session->destroy_notifiers);
+       const auto count = lttng_dynamic_array_get_count(&session->destroy_notifiers);
 
        for (i = 0; i < count; i++) {
                const struct ltt_session_destroy_notifier_element *element =
                        (ltt_session_destroy_notifier_element *) lttng_dynamic_array_get_element(
 
        for (i = 0; i < count; i++) {
                const struct ltt_session_destroy_notifier_element *element =
                        (ltt_session_destroy_notifier_element *) lttng_dynamic_array_get_element(
-                                       &session->destroy_notifiers, i);
+                               &session->destroy_notifiers, i);
 
                element->notifier(session, element->user_data);
        }
 
                element->notifier(session, element->user_data);
        }
@@ -957,29 +986,27 @@ void session_notify_destruction(const struct ltt_session *session)
 /*
  * Fire each clear notifier once, and remove them from the array.
  */
 /*
  * Fire each clear notifier once, and remove them from the array.
  */
-void session_notify_clear(struct ltt_session *session)
+void session_notify_clear(const ltt_session::locked_ref& session)
 {
        size_t i;
 {
        size_t i;
-       const size_t count = lttng_dynamic_array_get_count(
-                       &session->clear_notifiers);
+       const auto count = lttng_dynamic_array_get_count(&session->clear_notifiers);
 
        for (i = 0; i < count; i++) {
                const struct ltt_session_clear_notifier_element *element =
                        (ltt_session_clear_notifier_element *) lttng_dynamic_array_get_element(
 
        for (i = 0; i < count; i++) {
                const struct ltt_session_clear_notifier_element *element =
                        (ltt_session_clear_notifier_element *) lttng_dynamic_array_get_element(
-                                       &session->clear_notifiers, i);
+                               &session->clear_notifiers, i);
 
                element->notifier(session, element->user_data);
        }
        lttng_dynamic_array_clear(&session->clear_notifiers);
 }
 
 
                element->notifier(session, element->user_data);
        }
        lttng_dynamic_array_clear(&session->clear_notifiers);
 }
 
-static
-void session_release(struct urcu_ref *ref)
+static void session_release(struct urcu_ref *ref)
 {
        int ret;
        struct ltt_ust_session *usess;
        struct ltt_kernel_session *ksess;
 {
        int ret;
        struct ltt_ust_session *usess;
        struct ltt_kernel_session *ksess;
-       struct ltt_session *session = container_of(ref, typeof(*session), ref);
+       struct ltt_session *session = lttng::utils::container_of(ref, &ltt_session::ref_count);
        const bool session_published = session->published;
 
        LTTNG_ASSERT(!session->chunk_being_archived);
        const bool session_published = session->published;
 
        LTTNG_ASSERT(!session->chunk_being_archived);
@@ -1018,21 +1045,33 @@ void session_release(struct urcu_ref *ref)
 
        snapshot_destroy(&session->snapshot);
 
 
        snapshot_destroy(&session->snapshot);
 
-       pthread_mutex_destroy(&session->lock);
-
        if (session_published) {
        if (session_published) {
-               ASSERT_LOCKED(the_session_list.lock);
+               ASSERT_SESSION_LIST_LOCKED();
                del_session_list(session);
                del_session_ht(session);
        }
                del_session_list(session);
                del_session_ht(session);
        }
-       session_notify_destruction(session);
+
+       /*
+        * The notifiers make use of free-functions that expect a locked reference to a session.
+        * To create such a reference, we need to acquire the lock and acquire a reference (increase
+        * the ref-count). To ensure the release of the reference does not re-cross the zero value,
+        * set the refcount to a tombstone value.
+        */
+       session->ref_count.refcount = 0xDEAD5E55;
+       session_notify_destruction([session]() {
+               session_lock(session);
+               session_get(session);
+               return ltt_session::make_locked_ref(*session);
+       }());
+
+       pthread_mutex_destroy(&session->_lock);
 
        consumer_output_put(session->consumer);
        kernel_free_session(ksess);
 
        consumer_output_put(session->consumer);
        kernel_free_session(ksess);
-       session->kernel_session = NULL;
+       session->kernel_session = nullptr;
        if (usess) {
                trace_ust_free_session(usess);
        if (usess) {
                trace_ust_free_session(usess);
-               session->ust_session = NULL;
+               session->ust_session = nullptr;
        }
        lttng_dynamic_array_reset(&session->destroy_notifiers);
        lttng_dynamic_array_reset(&session->clear_notifiers);
        }
        lttng_dynamic_array_reset(&session->destroy_notifiers);
        lttng_dynamic_array_reset(&session->clear_notifiers);
@@ -1042,11 +1081,12 @@ void session_release(struct urcu_ref *ref)
        free(session);
        if (session_published) {
                /*
        free(session);
        if (session_published) {
                /*
-                * Broadcast after free-ing to ensure the memory is
-                * reclaimed before the main thread exits.
+                * Notify after free-ing to ensure the memory is
+                * reclaimed before the main thread exits (and prevent memory leak
+                * reports).
                 */
                 */
-               ASSERT_LOCKED(the_session_list.lock);
-               pthread_cond_broadcast(&the_session_list.removal_cond);
+               ASSERT_SESSION_LIST_LOCKED();
+               the_session_list.removal_cond.notify_all();
        }
 }
 
        }
 }
 
@@ -1056,7 +1096,7 @@ void session_release(struct urcu_ref *ref)
  */
 bool session_get(struct ltt_session *session)
 {
  */
 bool session_get(struct ltt_session *session)
 {
-       return urcu_ref_get_unless_zero(&session->ref);
+       return urcu_ref_get_unless_zero(&session->ref_count);
 }
 
 /*
 }
 
 /*
@@ -1071,9 +1111,9 @@ 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.
         */
         * The session list lock must be held as any session_put()
         * may cause the removal of the session from the session_list.
         */
-       ASSERT_LOCKED(the_session_list.lock);
-       LTTNG_ASSERT(session->ref.refcount);
-       urcu_ref_put(&session->ref, session_release);
+       ASSERT_SESSION_LIST_LOCKED();
+       LTTNG_ASSERT(session->ref_count.refcount);
+       urcu_ref_put(&session->ref_count, session_release);
 }
 
 /*
 }
 
 /*
@@ -1109,102 +1149,38 @@ void session_destroy(struct ltt_session *session)
        session_put(session);
 }
 
        session_put(session);
 }
 
-int session_add_destroy_notifier(struct ltt_session *session,
-               ltt_session_destroy_notifier notifier, void *user_data)
+int session_add_destroy_notifier(const ltt_session::locked_ref& session,
+                                ltt_session_destroy_notifier notifier,
+                                void *user_data)
 {
 {
-       const struct ltt_session_destroy_notifier_element element = {
-               .notifier = notifier,
-               .user_data = user_data
-       };
-
-       return lttng_dynamic_array_add_element(&session->destroy_notifiers,
-                       &element);
-}
-
-int session_add_clear_notifier(struct ltt_session *session,
-               ltt_session_clear_notifier notifier, void *user_data)
-{
-       const struct ltt_session_clear_notifier_element element = {
-               .notifier = notifier,
-               .user_data = user_data
-       };
-
-       return lttng_dynamic_array_add_element(&session->clear_notifiers,
-                       &element);
-}
-
-/*
- * Return a ltt_session structure ptr that matches name. If no session found,
- * NULL is returned. This must be called with the session list lock held using
- * session_lock_list and session_unlock_list.
- * A reference to the session is implicitly acquired by this function.
- */
-struct ltt_session *session_find_by_name(const char *name)
-{
-       struct ltt_session *iter;
-
-       LTTNG_ASSERT(name);
-       ASSERT_LOCKED(the_session_list.lock);
-
-       DBG2("Trying to find session by name %s", name);
-
-       cds_list_for_each_entry(iter, &the_session_list.head, list) {
-               if (!strncmp(iter->name, name, NAME_MAX) &&
-                               !iter->destroyed) {
-                       goto found;
-               }
-       }
+       const struct ltt_session_destroy_notifier_element element = { .notifier = notifier,
+                                                                     .user_data = user_data };
 
 
-       return NULL;
-found:
-       return session_get(iter) ? iter : NULL;
+       return lttng_dynamic_array_add_element(&session->destroy_notifiers, &element);
 }
 
 }
 
-/*
- * Return an ltt_session that matches the id. If no session is found,
- * NULL is returned. This must be called with rcu_read_lock and
- * session list lock held (to guarantee the lifetime of the session).
- */
-struct ltt_session *session_find_by_id(uint64_t id)
+int session_add_clear_notifier(const ltt_session::locked_ref& session,
+                              ltt_session_clear_notifier notifier,
+                              void *user_data)
 {
 {
-       struct lttng_ht_node_u64 *node;
-       struct lttng_ht_iter iter;
-       struct ltt_session *ls;
-
-       ASSERT_RCU_READ_LOCKED();
-       ASSERT_LOCKED(the_session_list.lock);
-
-       if (!ltt_sessions_ht_by_id) {
-               goto end;
-       }
-
-       lttng_ht_lookup(ltt_sessions_ht_by_id, &id, &iter);
-       node = lttng_ht_iter_get_node_u64(&iter);
-       if (node == NULL) {
-               goto end;
-       }
-       ls = caa_container_of(node, struct ltt_session, node);
-
-       DBG3("Session %" PRIu64 " found by id.", id);
-       return session_get(ls) ? ls : NULL;
+       const struct ltt_session_clear_notifier_element element = { .notifier = notifier,
+                                                                   .user_data = user_data };
 
 
-end:
-       DBG3("Session %" PRIu64 " NOT found by id", id);
-       return NULL;
+       return lttng_dynamic_array_add_element(&session->clear_notifiers, &element);
 }
 
 /*
  * Create a new session and add it to the session list.
  * Session list lock must be held by the caller.
  */
 }
 
 /*
  * Create a new session and add it to the session list.
  * Session list lock must be held by the caller.
  */
-enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
-               struct ltt_session **out_session)
+enum lttng_error_code
+session_create(const char *name, uid_t uid, gid_t gid, struct ltt_session **out_session)
 {
        int ret;
        enum lttng_error_code ret_code;
 {
        int ret;
        enum lttng_error_code ret_code;
-       struct ltt_session *new_session = NULL;
+       struct ltt_session *new_session = nullptr;
 
 
-       ASSERT_LOCKED(the_session_list.lock);
+       ASSERT_SESSION_LIST_LOCKED();
        if (name) {
                struct ltt_session *clashing_session;
 
        if (name) {
                struct ltt_session *clashing_session;
 
@@ -1223,15 +1199,15 @@ enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
        }
 
        lttng_dynamic_array_init(&new_session->destroy_notifiers,
        }
 
        lttng_dynamic_array_init(&new_session->destroy_notifiers,
-                       sizeof(struct ltt_session_destroy_notifier_element),
-                       NULL);
+                                sizeof(struct ltt_session_destroy_notifier_element),
+                                nullptr);
        lttng_dynamic_array_init(&new_session->clear_notifiers,
        lttng_dynamic_array_init(&new_session->clear_notifiers,
-                       sizeof(struct ltt_session_clear_notifier_element),
-                       NULL);
-       urcu_ref_init(&new_session->ref);
-       pthread_mutex_init(&new_session->lock, NULL);
+                                sizeof(struct ltt_session_clear_notifier_element),
+                                nullptr);
+       urcu_ref_init(&new_session->ref_count);
+       pthread_mutex_init(&new_session->_lock, nullptr);
 
 
-       new_session->creation_time = time(NULL);
+       new_session->creation_time = time(nullptr);
        if (new_session->creation_time == (time_t) -1) {
                PERROR("Failed to sample session creation time");
                ret_code = LTTNG_ERR_SESSION_FAIL;
        if (new_session->creation_time == (time_t) -1) {
                PERROR("Failed to sample session creation time");
                ret_code = LTTNG_ERR_SESSION_FAIL;
@@ -1240,7 +1216,7 @@ enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
 
        /* Create default consumer output. */
        new_session->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
 
        /* Create default consumer output. */
        new_session->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
-       if (new_session->consumer == NULL) {
+       if (new_session->consumer == nullptr) {
                ret_code = LTTNG_ERR_NOMEM;
                goto error;
        }
                ret_code = LTTNG_ERR_NOMEM;
                goto error;
        }
@@ -1273,16 +1249,17 @@ enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
 
                        if (i == 0) {
                                ret = snprintf(new_session->name,
 
                        if (i == 0) {
                                ret = snprintf(new_session->name,
-                                               sizeof(new_session->name),
-                                               "%s-%s",
-                                               DEFAULT_SESSION_NAME,
-                                               datetime);
+                                              sizeof(new_session->name),
+                                              "%s-%s",
+                                              DEFAULT_SESSION_NAME,
+                                              datetime);
                        } else {
                                ret = snprintf(new_session->name,
                        } else {
                                ret = snprintf(new_session->name,
-                                               sizeof(new_session->name),
-                                               "%s%d-%s",
-                                               DEFAULT_SESSION_NAME, i,
-                                               datetime);
+                                              sizeof(new_session->name),
+                                              "%s%d-%s",
+                                              DEFAULT_SESSION_NAME,
+                                              i,
+                                              datetime);
                        }
                        new_session->name_contains_creation_time = true;
                        if (ret == -1 || ret >= sizeof(new_session->name)) {
                        }
                        new_session->name_contains_creation_time = true;
                        if (ret == -1 || ret >= sizeof(new_session->name)) {
@@ -1295,8 +1272,7 @@ enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
                                goto error;
                        }
 
                                goto error;
                        }
 
-                       clashing_session =
-                                       session_find_by_name(new_session->name);
+                       clashing_session = session_find_by_name(new_session->name);
                        session_put(clashing_session);
                        if (!clashing_session) {
                                found_name = true;
                        session_put(clashing_session);
                        if (!clashing_session) {
                                found_name = true;
@@ -1318,7 +1294,7 @@ enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
                if (errno == ENAMETOOLONG) {
                        new_session->hostname[sizeof(new_session->hostname) - 1] = '\0';
                        ERR("Hostname exceeds the maximal permitted length and has been truncated to %s",
                if (errno == ENAMETOOLONG) {
                        new_session->hostname[sizeof(new_session->hostname) - 1] = '\0';
                        ERR("Hostname exceeds the maximal permitted length and has been truncated to %s",
-                                       new_session->hostname);
+                           new_session->hostname);
                } else {
                        ret_code = LTTNG_ERR_SESSION_FAIL;
                        goto error;
                } else {
                        ret_code = LTTNG_ERR_SESSION_FAIL;
                        goto error;
@@ -1353,8 +1329,10 @@ enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
         * set it up and, if valid, assign it to the session.
         */
        DBG("Tracing session %s created with ID %" PRIu64 " by uid = %d, gid = %d",
         * set it up and, if valid, assign it to the session.
         */
        DBG("Tracing session %s created with ID %" PRIu64 " by uid = %d, gid = %d",
-                       new_session->name, new_session->id, new_session->uid,
-                       new_session->gid);
+           new_session->name,
+           new_session->id,
+           new_session->uid,
+           new_session->gid);
        ret_code = LTTNG_OK;
 end:
        if (new_session) {
        ret_code = LTTNG_OK;
 end:
        if (new_session) {
@@ -1364,7 +1342,7 @@ end:
        return ret_code;
 error:
        session_put(new_session);
        return ret_code;
 error:
        session_put(new_session);
-       new_session = NULL;
+       new_session = nullptr;
        goto end;
 }
 
        goto end;
 }
 
@@ -1372,9 +1350,8 @@ error:
  * Check if the UID matches the session. Root user has access to all
  * sessions.
  */
  * Check if the UID matches the session. Root user has access to all
  * sessions.
  */
-bool session_access_ok(struct ltt_session *session, uid_t uid)
+bool session_access_ok(const ltt_session::locked_ref& session, uid_t uid)
 {
 {
-       LTTNG_ASSERT(session);
        return (uid == session->uid) || uid == 0;
 }
 
        return (uid == session->uid) || uid == 0;
 }
 
@@ -1393,13 +1370,12 @@ bool session_access_ok(struct ltt_session *session, uid_t uid)
  *
  * Must be called with the session and session_list locks held.
  */
  *
  * Must be called with the session and session_list locks held.
  */
-int session_reset_rotation_state(struct ltt_session *session,
-               enum lttng_rotation_state result)
+int session_reset_rotation_state(const ltt_session::locked_ref& session,
+                                enum lttng_rotation_state result)
 {
        int ret = 0;
 
 {
        int ret = 0;
 
-       ASSERT_LOCKED(the_session_list.lock);
-       ASSERT_LOCKED(session->lock);
+       ASSERT_SESSION_LIST_LOCKED();
 
        session->rotation_state = result;
        if (session->rotation_pending_check_timer_enabled) {
 
        session->rotation_state = result;
        if (session->rotation_pending_check_timer_enabled) {
@@ -1409,14 +1385,11 @@ int session_reset_rotation_state(struct ltt_session *session,
                uint64_t chunk_id;
                enum lttng_trace_chunk_status chunk_status;
 
                uint64_t chunk_id;
                enum lttng_trace_chunk_status chunk_status;
 
-               chunk_status = lttng_trace_chunk_get_id(
-                               session->chunk_being_archived,
-                               &chunk_id);
+               chunk_status = lttng_trace_chunk_get_id(session->chunk_being_archived, &chunk_id);
                LTTNG_ASSERT(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK);
                LTTNG_ASSERT(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK);
-               LTTNG_OPTIONAL_SET(&session->last_archived_chunk_id,
-                               chunk_id);
+               LTTNG_OPTIONAL_SET(&session->last_archived_chunk_id, chunk_id);
                lttng_trace_chunk_put(session->chunk_being_archived);
                lttng_trace_chunk_put(session->chunk_being_archived);
-               session->chunk_being_archived = NULL;
+               session->chunk_being_archived = nullptr;
                /*
                 * Fire the clear reply notifiers if we are completing a clear
                 * rotation.
                /*
                 * Fire the clear reply notifiers if we are completing a clear
                 * rotation.
@@ -1442,7 +1415,7 @@ bool sample_session_id_by_name(const char *name, uint64_t *id)
        struct lttng_ht_iter iter;
        struct ltt_session *ls;
 
        struct lttng_ht_iter iter;
        struct ltt_session *ls;
 
-       rcu_read_lock();
+       const lttng::urcu::read_lock_guard read_lock;
 
        if (!ltt_sessions_ht_by_name) {
                found = false;
 
        if (!ltt_sessions_ht_by_name) {
                found = false;
@@ -1450,35 +1423,48 @@ bool sample_session_id_by_name(const char *name, uint64_t *id)
        }
 
        lttng_ht_lookup(ltt_sessions_ht_by_name, name, &iter);
        }
 
        lttng_ht_lookup(ltt_sessions_ht_by_name, name, &iter);
-       node = lttng_ht_iter_get_node_str(&iter);
-       if (node == NULL) {
+       node = lttng_ht_iter_get_node<lttng_ht_node_str>(&iter);
+       if (node == nullptr) {
                found = false;
                goto end;
        }
 
                found = false;
                goto end;
        }
 
-       ls = caa_container_of(node, struct ltt_session, node_by_name);
+       ls = lttng::utils::container_of(node, &ltt_session::node_by_name);
        *id = ls->id;
        found = true;
 
        DBG3("Session id `%" PRIu64 "` sampled for session `%s", *id, name);
 end:
        *id = ls->id;
        found = true;
 
        DBG3("Session id `%" PRIu64 "` sampled for session `%s", *id, name);
 end:
-       rcu_read_unlock();
        return found;
 }
 
        return found;
 }
 
-void ls::details::locked_session_release(ltt_session *session)
+void ltt_session::_locked_session_release(ltt_session *session)
 {
 {
+       if (!session) {
+               return;
+       }
+
        session_unlock(session);
        session_put(session);
 }
 
        session_unlock(session);
        session_put(session);
 }
 
-ltt_session::locked_ptr ls::find_locked_session_by_id(ltt_session::id_t id)
+void ltt_session::_locked_const_session_release(const ltt_session *session)
+{
+       if (!session) {
+               return;
+       }
+
+       ltt_session::_const_session_unlock(*session);
+       ltt_session::_const_session_put(session);
+}
+
+ltt_session::locked_ref ltt_session::find_locked_session(ltt_session::id_t id)
 {
 {
-       lttng::urcu::read_lock_guard rcu_lock;
+       const lttng::urcu::read_lock_guard rcu_lock;
        auto session = session_find_by_id(id);
 
        if (!session) {
        auto session = session_find_by_id(id);
 
        if (!session) {
-               return nullptr;
+               LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
        }
 
        /*
        }
 
        /*
@@ -1486,17 +1472,419 @@ ltt_session::locked_ptr ls::find_locked_session_by_id(ltt_session::id_t id)
         * session.
         */
        session_lock(session);
         * session.
         */
        session_lock(session);
-       return ltt_session::locked_ptr(session);
+       return ltt_session::make_locked_ref(*session);
+}
+
+ltt_session::locked_ref ltt_session::find_locked_session(lttng::c_string_view name)
+{
+       const lttng::urcu::read_lock_guard rcu_lock;
+       auto session = session_find_by_name(name.data());
+
+       if (!session) {
+               LTTNG_THROW_SESSION_NOT_FOUND_BY_NAME_ERROR(name.data());
+       }
+
+       session_lock(session);
+       return ltt_session::make_locked_ref(*session);
 }
 
 }
 
-ltt_session::sptr ls::find_session_by_id(ltt_session::id_t id)
+ltt_session::const_locked_ref ltt_session::find_locked_const_session(ltt_session::id_t id)
 {
 {
-       lttng::urcu::read_lock_guard rcu_lock;
+       const lttng::urcu::read_lock_guard rcu_lock;
+       const auto *session = session_find_by_id(id);
+
+       if (!session) {
+               LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
+       }
+
+       session_lock(session);
+       return ltt_session::make_locked_ref(*session);
+}
+
+ltt_session::const_locked_ref ltt_session::find_locked_const_session(lttng::c_string_view name)
+{
+       const lttng::urcu::read_lock_guard rcu_lock;
+       const auto *session = session_find_by_name(name.data());
+
+       if (!session) {
+               LTTNG_THROW_SESSION_NOT_FOUND_BY_NAME_ERROR(name.data());
+       }
+
+       session_lock(session);
+       return ltt_session::make_locked_ref(*session);
+}
+
+ltt_session::ref ltt_session::find_session(ltt_session::id_t id)
+{
+       const lttng::urcu::read_lock_guard rcu_lock;
        auto session = session_find_by_id(id);
 
        if (!session) {
        auto session = session_find_by_id(id);
 
        if (!session) {
-               return nullptr;
+               LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
+       }
+
+       return ltt_session::make_ref(*session);
+}
+
+ltt_session::ref ltt_session::find_session(lttng::c_string_view name)
+{
+       const lttng::urcu::read_lock_guard rcu_lock;
+       auto session = session_find_by_name(name.data());
+
+       if (!session) {
+               LTTNG_THROW_SESSION_NOT_FOUND_BY_NAME_ERROR(name.data());
+       }
+
+       return ltt_session::make_ref(*session);
+}
+
+ltt_session::const_ref ltt_session::find_const_session(ltt_session::id_t id)
+{
+       const lttng::urcu::read_lock_guard rcu_lock;
+       const auto *session = session_find_by_id(id);
+
+       if (!session) {
+               LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
+       }
+
+       return ltt_session::make_ref(*session);
+}
+
+ltt_session::const_ref ltt_session::find_const_session(lttng::c_string_view name)
+{
+       const lttng::urcu::read_lock_guard rcu_lock;
+       const auto *session = session_find_by_name(name.data());
+
+       if (!session) {
+               LTTNG_THROW_SESSION_NOT_FOUND_BY_NAME_ERROR(name.data());
+       }
+
+       return ltt_session::make_ref(*session);
+}
+
+void ltt_session::_const_session_put(const 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_SESSION_LIST_LOCKED();
+       LTTNG_ASSERT(session->ref_count.refcount);
+       urcu_ref_put(&session->ref_count, session_release);
+}
+
+std::unique_lock<std::mutex> ls::lock_session_list()
+{
+       return std::unique_lock<std::mutex>(the_session_list.lock);
+}
+
+lttng::sessiond::user_space_consumer_channel_keys
+ltt_session::user_space_consumer_channel_keys() const
+{
+       switch (ust_session->buffer_type) {
+       case LTTNG_BUFFER_PER_PID:
+               return lttng::sessiond::user_space_consumer_channel_keys(*ust_session,
+                                                                        *ust_app_get_all());
+       case LTTNG_BUFFER_PER_UID:
+               return lttng::sessiond::user_space_consumer_channel_keys(
+                       *ust_session, ust_session->buffer_reg_uid_list);
+       default:
+               abort();
+       }
+}
+
+ls::user_space_consumer_channel_keys::iterator
+ls::user_space_consumer_channel_keys::begin() const noexcept
+{
+       return ls::user_space_consumer_channel_keys::iterator(_creation_context);
+}
+
+ls::user_space_consumer_channel_keys::iterator
+ls::user_space_consumer_channel_keys::end() const noexcept
+{
+       return ls::user_space_consumer_channel_keys::iterator(_creation_context, true);
+}
+
+ls::user_space_consumer_channel_keys::iterator&
+ls::user_space_consumer_channel_keys::iterator::operator++()
+{
+       if (_is_end) {
+               LTTNG_THROW_OUT_OF_RANGE(fmt::format(
+                       "Attempted to advance channel key iterator past the end of channel keys: iteration_mode={}",
+                       _creation_context._session.buffer_type));
+       }
+
+       switch (_creation_context._session.buffer_type) {
+       case LTTNG_BUFFER_PER_PID:
+               _advance_one_per_pid();
+               break;
+       case LTTNG_BUFFER_PER_UID:
+               _advance_one_per_uid();
+               break;
+       default:
+               abort();
+       }
+
+       return *this;
+}
+
+namespace {
+bool is_list_empty(const cds_list_head *head)
+{
+       return head == head->next;
+}
+
+bool is_last_element_of_list(const cds_list_head *head)
+{
+       return head->next == head->prev;
+}
+} /* namespace */
+
+ls::user_space_consumer_channel_keys::iterator::iterator(
+       const _iterator_creation_context& creation_context, bool is_end) :
+       _creation_context(creation_context), _is_end(is_end)
+{
+       if (_is_end) {
+               return;
+       }
+
+       switch (_creation_context._mode) {
+       case _iteration_mode::PER_PID:
+               _init_per_pid();
+               break;
+       case _iteration_mode::PER_UID:
+               _init_per_uid();
+               break;
+       }
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_skip_to_next_app_per_pid(
+       bool try_current) noexcept
+{
+       auto& position = _position._per_pid;
+
+       while (true) {
+               if (!try_current) {
+                       lttng_ht_get_next(_creation_context._container.apps,
+                                         &position.app_iterator);
+               } else {
+                       try_current = false;
+               }
+
+               const auto app_node =
+                       lttng_ht_iter_get_node<lttng_ht_node_ulong>(&position.app_iterator);
+               if (!app_node) {
+                       _is_end = true;
+                       return;
+               }
+
+               const auto& app = *lttng::utils::container_of(app_node, &ust_app::pid_n);
+               auto app_session = ust_app_lookup_app_session(&_creation_context._session, &app);
+
+               if (!app_session) {
+                       /* This app is not traced by the target session. */
+                       continue;
+               }
+
+               position.current_app_session = app_session->lock();
+
+               auto *registry = ust_app_get_session_registry(
+                       (*_position._per_pid.current_app_session)->get_identifier());
+               if (!registry) {
+                       DBG_FMT("Application session is being torn down: skipping application: app={}",
+                               app);
+                       continue;
+               }
+
+               position.current_registry_session = registry;
+               lttng_ht_get_first((*position.current_app_session)->channels,
+                                  &_position.channel_iterator);
+               break;
+       }
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_init_per_pid() noexcept
+{
+       auto& position = _position._per_pid;
+
+       lttng_ht_get_first(_creation_context._container.apps, &position.app_iterator);
+       _skip_to_next_app_per_pid(true);
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_init_per_uid() noexcept
+{
+       auto& position = _position._per_uid;
+
+       /* Start the iteration: get the first registry and point to its first channel. */
+       if (is_list_empty(&_creation_context._session.buffer_reg_uid_list)) {
+               _is_end = true;
+               return;
+       }
+
+       position.current_registry = lttng::utils::container_of(
+               _creation_context._session.buffer_reg_uid_list.next, &buffer_reg_uid::lnode);
+       lttng_ht_get_first(position.current_registry->registry->channels,
+                          &_position.channel_iterator);
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_advance_one_per_pid()
+{
+       auto& position = _position._per_pid;
+
+       if (!cds_lfht_iter_get_node(&_position.channel_iterator.iter)) {
+               /* Reached the last channel. Move on to the next app. */
+               _skip_to_next_app_per_pid(false);
+               return;
+       }
+
+       const auto current_app_node =
+               lttng_ht_iter_get_node<lttng_ht_node_ulong>(&position.app_iterator);
+       LTTNG_ASSERT(current_app_node);
+
+       lttng_ht_get_next((*position.current_app_session)->channels, &_position.channel_iterator);
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_advance_one_per_uid()
+{
+       auto& position = _position._per_uid;
+
+       if (!cds_lfht_iter_get_node(&_position.channel_iterator.iter)) {
+               /* Reached the last channel of the registry. Move on to the next registry. */
+               if (is_last_element_of_list(&position.current_registry->lnode)) {
+                       _is_end = true;
+                       return;
+               }
+
+               position.current_registry = lttng::utils::container_of(
+                       position.current_registry->lnode.next, &buffer_reg_uid::lnode);
+               cds_lfht_first(position.current_registry->registry->channels->ht,
+                              &_position.channel_iterator.iter);
+
+               /* Assumes a registry can't be empty. */
+               LTTNG_ASSERT(cds_lfht_iter_get_node(&_position.channel_iterator.iter));
+       }
+
+       cds_lfht_next(position.current_registry->registry->channels->ht,
+                     &_position.channel_iterator.iter);
+}
+
+bool ls::user_space_consumer_channel_keys::iterator::operator==(const iterator& other) const noexcept
+{
+       if (_is_end && other._is_end) {
+               return true;
        }
 
        }
 
-       return {session, session_put};
+       /* Channel keys are unique; use them to compare the iterators. */
+       return !_is_end && !other._is_end && **this == *other;
+}
+
+bool ls::user_space_consumer_channel_keys::iterator::operator!=(const iterator& other) const noexcept
+{
+       return !(*this == other);
 }
 }
+
+ls::user_space_consumer_channel_keys::iterator::key
+ls::user_space_consumer_channel_keys::iterator::_get_current_value_per_pid() const noexcept
+{
+       auto& position = _position._per_pid;
+
+       const auto *channel_node =
+               lttng_ht_iter_get_node<lttng_ht_node_str>(&_position.channel_iterator);
+       const auto current_app_node =
+               lttng_ht_iter_get_node<lttng_ht_node_ulong>(&position.app_iterator);
+       LTTNG_ASSERT(current_app_node);
+
+       const auto& app = *lttng::utils::container_of(current_app_node, &ust_app::pid_n);
+
+       if (channel_node) {
+               const auto& channel =
+                       *lttng::utils::container_of(channel_node, &ust_app_channel::node);
+
+               return { static_cast<consumer_bitness>(app.abi.bits_per_long),
+                        channel.key,
+                        ls::user_space_consumer_channel_keys::channel_type::DATA };
+       } else {
+               LTTNG_ASSERT(position.current_registry_session);
+
+               /*
+                * Once the last data channel is delivered (iter points to the 'end' of the ht),
+                * deliver the metadata channel's key.
+                */
+               return { static_cast<consumer_bitness>(app.abi.bits_per_long),
+                        position.current_registry_session->_metadata_key,
+                        ls::user_space_consumer_channel_keys::channel_type::METADATA };
+       }
+}
+
+ls::user_space_consumer_channel_keys::iterator::key
+ls::user_space_consumer_channel_keys::iterator::_get_current_value_per_uid() const noexcept
+{
+       const auto *channel_node =
+               lttng_ht_iter_get_node<lttng_ht_node_u64>(&_position.channel_iterator);
+
+       if (channel_node) {
+               const auto& channel =
+                       *lttng::utils::container_of(channel_node, &buffer_reg_channel::node);
+
+               return { static_cast<consumer_bitness>(
+                                _position._per_uid.current_registry->bits_per_long),
+                        channel.consumer_key,
+                        ls::user_space_consumer_channel_keys::channel_type::DATA };
+       } else {
+               /*
+                * Once the last data channel is delivered (iter points to the 'end' of the ht),
+                * deliver the metadata channel's key.
+                */
+               return { static_cast<consumer_bitness>(
+                                _position._per_uid.current_registry->bits_per_long),
+                        _position._per_uid.current_registry->registry->reg.ust->_metadata_key,
+                        ls::user_space_consumer_channel_keys::channel_type::METADATA };
+       }
+}
+
+ls::user_space_consumer_channel_keys::iterator::key
+ls::user_space_consumer_channel_keys::iterator::operator*() const
+{
+       if (_is_end) {
+               LTTNG_THROW_OUT_OF_RANGE(
+                       "Attempt to use operator* on user_space_consumer_channel_keys iterator at the end position");
+       }
+
+       switch (_creation_context._mode) {
+       case _iteration_mode::PER_PID:
+               return _get_current_value_per_pid();
+       case _iteration_mode::PER_UID:
+               return _get_current_value_per_uid();
+       }
+
+       std::abort();
+}
+
+ls::ust::registry_session *ls::user_space_consumer_channel_keys::iterator::get_registry_session()
+{
+       if (_is_end) {
+               LTTNG_THROW_OUT_OF_RANGE(
+                       "Attempt to get registry session on user_space_consumer_channel_keys iterator at the end position");
+       }
+
+       switch (_creation_context._mode) {
+       case _iteration_mode::PER_PID:
+               return _get_registry_session_per_pid();
+       case _iteration_mode::PER_UID:
+               return _get_registry_session_per_uid();
+       }
+
+       std::abort();
+}
+
+ls::ust::registry_session *
+ls::user_space_consumer_channel_keys::iterator::_get_registry_session_per_pid()
+{
+       return _position._per_pid.current_registry_session;
+}
+
+ls::ust::registry_session *
+ls::user_space_consumer_channel_keys::iterator::_get_registry_session_per_uid()
+{
+       return _position._per_uid.current_registry->registry->reg.ust;
+}
\ No newline at end of file
This page took 0.046588 seconds and 4 git commands to generate.