*/
#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>
const char *forbidden_name_chars = "/";
/* Global hash table to keep the sessions, indexed by id. */
-struct lttng_ht *ltt_sessions_ht_by_id = NULL;
+struct lttng_ht *ltt_sessions_ht_by_id = nullptr;
/* Global hash table to keep the sessions, indexed by name. */
-struct lttng_ht *ltt_sessions_ht_by_name = NULL;
+struct lttng_ht *ltt_sessions_ht_by_name = nullptr;
/*
* Init tracing session list.
*
* Please see session.h for more explanation and correct usage of the list.
*/
-struct ltt_session_list the_session_list = {
- .lock = PTHREAD_MUTEX_INITIALIZER,
- .removal_cond = PTHREAD_COND_INITIALIZER,
- .next_uuid = 0,
- .head = CDS_LIST_HEAD_INIT(the_session_list.head),
-};
+struct ltt_session_list the_session_list;
+
+/*
+ * Return a ltt_session structure ptr that matches name. If no session found,
+ * NULL is returned. This must be called with the session list lock held using
+ * session_lock_list and session_unlock_list.
+ * A reference to the session is implicitly acquired by this function.
+ */
+struct ltt_session *session_find_by_name(const char *name)
+{
+ struct ltt_session *session_to_return;
+
+ LTTNG_ASSERT(name);
+ ASSERT_SESSION_LIST_LOCKED();
+
+ DBG2("Trying to find session by name %s", name);
+
+ for (auto session : lttng::urcu::list_iteration_adapter<ltt_session, <t_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, <t_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 */
/*
/*
* Return a pointer to the session list.
*/
-struct ltt_session_list *session_get_list(void)
+struct ltt_session_list *session_get_list()
{
return &the_session_list;
}
/*
* Returns once the session list is empty.
*/
-void session_list_wait_empty(void)
+void session_list_wait_empty(std::unique_lock<std::mutex> list_lock)
{
- pthread_mutex_lock(&the_session_list.lock);
- while (!cds_list_empty(&the_session_list.head)) {
- pthread_cond_wait(&the_session_list.removal_cond, &the_session_list.lock);
- }
- pthread_mutex_unlock(&the_session_list.lock);
-}
-
-/*
- * Acquire session list lock
- */
-void session_lock_list(void)
-{
- pthread_mutex_lock(&the_session_list.lock);
+ /* Keep waiting until the session list is empty. */
+ the_session_list.removal_cond.wait(list_lock,
+ [] { return cds_list_empty(&the_session_list.head); });
}
/*
* Try to acquire session list lock
*/
-int session_trylock_list(void)
-{
- return pthread_mutex_trylock(&the_session_list.lock);
-}
-
-/*
- * Release session list lock
- */
-void session_unlock_list(void)
+int session_trylock_list() noexcept
{
- pthread_mutex_unlock(&the_session_list.lock);
+ /* Return 0 if successfully acquired. */
+ return the_session_list.lock.try_lock() ? 0 : 1;
}
/*
* Get the session's consumer destination type.
- *
- * The caller must hold the session lock.
*/
-enum consumer_dst_type session_get_consumer_destination_type(const struct ltt_session *session)
+enum consumer_dst_type session_get_consumer_destination_type(const ltt_session::locked_ref& session)
{
/*
* The output information is duplicated in both of those session types.
/*
* Get the session's consumer network hostname.
* The caller must ensure that the destination is of type "net".
- *
- * The caller must hold the session lock.
*/
-const char *session_get_net_consumer_hostname(const struct ltt_session *session)
+const char *session_get_net_consumer_hostname(const ltt_session::locked_ref& session)
{
- const char *hostname = NULL;
+ const char *hostname = nullptr;
const struct consumer_output *output;
output = session->kernel_session ? session->kernel_session->consumer :
/*
* 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)
{
/*
* Get the location of the latest trace archive produced by a rotation.
- *
- * The caller must hold the session lock.
*/
struct lttng_trace_archive_location *
-session_get_trace_archive_location(const struct ltt_session *session)
+session_get_trace_archive_location(const ltt_session::locked_ref& session)
{
int ret;
- struct lttng_trace_archive_location *location = NULL;
- char *chunk_path = NULL;
+ struct lttng_trace_archive_location *location = nullptr;
+ char *chunk_path = nullptr;
if (session->rotation_state != LTTNG_ROTATION_STATE_COMPLETED ||
!session->last_archived_chunk_name) {
*
* The session list lock must be held.
*/
-static int ltt_sessions_ht_alloc(void)
+static int ltt_sessions_ht_alloc()
{
int ret = 0;
*
* The session list lock must be held.
*/
-static void ltt_sessions_ht_destroy(void)
+static void ltt_sessions_ht_destroy()
{
if (ltt_sessions_ht_by_id) {
lttng_ht_destroy(ltt_sessions_ht_by_id);
- ltt_sessions_ht_by_id = NULL;
+ ltt_sessions_ht_by_id = nullptr;
}
if (ltt_sessions_ht_by_name) {
lttng_ht_destroy(ltt_sessions_ht_by_name);
- ltt_sessions_ht_by_name = NULL;
+ ltt_sessions_ht_by_name = nullptr;
}
return;
* Return `false` if hash table objects are null.
* The session list lock must be held.
*/
-static bool ltt_sessions_ht_empty(void)
+static bool ltt_sessions_ht_empty()
{
bool empty = false;
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();
}
}
/*
* Acquire session lock
*/
-void session_lock(struct ltt_session *session)
+void session_lock(const ltt_session *session)
{
LTTNG_ASSERT(session);
+ session->lock();
+}
+
+void ltt_session::lock() const noexcept
+{
+ pthread_mutex_lock(&_lock);
+}
- pthread_mutex_lock(&session->lock);
+void ltt_session::unlock() const noexcept
+{
+ ltt_session::_const_session_unlock(*this);
}
/*
* Release session lock
*/
-void session_unlock(struct ltt_session *session)
+void session_unlock(const ltt_session *session)
{
LTTNG_ASSERT(session);
+ session->unlock();
+}
- pthread_mutex_unlock(&session->lock);
+void ltt_session::_const_session_unlock(const ltt_session& session)
+{
+ pthread_mutex_unlock(&session._lock);
}
-static int _session_set_trace_chunk_no_lock_check(struct ltt_session *session,
+static int _session_set_trace_chunk_no_lock_check(const ltt_session::locked_ref& session,
struct lttng_trace_chunk *new_trace_chunk,
struct lttng_trace_chunk **_current_trace_chunk)
{
int ret = 0;
unsigned int i, refs_to_acquire = 0, refs_acquired = 0, refs_to_release = 0;
- struct cds_lfht_iter iter;
- struct consumer_socket *socket;
struct lttng_trace_chunk *current_trace_chunk;
uint64_t chunk_id;
enum lttng_trace_chunk_status chunk_status;
- rcu_read_lock();
+ const lttng::urcu::read_lock_guard read_lock;
/*
* Ownership of current trace chunk is transferred to
* `current_trace_chunk`.
*/
current_trace_chunk = session->current_trace_chunk;
- session->current_trace_chunk = NULL;
+ session->current_trace_chunk = nullptr;
if (session->ust_session) {
lttng_trace_chunk_put(session->ust_session->current_trace_chunk);
- session->ust_session->current_trace_chunk = NULL;
+ session->ust_session->current_trace_chunk = nullptr;
}
if (session->kernel_session) {
lttng_trace_chunk_put(session->kernel_session->current_trace_chunk);
- session->kernel_session->current_trace_chunk = NULL;
+ session->kernel_session->current_trace_chunk = nullptr;
}
if (!new_trace_chunk) {
ret = 0;
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,
}
}
}
+
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 ==
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,
end:
if (_current_trace_chunk) {
*_current_trace_chunk = current_trace_chunk;
- current_trace_chunk = NULL;
+ current_trace_chunk = nullptr;
}
end_no_move:
- rcu_read_unlock();
lttng_trace_chunk_put(current_trace_chunk);
return ret;
error:
if (session->ust_session) {
- session->ust_session->current_trace_chunk = NULL;
+ session->ust_session->current_trace_chunk = nullptr;
}
if (session->kernel_session) {
- session->kernel_session->current_trace_chunk = NULL;
+ session->kernel_session->current_trace_chunk = nullptr;
}
/*
* Release references taken in the case where all references could not
}
struct lttng_trace_chunk *
-session_create_new_trace_chunk(const struct ltt_session *session,
+session_create_new_trace_chunk(const ltt_session::locked_ref& session,
const struct consumer_output *consumer_output_override,
const char *session_base_path_override,
const char *chunk_name_override)
{
int ret;
- struct lttng_trace_chunk *trace_chunk = NULL;
+ struct lttng_trace_chunk *trace_chunk = nullptr;
enum lttng_trace_chunk_status chunk_status;
- const time_t chunk_creation_ts = time(NULL);
+ const time_t chunk_creation_ts = time(nullptr);
bool is_local_trace;
const char *base_path;
- struct lttng_directory_handle *session_output_directory = NULL;
+ struct lttng_directory_handle *session_output_directory = nullptr;
const struct lttng_credentials session_credentials = {
.uid = LTTNG_OPTIONAL_INIT_VALUE(session->uid),
.gid = LTTNG_OPTIONAL_INIT_VALUE(session->gid),
if (!session->rotated) {
new_path = "";
} else {
- new_path = NULL;
+ new_path = nullptr;
}
} else {
new_path = DEFAULT_CHUNK_TMP_NEW_DIRECTORY;
}
chunk_status = lttng_trace_chunk_set_as_owner(trace_chunk, session_output_directory);
lttng_directory_handle_put(session_output_directory);
- session_output_directory = NULL;
+ session_output_directory = nullptr;
if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
goto error;
}
error:
lttng_directory_handle_put(session_output_directory);
lttng_trace_chunk_put(trace_chunk);
- trace_chunk = NULL;
+ trace_chunk = nullptr;
goto end;
}
-int session_close_trace_chunk(struct ltt_session *session,
+int session_close_trace_chunk(const ltt_session::locked_ref& session,
struct lttng_trace_chunk *trace_chunk,
enum lttng_trace_chunk_command_type close_command,
char *closed_trace_chunk_path)
{
int ret = 0;
bool error_occurred = false;
- struct cds_lfht_iter iter;
- struct consumer_socket *socket;
enum lttng_trace_chunk_status chunk_status;
- const time_t chunk_close_timestamp = time(NULL);
+ const time_t chunk_close_timestamp = time(nullptr);
const char *new_path;
chunk_status = lttng_trace_chunk_set_close_command(trace_chunk, close_command);
new_path = "";
} else {
/* Use chunk name for new chunk. */
- new_path = NULL;
+ new_path = nullptr;
}
if (session->current_trace_chunk &&
!lttng_trace_chunk_get_name_overridden(session->current_trace_chunk)) {
if (!session->rotated) {
old_path = "";
} else {
- old_path = NULL;
+ old_path = nullptr;
}
/* We need to move back the .tmp_old_chunk to its rightful place. */
chunk_status = lttng_trace_chunk_rename_path(trace_chunk, old_path);
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,
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,
* daemon as the same "offset" in a metadata stream will no longer point
* to the same content.
*/
-static enum lttng_error_code session_kernel_open_packets(struct ltt_session *session)
+static enum lttng_error_code session_kernel_open_packets(const ltt_session::locked_ref& session)
{
enum lttng_error_code ret = LTTNG_OK;
- struct consumer_socket *socket;
struct lttng_ht_iter iter;
struct cds_lfht_node *node;
- struct ltt_kernel_channel *chan;
- rcu_read_lock();
+ const lttng::urcu::read_lock_guard read_lock;
cds_lfht_first(session->kernel_session->consumer->socks->ht, &iter.iter);
node = cds_lfht_iter_get_node(&iter.iter);
- socket = caa_container_of(node, typeof(*socket), node.node);
+ auto *socket = lttng_ht_node_container_of(node, &consumer_socket::node);
- cds_list_for_each_entry (chan, &session->kernel_session->channel_list.head, list) {
+ for (auto chan :
+ lttng::urcu::list_iteration_adapter<ltt_kernel_channel, <t_kernel_channel::list>(
+ session->kernel_session->channel_list.head)) {
int open_ret;
DBG("Open packet of kernel channel: channel key = %" PRIu64
}
end:
- rcu_read_unlock();
return ret;
}
-enum lttng_error_code session_open_packets(struct ltt_session *session)
+enum lttng_error_code session_open_packets(const ltt_session::locked_ref& session)
{
enum lttng_error_code ret = LTTNG_OK;
*
* 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 =
/*
* Fire each clear notifier once, and remove them from the array.
*/
-void session_notify_clear(struct ltt_session *session)
+void session_notify_clear(const ltt_session::locked_ref& session)
{
size_t i;
- const size_t count = lttng_dynamic_array_get_count(&session->clear_notifiers);
+ const auto count = lttng_dynamic_array_get_count(&session->clear_notifiers);
for (i = 0; i < count; i++) {
const struct ltt_session_clear_notifier_element *element =
int ret;
struct ltt_ust_session *usess;
struct ltt_kernel_session *ksess;
- struct ltt_session *session = lttng::utils::container_of(ref, <t_session::ref);
+ struct ltt_session *session = lttng::utils::container_of(ref, <t_session::ref_count);
const bool session_published = session->published;
LTTNG_ASSERT(!session->chunk_being_archived);
snapshot_destroy(&session->snapshot);
- pthread_mutex_destroy(&session->lock);
-
if (session_published) {
- ASSERT_LOCKED(the_session_list.lock);
+ ASSERT_SESSION_LIST_LOCKED();
del_session_list(session);
del_session_ht(session);
}
- session_notify_destruction(session);
+
+ /*
+ * The notifiers make use of free-functions that expect a locked reference to a session.
+ * To create such a reference, we need to acquire the lock and acquire a reference (increase
+ * the ref-count). To ensure the release of the reference does not re-cross the zero value,
+ * set the refcount to a tombstone value.
+ */
+ session->ref_count.refcount = 0xDEAD5E55;
+ session_notify_destruction([session]() {
+ session_lock(session);
+ session_get(session);
+ return ltt_session::make_locked_ref(*session);
+ }());
+
+ pthread_mutex_destroy(&session->_lock);
consumer_output_put(session->consumer);
kernel_free_session(ksess);
- session->kernel_session = NULL;
+ session->kernel_session = nullptr;
if (usess) {
trace_ust_free_session(usess);
- session->ust_session = NULL;
+ session->ust_session = nullptr;
}
lttng_dynamic_array_reset(&session->destroy_notifiers);
lttng_dynamic_array_reset(&session->clear_notifiers);
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();
}
}
*/
bool session_get(struct ltt_session *session)
{
- return urcu_ref_get_unless_zero(&session->ref);
+ return urcu_ref_get_unless_zero(&session->ref_count);
}
/*
* 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);
}
/*
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)
{
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)
{
return lttng_dynamic_array_add_element(&session->clear_notifiers, &element);
}
-/*
- * Return a ltt_session structure ptr that matches name. If no session found,
- * NULL is returned. This must be called with the session list lock held using
- * session_lock_list and session_unlock_list.
- * A reference to the session is implicitly acquired by this function.
- */
-struct ltt_session *session_find_by_name(const char *name)
-{
- struct ltt_session *iter;
-
- LTTNG_ASSERT(name);
- ASSERT_LOCKED(the_session_list.lock);
-
- DBG2("Trying to find session by name %s", name);
-
- cds_list_for_each_entry (iter, &the_session_list.head, list) {
- if (!strncmp(iter->name, name, NAME_MAX) && !iter->destroyed) {
- goto found;
- }
- }
-
- return NULL;
-found:
- return session_get(iter) ? iter : NULL;
-}
-
-/*
- * Return an ltt_session that matches the id. If no session is found,
- * NULL is returned. This must be called with rcu_read_lock and
- * session list lock held (to guarantee the lifetime of the session).
- */
-struct ltt_session *session_find_by_id(uint64_t id)
-{
- struct lttng_ht_node_u64 *node;
- struct lttng_ht_iter iter;
- struct ltt_session *ls;
-
- ASSERT_RCU_READ_LOCKED();
- ASSERT_LOCKED(the_session_list.lock);
-
- if (!ltt_sessions_ht_by_id) {
- goto end;
- }
-
- lttng_ht_lookup(ltt_sessions_ht_by_id, &id, &iter);
- node = lttng_ht_iter_get_node_u64(&iter);
- if (node == NULL) {
- goto end;
- }
- ls = lttng::utils::container_of(node, <t_session::node);
-
- DBG3("Session %" PRIu64 " found by id.", id);
- return session_get(ls) ? ls : NULL;
-
-end:
- DBG3("Session %" PRIu64 " NOT found by id", id);
- return NULL;
-}
-
/*
* Create a new session and add it to the session list.
* Session list lock must be held by the caller.
{
int ret;
enum lttng_error_code ret_code;
- struct ltt_session *new_session = NULL;
+ struct ltt_session *new_session = nullptr;
- ASSERT_LOCKED(the_session_list.lock);
+ ASSERT_SESSION_LIST_LOCKED();
if (name) {
struct ltt_session *clashing_session;
lttng_dynamic_array_init(&new_session->destroy_notifiers,
sizeof(struct ltt_session_destroy_notifier_element),
- NULL);
+ nullptr);
lttng_dynamic_array_init(&new_session->clear_notifiers,
sizeof(struct ltt_session_clear_notifier_element),
- NULL);
- urcu_ref_init(&new_session->ref);
- pthread_mutex_init(&new_session->lock, NULL);
+ nullptr);
+ urcu_ref_init(&new_session->ref_count);
+ pthread_mutex_init(&new_session->_lock, nullptr);
- new_session->creation_time = time(NULL);
+ new_session->creation_time = time(nullptr);
if (new_session->creation_time == (time_t) -1) {
PERROR("Failed to sample session creation time");
ret_code = LTTNG_ERR_SESSION_FAIL;
/* Create default consumer output. */
new_session->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
- if (new_session->consumer == NULL) {
+ if (new_session->consumer == nullptr) {
ret_code = LTTNG_ERR_NOMEM;
goto error;
}
return ret_code;
error:
session_put(new_session);
- new_session = NULL;
+ new_session = nullptr;
goto end;
}
* 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;
}
*
* Must be called with the session and session_list locks held.
*/
-int session_reset_rotation_state(struct ltt_session *session, enum lttng_rotation_state result)
+int session_reset_rotation_state(const ltt_session::locked_ref& session,
+ enum lttng_rotation_state result)
{
int ret = 0;
- ASSERT_LOCKED(the_session_list.lock);
- ASSERT_LOCKED(session->lock);
+ ASSERT_SESSION_LIST_LOCKED();
session->rotation_state = result;
if (session->rotation_pending_check_timer_enabled) {
LTTNG_ASSERT(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK);
LTTNG_OPTIONAL_SET(&session->last_archived_chunk_id, chunk_id);
lttng_trace_chunk_put(session->chunk_being_archived);
- session->chunk_being_archived = NULL;
+ session->chunk_being_archived = nullptr;
/*
* Fire the clear reply notifiers if we are completing a clear
* rotation.
struct lttng_ht_iter iter;
struct ltt_session *ls;
- rcu_read_lock();
+ const lttng::urcu::read_lock_guard read_lock;
if (!ltt_sessions_ht_by_name) {
found = false;
}
lttng_ht_lookup(ltt_sessions_ht_by_name, name, &iter);
- node = lttng_ht_iter_get_node_str(&iter);
- if (node == NULL) {
+ node = lttng_ht_iter_get_node<lttng_ht_node_str>(&iter);
+ if (node == nullptr) {
found = false;
goto end;
}
DBG3("Session id `%" PRIu64 "` sampled for session `%s", *id, name);
end:
- rcu_read_unlock();
return found;
}
-void ls::details::locked_session_release(ltt_session *session)
+void ltt_session::_locked_session_release(ltt_session *session)
{
+ if (!session) {
+ return;
+ }
+
session_unlock(session);
session_put(session);
}
-ltt_session::locked_ptr ls::find_locked_session_by_id(ltt_session::id_t id)
+void ltt_session::_locked_const_session_release(const ltt_session *session)
{
- lttng::urcu::read_lock_guard rcu_lock;
+ if (!session) {
+ return;
+ }
+
+ ltt_session::_const_session_unlock(*session);
+ ltt_session::_const_session_put(session);
+}
+
+ltt_session::locked_ref ltt_session::find_locked_session(ltt_session::id_t id)
+{
+ const lttng::urcu::read_lock_guard rcu_lock;
auto session = session_find_by_id(id);
if (!session) {
- return nullptr;
+ LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
}
/*
* session.
*/
session_lock(session);
- return ltt_session::locked_ptr(session);
+ return ltt_session::make_locked_ref(*session);
}
-ltt_session::sptr ls::find_session_by_id(ltt_session::id_t id)
+ltt_session::locked_ref ltt_session::find_locked_session(lttng::c_string_view name)
{
- lttng::urcu::read_lock_guard rcu_lock;
+ const lttng::urcu::read_lock_guard rcu_lock;
+ auto session = session_find_by_name(name.data());
+
+ if (!session) {
+ LTTNG_THROW_SESSION_NOT_FOUND_BY_NAME_ERROR(name.data());
+ }
+
+ session_lock(session);
+ return ltt_session::make_locked_ref(*session);
+}
+
+ltt_session::const_locked_ref ltt_session::find_locked_const_session(ltt_session::id_t id)
+{
+ const lttng::urcu::read_lock_guard rcu_lock;
+ const auto *session = session_find_by_id(id);
+
+ if (!session) {
+ LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
+ }
+
+ session_lock(session);
+ return ltt_session::make_locked_ref(*session);
+}
+
+ltt_session::const_locked_ref ltt_session::find_locked_const_session(lttng::c_string_view name)
+{
+ const lttng::urcu::read_lock_guard rcu_lock;
+ const auto *session = session_find_by_name(name.data());
+
+ if (!session) {
+ LTTNG_THROW_SESSION_NOT_FOUND_BY_NAME_ERROR(name.data());
+ }
+
+ session_lock(session);
+ return ltt_session::make_locked_ref(*session);
+}
+
+ltt_session::ref ltt_session::find_session(ltt_session::id_t id)
+{
+ const lttng::urcu::read_lock_guard rcu_lock;
auto session = session_find_by_id(id);
if (!session) {
- return nullptr;
+ LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
}
- return { session, session_put };
+ return ltt_session::make_ref(*session);
}
+
+ltt_session::ref ltt_session::find_session(lttng::c_string_view name)
+{
+ const lttng::urcu::read_lock_guard rcu_lock;
+ auto session = session_find_by_name(name.data());
+
+ if (!session) {
+ LTTNG_THROW_SESSION_NOT_FOUND_BY_NAME_ERROR(name.data());
+ }
+
+ return ltt_session::make_ref(*session);
+}
+
+ltt_session::const_ref ltt_session::find_const_session(ltt_session::id_t id)
+{
+ const lttng::urcu::read_lock_guard rcu_lock;
+ const auto *session = session_find_by_id(id);
+
+ if (!session) {
+ LTTNG_THROW_SESSION_NOT_FOUND_BY_ID_ERROR(id);
+ }
+
+ return ltt_session::make_ref(*session);
+}
+
+ltt_session::const_ref ltt_session::find_const_session(lttng::c_string_view name)
+{
+ const lttng::urcu::read_lock_guard rcu_lock;
+ const auto *session = session_find_by_name(name.data());
+
+ if (!session) {
+ LTTNG_THROW_SESSION_NOT_FOUND_BY_NAME_ERROR(name.data());
+ }
+
+ return ltt_session::make_ref(*session);
+}
+
+void ltt_session::_const_session_put(const ltt_session *session)
+{
+ /*
+ * The session list lock must be held as any session_put()
+ * may cause the removal of the session from the session_list.
+ */
+ ASSERT_SESSION_LIST_LOCKED();
+ LTTNG_ASSERT(session->ref_count.refcount);
+ urcu_ref_put(&session->ref_count, session_release);
+}
+
+std::unique_lock<std::mutex> ls::lock_session_list()
+{
+ return std::unique_lock<std::mutex>(the_session_list.lock);
+}
+
+lttng::sessiond::user_space_consumer_channel_keys
+ltt_session::user_space_consumer_channel_keys() const
+{
+ switch (ust_session->buffer_type) {
+ case LTTNG_BUFFER_PER_PID:
+ return lttng::sessiond::user_space_consumer_channel_keys(*ust_session,
+ *ust_app_get_all());
+ case LTTNG_BUFFER_PER_UID:
+ return lttng::sessiond::user_space_consumer_channel_keys(
+ *ust_session, ust_session->buffer_reg_uid_list);
+ default:
+ abort();
+ }
+}
+
+ls::user_space_consumer_channel_keys::iterator
+ls::user_space_consumer_channel_keys::begin() const noexcept
+{
+ return ls::user_space_consumer_channel_keys::iterator(_creation_context);
+}
+
+ls::user_space_consumer_channel_keys::iterator
+ls::user_space_consumer_channel_keys::end() const noexcept
+{
+ return ls::user_space_consumer_channel_keys::iterator(_creation_context, true);
+}
+
+ls::user_space_consumer_channel_keys::iterator&
+ls::user_space_consumer_channel_keys::iterator::operator++()
+{
+ if (_is_end) {
+ LTTNG_THROW_OUT_OF_RANGE(fmt::format(
+ "Attempted to advance channel key iterator past the end of channel keys: iteration_mode={}",
+ _creation_context._session.buffer_type));
+ }
+
+ switch (_creation_context._session.buffer_type) {
+ case LTTNG_BUFFER_PER_PID:
+ _advance_one_per_pid();
+ break;
+ case LTTNG_BUFFER_PER_UID:
+ _advance_one_per_uid();
+ break;
+ default:
+ abort();
+ }
+
+ return *this;
+}
+
+namespace {
+bool is_list_empty(const cds_list_head *head)
+{
+ return head == head->next;
+}
+
+bool is_last_element_of_list(const cds_list_head *head)
+{
+ return head->next == head->prev;
+}
+} /* namespace */
+
+ls::user_space_consumer_channel_keys::iterator::iterator(
+ const _iterator_creation_context& creation_context, bool is_end) :
+ _creation_context(creation_context), _is_end(is_end)
+{
+ if (_is_end) {
+ return;
+ }
+
+ switch (_creation_context._mode) {
+ case _iteration_mode::PER_PID:
+ _init_per_pid();
+ break;
+ case _iteration_mode::PER_UID:
+ _init_per_uid();
+ break;
+ }
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_skip_to_next_app_per_pid(
+ bool try_current) noexcept
+{
+ auto& position = _position._per_pid;
+
+ while (true) {
+ if (!try_current) {
+ lttng_ht_get_next(_creation_context._container.apps,
+ &position.app_iterator);
+ } else {
+ try_current = false;
+ }
+
+ const auto app_node =
+ lttng_ht_iter_get_node<lttng_ht_node_ulong>(&position.app_iterator);
+ if (!app_node) {
+ _is_end = true;
+ return;
+ }
+
+ const auto& app = *lttng::utils::container_of(app_node, &ust_app::pid_n);
+ auto app_session = ust_app_lookup_app_session(&_creation_context._session, &app);
+
+ if (!app_session) {
+ /* This app is not traced by the target session. */
+ continue;
+ }
+
+ position.current_app_session = app_session->lock();
+
+ auto *registry = ust_app_get_session_registry(
+ (*_position._per_pid.current_app_session)->get_identifier());
+ if (!registry) {
+ DBG_FMT("Application session is being torn down: skipping application: app={}",
+ app);
+ continue;
+ }
+
+ position.current_registry_session = registry;
+ lttng_ht_get_first((*position.current_app_session)->channels,
+ &_position.channel_iterator);
+ break;
+ }
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_init_per_pid() noexcept
+{
+ auto& position = _position._per_pid;
+
+ lttng_ht_get_first(_creation_context._container.apps, &position.app_iterator);
+ _skip_to_next_app_per_pid(true);
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_init_per_uid() noexcept
+{
+ auto& position = _position._per_uid;
+
+ /* Start the iteration: get the first registry and point to its first channel. */
+ if (is_list_empty(&_creation_context._session.buffer_reg_uid_list)) {
+ _is_end = true;
+ return;
+ }
+
+ position.current_registry = lttng::utils::container_of(
+ _creation_context._session.buffer_reg_uid_list.next, &buffer_reg_uid::lnode);
+ lttng_ht_get_first(position.current_registry->registry->channels,
+ &_position.channel_iterator);
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_advance_one_per_pid()
+{
+ auto& position = _position._per_pid;
+
+ if (!cds_lfht_iter_get_node(&_position.channel_iterator.iter)) {
+ /* Reached the last channel. Move on to the next app. */
+ _skip_to_next_app_per_pid(false);
+ return;
+ }
+
+ const auto current_app_node =
+ lttng_ht_iter_get_node<lttng_ht_node_ulong>(&position.app_iterator);
+ LTTNG_ASSERT(current_app_node);
+
+ lttng_ht_get_next((*position.current_app_session)->channels, &_position.channel_iterator);
+}
+
+void ls::user_space_consumer_channel_keys::iterator::_advance_one_per_uid()
+{
+ auto& position = _position._per_uid;
+
+ if (!cds_lfht_iter_get_node(&_position.channel_iterator.iter)) {
+ /* Reached the last channel of the registry. Move on to the next registry. */
+ if (is_last_element_of_list(&position.current_registry->lnode)) {
+ _is_end = true;
+ return;
+ }
+
+ position.current_registry = lttng::utils::container_of(
+ position.current_registry->lnode.next, &buffer_reg_uid::lnode);
+ cds_lfht_first(position.current_registry->registry->channels->ht,
+ &_position.channel_iterator.iter);
+
+ /* Assumes a registry can't be empty. */
+ LTTNG_ASSERT(cds_lfht_iter_get_node(&_position.channel_iterator.iter));
+ }
+
+ cds_lfht_next(position.current_registry->registry->channels->ht,
+ &_position.channel_iterator.iter);
+}
+
+bool ls::user_space_consumer_channel_keys::iterator::operator==(const iterator& other) const noexcept
+{
+ if (_is_end && other._is_end) {
+ return true;
+ }
+
+ /* Channel keys are unique; use them to compare the iterators. */
+ return !_is_end && !other._is_end && **this == *other;
+}
+
+bool ls::user_space_consumer_channel_keys::iterator::operator!=(const iterator& other) const noexcept
+{
+ return !(*this == other);
+}
+
+ls::user_space_consumer_channel_keys::iterator::key
+ls::user_space_consumer_channel_keys::iterator::_get_current_value_per_pid() const noexcept
+{
+ auto& position = _position._per_pid;
+
+ const auto *channel_node =
+ lttng_ht_iter_get_node<lttng_ht_node_str>(&_position.channel_iterator);
+ const auto current_app_node =
+ lttng_ht_iter_get_node<lttng_ht_node_ulong>(&position.app_iterator);
+ LTTNG_ASSERT(current_app_node);
+
+ const auto& app = *lttng::utils::container_of(current_app_node, &ust_app::pid_n);
+
+ if (channel_node) {
+ const auto& channel =
+ *lttng::utils::container_of(channel_node, &ust_app_channel::node);
+
+ return { static_cast<consumer_bitness>(app.abi.bits_per_long),
+ channel.key,
+ ls::user_space_consumer_channel_keys::channel_type::DATA };
+ } else {
+ LTTNG_ASSERT(position.current_registry_session);
+
+ /*
+ * Once the last data channel is delivered (iter points to the 'end' of the ht),
+ * deliver the metadata channel's key.
+ */
+ return { static_cast<consumer_bitness>(app.abi.bits_per_long),
+ position.current_registry_session->_metadata_key,
+ ls::user_space_consumer_channel_keys::channel_type::METADATA };
+ }
+}
+
+ls::user_space_consumer_channel_keys::iterator::key
+ls::user_space_consumer_channel_keys::iterator::_get_current_value_per_uid() const noexcept
+{
+ const auto *channel_node =
+ lttng_ht_iter_get_node<lttng_ht_node_u64>(&_position.channel_iterator);
+
+ if (channel_node) {
+ const auto& channel =
+ *lttng::utils::container_of(channel_node, &buffer_reg_channel::node);
+
+ return { static_cast<consumer_bitness>(
+ _position._per_uid.current_registry->bits_per_long),
+ channel.consumer_key,
+ ls::user_space_consumer_channel_keys::channel_type::DATA };
+ } else {
+ /*
+ * Once the last data channel is delivered (iter points to the 'end' of the ht),
+ * deliver the metadata channel's key.
+ */
+ return { static_cast<consumer_bitness>(
+ _position._per_uid.current_registry->bits_per_long),
+ _position._per_uid.current_registry->registry->reg.ust->_metadata_key,
+ ls::user_space_consumer_channel_keys::channel_type::METADATA };
+ }
+}
+
+ls::user_space_consumer_channel_keys::iterator::key
+ls::user_space_consumer_channel_keys::iterator::operator*() const
+{
+ if (_is_end) {
+ LTTNG_THROW_OUT_OF_RANGE(
+ "Attempt to use operator* on user_space_consumer_channel_keys iterator at the end position");
+ }
+
+ switch (_creation_context._mode) {
+ case _iteration_mode::PER_PID:
+ return _get_current_value_per_pid();
+ case _iteration_mode::PER_UID:
+ return _get_current_value_per_uid();
+ }
+
+ std::abort();
+}
+
+ls::ust::registry_session *ls::user_space_consumer_channel_keys::iterator::get_registry_session()
+{
+ if (_is_end) {
+ LTTNG_THROW_OUT_OF_RANGE(
+ "Attempt to get registry session on user_space_consumer_channel_keys iterator at the end position");
+ }
+
+ switch (_creation_context._mode) {
+ case _iteration_mode::PER_PID:
+ return _get_registry_session_per_pid();
+ case _iteration_mode::PER_UID:
+ return _get_registry_session_per_uid();
+ }
+
+ std::abort();
+}
+
+ls::ust::registry_session *
+ls::user_space_consumer_channel_keys::iterator::_get_registry_session_per_pid()
+{
+ return _position._per_pid.current_registry_session;
+}
+
+ls::ust::registry_session *
+ls::user_space_consumer_channel_keys::iterator::_get_registry_session_per_uid()
+{
+ return _position._per_uid.current_registry->registry->reg.ust;
+}
\ No newline at end of file