X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fsession.c;h=16431ca15ca19d3cd3260ee99e6a4c5163232d35;hp=1e5a81831c978451b0df61ad19712eea3a3c3fac;hb=731c1b1217bdbb47501426a6a0a2220ce4bc442c;hpb=890d8fe47755c3bad936389cf48ffa141cff41c9 diff --git a/src/bin/lttng-sessiond/session.c b/src/bin/lttng-sessiond/session.c index 1e5a81831..16431ca15 100644 --- a/src/bin/lttng-sessiond/session.c +++ b/src/bin/lttng-sessiond/session.c @@ -30,6 +30,8 @@ #include #include "session.h" +#include "utils.h" +#include "trace-ust.h" /* * NOTES: @@ -54,6 +56,9 @@ static struct ltt_session_list ltt_session_list = { /* These characters are forbidden in a session name. Used by validate_name. */ static const char *forbidden_name_chars = "/"; +/* Global hash table to keep the sessions, indexed by id. */ +static struct lttng_ht *ltt_sessions_ht_by_id = NULL; + /* * Validate the session name for forbidden characters. * @@ -129,6 +134,14 @@ void session_lock_list(void) pthread_mutex_lock(<t_session_list.lock); } +/* + * Try to acquire session list lock + */ +int session_trylock_list(void) +{ + return pthread_mutex_trylock(<t_session_list.lock); +} + /* * Release session list lock */ @@ -137,6 +150,175 @@ void session_unlock_list(void) pthread_mutex_unlock(<t_session_list.lock); } +/* + * 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) +{ + /* + * The output information is duplicated in both of those session types. + * Hence, it doesn't matter from which it is retrieved. However, it is + * possible for only one of them to be set. + */ + return session->kernel_session ? + session->kernel_session->consumer->type : + session->ust_session->consumer->type; +} + +/* + * 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 *hostname = NULL; + const struct consumer_output *output; + + output = session->kernel_session ? + session->kernel_session->consumer : + session->ust_session->consumer; + + /* + * hostname is assumed to be the same for both control and data + * connections. + */ + switch (output->dst.net.control.dtype) { + case LTTNG_DST_IPV4: + hostname = output->dst.net.control.dst.ipv4; + break; + case LTTNG_DST_IPV6: + hostname = output->dst.net.control.dst.ipv6; + break; + default: + abort(); + } + return hostname; +} + +/* + * 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, + uint16_t *control_port, uint16_t *data_port) +{ + const struct consumer_output *output; + + output = session->kernel_session ? + session->kernel_session->consumer : + session->ust_session->consumer; + *control_port = output->dst.net.control.port; + *data_port = output->dst.net.data.port; +} + +/* + * Allocate the ltt_sessions_ht_by_id HT. + * + * The session list lock must be held. + */ +int ltt_sessions_ht_alloc(void) +{ + int ret = 0; + + DBG("Allocating ltt_sessions_ht_by_id"); + ltt_sessions_ht_by_id = lttng_ht_new(0, LTTNG_HT_TYPE_U64); + if (!ltt_sessions_ht_by_id) { + ret = -1; + ERR("Failed to allocate ltt_sessions_ht_by_id"); + goto end; + } +end: + return ret; +} + +/* + * Destroy the ltt_sessions_ht_by_id HT. + * + * The session list lock must be held. + */ +static void ltt_sessions_ht_destroy(void) +{ + if (!ltt_sessions_ht_by_id) { + return; + } + ht_cleanup_push(ltt_sessions_ht_by_id); + ltt_sessions_ht_by_id = NULL; +} + +/* + * Add a ltt_session to the ltt_sessions_ht_by_id. + * If unallocated, the ltt_sessions_ht_by_id HT is allocated. + * The session list lock must be held. + */ +static void add_session_ht(struct ltt_session *ls) +{ + int ret; + + assert(ls); + + if (!ltt_sessions_ht_by_id) { + ret = ltt_sessions_ht_alloc(); + if (ret) { + ERR("Error allocating the sessions HT"); + goto end; + } + } + lttng_ht_node_init_u64(&ls->node, ls->id); + lttng_ht_add_unique_u64(ltt_sessions_ht_by_id, &ls->node); + +end: + return; +} + +/* + * Test if ltt_sessions_ht_by_id is empty. + * Return 1 if empty, 0 if not empty. + * The session list lock must be held. + */ +static int ltt_sessions_ht_empty(void) +{ + int ret; + + if (!ltt_sessions_ht_by_id) { + ret = 1; + goto end; + } + + ret = lttng_ht_get_count(ltt_sessions_ht_by_id) ? 0 : 1; +end: + return ret; +} + +/* + * Remove a ltt_session from the ltt_sessions_ht_by_id. + * If empty, the ltt_sessions_ht_by_id HT is freed. + * The session list lock must be held. + */ +static void del_session_ht(struct ltt_session *ls) +{ + struct lttng_ht_iter iter; + int ret; + + assert(ls); + assert(ltt_sessions_ht_by_id); + + iter.iter.node = &ls->node.node; + ret = lttng_ht_del(ltt_sessions_ht_by_id, &iter); + assert(!ret); + + if (ltt_sessions_ht_empty()) { + DBG("Empty ltt_sessions_ht_by_id, destroying it"); + ltt_sessions_ht_destroy(); + } +} + /* * Acquire session lock */ @@ -159,7 +341,7 @@ void session_unlock(struct ltt_session *session) /* * Return a ltt_session structure ptr that matches name. If no session found, - * NULL is returned. This must be called with the session lock held using + * NULL is returned. This must be called with the session list lock held using * session_lock_list and session_unlock_list. */ struct ltt_session *session_find_by_name(const char *name) @@ -182,6 +364,36 @@ found: return iter; } +/* + * 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; + + 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 = caa_container_of(node, struct ltt_session, node); + + DBG3("Session %" PRIu64 " found by id.", id); + return ls; + +end: + DBG3("Session %" PRIu64 " NOT found by id", id); + return NULL; +} + /* * Delete session from the session list and free the memory. * @@ -193,9 +405,10 @@ int session_destroy(struct ltt_session *session) /* Safety check */ assert(session); - DBG("Destroying session %s", session->name); + DBG("Destroying session %s (id %" PRIu64 ")", session->name, session->id); del_session_list(session); pthread_mutex_destroy(&session->lock); + del_session_ht(session); consumer_output_put(session->consumer); snapshot_destroy(&session->snapshot); @@ -264,16 +477,28 @@ int session_create(char *name, uid_t uid, gid_t gid) goto error; } + new_session->rotate_pending = false; + new_session->rotation_state = LTTNG_ROTATION_STATE_NO_ROTATION; + new_session->rotate_pending_relay = false; + new_session->rotate_relay_pending_timer_enabled = false; + new_session->rotate_timer = false; + /* Add new session to the session list */ session_lock_list(); new_session->id = add_session_list(new_session); + /* + * Add the new session to the ltt_sessions_ht_by_id. + * No ownership is taken by the hash table; it is merely + * a wrapper around the session list used for faster access + * by session id. + */ + add_session_ht(new_session); session_unlock_list(); /* * Consumer is let to NULL since the create_session_uri command will set it * up and, if valid, assign it to the session. */ - DBG("Tracing session %s created with ID %" PRIu64 " by UID %d GID %d", name, new_session->id, new_session->uid, new_session->gid);