Use compiler-agnostic defines to silence warning
[lttng-tools.git] / src / bin / lttng-sessiond / session.cpp
index 54b255e056dff80b445420e5ed33b73b0c0d0a3b..8d6bc5c37ed574a18ac6792b674e7337e39f8106 100644 (file)
@@ -6,15 +6,18 @@
  */
 
 #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>
@@ -59,21 +62,77 @@ namespace ls = lttng::sessiond;
 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. */
-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.
  */
-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 */
 
 /*
@@ -138,7 +197,7 @@ static void del_session_list(struct ltt_session *ls)
 /*
  * 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;
 }
@@ -146,45 +205,26 @@ struct ltt_session_list *session_get_list(void)
 /*
  * 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
  */
-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.
- *
- * 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.
@@ -198,12 +238,10 @@ enum consumer_dst_type session_get_consumer_destination_type(const struct ltt_se
 /*
  * 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;
 
        output = session->kernel_session ? session->kernel_session->consumer :
@@ -229,10 +267,8 @@ 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".
- *
- * The caller must hold the session lock.
  */
-void session_get_net_consumer_ports(const struct ltt_session *session,
+void session_get_net_consumer_ports(const ltt_session::locked_ref& session,
                                    uint16_t *control_port,
                                    uint16_t *data_port)
 {
@@ -246,15 +282,13 @@ void session_get_net_consumer_ports(const struct ltt_session *session,
 
 /*
  * 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)
+session_get_trace_archive_location(const ltt_session::locked_ref& session)
 {
        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 ||
            !session->last_archived_chunk_name) {
@@ -300,7 +334,7 @@ end:
  *
  * The session list lock must be held.
  */
-static int ltt_sessions_ht_alloc(void)
+static int ltt_sessions_ht_alloc()
 {
        int ret = 0;
 
@@ -329,16 +363,16 @@ end:
  *
  * 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);
-               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);
-               ltt_sessions_ht_by_name = NULL;
+               ltt_sessions_ht_by_name = nullptr;
        }
 
        return;
@@ -381,7 +415,7 @@ end:
  * 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;
 
@@ -438,7 +472,7 @@ static void del_session_ht(struct ltt_session *ls)
        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();
        }
 }
@@ -446,49 +480,60 @@ static void del_session_ht(struct ltt_session *ls)
 /*
  * Acquire session lock
  */
-void session_lock(struct ltt_session *session)
+void session_lock(const ltt_session *session)
 {
        LTTNG_ASSERT(session);
+       session->lock();
+}
+
+void ltt_session::lock() const noexcept
+{
+       pthread_mutex_lock(&_lock);
+}
 
-       pthread_mutex_lock(&session->lock);
+void ltt_session::unlock() const noexcept
+{
+       ltt_session::_const_session_unlock(*this);
 }
 
 /*
  * Release session lock
  */
