Use compiler-agnostic defines to silence warning
[lttng-tools.git] / src / bin / lttng-sessiond / session.cpp
index 0532a76867585fe8e7c22f4115a7abc8563e7330..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>
@@ -68,12 +71,68 @@ struct lttng_ht *ltt_sessions_ht_by_name = nullptr;
  *
  * 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 */
 
 /*
@@ -146,21 +205,11 @@ struct ltt_session_list *session_get_list()
 /*
  * Returns once the session list is empty.
  */
-void session_list_wait_empty()
+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() noexcept
-{
-       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); });
 }
 
 /*
@@ -168,23 +217,14 @@ void session_lock_list() noexcept
  */
 int session_trylock_list() noexcept
 {
-       return pthread_mutex_trylock(&the_session_list.lock);
-}
-
-/*
- * Release session list lock
- */
-void session_unlock_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,10 +238,8 @@ 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 = nullptr;
        const struct consumer_output *output;
@@ -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,11 +282,9 @@ 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 = nullptr;
@@ -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,36 +480,47 @@ 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();
+}
 
-       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
  */
-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;
 
-       lttng::urcu::read_lock_guard read_lock;
+       const lttng::urcu::read_lock_guard read_lock;
        /*
         * Ownership of current trace chunk is transferred to
         * `current_trace_chunk`.
@@ -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,
@@ -602,7 +656,7 @@ 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)
@@ -709,15 +763,13 @@ error:
        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(nullptr);
        const char *new_path;
@@ -782,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,
@@ -800,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,
@@ -836,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;
 
-       lttng::urcu::read_lock_guard 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
@@ -871,7 +929,7 @@ end:
        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;
 
@@ -902,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 =
@@ -928,19 +986,19 @@ 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(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 =
                        (ltt_session_clear_notifier_element *) lttng_dynamic_array_get_element(
-                               &session.clear_notifiers, i);
+                               &session->clear_notifiers, i);
 
-               element->notifier(&session, element->user_data);
+               element->notifier(session, element->user_data);
        }
-       lttng_dynamic_array_clear(&session.clear_notifiers);
+       lttng_dynamic_array_clear(&session->clear_notifiers);
 }
 
 static void session_release(struct urcu_ref *ref)
@@ -948,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);
@@ -987,14 +1045,26 @@ 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);
@@ -1011,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();
        }
 }
 
@@ -1025,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);
 }
 
 /*
@@ -1040,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);
 }
 
 /*
@@ -1078,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)
 {
@@ -1088,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)
 {
@@ -1098,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 nullptr;
-found:
-       return session_get(iter) ? iter : 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_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 == 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;
-}
-
 /*
  * Create a new session and add it to the session list.
  * Session list lock must be held by the caller.
@@ -1168,7 +1180,7 @@ session_create(const char *name, uid_t uid, gid_t gid, struct ltt_session **out_
        enum lttng_error_code ret_code;
        struct ltt_session *new_session = nullptr;
 
-       ASSERT_LOCKED(the_session_list.lock);
+       ASSERT_SESSION_LIST_LOCKED();
        if (name) {
                struct ltt_session *clashing_session;
 
@@ -1192,8 +1204,8 @@ session_create(const char *name, uid_t uid, gid_t gid, struct ltt_session **out_
        lttng_dynamic_array_init(&new_session->clear_notifiers,
                                 sizeof(struct ltt_session_clear_notifier_element),
                                 nullptr);
-       urcu_ref_init(&new_session->ref);
-       pthread_mutex_init(&new_session->lock, nullptr);
+       urcu_ref_init(&new_session->ref_count);
+       pthread_mutex_init(&new_session->_lock, nullptr);
 
        new_session->creation_time = time(nullptr);
        if (new_session->creation_time == (time_t) -1) {
@@ -1338,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;
 }
 
@@ -1359,26 +1370,26 @@ 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(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) {
+       session->rotation_state = result;
+       if (session->rotation_pending_check_timer_enabled) {
                ret = timer_session_rotation_pending_check_stop(session);
        }
-       if (session.chunk_being_archived) {
+       if (session->chunk_being_archived) {
                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_OPTIONAL_SET(&session.last_archived_chunk_id, chunk_id);
-               lttng_trace_chunk_put(session.chunk_being_archived);
-               session.chunk_being_archived = nullptr;
+               LTTNG_OPTIONAL_SET(&session->last_archived_chunk_id, chunk_id);
+               lttng_trace_chunk_put(session->chunk_being_archived);
+               session->chunk_being_archived = nullptr;
                /*
                 * Fire the clear reply notifiers if we are completing a clear
                 * rotation.
@@ -1404,7 +1415,7 @@ bool sample_session_id_by_name(const char *name, uint64_t *id)
        struct lttng_ht_iter iter;
        struct ltt_session *ls;
 
-       lttng::urcu::read_lock_guard read_lock;
+       const lttng::urcu::read_lock_guard read_lock;
 
        if (!ltt_sessions_ht_by_name) {
                found = false;
@@ -1412,7 +1423,7 @@ 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);
+       node = lttng_ht_iter_get_node<lttng_ht_node_str>(&iter);
        if (node == nullptr) {
                found = false;
                goto end;
@@ -1427,7 +1438,7 @@ end:
        return found;
 }
 
-void ls::details::locked_session_release(ltt_session *session)
+void ltt_session::_locked_session_release(ltt_session *session)
 {
        if (!session) {
                return;
@@ -1437,13 +1448,23 @@ void ls::details::locked_session_release(ltt_session *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) {
-               return nullptr;
+               LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
        }
 
        /*
@@ -1451,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::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::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::sptr ls::find_session_by_id(ltt_session::id_t id)
+ltt_session::ref ltt_session::find_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) {
-               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;
        }
 
-       return { session, session_put };
+       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.037502 seconds and 4 git commands to generate.