From: Jérémie Galarneau Date: Thu, 13 Jun 2024 21:50:04 +0000 (+0000) Subject: refactor: session: provide an iterator over consumer data channel keys X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=16d6497789d2c497820eb6b0e1db030a74115aa3;p=lttng-tools.git refactor: session: provide an iterator over consumer data channel keys The code iterating over the various data channel keys of the userspace domain is relatively complex and repeated in many places. It is refactored to provide an iterator that can be used in those various places. Change-Id: I560484f63757b5da0313dd651724bbea9bbd6867 Signed-off-by: Jérémie Galarneau --- diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am index 7dc4bbe4e..05a7a11ce 100644 --- a/src/bin/lttng-sessiond/Makefile.am +++ b/src/bin/lttng-sessiond/Makefile.am @@ -72,7 +72,7 @@ liblttng_sessiond_common_la_SOURCES += trace-ust.cpp ust-registry.cpp ust-app.cp ust-consumer.cpp ust-consumer.hpp notify-apps.cpp \ ust-clock-class.hpp ust-clock-class.cpp \ agent-thread.cpp agent-thread.hpp \ - ust-field-convert.cpp ust-field-convert.hpp \ + ust-field-convert.cpp ust-field-quirks.hpp \ ust-sigbus.cpp \ ust-registry-session.cpp ust-registry-session.hpp \ ust-registry-event.cpp ust-registry-event.hpp \ diff --git a/src/bin/lttng-sessiond/buffer-registry.hpp b/src/bin/lttng-sessiond/buffer-registry.hpp index 2bdc58367..f266fbce2 100644 --- a/src/bin/lttng-sessiond/buffer-registry.hpp +++ b/src/bin/lttng-sessiond/buffer-registry.hpp @@ -78,7 +78,7 @@ struct buffer_reg_uid { /* Indexed by session id. */ struct lttng_ht_node_u64 node; - /* Node of a linked list used to teardown object at a destroy session. */ + /* Node of the ust session's buffer_reg_uid_list. */ struct cds_list_head lnode; char root_shm_path[PATH_MAX]; diff --git a/src/bin/lttng-sessiond/client.cpp b/src/bin/lttng-sessiond/client.cpp index b4958e374..89989f377 100644 --- a/src/bin/lttng-sessiond/client.cpp +++ b/src/bin/lttng-sessiond/client.cpp @@ -589,7 +589,7 @@ static unsigned int lttng_sessions_count(uid_t uid, gid_t gid __attribute__((unu auto session = [raw_session_ptr]() { session_get(raw_session_ptr); raw_session_ptr->lock(); - return ltt_session::locked_ref(*raw_session_ptr); + return ltt_session::make_locked_ref(*raw_session_ptr); }(); /* Only count the sessions the user can control. */ diff --git a/src/bin/lttng-sessiond/cmd.cpp b/src/bin/lttng-sessiond/cmd.cpp index 8817b4568..6aa9c9402 100644 --- a/src/bin/lttng-sessiond/cmd.cpp +++ b/src/bin/lttng-sessiond/cmd.cpp @@ -3159,7 +3159,7 @@ cmd_create_session_from_descriptor(struct lttng_session_descriptor *descriptor, [new_session]() { session_get(new_session); new_session->lock(); - return ltt_session::locked_ref(*new_session); + return ltt_session::make_locked_ref(*new_session); }(), [](const ltt_session::locked_ref& session, void *user_data __attribute__((unused))) { @@ -3216,7 +3216,7 @@ cmd_create_session_from_descriptor(struct lttng_session_descriptor *descriptor, [new_session]() { session_get(new_session); new_session->lock(); - return ltt_session::locked_ref(*new_session); + return ltt_session::make_locked_ref(*new_session); }(), descriptor); if (ret_code != LTTNG_OK) { @@ -3980,7 +3980,7 @@ void cmd_list_lttng_sessions(struct lttng_session *sessions, auto session = [raw_session_ptr]() { session_get(raw_session_ptr); raw_session_ptr->lock(); - return ltt_session::locked_ref(*raw_session_ptr); + return ltt_session::make_locked_ref(*raw_session_ptr); }(); /* diff --git a/src/bin/lttng-sessiond/main.cpp b/src/bin/lttng-sessiond/main.cpp index ee4e4690b..b5a42b5dc 100644 --- a/src/bin/lttng-sessiond/main.cpp +++ b/src/bin/lttng-sessiond/main.cpp @@ -1296,7 +1296,7 @@ static void destroy_all_sessions_and_wait() const auto session = [raw_session_ptr]() { session_get(raw_session_ptr); raw_session_ptr->lock(); - return ltt_session::locked_ref(*raw_session_ptr); + return ltt_session::make_locked_ref(*raw_session_ptr); }(); if (session->destroyed) { diff --git a/src/bin/lttng-sessiond/rotation-thread.cpp b/src/bin/lttng-sessiond/rotation-thread.cpp index 71f9bbcb5..10e065672 100644 --- a/src/bin/lttng-sessiond/rotation-thread.cpp +++ b/src/bin/lttng-sessiond/rotation-thread.cpp @@ -548,7 +548,7 @@ void ls::rotation_thread::_handle_job_queue() /* locked_ref will unlock the session and release the ref held by the job. */ session_lock(job->session); - auto session = ltt_session::locked_ref(*job->session); + auto session = ltt_session::make_locked_ref(*job->session); if (run_job(*job, session, _notification_thread_handle)) { return; diff --git a/src/bin/lttng-sessiond/save.cpp b/src/bin/lttng-sessiond/save.cpp index b65bcf9f2..7e3c49290 100644 --- a/src/bin/lttng-sessiond/save.cpp +++ b/src/bin/lttng-sessiond/save.cpp @@ -2762,7 +2762,7 @@ int cmd_save_sessions(struct lttng_save_session_attr *attr, lttng_sock_cred *cre auto session = [raw_session_ptr]() { session_get(raw_session_ptr); raw_session_ptr->lock(); - return ltt_session::locked_ref(*raw_session_ptr); + return ltt_session::make_locked_ref(*raw_session_ptr); }(); const auto save_ret = save_session(session, attr, creds); diff --git a/src/bin/lttng-sessiond/session.cpp b/src/bin/lttng-sessiond/session.cpp index cfa8c8b03..ea92db57f 100644 --- a/src/bin/lttng-sessiond/session.cpp +++ b/src/bin/lttng-sessiond/session.cpp @@ -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 +#include #include #include #include @@ -475,7 +478,7 @@ 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(); @@ -494,7 +497,7 @@ void ltt_session::unlock() const noexcept /* * Release session lock */ -void session_unlock(struct ltt_session *session) +void session_unlock(const ltt_session *session) { LTTNG_ASSERT(session); session->unlock(); @@ -1045,7 +1048,7 @@ static void session_release(struct urcu_ref *ref) session_notify_destruction([session]() { session_lock(session); session_get(session); - return ltt_session::locked_ref(*session); + return ltt_session::make_locked_ref(*session); }()); pthread_mutex_destroy(&session->_lock); @@ -1456,7 +1459,7 @@ ltt_session::locked_ref ltt_session::find_locked_session(ltt_session::id_t id) * session. */ session_lock(session); - return ltt_session::locked_ref(*session); + return ltt_session::make_locked_ref(*session); } ltt_session::locked_ref ltt_session::find_locked_session(lttng::c_string_view name) @@ -1469,33 +1472,33 @@ ltt_session::locked_ref ltt_session::find_locked_session(lttng::c_string_view na } session_lock(session); - return ltt_session::locked_ref(*session); + return ltt_session::make_locked_ref(*session); } ltt_session::const_locked_ref ltt_session::find_locked_const_session(ltt_session::id_t id) { lttng::urcu::read_lock_guard rcu_lock; - auto session = session_find_by_id(id); + 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::const_locked_ref(*session); + return ltt_session::make_locked_ref(*session); } ltt_session::const_locked_ref ltt_session::find_locked_const_session(lttng::c_string_view name) { lttng::urcu::read_lock_guard rcu_lock; - auto session = session_find_by_name(name.data()); + 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::const_locked_ref(*session); + return ltt_session::make_locked_ref(*session); } ltt_session::ref ltt_session::find_session(ltt_session::id_t id) @@ -1507,7 +1510,7 @@ ltt_session::ref ltt_session::find_session(ltt_session::id_t id) LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id); } - return ltt_session::ref(*session); + return ltt_session::make_ref(*session); } ltt_session::ref ltt_session::find_session(lttng::c_string_view name) @@ -1519,31 +1522,31 @@ ltt_session::ref ltt_session::find_session(lttng::c_string_view name) LTTNG_THROW_SESSION_NOT_FOUND_BY_NAME_ERROR(name.data()); } - return ltt_session::ref(*session); + return ltt_session::make_ref(*session); } ltt_session::const_ref ltt_session::find_const_session(ltt_session::id_t id) { lttng::urcu::read_lock_guard rcu_lock; - auto session = session_find_by_id(id); + const auto *session = session_find_by_id(id); if (!session) { LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id); } - return ltt_session::const_ref(*session); + return ltt_session::make_ref(*session); } ltt_session::const_ref ltt_session::find_const_session(lttng::c_string_view name) { lttng::urcu::read_lock_guard rcu_lock; - auto session = session_find_by_name(name.data()); + const auto *session = session_find_by_name(name.data()); if (!session) { LTTNG_THROW_SESSION_NOT_FOUND_BY_NAME_ERROR(name.data()); } - return ltt_session::const_ref(*session); + return ltt_session::make_ref(*session); } void ltt_session::_const_session_put(const ltt_session *session) @@ -1561,3 +1564,314 @@ std::unique_lock ls::lock_session_list() { return std::unique_lock(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(&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(&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(&_position.channel_iterator); + const auto current_app_node = + lttng_ht_iter_get_node(&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(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(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(&_position.channel_iterator); + + if (channel_node) { + const auto& channel = + *lttng::utils::container_of(channel_node, &buffer_reg_channel::node); + + return { static_cast( + _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( + _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 diff --git a/src/bin/lttng-sessiond/session.hpp b/src/bin/lttng-sessiond/session.hpp index d86147ac4..3f1dda990 100644 --- a/src/bin/lttng-sessiond/session.hpp +++ b/src/bin/lttng-sessiond/session.hpp @@ -11,6 +11,8 @@ #include "consumer.hpp" #include "snapshot.hpp" #include "trace-kernel.hpp" +#include "trace-ust.hpp" +#include "ust-app.hpp" #include #include @@ -18,6 +20,7 @@ #include #include #include +#include #include #include @@ -35,11 +38,12 @@ struct ltt_ust_session; struct ltt_session; struct ltt_session_list; +struct buffer_reg_uid; enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid, struct ltt_session **out_session); -void session_lock(struct ltt_session *session); -void session_unlock(struct ltt_session *session); +void session_lock(const ltt_session *session); +void session_unlock(const ltt_session *session); bool session_get(struct ltt_session *session); void session_put(struct ltt_session *session); @@ -92,12 +96,165 @@ struct ltt_session_list { struct cds_list_head head = CDS_LIST_HEAD_INIT(head); }; +namespace lttng { +namespace sessiond { +class user_space_consumer_channel_keys { + friend ltt_session; + +public: + class iterator; + + enum class consumer_bitness : std::uint8_t { + ABI_32 = 32, + ABI_64 = 64, + }; + + enum class channel_type : std::uint8_t { + METADATA, + DATA, + }; + + iterator begin() const noexcept; + iterator end() const noexcept; + +private: + enum class _iteration_mode : std::uint8_t { + PER_PID, + PER_UID, + + }; + + struct _iterator_creation_context { + const _iteration_mode _mode; + const ltt_ust_session& _session; + union { + lttng_ht *apps; + const cds_list_head *buffer_registry; + } _container; + }; + +public: + class iterator : public std::iterator { + friend user_space_consumer_channel_keys; + + public: + struct key { + /* Bitness is needed to query the appropriate consumer daemon. */ + consumer_bitness bitness; + std::uint64_t key_value; + channel_type type; + + bool operator==(const key& other) + { + return bitness == other.bitness && key_value == other.key_value && + type == other.type; + } + }; + + /* + * Copy constructor disabled since it would require handling the copy of locked + * references. + */ + iterator(const iterator& other) = delete; + iterator(iterator&& other) = default; + ~iterator() = default; + + iterator& operator++(); + bool operator==(const iterator& other) const noexcept; + bool operator!=(const iterator& other) const noexcept; + key operator*() const; + + /* + * Get the session registry of the channel currently + * pointed by the iterator. Never returns nullptr. + */ + lttng::sessiond::ust::registry_session *get_registry_session(); + + private: + struct _iterator_position { + struct { + lttng_ht_iter app_iterator = {}; + nonstd::optional + current_app_session; + lttng::sessiond::ust::registry_session *current_registry_session = + nullptr; + } _per_pid; + struct { + buffer_reg_uid *current_registry = nullptr; + } _per_uid; + + lttng_ht_iter channel_iterator = {}; + }; + + explicit iterator(const _iterator_creation_context& creation_context, + bool is_end = false); + + void _init_per_pid() noexcept; + void _skip_to_next_app_per_pid(bool try_current) noexcept; + void _advance_one_per_pid(); + key _get_current_value_per_pid() const noexcept; + lttng::sessiond::ust::registry_session *_get_registry_session_per_pid(); + + void _init_per_uid() noexcept; + void _advance_one_per_uid(); + key _get_current_value_per_uid() const noexcept; + lttng::sessiond::ust::registry_session *_get_registry_session_per_uid(); + + const _iterator_creation_context& _creation_context; + _iterator_position _position; + bool _is_end; + }; + +private: + user_space_consumer_channel_keys(const ltt_ust_session& ust_session, lttng_ht& apps) : + _creation_context{ _iteration_mode::PER_PID, ust_session, { .apps = &apps } } + { + } + + user_space_consumer_channel_keys(const ltt_ust_session& ust_session, + const cds_list_head& buffer_registry) : + _creation_context{ _iteration_mode::PER_UID, + ust_session, + { .buffer_registry = &buffer_registry } } + { + } + + class _scoped_rcu_read_lock { + public: + _scoped_rcu_read_lock() + { + rcu_read_lock(); + } + + ~_scoped_rcu_read_lock() + { + if (_armed) { + rcu_read_unlock(); + } + } + + _scoped_rcu_read_lock(_scoped_rcu_read_lock&& other) + { + other._armed = false; + } + + private: + bool _armed = true; + }; + + _scoped_rcu_read_lock _read_lock; + _iterator_creation_context _creation_context; +}; +} /* namespace sessiond */ +} /* namespace lttng */ + /* * This data structure contains information needed to identify a tracing * session for both LTTng and UST. */ struct ltt_session { using id_t = uint64_t; + friend lttng::sessiond::user_space_consumer_channel_keys::iterator; private: static void _locked_session_release(ltt_session *session); @@ -123,9 +280,35 @@ public: lttng::memory::create_deleter_class::deleter>; + static locked_ref make_locked_ref(ltt_session& session) + { + return lttng::make_non_copyable_reference(session); + } + + static const_locked_ref make_locked_ref(const ltt_session& session) + { + return lttng::make_non_copyable_reference(session); + } + + static ref make_ref(ltt_session& session) + { + return lttng::make_non_copyable_reference( + session); + } + + static const_ref make_ref(const ltt_session& session) + { + return lttng::make_non_copyable_reference(session); + } + void lock() const noexcept; void unlock() const noexcept; + lttng::sessiond::user_space_consumer_channel_keys user_space_consumer_channel_keys() const; + /* * Session list lock must be acquired by the caller. * @@ -459,4 +642,34 @@ bool session_output_supports_trace_chunks(const struct ltt_session *session); */ bool sample_session_id_by_name(const char *name, uint64_t *id); +const char *session_get_base_path(const ltt_session::locked_ref& session); + +#ifdef HAVE_LIBLTTNG_UST_CTL + +enum lttng_error_code ust_app_rotate_session(const ltt_session::locked_ref& session); +enum lttng_error_code ust_app_clear_session(const ltt_session::locked_ref& session); +enum lttng_error_code ust_app_open_packets(const ltt_session::locked_ref& session); + +#else /* HAVE_LIBLTTNG_UST_CTL */ + +static inline enum lttng_error_code ust_app_rotate_session(const ltt_session::locked_ref& session + __attribute__((unused))) +{ + return LTTNG_ERR_UNK; +} + +static inline enum lttng_error_code ust_app_clear_session(const ltt_session::locked_ref& session + __attribute__((unused))) +{ + return LTTNG_ERR_UNK; +} + +static inline enum lttng_error_code ust_app_open_packets(const ltt_session::locked_ref& session + __attribute__((unused))) +{ + return LTTNG_ERR_UNK; +} + +#endif /* HAVE_LIBLTTNG_UST_CTL */ + #endif /* _LTT_SESSION_H */ diff --git a/src/bin/lttng-sessiond/ust-app.cpp b/src/bin/lttng-sessiond/ust-app.cpp index 0e40506ff..cc23c75fa 100644 --- a/src/bin/lttng-sessiond/ust-app.cpp +++ b/src/bin/lttng-sessiond/ust-app.cpp @@ -22,7 +22,7 @@ #include "session.hpp" #include "ust-app.hpp" #include "ust-consumer.hpp" -#include "ust-field-convert.hpp" +#include "ust-field-quirks.hpp" #include "utils.hpp" #include @@ -76,8 +76,6 @@ static pthread_mutex_t next_channel_key_lock = PTHREAD_MUTEX_INITIALIZER; static uint64_t _next_session_id; static pthread_mutex_t next_session_id_lock = PTHREAD_MUTEX_INITIALIZER; -namespace { - /* * Return the session registry according to the buffer type of the given * session. @@ -85,28 +83,28 @@ namespace { * A registry per UID object MUST exists before calling this function or else * it LTTNG_ASSERT() if not found. RCU read side lock must be acquired. */ -lsu::registry_session *get_session_registry(const struct ust_app_session *ua_sess) +lsu::registry_session *ust_app_get_session_registry(const ust_app_session::identifier& ua_sess_id) { lsu::registry_session *registry = nullptr; - LTTNG_ASSERT(ua_sess); - - switch (ua_sess->buffer_type) { - case LTTNG_BUFFER_PER_PID: + switch (ua_sess_id.allocation_policy) { + case ust_app_session::identifier::buffer_allocation_policy::PER_PID: { - struct buffer_reg_pid *reg_pid = buffer_reg_pid_find(ua_sess->id); + struct buffer_reg_pid *reg_pid = buffer_reg_pid_find(ua_sess_id.id); if (!reg_pid) { goto error; } registry = reg_pid->registry->reg.ust; break; } - case LTTNG_BUFFER_PER_UID: + case ust_app_session::identifier::buffer_allocation_policy::PER_UID: { - struct buffer_reg_uid *reg_uid = - buffer_reg_uid_find(ua_sess->tracing_id, - ua_sess->bits_per_long, - lttng_credentials_get_uid(&ua_sess->real_credentials)); + struct buffer_reg_uid *reg_uid = buffer_reg_uid_find( + ua_sess_id.session_id, + ua_sess_id.abi == ust_app_session::identifier::application_abi::ABI_32 ? + 32 : + 64, + lttng_credentials_get_uid(&ua_sess_id.app_credentials)); if (!reg_uid) { goto error; } @@ -121,9 +119,11 @@ error: return registry; } -lsu::registry_session::locked_ref get_locked_session_registry(const struct ust_app_session *ua_sess) +namespace { +lsu::registry_session::locked_ref +get_locked_session_registry(const ust_app_session::identifier& identifier) { - auto session = get_session_registry(ua_sess); + auto session = ust_app_get_session_registry(identifier); if (session) { pthread_mutex_lock(&session->_lock); } @@ -931,7 +931,7 @@ static void delete_ust_app_session(int sock, struct ust_app_session *ua_sess, st LTTNG_ASSERT(!ua_sess->deleted); ua_sess->deleted = true; - auto locked_registry = get_locked_session_registry(ua_sess); + auto locked_registry = get_locked_session_registry(locked_ua_sess->get_identifier()); /* Registry can be null on error path during initialization. */ if (locked_registry) { /* Push metadata for application before freeing the application. */ @@ -1185,9 +1185,10 @@ error_free: /* * Alloc new UST app channel. */ -static struct ust_app_channel *alloc_ust_app_channel(const char *name, - struct ust_app_session *ua_sess, - struct lttng_ust_abi_channel_attr *attr) +static struct ust_app_channel * +alloc_ust_app_channel(const char *name, + const ust_app_session::locked_weak_ref& ua_sess, + struct lttng_ust_abi_channel_attr *attr) { struct ust_app_channel *ua_chan; @@ -1204,7 +1205,7 @@ static struct ust_app_channel *alloc_ust_app_channel(const char *name, ua_chan->enabled = true; ua_chan->handle = -1; - ua_chan->session = ua_sess; + ua_chan->session = &ua_sess.get(); ua_chan->key = get_next_channel_key(); ua_chan->ctx = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG); ua_chan->events = lttng_ht_new(0, LTTNG_HT_TYPE_STRING); @@ -1832,7 +1833,7 @@ error: * Disable the specified channel on to UST tracer for the UST session. */ static int disable_ust_channel(struct ust_app *app, - struct ust_app_session *ua_sess, + const ust_app_session::locked_weak_ref& ua_sess, struct ust_app_channel *ua_chan) { int ret; @@ -1875,7 +1876,7 @@ error: * Enable the specified channel on to UST tracer for the UST session. */ static int enable_ust_channel(struct ust_app *app, - struct ust_app_session *ua_sess, + const ust_app_session::locked_weak_ref& ua_sess, struct ust_app_channel *ua_chan) { int ret; @@ -2518,9 +2519,8 @@ error: /* * Lookup sesison wrapper. */ -static void __lookup_session_by_app(const struct ltt_ust_session *usess, - struct ust_app *app, - struct lttng_ht_iter *iter) +static void +__lookup_session_by_app(const ltt_ust_session *usess, const ust_app *app, lttng_ht_iter *iter) { /* Get right UST app session from app */ lttng_ht_lookup(app->sessions, &usess->id, iter); @@ -2530,8 +2530,8 @@ static void __lookup_session_by_app(const struct ltt_ust_session *usess, * Return ust app session from the app session hashtable using the UST session * id. */ -static struct ust_app_session *lookup_session_by_app(const struct ltt_ust_session *usess, - struct ust_app *app) +ust_app_session *ust_app_lookup_app_session(const struct ltt_ust_session *usess, + const struct ust_app *app) { struct lttng_ht_iter iter; struct lttng_ht_node_u64 *node; @@ -2716,7 +2716,7 @@ static int find_or_create_ust_app_session(struct ltt_ust_session *usess, health_code_update(); - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (ua_sess == nullptr) { DBG2("UST app pid: %d session id %" PRIu64 " not found, creating it", app->pid, @@ -2976,7 +2976,7 @@ error: /* * Lookup ust app channel for session and disable it on the tracer side. */ -static int disable_ust_app_channel(struct ust_app_session *ua_sess, +static int disable_ust_app_channel(const ust_app_session::locked_weak_ref& ua_sess, struct ust_app_channel *ua_chan, struct ust_app *app) { @@ -2997,7 +2997,7 @@ error: * Lookup ust app channel for session and enable it on the tracer side. This * MUST be called with a RCU read side lock acquired. */ -static int enable_ust_app_channel(struct ust_app_session *ua_sess, +static int enable_ust_app_channel(const ust_app_session::locked_weak_ref& ua_sess, struct ltt_ust_channel *uchan, struct ust_app *app) { @@ -3555,7 +3555,7 @@ error: */ static int create_channel_per_pid(struct ust_app *app, struct ltt_ust_session *usess, - struct ust_app_session *ua_sess, + const ust_app_session::locked_weak_ref& ua_sess, struct ust_app_channel *ua_chan) { int ret; @@ -3565,14 +3565,13 @@ static int create_channel_per_pid(struct ust_app *app, LTTNG_ASSERT(app); LTTNG_ASSERT(usess); - LTTNG_ASSERT(ua_sess); LTTNG_ASSERT(ua_chan); DBG("UST app creating channel %s with per PID buffers", ua_chan->name); lttng::urcu::read_lock_guard read_lock; - registry = get_session_registry(ua_sess); + registry = ust_app_get_session_registry(ua_sess->get_identifier()); /* The UST app session lock is held, registry shall not be null. */ LTTNG_ASSERT(registry); @@ -3593,13 +3592,14 @@ static int create_channel_per_pid(struct ust_app *app, } /* Create and get channel on the consumer side. */ - ret = do_consumer_create_channel(usess, ua_sess, ua_chan, app->abi.bits_per_long, registry); + ret = do_consumer_create_channel( + usess, &ua_sess.get(), ua_chan, app->abi.bits_per_long, registry); if (ret < 0) { ERR("Error creating UST channel \"%s\" on the consumer daemon", ua_chan->name); goto error_remove_from_registry; } - ret = send_channel_pid_to_ust(app, ua_sess, ua_chan); + ret = send_channel_pid_to_ust(app, &ua_sess.get(), ua_chan); if (ret < 0) { if (ret != -ENOTCONN) { ERR("Error sending channel to application"); @@ -3653,7 +3653,7 @@ error: */ static int ust_app_channel_send(struct ust_app *app, struct ltt_ust_session *usess, - struct ust_app_session *ua_sess, + const ust_app_session::locked_weak_ref& ua_sess, struct ust_app_channel *ua_chan) { int ret; @@ -3661,7 +3661,6 @@ static int ust_app_channel_send(struct ust_app *app, LTTNG_ASSERT(app); LTTNG_ASSERT(usess); LTTNG_ASSERT(usess->active); - LTTNG_ASSERT(ua_sess); LTTNG_ASSERT(ua_chan); ASSERT_RCU_READ_LOCKED(); @@ -3669,7 +3668,7 @@ static int ust_app_channel_send(struct ust_app *app, switch (usess->buffer_type) { case LTTNG_BUFFER_PER_UID: { - ret = create_channel_per_uid(app, usess, ua_sess, ua_chan); + ret = create_channel_per_uid(app, usess, &ua_sess.get(), ua_chan); if (ret < 0) { goto error; } @@ -3712,7 +3711,7 @@ error: * * Return 0 on success or else a negative value. */ -static int ust_app_channel_allocate(struct ust_app_session *ua_sess, +static int ust_app_channel_allocate(const ust_app_session::locked_weak_ref& ua_sess, struct ltt_ust_channel *uchan, enum lttng_ust_abi_chan_type type, struct ltt_ust_session *usess __attribute__((unused)), @@ -3877,7 +3876,7 @@ end: * * Called with UST app session lock held and RCU read side lock. */ -static int create_ust_app_metadata(struct ust_app_session *ua_sess, +static int create_ust_app_metadata(const ust_app_session::locked_weak_ref& ua_sess, struct ust_app *app, struct consumer_output *consumer) { @@ -3885,12 +3884,11 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, struct ust_app_channel *metadata; struct consumer_socket *socket; - LTTNG_ASSERT(ua_sess); LTTNG_ASSERT(app); LTTNG_ASSERT(consumer); ASSERT_RCU_READ_LOCKED(); - auto locked_registry = get_locked_session_registry(ua_sess); + auto locked_registry = get_locked_session_registry(ua_sess->get_identifier()); /* The UST app session is held registry shall not be null. */ LTTNG_ASSERT(locked_registry); @@ -3943,7 +3941,7 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, * never added or monitored until we do a first push metadata to the * consumer. */ - ret = ust_consumer_ask_channel(ua_sess, + ret = ust_consumer_ask_channel(&ua_sess.get(), metadata, consumer, socket, @@ -4361,7 +4359,8 @@ static void ust_app_unregister(ust_app& app) * The close metadata below nullifies the metadata pointer in the * session so the delete session will NOT push/close a second time. */ - auto locked_registry = get_locked_session_registry(ua_sess); + auto locked_registry = + get_locked_session_registry(locked_ua_sess->get_identifier()); if (locked_registry) { /* Push metadata for application before freeing the application. */ (void) push_metadata(locked_registry, ua_sess->consumer); @@ -4863,7 +4862,7 @@ int ust_app_disable_channel_glb(struct ltt_ust_session *usess, struct ltt_ust_ch */ continue; } - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (ua_sess == nullptr) { continue; } @@ -4879,7 +4878,7 @@ int ust_app_disable_channel_glb(struct ltt_ust_session *usess, struct ltt_ust_ch LTTNG_ASSERT(ua_chan->enabled); /* Disable channel onto application */ - ret = disable_ust_app_channel(ua_sess, ua_chan, app); + ret = disable_ust_app_channel(ua_sess->lock(), ua_chan, app); if (ret < 0) { /* XXX: We might want to report this error at some point... */ continue; @@ -4917,13 +4916,13 @@ int ust_app_enable_channel_glb(struct ltt_ust_session *usess, struct ltt_ust_cha */ continue; } - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (ua_sess == nullptr) { continue; } /* Enable channel onto application */ - ret = enable_ust_app_channel(ua_sess, uchan, app); + ret = enable_ust_app_channel(ua_sess->lock(), uchan, app); if (ret < 0) { /* XXX: We might want to report this error at some point... */ continue; @@ -4968,7 +4967,7 @@ int ust_app_disable_event_glb(struct ltt_ust_session *usess, */ continue; } - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (ua_sess == nullptr) { /* Next app */ continue; @@ -5017,7 +5016,7 @@ int ust_app_disable_event_glb(struct ltt_ust_session *usess, /* The ua_sess lock must be held by the caller. */ static int ust_app_channel_create(struct ltt_ust_session *usess, - struct ust_app_session *ua_sess, + const ust_app_session::locked_weak_ref& ua_sess, struct ltt_ust_channel *uchan, struct ust_app *app, struct ust_app_channel **_ua_chan) @@ -5025,8 +5024,6 @@ static int ust_app_channel_create(struct ltt_ust_session *usess, int ret = 0; struct ust_app_channel *ua_chan = nullptr; - LTTNG_ASSERT(ua_sess); - if (!strncmp(uchan->name, DEFAULT_METADATA_NAME, sizeof(uchan->name))) { copy_channel_attr_to_ustctl(&ua_sess->metadata_attr, &uchan->attr); ret = 0; @@ -5123,7 +5120,7 @@ int ust_app_enable_event_glb(struct ltt_ust_session *usess, */ continue; } - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (!ua_sess) { /* The application has problem or is probably dead. */ continue; @@ -5207,7 +5204,7 @@ int ust_app_create_event_glb(struct ltt_ust_session *usess, continue; } - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (!ua_sess) { /* The application has problem or is probably dead. */ continue; @@ -5266,7 +5263,7 @@ static int ust_app_start_trace(struct ltt_ust_session *usess, struct ust_app *ap return 0; } - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (ua_sess == nullptr) { /* The session is in teardown process. Ignore and continue. */ return 0; @@ -5356,7 +5353,7 @@ static int ust_app_stop_trace(struct ltt_ust_session *usess, struct ust_app *app return 0; } - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (ua_sess == nullptr) { return 0; } @@ -5432,7 +5429,8 @@ static int ust_app_stop_trace(struct ltt_ust_session *usess, struct ust_app *app health_code_update(); { - auto locked_registry = get_locked_session_registry(ua_sess); + auto locked_registry = + get_locked_session_registry(locked_ua_sess->get_identifier()); /* The UST app session is held registry shall not be null. */ LTTNG_ASSERT(locked_registry); @@ -5556,7 +5554,7 @@ static int ust_app_flush_session(struct ltt_ust_session *usess) lttng::urcu::read_lock_guard read_lock; cds_lfht_for_each_entry (ust_app_ht->ht, &iter.iter, app, pid_n.node) { - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (ua_sess == nullptr) { continue; } @@ -5690,7 +5688,7 @@ static int ust_app_clear_quiescent_session(struct ltt_ust_session *usess) lttng::urcu::read_lock_guard read_lock; cds_lfht_for_each_entry (ust_app_ht->ht, &iter.iter, app, pid_n.node) { - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (ua_sess == nullptr) { continue; } @@ -5863,7 +5861,7 @@ int ust_app_destroy_trace_all(struct ltt_ust_session *usess) /* The ua_sess lock must be held by the caller. */ static int find_or_create_ust_app_channel(struct ltt_ust_session *usess, - struct ust_app_session *ua_sess, + const ust_app_session::locked_weak_ref& ua_sess, struct ust_app *app, struct ltt_ust_channel *uchan, struct ust_app_channel **ua_chan) @@ -6066,7 +6064,7 @@ end: * RCU read lock must be held by the caller. */ static void ust_app_synchronize_all_channels(struct ltt_ust_session *usess, - struct ust_app_session *ua_sess, + const ust_app_session::locked_weak_ref& ua_sess, struct ust_app *app) { int ret = 0; @@ -6074,7 +6072,6 @@ static void ust_app_synchronize_all_channels(struct ltt_ust_session *usess, struct ltt_ust_channel *uchan; LTTNG_ASSERT(usess); - LTTNG_ASSERT(ua_sess); LTTNG_ASSERT(app); ASSERT_RCU_READ_LOCKED(); @@ -6151,7 +6148,7 @@ static void ust_app_synchronize(struct ltt_ust_session *usess, struct ust_app *a { lttng::urcu::read_lock_guard read_lock; - ust_app_synchronize_all_channels(usess, ua_sess, app); + ust_app_synchronize_all_channels(usess, locked_ua_sess, app); /* * Create the metadata for the application. This returns gracefully if a @@ -6162,7 +6159,7 @@ static void ust_app_synchronize(struct ltt_ust_session *usess, struct ust_app *a * daemon, the consumer will use this assumption to send the * "STREAMS_SENT" message to the relay daemon. */ - ret = create_ust_app_metadata(ua_sess, app, usess->consumer); + ret = create_ust_app_metadata(locked_ua_sess, app, usess->consumer); if (ret < 0) { ERR("Metadata creation failed for app sock %d for session id %" PRIu64, app->sock, @@ -6175,7 +6172,7 @@ static void ust_app_global_destroy(struct ltt_ust_session *usess, struct ust_app { struct ust_app_session *ua_sess; - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (ua_sess == nullptr) { return; } @@ -6295,7 +6292,7 @@ int ust_app_add_ctx_channel_glb(struct ltt_ust_session *usess, */ continue; } - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (ua_sess == nullptr) { continue; } @@ -6476,7 +6473,15 @@ static int handle_app_register_channel_notification(int sock, ua_sess = ua_chan->session; /* Get right session registry depending on the session buffer type. */ - auto locked_registry_session = get_locked_session_registry(ua_sess); + + /* + * HACK: ua_sess is already locked by the client thread. This is called + * in the context of the handling of a notification from the application. + */ + auto locked_ua_sess = ust_app_session::make_locked_weak_ref(*ua_sess); + auto locked_registry_session = + get_locked_session_registry(locked_ua_sess->get_identifier()); + locked_ua_sess.release(); if (!locked_registry_session) { DBG("Application session is being torn down. Abort event notify"); return 0; @@ -6648,7 +6653,7 @@ static int add_event_ust_registry(int sock, } { - auto locked_registry = get_locked_session_registry(ua_sess); + auto locked_registry = get_locked_session_registry(ua_sess->get_identifier()); if (locked_registry) { /* * From this point on, this call acquires the ownership of the signature, @@ -6763,7 +6768,7 @@ static int add_enum_ust_registry(int sock, return 0; } - auto locked_registry = get_locked_session_registry(ua_sess); + auto locked_registry = get_locked_session_registry(ua_sess->get_identifier()); if (!locked_registry) { DBG("Application session is being torn down (registry not found). Aborting enum registration."); return 0; @@ -7184,7 +7189,7 @@ enum lttng_error_code ust_app_snapshot_record(const struct ltt_ust_session *uses char pathname[PATH_MAX]; size_t consumer_path_offset = 0; - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (!ua_sess) { /* Session not associated with this app. */ continue; @@ -7232,7 +7237,7 @@ enum lttng_error_code ust_app_snapshot_record(const struct ltt_ust_session *uses } } - registry = get_session_registry(ua_sess); + registry = ust_app_get_session_registry(ua_sess->get_identifier()); if (!registry) { DBG("Application session is being torn down. Skip application."); continue; @@ -7309,7 +7314,7 @@ uint64_t ust_app_get_size_one_more_packet_per_stream(const struct ltt_ust_sessio struct ust_app_session *ua_sess; struct lttng_ht_iter chan_iter; - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (!ua_sess) { /* Session not associated with this app. */ continue; @@ -7396,7 +7401,7 @@ int ust_app_pid_get_channel_runtime_stats(struct ltt_ust_session *usess, cds_lfht_for_each_entry (ust_app_ht->ht, &iter.iter, app, pid_n.node) { struct lttng_ht_iter uiter; - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (ua_sess == nullptr) { continue; } @@ -7443,7 +7448,7 @@ static int ust_app_regenerate_statedump(struct ltt_ust_session *usess, struct us const auto update_health_code_on_exit = lttng::make_scope_exit([]() noexcept { health_code_update(); }); - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (ua_sess == nullptr) { /* The session is in teardown process. Ignore and continue. */ return 0; @@ -7585,7 +7590,7 @@ enum lttng_error_code ust_app_rotate_session(const ltt_session::locked_ref& sess ust_app_reference app(raw_app); raw_app = nullptr; - ua_sess = lookup_session_by_app(usess, app.get()); + ua_sess = ust_app_lookup_app_session(usess, app.get()); if (!ua_sess) { /* Session not associated with this app. */ continue; @@ -7599,7 +7604,7 @@ enum lttng_error_code ust_app_rotate_session(const ltt_session::locked_ref& sess goto error; } - registry = get_session_registry(ua_sess); + registry = ust_app_get_session_registry(ua_sess->get_identifier()); LTTNG_ASSERT(registry); /* Rotate the data channels. */ @@ -7706,13 +7711,13 @@ enum lttng_error_code ust_app_create_channel_subdirectories(const struct ltt_ust struct ust_app_session *ua_sess; lsu::registry_session *registry; - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (!ua_sess) { /* Session not associated with this app. */ continue; } - registry = get_session_registry(ua_sess); + registry = ust_app_get_session_registry(ua_sess->get_identifier()); if (!registry) { DBG("Application session is being torn down. Skip application."); continue; @@ -7825,7 +7830,7 @@ enum lttng_error_code ust_app_clear_session(const ltt_session::locked_ref& sessi struct ust_app_session *ua_sess; lsu::registry_session *registry; - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (!ua_sess) { /* Session not associated with this app. */ continue; @@ -7839,7 +7844,7 @@ enum lttng_error_code ust_app_clear_session(const ltt_session::locked_ref& sessi goto error_socket; } - registry = get_session_registry(ua_sess); + registry = ust_app_get_session_registry(ua_sess->get_identifier()); if (!registry) { DBG("Application session is being torn down. Skip application."); continue; @@ -7967,7 +7972,7 @@ enum lttng_error_code ust_app_open_packets(const ltt_session::locked_ref& sessio struct ust_app_session *ua_sess; lsu::registry_session *registry; - ua_sess = lookup_session_by_app(usess, app); + ua_sess = ust_app_lookup_app_session(usess, app); if (!ua_sess) { /* Session not associated with this app. */ continue; @@ -7981,7 +7986,7 @@ enum lttng_error_code ust_app_open_packets(const ltt_session::locked_ref& sessio goto error; } - registry = get_session_registry(ua_sess); + registry = ust_app_get_session_registry(ua_sess->get_identifier()); if (!registry) { DBG("Application session is being torn down. Skip application."); continue; @@ -8066,24 +8071,7 @@ void ust_app_put(struct ust_app *app) urcu_ref_put(&app->ref, ust_app_release); } -ust_app_session::const_locked_weak_ref ust_app_session::lock() const noexcept -{ - pthread_mutex_lock(&_lock); - return ust_app_session::const_locked_weak_ref(*this); -} - -ust_app_session::locked_weak_ref ust_app_session::lock() noexcept -{ - pthread_mutex_lock(&_lock); - return ust_app_session::locked_weak_ref(*this); -} - -void ust_app_session::_const_session_unlock(const ust_app_session *session) +lttng_ht *ust_app_get_all() { - pthread_mutex_unlock(&session->_lock); -} - -void ust_app_session::_session_unlock(ust_app_session *session) -{ - pthread_mutex_unlock(&session->_lock); -} + return ust_app_ht; +} \ No newline at end of file diff --git a/src/bin/lttng-sessiond/ust-app.hpp b/src/bin/lttng-sessiond/ust-app.hpp index e38ee830b..02c4d7d0e 100644 --- a/src/bin/lttng-sessiond/ust-app.hpp +++ b/src/bin/lttng-sessiond/ust-app.hpp @@ -9,14 +9,13 @@ #ifndef _LTT_UST_APP_H #define _LTT_UST_APP_H -#include "session.hpp" +#include "trace-class.hpp" #include "trace-ust.hpp" -#include "ust-field-convert.hpp" -#include "ust-registry-session.hpp" -#include "ust-registry.hpp" +#include "ust-field-quirks.hpp" #include #include +#include #include #include @@ -30,6 +29,14 @@ struct lttng_bytecode; struct lttng_ust_filter_bytecode; +namespace lttng { +namespace sessiond { +namespace ust { +class registry_session; +} /* namespace ust */ +} /* namespace sessiond */ +} /* namespace lttng */ + extern int the_ust_consumerd64_fd, the_ust_consumerd32_fd; /* @@ -192,8 +199,15 @@ struct ust_app_channel { struct ust_app_session { private: - static void _session_unlock(ust_app_session *session); - static void _const_session_unlock(const ust_app_session *session); + static void _session_unlock(ust_app_session *session) + { + _const_session_unlock(session); + } + + static void _const_session_unlock(const ust_app_session *session) + { + pthread_mutex_unlock(&session->_lock); + } public: using locked_weak_ref = lttng::non_copyable_reference< @@ -205,8 +219,80 @@ public: lttng::memory::create_deleter_class::deleter>; - ust_app_session::const_locked_weak_ref lock() const noexcept; - ust_app_session::locked_weak_ref lock() noexcept; + static locked_weak_ref make_locked_weak_ref(ust_app_session& ua_session) + { + return lttng::make_non_copyable_reference(ua_session); + } + + static const_locked_weak_ref make_locked_weak_ref(const ust_app_session& ua_session) + { + return lttng::make_non_copyable_reference( + ua_session); + } + + ust_app_session::const_locked_weak_ref lock() const noexcept + { + pthread_mutex_lock(&_lock); + return ust_app_session::make_locked_weak_ref(*this); + } + + ust_app_session::locked_weak_ref lock() noexcept + { + pthread_mutex_lock(&_lock); + return ust_app_session::make_locked_weak_ref(*this); + } + + struct identifier { + enum class application_abi : std::uint8_t { ABI_32 = 32, ABI_64 = 64 }; + enum class buffer_allocation_policy : std::uint8_t { PER_PID, PER_UID }; + + /* Unique identifier of the ust_app_session. */ + std::uint64_t id; + /* Unique identifier of the ltt_session. */ + std::uint64_t session_id; + /* Credentials of the application which owns the ust_app_session. */ + lttng_credentials app_credentials; + application_abi abi; + buffer_allocation_policy allocation_policy; + }; + + identifier get_identifier() const noexcept + { + /* + * To work around synchro design issues, this method allows the sampling + * of a ust_app_session's identifying properties without taking its lock. + * + * Since those properties are immutable, it is safe to sample them without + * holding the lock (as long as the existence of the instance is somehow + * guaranteed). + * + * The locking issue that motivates this method is that the application + * notitication handling thread needs to access the registry_session in response to + * a message from the application. The ust_app_session's ID is needed to look-up the + * registry session. + * + * The application's message can be emited in response to a command from the + * session daemon that is emited by the client thread. + * + * During that command, the client thread holds the ust_app_session lock until + * the application replies to the command. This causes the notification thread + * to block when it attempts to sample the ust_app_session's ID properties. + */ + LTTNG_ASSERT(bits_per_long == 32 || bits_per_long == 64); + LTTNG_ASSERT(buffer_type == LTTNG_BUFFER_PER_PID || + buffer_type == LTTNG_BUFFER_PER_UID); + + return { .id = id, + .session_id = tracing_id, + .app_credentials = real_credentials, + .abi = bits_per_long == 32 ? identifier::application_abi::ABI_32 : + identifier::application_abi::ABI_64, + .allocation_policy = buffer_type == LTTNG_BUFFER_PER_PID ? + identifier::buffer_allocation_policy::PER_PID : + identifier::buffer_allocation_policy::PER_UID }; + } bool enabled = false; /* started: has the session been in started state at any time ? */ @@ -421,9 +507,7 @@ int ust_app_recv_notify(int sock); void ust_app_add(struct ust_app *app); struct ust_app *ust_app_create(struct ust_register_msg *msg, int sock); void ust_app_notify_sock_unregister(int sock); -ssize_t ust_app_push_metadata(const lttng::sessiond::ust::registry_session::locked_ref& registry, - struct consumer_socket *socket, - int send_zero_data); + enum lttng_error_code ust_app_snapshot_record(const struct ltt_ust_session *usess, const struct consumer_output *output, uint64_t nb_packets_per_stream); @@ -444,11 +528,8 @@ int ust_app_pid_get_channel_runtime_stats(struct ltt_ust_session *usess, uint64_t *discarded, uint64_t *lost); int ust_app_regenerate_statedump_all(struct ltt_ust_session *usess); -enum lttng_error_code ust_app_rotate_session(const ltt_session::locked_ref& session); enum lttng_error_code ust_app_create_channel_subdirectories(const struct ltt_ust_session *session); int ust_app_release_object(struct ust_app *app, struct lttng_ust_abi_object_data *data); -enum lttng_error_code ust_app_clear_session(const ltt_session::locked_ref& session); -enum lttng_error_code ust_app_open_packets(const ltt_session::locked_ref& session); int ust_app_setup_event_notifier_group(struct ust_app *app); @@ -457,6 +538,13 @@ static inline int ust_app_supported() return 1; } +ust_app_session *ust_app_lookup_app_session(const struct ltt_ust_session *usess, + const struct ust_app *app); +lttng::sessiond::ust::registry_session * +ust_app_get_session_registry(const ust_app_session::identifier& identifier); + +lttng_ht *ust_app_get_all(); + bool ust_app_supports_notifiers(const struct ust_app *app); bool ust_app_supports_counters(const struct ust_app *app); @@ -631,14 +719,6 @@ static inline void ust_app_notify_sock_unregister(int sock __attribute__((unused { } -static inline ssize_t ust_app_push_metadata(lttng::sessiond::ust::registry_session *registry - __attribute__((unused)), - struct consumer_socket *socket __attribute__((unused)), - int send_zero_data __attribute__((unused))) -{ - return 0; -} - static inline enum lttng_error_code ust_app_snapshot_record(struct ltt_ust_session *usess __attribute__((unused)), const struct consumer_output *output __attribute__((unused)), @@ -723,35 +803,33 @@ static inline int ust_app_regenerate_statedump_all(struct ltt_ust_session *usess return 0; } -static inline enum lttng_error_code ust_app_rotate_session(const ltt_session::locked_ref& session - __attribute__((unused))) +static inline enum lttng_error_code +ust_app_create_channel_subdirectories(const struct ltt_ust_session *session __attribute__((unused))) { return LTTNG_ERR_UNK; } -static inline enum lttng_error_code -ust_app_create_channel_subdirectories(const struct ltt_ust_session *session __attribute__((unused))) +static inline ust_app_session *ust_app_lookup_app_session(const ltt_ust_session *, const ust_app *) { - return LTTNG_ERR_UNK; + return nullptr; } -static inline int ust_app_release_object(struct ust_app *app __attribute__((unused)), - struct lttng_ust_abi_object_data *data - __attribute__((unused))) +static inline lttng::sessiond::ust::registry_session * +ust_app_get_session_registry(const ust_app_session::identifier&) { - return 0; + return nullptr; } -static inline enum lttng_error_code ust_app_clear_session(const ltt_session::locked_ref& session - __attribute__((unused))) +static inline lttng_ht *ust_app_get_all() { - return LTTNG_ERR_UNK; + return nullptr; } -static inline enum lttng_error_code ust_app_open_packets(const ltt_session::locked_ref& session - __attribute__((unused))) +static inline int ust_app_release_object(struct ust_app *app __attribute__((unused)), + struct lttng_ust_abi_object_data *data + __attribute__((unused))) { - return LTTNG_ERR_UNK; + return 0; } static inline void ust_app_get(ust_app& app __attribute__((unused))) diff --git a/src/bin/lttng-sessiond/ust-consumer.hpp b/src/bin/lttng-sessiond/ust-consumer.hpp index 9fc83e6ab..212dd8248 100644 --- a/src/bin/lttng-sessiond/ust-consumer.hpp +++ b/src/bin/lttng-sessiond/ust-consumer.hpp @@ -15,6 +15,14 @@ #include +namespace lttng { +namespace sessiond { +namespace ust { +class registry_session; +} /* namespace ust */ +} /* namespace sessiond */ +} /* namespace lttng */ + int ust_consumer_ask_channel(struct ust_app_session *ua_sess, struct ust_app_channel *ua_chan, struct consumer_output *consumer, diff --git a/src/bin/lttng-sessiond/ust-field-convert.cpp b/src/bin/lttng-sessiond/ust-field-convert.cpp index b51ba7bfc..888fe058c 100644 --- a/src/bin/lttng-sessiond/ust-field-convert.cpp +++ b/src/bin/lttng-sessiond/ust-field-convert.cpp @@ -5,7 +5,11 @@ * */ -#include "ust-field-convert.hpp" +#include "field.hpp" +#include "ust-app.hpp" +#include "ust-field-quirks.hpp" +#include "ust-registry-session.hpp" +#include "ust-registry.hpp" #include #include diff --git a/src/bin/lttng-sessiond/ust-field-convert.hpp b/src/bin/lttng-sessiond/ust-field-convert.hpp deleted file mode 100644 index 063abcd68..000000000 --- a/src/bin/lttng-sessiond/ust-field-convert.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2022 Jérémie Galarneau - * - * SPDX-License-Identifier: GPL-2.0-only - * - */ - -#ifndef LTTNG_UST_FIELD_CONVERT_H -#define LTTNG_UST_FIELD_CONVERT_H - -#include "field.hpp" -#include "ust-registry-session.hpp" -#include "ust-registry.hpp" - -#include -#include -#include - -namespace lttng { -namespace sessiond { -namespace ust { - -enum class ctl_field_quirks : unsigned int { - NONE = 0, - /* - * LTTng-UST with ABI major version <= 9 express variants with a tag - * enumeration that doesn't match the fields of the variant. The - * tag's mapping names are systematically prefixed with an underscore. - */ - UNDERSCORE_PREFIXED_VARIANT_TAG_MAPPINGS = 1 << 0, -}; - -inline ctl_field_quirks operator&(ctl_field_quirks lhs, ctl_field_quirks rhs) -{ - using enum_type = std::underlying_type::type; - return ctl_field_quirks(static_cast(lhs) & static_cast(rhs)); -} - -inline ctl_field_quirks operator|(ctl_field_quirks lhs, ctl_field_quirks rhs) -{ - using enum_type = std::underlying_type::type; - return ctl_field_quirks(static_cast(lhs) | static_cast(rhs)); -} - -std::vector -create_trace_fields_from_ust_ctl_fields(const lttng::sessiond::ust::registry_session& session, - const lttng_ust_ctl_field *fields, - std::size_t field_count, - trace::field_location::root lookup_root, - ctl_field_quirks quirks = ctl_field_quirks::NONE); - -} /* namespace ust */ -} /* namespace sessiond */ -} /* namespace lttng */ - -#endif /* LTTNG_UST_FIELD_CONVERT_H */ diff --git a/src/bin/lttng-sessiond/ust-field-quirks.hpp b/src/bin/lttng-sessiond/ust-field-quirks.hpp new file mode 100644 index 000000000..82ce0fc86 --- /dev/null +++ b/src/bin/lttng-sessiond/ust-field-quirks.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 Jérémie Galarneau + * + * SPDX-License-Identifier: GPL-2.0-only + * + */ + +#ifndef LTTNG_UST_FIELD_CONVERT_H +#define LTTNG_UST_FIELD_CONVERT_H + +#include +#include +#include + +namespace lttng { +namespace sessiond { +namespace ust { + +enum class ctl_field_quirks : unsigned int { + NONE = 0, + /* + * LTTng-UST with ABI major version <= 9 express variants with a tag + * enumeration that doesn't match the fields of the variant. The + * tag's mapping names are systematically prefixed with an underscore. + */ + UNDERSCORE_PREFIXED_VARIANT_TAG_MAPPINGS = 1 << 0, +}; + +inline ctl_field_quirks operator&(ctl_field_quirks lhs, ctl_field_quirks rhs) +{ + using enum_type = std::underlying_type::type; + return ctl_field_quirks(static_cast(lhs) & static_cast(rhs)); +} + +inline ctl_field_quirks operator|(ctl_field_quirks lhs, ctl_field_quirks rhs) +{ + using enum_type = std::underlying_type::type; + return ctl_field_quirks(static_cast(lhs) | static_cast(rhs)); +} + +} /* namespace ust */ +} /* namespace sessiond */ +} /* namespace lttng */ + +#endif /* LTTNG_UST_FIELD_CONVERT_H */ diff --git a/src/bin/lttng-sessiond/ust-registry-session.cpp b/src/bin/lttng-sessiond/ust-registry-session.cpp index 8441b4e2c..860e623cd 100644 --- a/src/bin/lttng-sessiond/ust-registry-session.cpp +++ b/src/bin/lttng-sessiond/ust-registry-session.cpp @@ -13,7 +13,8 @@ #include "trace-class.hpp" #include "tsdl-trace-class-visitor.hpp" #include "ust-app.hpp" -#include "ust-field-convert.hpp" +#include "ust-field-quirks.hpp" +#include "ust-registry-session.hpp" #include "ust-registry.hpp" #include diff --git a/src/bin/lttng-sessiond/ust-registry-session.hpp b/src/bin/lttng-sessiond/ust-registry-session.hpp index 404eabbe0..48efd8848 100644 --- a/src/bin/lttng-sessiond/ust-registry-session.hpp +++ b/src/bin/lttng-sessiond/ust-registry-session.hpp @@ -206,4 +206,18 @@ private: } /* namespace sessiond */ } /* namespace lttng */ +#ifdef HAVE_LIBLTTNG_UST_CTL +ssize_t ust_app_push_metadata(const lttng::sessiond::ust::registry_session::locked_ref& registry, + struct consumer_socket *socket, + int send_zero_data); +#else /* HAVE_LIBLTTNG_UST_CTL */ +static inline ssize_t ust_app_push_metadata(lttng::sessiond::ust::registry_session *registry + __attribute__((unused)), + struct consumer_socket *socket __attribute__((unused)), + int send_zero_data __attribute__((unused))) +{ + return 0; +} +#endif /* HAVE_LIBLTTNG_UST_CTL */ + #endif /* LTTNG_UST_REGISTRY_SESSION_H */ diff --git a/src/bin/lttng-sessiond/ust-registry.hpp b/src/bin/lttng-sessiond/ust-registry.hpp index 4bb14be6f..c0a8ce374 100644 --- a/src/bin/lttng-sessiond/ust-registry.hpp +++ b/src/bin/lttng-sessiond/ust-registry.hpp @@ -12,10 +12,10 @@ #include "event-class.hpp" #include "field.hpp" #include "lttng-ust-ctl.hpp" -#include "session.hpp" #include "stream-class.hpp" #include "trace-class.hpp" #include "ust-clock-class.hpp" +#include "ust-field-quirks.hpp" #include "ust-registry-channel.hpp" #include "ust-registry-event.hpp" @@ -263,4 +263,17 @@ static inline int ust_metadata_event_statedump(lttng::sessiond::ust::registry_se #endif /* HAVE_LIBLTTNG_UST_CTL */ +namespace lttng { +namespace sessiond { +namespace ust { +std::vector +create_trace_fields_from_ust_ctl_fields(const lttng::sessiond::ust::registry_session& session, + const lttng_ust_ctl_field *fields, + std::size_t field_count, + trace::field_location::root lookup_root, + ctl_field_quirks quirks = ctl_field_quirks::NONE); +} // namespace ust +} /* namespace sessiond */ +} /* namespace lttng */ + #endif /* LTTNG_UST_REGISTRY_H */ diff --git a/src/bin/lttng-sessiond/utils.hpp b/src/bin/lttng-sessiond/utils.hpp index 2f9bf8e62..d2c621a70 100644 --- a/src/bin/lttng-sessiond/utils.hpp +++ b/src/bin/lttng-sessiond/utils.hpp @@ -8,8 +8,6 @@ #ifndef _LTT_UTILS_H #define _LTT_UTILS_H -#include "session.hpp" - struct lttng_ht; struct consumer_output; @@ -20,7 +18,6 @@ int loglevels_match(int a_loglevel_type, int b_loglevel_type, int b_loglevel_value, int loglevel_all_type); -const char *session_get_base_path(const ltt_session::locked_ref& session); const char *consumer_output_get_base_path(const struct consumer_output *output); #endif /* _LTT_UTILS_H */ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 257347ce2..68ab02f04 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -57,6 +57,7 @@ libcommon_lgpl_la_SOURCES = \ actions/rate-policy.cpp \ buffer-view.hpp buffer-view.cpp \ channel.cpp \ + ctl/format.hpp \ compiler.hpp \ conditions/buffer-usage.cpp \ conditions/condition.cpp \ diff --git a/src/common/ctl/format.hpp b/src/common/ctl/format.hpp new file mode 100644 index 000000000..ce957b0ab --- /dev/null +++ b/src/common/ctl/format.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 Jérémie Galarneau + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_COMMON_CTL_FORMAT_H +#define LTTNG_COMMON_CTL_FORMAT_H + +#include + +#include + +/* + * Due to a bug in g++ < 7.1, this specialization must be enclosed in the fmt namespace, + * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480. + */ +namespace fmt { +template <> +struct formatter : formatter { + template + typename FormatContextType::iterator format(lttng_buffer_type buffer_type, + FormatContextType& ctx) + { + auto name = "unknown"; + + switch (buffer_type) { + case LTTNG_BUFFER_PER_PID: + name = "per-pid"; + break; + case LTTNG_BUFFER_PER_UID: + name = "per-uid"; + break; + case LTTNG_BUFFER_GLOBAL: + name = "global"; + break; + } + + return format_to(ctx.out(), name); + } +}; +} /* namespace fmt */ + +#endif /* LTTNG_COMMON_CTL_FORMAT_H */ \ No newline at end of file diff --git a/src/common/exception.cpp b/src/common/exception.cpp index 4375f8159..9288aaa07 100644 --- a/src/common/exception.cpp +++ b/src/common/exception.cpp @@ -38,6 +38,11 @@ lttng::allocation_failure::allocation_failure(const std::string& msg, { } +lttng::out_of_range::out_of_range(const std::string& msg, const lttng::source_location& location) : + lttng::runtime_error(msg, location) +{ +} + lttng::unsupported_error::unsupported_error(const std::string& msg, const lttng::source_location& location) : lttng::runtime_error(msg, location) diff --git a/src/common/exception.hpp b/src/common/exception.hpp index 340231734..6c926b62f 100644 --- a/src/common/exception.hpp +++ b/src/common/exception.hpp @@ -22,7 +22,8 @@ throw lttng::ctl::error(msg, error_code, LTTNG_SOURCE_LOCATION()) #define LTTNG_THROW_POSIX(msg, errno_code) \ throw lttng::posix_error(msg, errno_code, LTTNG_SOURCE_LOCATION()) -#define LTTNG_THROW_ERROR(msg) throw lttng::runtime_error(msg, LTTNG_SOURCE_LOCATION()) +#define LTTNG_THROW_ERROR(msg) throw lttng::runtime_error(msg, LTTNG_SOURCE_LOCATION()) +#define LTTNG_THROW_OUT_OF_RANGE(msg) throw lttng::out_of_range(msg, LTTNG_SOURCE_LOCATION()) #define LTTNG_THROW_ALLOCATION_FAILURE_ERROR(msg, allocation_size) \ throw lttng::allocation_failure(msg, allocation_size, LTTNG_SOURCE_LOCATION()) #define LTTNG_THROW_UNSUPPORTED_ERROR(msg) \ @@ -110,6 +111,19 @@ public: std::size_t allocation_size; }; +/** + * @class out_of_range + * @brief Represents an out of range access error. + * + * Thrown when attempting to access a container out of its valid range (e.g., advancing an iterator + * past end()). + */ +class out_of_range : public lttng::runtime_error { +public: + explicit out_of_range(const std::string& msg, + const lttng::source_location& source_location); +}; + /** * @class unsupported_error * @brief Represents an error for unsupported features. diff --git a/src/common/reference.hpp b/src/common/reference.hpp index ccf5f4e86..d98b2181d 100644 --- a/src/common/reference.hpp +++ b/src/common/reference.hpp @@ -16,18 +16,28 @@ namespace lttng { template class non_copyable_reference { public: - explicit non_copyable_reference(ReferencedType& instance) noexcept : _value(&instance) - { - } + using referenced_type = ReferencedType; + using deleter = CustomDeleter; non_copyable_reference(non_copyable_reference&& other) noexcept : _value(other._value) { - other._value = nullptr; + _value = other._value; + other.release(); } non_copyable_reference() = delete; non_copyable_reference(const non_copyable_reference&) = delete; - non_copyable_reference& operator=(non_copyable_reference&&) = delete; + non_copyable_reference& operator=(non_copyable_reference&& other) noexcept + { + if (this != &other) { + _clean_up(); + _value = other._value; + other.release(); + } + + return *this; + } + non_copyable_reference& operator=(const non_copyable_reference&) = delete; ReferencedType& get() const noexcept @@ -45,7 +55,22 @@ public: return *_value; } + void release() noexcept + { + _value = nullptr; + } + ~non_copyable_reference() + { + _clean_up(); + } + +private: + explicit non_copyable_reference(ReferencedType& instance) noexcept : _value(&instance) + { + } + + void _clean_up() { if (!_value) { return; @@ -53,12 +78,23 @@ public: typename CustomDeleter::deleter del; del(_value); + release(); } -private: + template + friend non_copyable_reference + make_non_copyable_reference(FactoryReferencedType&); + ReferencedType *_value = nullptr; }; +template +non_copyable_reference +make_non_copyable_reference(ReferencedType& instance) +{ + return non_copyable_reference(instance); +} + } /* namespace lttng */ #endif /* LTTNG_REFERENCE_H */ diff --git a/tests/unit/test_session.cpp b/tests/unit/test_session.cpp index f972c44bb..37de10d3b 100644 --- a/tests/unit/test_session.cpp +++ b/tests/unit/test_session.cpp @@ -308,7 +308,7 @@ static void test_large_session_number() cds_list_for_each_entry_safe (iter, tmp, &session_list->head, list) { ret = destroy_one_session([iter]() { session_get(iter); - return ltt_session::ref(*iter); + return ltt_session::make_ref(*iter); }()); if (ret < 0) {