-void session_unlock(struct ltt_session *session)
+void session_unlock(const ltt_session *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,
+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;
-       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;
 
-       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;
-       session->current_trace_chunk = NULL;
+       session->current_trace_chunk = nullptr;
        if (session->ust_session) {
                lttng_trace_chunk_put(session->ust_session->current_trace_chunk);
-               session->ust_session->current_trace_chunk = NULL;
+               session->ust_session->current_trace_chunk = nullptr;
        }
        if (session->kernel_session) {
                lttng_trace_chunk_put(session->kernel_session->current_trace_chunk);
-               session->kernel_session->current_trace_chunk = NULL;
+               session->kernel_session->current_trace_chunk = nullptr;
        }
        if (!new_trace_chunk) {
                ret = 0;
@@ -524,8 +569,12 @@ static int _session_set_trace_chunk_no_lock_check(struct ltt_session *session,
                                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,
                                                          relayd_id,
@@ -538,6 +587,7 @@ static int _session_set_trace_chunk_no_lock_check(struct ltt_session *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 ==
@@ -553,8 +603,12 @@ static int _session_set_trace_chunk_no_lock_check(struct ltt_session *session,
                                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,
                                                          relayd_id,
@@ -577,18 +631,17 @@ static int _session_set_trace_chunk_no_lock_check(struct ltt_session *session,
 end:
        if (_current_trace_chunk) {
                *_current_trace_chunk = current_trace_chunk;
-               current_trace_chunk = NULL;
+               current_trace_chunk = nullptr;
        }
 end_no_move:
-       rcu_read_unlock();
        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) {
-               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
@@ -603,18 +656,18 @@ error:
 }
 
 struct lttng_trace_chunk *
-session_create_new_trace_chunk(const struct ltt_session *session,
+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;
-       struct lttng_trace_chunk *trace_chunk = NULL;
+       struct lttng_trace_chunk *trace_chunk = nullptr;
        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;
-       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),
@@ -655,7 +708,7 @@ session_create_new_trace_chunk(const struct ltt_session *session,
                if (!session->rotated) {
                        new_path = "";
                } else {
-                       new_path = NULL;
+                       new_path = nullptr;
                }
        } else {
                new_path = DEFAULT_CHUNK_TMP_NEW_DIRECTORY;
@@ -697,7 +750,7 @@ session_create_new_trace_chunk(const struct ltt_session *session,
        }
        chunk_status = lttng_trace_chunk_set_as_owner(trace_chunk, 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;
        }
@@ -706,21 +759,19 @@ end:
 error:
        lttng_directory_handle_put(session_output_directory);
        lttng_trace_chunk_put(trace_chunk);
-       trace_chunk = NULL;
+       trace_chunk = nullptr;
        goto end;
 }
 
-int session_close_trace_chunk(struct ltt_session *session,
+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;
-       struct cds_lfht_iter iter;
-       struct consumer_socket *socket;
        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;
 
        chunk_status = lttng_trace_chunk_set_close_command(trace_chunk, close_command);
@@ -741,7 +792,7 @@ int session_close_trace_chunk(struct ltt_session *session,
                new_path = "";
        } else {
                /* Use chunk name for new chunk. */
-               new_path = NULL;
+               new_path = nullptr;
        }
        if (session->current_trace_chunk &&
            !lttng_trace_chunk_get_name_overridden(session->current_trace_chunk)) {
@@ -760,7 +811,7 @@ int session_close_trace_chunk(struct ltt_session *session,
                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. */
                chunk_status = lttng_trace_chunk_rename_path(trace_chunk, old_path);
@@ -783,8 +834,11 @@ int session_close_trace_chunk(struct ltt_session *session,
        if (session->ust_session) {
                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,
                                                         relayd_id,
@@ -801,8 +855,11 @@ int session_close_trace_chunk(struct ltt_session *session,
        if (session->kernel_session) {
                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,
                                                         relayd_id,
@@ -837,21 +894,21 @@ end:
  * 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;
-       struct consumer_socket *socket;
        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);
-       socket = caa_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
@@ -869,11 +926,10 @@ static enum lttng_error_code session_kernel_open_packets(struct ltt_session *ses
        }
 
 end:
-       rcu_read_unlock();
        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;
 
@@ -904,19 +960,19 @@ end:
  *
  * Must be called with the session lock held.
  */
-int session_set_trace_chunk(struct ltt_session *session,
+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);
+       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;
-       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 =
@@ -930,10 +986,10 @@ static void session_notify_destruction(const struct ltt_session *session)
 /*
  * 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;
-       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 =
@@ -950,7 +1006,7 @@ static void session_release(struct urcu_ref *ref)
        int ret;
        struct ltt_ust_session *usess;
        struct ltt_kernel_session *ksess;
-       struct ltt_session *session = lttng::utils::container_of(ref, &ltt_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);
@@ -989,21 +1045,33 @@ static void session_release(struct urcu_ref *ref)
 
        snapshot_destroy(&session->snapshot);
 
-       pthread_mutex_destroy(&session->lock);
-
        if (session_published) {
-               ASSERT_LOCKED(the_session_list.lock);
+               ASSERT_SESSION_LIST_LOCKED();
                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);
-       session->kernel_session = NULL;
+       session->kernel_session = nullptr;
        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);
@@ -1013,11 +1081,12 @@ static void session_release(struct urcu_ref *ref)
        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();
        }
 }
 
@@ -1027,7 +1096,7 @@ static void session_release(struct urcu_ref *ref)
  */
 bool session_get(struct ltt_session *session)
 {
-       return urcu_ref_get_unless_zero(&session->ref);
+       return urcu_ref_get_unless_zero(&session->ref_count);
 }
 
 /*
@@ -1042,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.
         */
-       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);
 }
 
 /*
@@ -1080,7 +1149,7 @@ void session_destroy(struct ltt_session *session)
        session_put(session);
 }
 
-int session_add_destroy_notifier(struct ltt_session *session,
+int session_add_destroy_notifier(const ltt_session::locked_ref& session,
                                 ltt_session_destroy_notifier notifier,
                                 void *user_data)
 {
@@ -1090,7 +1159,7 @@ int session_add_destroy_notifier(struct ltt_session *session,
        return lttng_dynamic_array_add_element(&session->destroy_notifiers, &element);
 }
 
-int session_add_clear_notifier(struct ltt_session *session,
+int session_add_clear_notifier(const ltt_session::locked_ref& session,
                               ltt_session_clear_notifier notifier,
                               void *user_data)
 {
@@ -1100,65 +1169,6 @@ int session_add_clear_notifier(struct ltt_session *session,
        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;
-               }
-       }
-
-       return NULL;
-found:
-       return session_get(iter) ? iter : NULL;
-}
-
-/*
- * 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_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 = lttng::utils::container_of(node, &ltt_session::node);
-
-       DBG3("Session %" PRIu64 " found by id.", id);
-       return session_get(ls) ? ls : NULL;
-
-end:
-       DBG3("Session %" PRIu64 " NOT found by id", id);
-       return NULL;
-}
-
 /*
  * Create a new session and add it to the session list.
  * Session list lock must be held by the caller.
@@ -1168,9 +1178,9 @@ session_create(const char *name, uid_t uid, gid_t gid, struct ltt_session **out_
 {
        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;
 
@@ -1190,14 +1200,14 @@ session_create(const char *name, uid_t uid, gid_t gid, struct ltt_session **out_
 
        lttng_dynamic_array_init(&new_session->destroy_notifiers,
                                 sizeof(struct ltt_session_destroy_notifier_element),
-                                NULL);
+                                nullptr);
        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);
+                                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;
@@ -1206,7 +1216,7 @@ session_create(const char *name, uid_t uid, gid_t gid, struct ltt_session **out_
 
        /* 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;
        }
@@ -1332,7 +1342,7 @@ end:
        return ret_code;
 error:
        session_put(new_session);
-       new_session = NULL;
+       new_session = nullptr;
        goto end;
 }
 
@@ -1340,9 +1350,8 @@ error:
  * 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;
 }
 
@@ -1361,12 +1370,12 @@ bool session_access_ok(struct ltt_session *session, uid_t uid)
  *
  * 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;
 
-       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) {
@@ -1380,7 +1389,7 @@ int session_reset_rotation_state(struct ltt_session *session, enum lttng_rotatio
                LTTNG_ASSERT(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK);
                LTTNG_OPTIONAL_SET(&session->last_archived_chunk_id, chunk_id);
                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.
@@ -1406,7 +1415,7 @@ bool sample_session_id_by_name(const char *name, uint64_t *id)
        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;
@@ -1414,8 +1423,8 @@ bool sample_session_id_by_name(const char *name, uint64_t *id)
        }
 
        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;
        }
@@ -1426,23 +1435,36 @@ bool sample_session_id_by_name(const char *name, uint64_t *id)
 
        DBG3("Session id `%" PRIu64 "` sampled for session `%s", *id, name);
 end:
-       rcu_read_unlock();
        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);
 }
 
-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)
 {
-       lttng::urcu::read_lock_guard rcu_lock;
+       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)
+{
+       const lttng::urcu::read_lock_guard rcu_lock;
        auto session = session_find_by_id(id);
 
        if (!session) {
-               return nullptr;
+               LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
        }
 
        /*
@@ -1450,17 +1472,419 @@ ltt_session::locked_ptr ls::find_locked_session_by_id(ltt_session::id_t id)
         * session.
         */
        session_lock(session);
-       return ltt_session::locked_ptr(session);
+       return ltt_session::make_locked_ref(*session);
 }
 
-ltt_session::sptr ls::find_session_by_id(ltt_session::id_t id)
+ltt_session::locked_ref ltt_session::find_locked_session(lttng::c_string_view name)
 {
-       lttng::urcu::read_lock_guard rcu_lock;
+       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::const_locked_ref ltt_session::find_locked_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);
+       }
+
+       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) {
-               return nullptr;
+               LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
        }
 
-       return { session, session_put };
+       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;
+       }
+
+       /* 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.054241 seconds and 4 git commands to generate.