+ LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
+ }
+
+ return ltt_session::make_ref(*session);
+}
+
+ltt_session::ref ltt_session::find_session(lttng::c_string_view name)
+{
+ const lttng::urcu::read_lock_guard rcu_lock;
+ auto session = session_find_by_name(name.data());
+
+ if (!session) {
+ LTTNG_THROW_SESSION_NOT_FOUND_BY_NAME_ERROR(name.data());
+ }
+
+ return ltt_session::make_ref(*session);
+}
+
+ltt_session::const_ref ltt_session::find_const_session(ltt_session::id_t id)
+{
+ const lttng::urcu::read_lock_guard rcu_lock;
+ const auto *session = session_find_by_id(id);
+
+ if (!session) {
+ LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
+ }
+
+ return ltt_session::make_ref(*session);
+}
+
+ltt_session::const_ref ltt_session::find_const_session(lttng::c_string_view name)
+{
+ const lttng::urcu::read_lock_guard rcu_lock;
+ const auto *session = session_find_by_name(name.data());
+
+ if (!session) {
+ LTTNG_THROW_SESSION_NOT_FOUND_BY_NAME_ERROR(name.data());
+ }
+
+ return ltt_session::make_ref(*session);
+}
+
+void ltt_session::_const_session_put(const ltt_session *session)
+{
+ /*
+ * The session list lock must be held as any session_put()
+ * may cause the removal of the session from the session_list.
+ */
+ ASSERT_SESSION_LIST_LOCKED();
+ LTTNG_ASSERT(session->ref_count.refcount);
+ urcu_ref_put(&session->ref_count, session_release);
+}
+
+std::unique_lock<std::mutex> ls::lock_session_list()
+{
+ return std::unique_lock<std::mutex>(the_session_list.lock);
+}
+
+lttng::sessiond::user_space_consumer_channel_keys
+ltt_session::user_space_consumer_channel_keys() const
+{
+ switch (ust_session->buffer_type) {
+ case LTTNG_BUFFER_PER_PID:
+ return lttng::sessiond::user_space_consumer_channel_keys(*ust_session,
+ *ust_app_get_all());
+ case LTTNG_BUFFER_PER_UID:
+ return lttng::sessiond::user_space_consumer_channel_keys(
+ *ust_session, ust_session->buffer_reg_uid_list);
+ default:
+ abort();
+ }
+}
+
+ls::user_space_consumer_channel_keys::iterator
+ls::user_space_consumer_channel_keys::begin() const noexcept
+{
+ return ls::user_space_consumer_channel_keys::iterator(_creation_context);
+}
+
+ls::user_space_consumer_channel_keys::iterator
+ls::user_space_consumer_channel_keys::end() const noexcept
+{
+ return ls::user_space_consumer_channel_keys::iterator(_creation_context, true);
+}
+
+ls::user_space_consumer_channel_keys::iterator&
+ls::user_space_consumer_channel_keys::iterator::operator++()
+{
+ if (_is_end) {
+ LTTNG_THROW_OUT_OF_RANGE(fmt::format(
+ "Attempted to advance channel key iterator past the end of channel keys: iteration_mode={}",
+ _creation_context._session.buffer_type));
+ }
+
+ switch (_creation_context._session.buffer_type) {
+ case LTTNG_BUFFER_PER_PID:
+ _advance_one_per_pid();
+ break;
+ case LTTNG_BUFFER_PER_UID:
+ _advance_one_per_uid();
+ break;
+ default:
+ abort();
+ }
+
+ return *this;
+}
+
+namespace {
+bool is_list_empty(const cds_list_head *head)
+{
+ return head == head->next;
+}
+
+bool is_last_element_of_list(const cds_list_head *head)
+{
+ return head->next == head->prev;
+}
+} /* namespace */
+
+ls::user_space_consumer_channel_keys::iterator::iterator(
+ const _iterator_creation_context& creation_context, bool is_end) :
+ _creation_context(creation_context), _is_end(is_end)
+{
+ if (_is_end) {
+ return;
+ }
+
+ switch (_creation_context._mode) {
+ case _iteration_mode::PER_PID:
+ _init_per_pid();
+ break;
+ case _iteration_mode::PER_UID:
+ _init_per_uid();
+ break;
+ }
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_skip_to_next_app_per_pid(
+ bool try_current) noexcept
+{
+ auto& position = _position._per_pid;
+
+ while (true) {
+ if (!try_current) {
+ lttng_ht_get_next(_creation_context._container.apps,
+ &position.app_iterator);
+ } else {
+ try_current = false;
+ }
+
+ const auto app_node =
+ lttng_ht_iter_get_node<lttng_ht_node_ulong>(&position.app_iterator);
+ if (!app_node) {
+ _is_end = true;
+ return;
+ }
+
+ const auto& app = *lttng::utils::container_of(app_node, &ust_app::pid_n);
+ auto app_session = ust_app_lookup_app_session(&_creation_context._session, &app);
+
+ if (!app_session) {
+ /* This app is not traced by the target session. */
+ continue;
+ }
+
+ position.current_app_session = app_session->lock();
+
+ auto *registry = ust_app_get_session_registry(
+ (*_position._per_pid.current_app_session)->get_identifier());
+ if (!registry) {
+ DBG_FMT("Application session is being torn down: skipping application: app={}",
+ app);
+ continue;
+ }
+
+ position.current_registry_session = registry;
+ lttng_ht_get_first((*position.current_app_session)->channels,
+ &_position.channel_iterator);
+ break;
+ }
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_init_per_pid() noexcept
+{
+ auto& position = _position._per_pid;
+
+ lttng_ht_get_first(_creation_context._container.apps, &position.app_iterator);
+ _skip_to_next_app_per_pid(true);
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_init_per_uid() noexcept
+{
+ auto& position = _position._per_uid;
+
+ /* Start the iteration: get the first registry and point to its first channel. */
+ if (is_list_empty(&_creation_context._session.buffer_reg_uid_list)) {
+ _is_end = true;
+ return;
+ }
+
+ position.current_registry = lttng::utils::container_of(
+ _creation_context._session.buffer_reg_uid_list.next, &buffer_reg_uid::lnode);
+ lttng_ht_get_first(position.current_registry->registry->channels,
+ &_position.channel_iterator);
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_advance_one_per_pid()
+{
+ auto& position = _position._per_pid;
+
+ if (!cds_lfht_iter_get_node(&_position.channel_iterator.iter)) {
+ /* Reached the last channel. Move on to the next app. */
+ _skip_to_next_app_per_pid(false);
+ return;
+ }
+
+ const auto current_app_node =
+ lttng_ht_iter_get_node<lttng_ht_node_ulong>(&position.app_iterator);
+ LTTNG_ASSERT(current_app_node);
+
+ lttng_ht_get_next((*position.current_app_session)->channels, &_position.channel_iterator);
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_advance_one_per_uid()
+{
+ auto& position = _position._per_uid;
+
+ if (!cds_lfht_iter_get_node(&_position.channel_iterator.iter)) {
+ /* Reached the last channel of the registry. Move on to the next registry. */
+ if (is_last_element_of_list(&position.current_registry->lnode)) {
+ _is_end = true;
+ return;
+ }
+
+ position.current_registry = lttng::utils::container_of(
+ position.current_registry->lnode.next, &buffer_reg_uid::lnode);
+ cds_lfht_first(position.current_registry->registry->channels->ht,
+ &_position.channel_iterator.iter);
+
+ /* Assumes a registry can't be empty. */
+ LTTNG_ASSERT(cds_lfht_iter_get_node(&_position.channel_iterator.iter));
+ }
+
+ cds_lfht_next(position.current_registry->registry->channels->ht,
+ &_position.channel_iterator.iter);
+}
+
+bool ls::user_space_consumer_channel_keys::iterator::operator==(const iterator& other) const noexcept
+{
+ if (_is_end && other._is_end) {
+ return true;