X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fsession.c;h=e7967f45ef3bafe3c990dbd0521f60c01dd5b828;hp=38dbf6128c31639b668910ede62fc4a51f19d7c0;hb=c8a9de5a85fb150d3ceaa5ca1a8b1b2b91d050d5;hpb=92816cc33a1add3c8276839bd6335e17423577dd diff --git a/src/bin/lttng-sessiond/session.c b/src/bin/lttng-sessiond/session.c index 38dbf6128..e7967f45e 100644 --- a/src/bin/lttng-sessiond/session.c +++ b/src/bin/lttng-sessiond/session.c @@ -25,14 +25,18 @@ #include #include #include +#include #include #include #include +#include "lttng-sessiond.h" +#include "kernel.h" #include "session.h" #include "utils.h" #include "trace-ust.h" +#include "timer.h" /* * NOTES: @@ -51,6 +55,7 @@ static struct ltt_session_list ltt_session_list = { .head = CDS_LIST_HEAD_INIT(ltt_session_list.head), .lock = PTHREAD_MUTEX_INITIALIZER, + .removal_cond = PTHREAD_COND_INITIALIZER, .next_uuid = 0, }; @@ -127,6 +132,19 @@ struct ltt_session_list *session_get_list(void) return <t_session_list; } +/* + * Returns once the session list is empty. + */ +void session_list_wait_empty(void) +{ + pthread_mutex_lock(<t_session_list.lock); + while (!cds_list_empty(<t_session_list.head)) { + pthread_cond_wait(<t_session_list.removal_cond, + <t_session_list.lock); + } + pthread_mutex_unlock(<t_session_list.lock); +} + /* * Acquire session list lock */ @@ -382,29 +400,123 @@ void session_unlock(struct ltt_session *session) pthread_mutex_unlock(&session->lock); } +static +void session_release(struct urcu_ref *ref) +{ + int ret; + struct ltt_ust_session *usess; + struct ltt_kernel_session *ksess; + struct ltt_session *session = container_of(ref, typeof(*session), ref); + + usess = session->ust_session; + ksess = session->kernel_session; + + /* Clean kernel session teardown */ + kernel_destroy_session(ksess); + + /* UST session teardown */ + if (usess) { + /* Close any relayd session */ + consumer_output_send_destroy_relayd(usess->consumer); + + /* Destroy every UST application related to this session. */ + ret = ust_app_destroy_trace_all(usess); + if (ret) { + ERR("Error in ust_app_destroy_trace_all"); + } + + /* Clean up the rest. */ + trace_ust_destroy_session(usess); + } + + /* + * Must notify the kernel thread here to update it's poll set in order to + * remove the channel(s)' fd just destroyed. + */ + ret = notify_thread_pipe(kernel_poll_pipe[1]); + if (ret < 0) { + PERROR("write kernel poll pipe"); + } + + DBG("Destroying session %s (id %" PRIu64 ")", session->name, session->id); + pthread_mutex_destroy(&session->lock); + + consumer_output_put(session->consumer); + snapshot_destroy(&session->snapshot); + + ASSERT_LOCKED(ltt_session_list.lock); + del_session_list(session); + del_session_ht(session); + pthread_cond_broadcast(<t_session_list.removal_cond); + free(session); +} + +/* + * Acquire a reference to a session. + * This function may fail (return false); its return value must be checked. + */ +bool session_get(struct ltt_session *session) +{ + return urcu_ref_get_unless_zero(&session->ref); +} + +/* + * Release a reference to a session. + */ +void session_put(struct ltt_session *session) +{ + /* + * The session list lock must be held as any session_put() + * may cause the removal of the session from the session_list. + */ + ASSERT_LOCKED(ltt_session_list.lock); + assert(session->ref.refcount); + urcu_ref_put(&session->ref, session_release); +} + +/* + * Destroy a session. + * + * This method does not immediately release/free the session as other + * components may still hold a reference to the session. However, + * the session should no longer be presented to the user. + * + * Releases the session list's reference to the session + * and marks it as destroyed. Iterations on the session list should be + * mindful of the "destroyed" flag. + */ +void session_destroy(struct ltt_session *session) +{ + assert(!session->destroyed); + session->destroyed = true; + session_put(session); +} + /* * 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; assert(name); + ASSERT_LOCKED(ltt_session_list.lock); DBG2("Trying to find session by name %s", name); cds_list_for_each_entry(iter, <t_session_list.head, list) { - if (strncmp(iter->name, name, NAME_MAX) == 0) { + if (!strncmp(iter->name, name, NAME_MAX) && + !iter->destroyed) { goto found; } } - iter = NULL; - + return NULL; found: - return iter; + return session_get(iter) ? iter : NULL; } /* @@ -418,6 +530,8 @@ struct ltt_session *session_find_by_id(uint64_t id) struct lttng_ht_iter iter; struct ltt_session *ls; + ASSERT_LOCKED(ltt_session_list.lock); + if (!ltt_sessions_ht_by_id) { goto end; } @@ -430,36 +544,13 @@ struct ltt_session *session_find_by_id(uint64_t id) ls = caa_container_of(node, struct ltt_session, node); DBG3("Session %" PRIu64 " found by id.", id); - return ls; + return session_get(ls) ? ls : NULL; end: DBG3("Session %" PRIu64 " NOT found by id", id); return NULL; } -/* - * Delete session from the session list and free the memory. - * - * Return -1 if no session is found. On success, return 1; - * Should *NOT* be called with RCU read-side lock held. - */ -int session_destroy(struct ltt_session *session) -{ - /* Safety check */ - assert(session); - - 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); - free(session); - - return LTTNG_OK; -} - /* * Create a brand new session and add it to the session list. */ @@ -476,6 +567,8 @@ int session_create(char *name, uid_t uid, gid_t gid) goto error_malloc; } + urcu_ref_init(&new_session->ref); + /* Define session name */ if (name != NULL) { if (snprintf(new_session->name, NAME_MAX, "%s", name) < 0) { @@ -570,3 +663,36 @@ int session_access_ok(struct ltt_session *session, uid_t uid, gid_t gid) return 1; } } + +/* + * Set a session's rotation state and reset all associated state. + * + * This function resets the rotation state (check timers, pending + * flags, etc.) and sets the result of the last rotation. The result + * can be queries by a liblttng-ctl client. + * + * Be careful of the result passed to this function. For instance, + * on failure to launch a rotation, a client will expect the rotation + * state to be set to "NO_ROTATION". If an error occured while the + * rotation was "ONGOING", result should be set to "ERROR", which will + * allow a client to report it. + * + * 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 ret = 0; + + ASSERT_LOCKED(ltt_session_list.lock); + ASSERT_LOCKED(session->lock); + + session->rotation_pending_local = false; + session->rotation_pending_relay = false; + session->rotated_after_last_stop = false; + session->rotation_state = result; + if (session->rotation_pending_check_timer_enabled) { + ret = timer_session_rotation_pending_check_stop(session); + } + return ret; +}