From: Mathieu Desnoyers Date: Mon, 26 Jan 2015 19:01:12 +0000 (-0500) Subject: Implement UST PID tracker X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=a9ad0c8f;p=lttng-tools.git Implement UST PID tracker Signed-off-by: Mathieu Desnoyers Signed-off-by: Jérémie Galarneau --- diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index 546da2e53..9ae5cff39 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -926,6 +926,8 @@ error: /* * Command LTTNG_TRACK_PID processed by the client thread. + * + * Called with session lock held. */ int cmd_track_pid(struct ltt_session *session, int domain, int pid) { @@ -949,6 +951,17 @@ int cmd_track_pid(struct ltt_session *session, int domain, int pid) break; } case LTTNG_DOMAIN_UST: + { + struct ltt_ust_session *usess; + + usess = session->ust_session; + + ret = trace_ust_track_pid(usess, pid); + if (ret != LTTNG_OK) { + goto error; + } + break; + } default: ret = LTTNG_ERR_UNKNOWN_DOMAIN; goto error; @@ -963,6 +976,8 @@ error: /* * Command LTTNG_UNTRACK_PID processed by the client thread. + * + * Called with session lock held. */ int cmd_untrack_pid(struct ltt_session *session, int domain, int pid) { @@ -986,6 +1001,17 @@ int cmd_untrack_pid(struct ltt_session *session, int domain, int pid) break; } case LTTNG_DOMAIN_UST: + { + struct ltt_ust_session *usess; + + usess = session->ust_session; + + ret = trace_ust_untrack_pid(usess, pid); + if (ret != LTTNG_OK) { + goto error; + } + break; + } default: ret = LTTNG_ERR_UNKNOWN_DOMAIN; goto error; @@ -1925,6 +1951,8 @@ ssize_t cmd_list_syscalls(struct lttng_event **events) /* * Command LTTNG_START_TRACE processed by the client thread. + * + * Called with session mutex held. */ int cmd_start_trace(struct ltt_session *session) { @@ -2285,6 +2313,8 @@ error: /* * Command LTTNG_DESTROY_SESSION processed by the client thread. + * + * Called with session lock held. */ int cmd_destroy_session(struct ltt_session *session, int wpipe) { diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 21b4cf326..966f60917 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -994,10 +994,30 @@ static void update_ust_app(int app_sock) /* For all tracing session(s) */ cds_list_for_each_entry_safe(sess, stmp, &session_list_ptr->head, list) { + struct ust_app *app; + session_lock(sess); - if (sess->ust_session) { - ust_app_global_update(sess->ust_session, app_sock); + if (!sess->ust_session) { + goto unlock_session; } + + rcu_read_lock(); + assert(app_sock >= 0); + app = ust_app_find_by_sock(app_sock); + if (app == NULL) { + /* + * Application can be unregistered before so + * this is possible hence simply stopping the + * update. + */ + DBG3("UST app update failed to find app sock %d", + app_sock); + goto unlock_rcu; + } + ust_app_global_update(sess->ust_session, app); + unlock_rcu: + rcu_read_unlock(); + unlock_session: session_unlock(sess); } } diff --git a/src/bin/lttng-sessiond/trace-ust.c b/src/bin/lttng-sessiond/trace-ust.c index 4f06f1b06..e74ed62ba 100644 --- a/src/bin/lttng-sessiond/trace-ust.c +++ b/src/bin/lttng-sessiond/trace-ust.c @@ -29,6 +29,7 @@ #include "buffer-registry.h" #include "trace-ust.h" #include "utils.h" +#include "ust-app.h" /* * Match function for the events hash table lookup. @@ -567,6 +568,246 @@ error: return NULL; } +static +void destroy_pid_tracker_node_rcu(struct rcu_head *head) +{ + struct ust_pid_tracker_node *tracker_node = + caa_container_of(head, struct ust_pid_tracker_node, node.head); + free(tracker_node); +} + +static +void destroy_pid_tracker_node(struct ust_pid_tracker_node *tracker_node) +{ + + call_rcu(&tracker_node->node.head, destroy_pid_tracker_node_rcu); +} + +static +int init_pid_tracker(struct ust_pid_tracker *pid_tracker) +{ + int ret = 0; + + pid_tracker->ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG); + if (!pid_tracker->ht) { + ret = -1; + goto end; + } + +end: + return ret; +} + +/* + * Teardown pid tracker content, but don't free pid_tracker object. + */ +static +void fini_pid_tracker(struct ust_pid_tracker *pid_tracker) +{ + struct ust_pid_tracker_node *tracker_node; + struct lttng_ht_iter iter; + + if (!pid_tracker->ht) { + return; + } + rcu_read_lock(); + cds_lfht_for_each_entry(pid_tracker->ht->ht, + &iter.iter, tracker_node, node.node) { + int ret = lttng_ht_del(pid_tracker->ht, &iter); + + assert(!ret); + destroy_pid_tracker_node(tracker_node); + } + rcu_read_unlock(); + ht_cleanup_push(pid_tracker->ht); + pid_tracker->ht = NULL; +} + +static +struct ust_pid_tracker_node *pid_tracker_lookup( + struct ust_pid_tracker *pid_tracker, int pid, + struct lttng_ht_iter *iter) +{ + unsigned long _pid = (unsigned long) pid; + struct lttng_ht_node_ulong *node; + + lttng_ht_lookup(pid_tracker->ht, (void *) _pid, iter); + node = lttng_ht_iter_get_node_ulong(iter); + if (node) { + return caa_container_of(node, struct ust_pid_tracker_node, + node); + } else { + return NULL; + } +} + +static +int pid_tracker_add_pid(struct ust_pid_tracker *pid_tracker, int pid) +{ + int retval = LTTNG_OK; + struct ust_pid_tracker_node *tracker_node; + struct lttng_ht_iter iter; + + if (pid < 0) { + retval = LTTNG_ERR_INVALID; + goto end; + } + tracker_node = pid_tracker_lookup(pid_tracker, pid, &iter); + if (tracker_node) { + /* Already exists. */ + retval = LTTNG_ERR_INVALID; + goto end; + } + tracker_node = zmalloc(sizeof(*tracker_node)); + if (!tracker_node) { + retval = LTTNG_ERR_NOMEM; + goto end; + } + lttng_ht_node_init_ulong(&tracker_node->node, (unsigned long) pid); + lttng_ht_add_unique_ulong(pid_tracker->ht, &tracker_node->node); +end: + return retval; +} + +static +int pid_tracker_del_pid(struct ust_pid_tracker *pid_tracker, int pid) +{ + int retval = LTTNG_OK, ret; + struct ust_pid_tracker_node *tracker_node; + struct lttng_ht_iter iter; + + if (pid < 0) { + retval = LTTNG_ERR_INVALID; + goto end; + } + tracker_node = pid_tracker_lookup(pid_tracker, pid, &iter); + if (!tracker_node) { + /* Not found */ + retval = LTTNG_ERR_INVALID; + goto end; + } + ret = lttng_ht_del(pid_tracker->ht, &iter); + assert(!ret); + + destroy_pid_tracker_node(tracker_node); +end: + return retval; +} + +/* + * The session lock is held when calling this function. + */ +int trace_ust_pid_tracker_lookup(struct ltt_ust_session *session, int pid) +{ + struct lttng_ht_iter iter; + + if (!session->pid_tracker.ht) { + return 1; + } + if (pid_tracker_lookup(&session->pid_tracker, pid, &iter)) { + return 1; + } + return 0; +} + +/* + * Called with the session lock held. + */ +int trace_ust_track_pid(struct ltt_ust_session *session, int pid) +{ + int retval = LTTNG_OK; + + if (pid == -1) { + /* Track all pids: destroy tracker if exists. */ + if (session->pid_tracker.ht) { + fini_pid_tracker(&session->pid_tracker); + /* Ensure all apps have session. */ + ust_app_global_update_all(session); + } + } else { + int ret; + + if (!session->pid_tracker.ht) { + /* Create tracker. */ + if (init_pid_tracker(&session->pid_tracker)) { + ERR("Error initializing PID tracker"); + retval = LTTNG_ERR_NOMEM; + goto end; + } + ret = pid_tracker_add_pid(&session->pid_tracker, pid); + if (ret != LTTNG_OK) { + retval = ret; + fini_pid_tracker(&session->pid_tracker); + goto end; + } + /* Remove all apps from session except pid. */ + ust_app_global_update_all(session); + } else { + struct ust_app *app; + + ret = pid_tracker_add_pid(&session->pid_tracker, pid); + if (ret != LTTNG_OK) { + retval = ret; + goto end; + } + /* Add session to application */ + app = ust_app_find_by_pid(pid); + if (app) { + ust_app_global_update(session, app); + } + } + } +end: + return retval; +} + +/* + * Called with the session lock held. + */ +int trace_ust_untrack_pid(struct ltt_ust_session *session, int pid) +{ + int retval = LTTNG_OK; + + if (pid == -1) { + /* Create empty tracker, replace old tracker. */ + struct ust_pid_tracker tmp_tracker; + + tmp_tracker = session->pid_tracker; + if (init_pid_tracker(&session->pid_tracker)) { + ERR("Error initializing PID tracker"); + retval = LTTNG_ERR_NOMEM; + /* Rollback operation. */ + session->pid_tracker = tmp_tracker; + goto end; + } + fini_pid_tracker(&tmp_tracker); + + /* Remove session from all applications */ + ust_app_global_update_all(session); + } else { + int ret; + struct ust_app *app; + + if (!session->pid_tracker.ht) { + retval = LTTNG_ERR_INVALID; + goto end; + } + /* Remove PID from tracker */ + ret = pid_tracker_del_pid(&session->pid_tracker, pid); + if (ret != LTTNG_OK) { + retval = ret; + goto end; + } + /* Remove session from application. */ + app = ust_app_find_by_pid(pid); + if (app) { + ust_app_global_update(session, app); + } + } +end: + return retval; +} + /* * RCU safe free context structure. */ @@ -784,5 +1025,7 @@ void trace_ust_destroy_session(struct ltt_ust_session *session) consumer_destroy_output(session->consumer); consumer_destroy_output(session->tmp_consumer); + fini_pid_tracker(&session->pid_tracker); + free(session); } diff --git a/src/bin/lttng-sessiond/trace-ust.h b/src/bin/lttng-sessiond/trace-ust.h index 8be813877..ed1883c76 100644 --- a/src/bin/lttng-sessiond/trace-ust.h +++ b/src/bin/lttng-sessiond/trace-ust.h @@ -74,6 +74,14 @@ struct ltt_ust_domain_global { struct cds_list_head registry_buffer_uid_list; }; +struct ust_pid_tracker_node { + struct lttng_ht_node_ulong node; +}; + +struct ust_pid_tracker { + struct lttng_ht *ht; +}; + /* UST session */ struct ltt_ust_session { uint64_t id; /* Unique identifier of session */ @@ -119,6 +127,8 @@ struct ltt_ust_session { */ char root_shm_path[PATH_MAX]; char shm_path[PATH_MAX]; + + struct ust_pid_tracker pid_tracker; }; /* @@ -191,6 +201,9 @@ void trace_ust_destroy_session(struct ltt_ust_session *session); void trace_ust_destroy_channel(struct ltt_ust_channel *channel); void trace_ust_destroy_event(struct ltt_ust_event *event); +int trace_ust_track_pid(struct ltt_ust_session *session, int pid); +int trace_ust_untrack_pid(struct ltt_ust_session *session, int pid); + #else /* HAVE_LIBLTTNG_UST_CTL */ static inline int trace_ust_ht_match_event(struct cds_lfht_node *node, @@ -272,6 +285,16 @@ struct agent *trace_ust_find_agent(struct ltt_ust_session *session, { return NULL; } +static inline +int trace_ust_track_pid(struct ltt_ust_session *session, int pid) +{ + return 0; +} +static inline +int trace_ust_untrack_pid(struct ltt_ust_session *session, int pid) +{ + return 0; +} #endif /* HAVE_LIBLTTNG_UST_CTL */ diff --git a/src/bin/lttng-sessiond/ust-app.c b/src/bin/lttng-sessiond/ust-app.c index 183d12559..c30792c3c 100644 --- a/src/bin/lttng-sessiond/ust-app.c +++ b/src/bin/lttng-sessiond/ust-app.c @@ -3726,6 +3726,11 @@ int ust_app_create_channel_glb(struct ltt_ust_session *usess, */ continue; } + if (!trace_ust_pid_tracker_lookup(usess, app->pid)) { + /* Skip. */ + continue; + } + /* * Create session on the tracer side and add it to app session HT. Note * that if session exist, it will simply return a pointer to the ust @@ -4353,46 +4358,26 @@ int ust_app_destroy_trace_all(struct ltt_ust_session *usess) return 0; } -/* - * Add channels/events from UST global domain to registered apps at sock. - */ -void ust_app_global_update(struct ltt_ust_session *usess, int sock) +static +void ust_app_global_create(struct ltt_ust_session *usess, struct ust_app *app) { int ret = 0; struct lttng_ht_iter iter, uiter; - struct ust_app *app; struct ust_app_session *ua_sess = NULL; struct ust_app_channel *ua_chan; struct ust_app_event *ua_event; struct ust_app_ctx *ua_ctx; + int is_created = 0; - assert(usess); - assert(sock >= 0); - - DBG2("UST app global update for app sock %d for session id %" PRIu64, sock, - usess->id); - - rcu_read_lock(); - - app = ust_app_find_by_sock(sock); - if (app == NULL) { - /* - * Application can be unregistered before so this is possible hence - * simply stopping the update. - */ - DBG3("UST app update failed to find app sock %d", sock); - goto error; - } - - if (!app->compatible) { - goto error; - } - - ret = create_ust_app_session(usess, app, &ua_sess, NULL); + ret = create_ust_app_session(usess, app, &ua_sess, &is_created); if (ret < 0) { /* Tracer is probably gone or ENOMEM. */ goto error; } + if (!is_created) { + /* App session already created. */ + goto end; + } assert(ua_sess); pthread_mutex_lock(&ua_sess->lock); @@ -4446,9 +4431,8 @@ void ust_app_global_update(struct ltt_ust_session *usess, int sock) DBG2("UST trace started for app pid %d", app->pid); } - +end: /* Everything went well at this point. */ - rcu_read_unlock(); return; error_unlock: @@ -4457,10 +4441,60 @@ error: if (ua_sess) { destroy_app_session(app, ua_sess); } - rcu_read_unlock(); return; } +static +void ust_app_global_destroy(struct ltt_ust_session *usess, struct ust_app *app) +{ + struct ust_app_session *ua_sess; + + ua_sess = lookup_session_by_app(usess, app); + if (ua_sess == NULL) { + return; + } + destroy_app_session(app, ua_sess); +} + +/* + * Add channels/events from UST global domain to registered apps at sock. + * + * Called with session lock held. + * Called with RCU read-side lock held. + */ +void ust_app_global_update(struct ltt_ust_session *usess, struct ust_app *app) +{ + assert(usess); + + DBG2("UST app global update for app sock %d for session id %" PRIu64, + app->sock, usess->id); + + if (!app->compatible) { + return; + } + + if (trace_ust_pid_tracker_lookup(usess, app->pid)) { + ust_app_global_create(usess, app); + } else { + ust_app_global_destroy(usess, app); + } +} + +/* + * Called with session lock held. + */ +void ust_app_global_update_all(struct ltt_ust_session *usess) +{ + struct lttng_ht_iter iter; + struct ust_app *app; + + rcu_read_lock(); + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { + ust_app_global_update(usess, app); + } + rcu_read_unlock(); +} + /* * Add context to a specific channel for global UST domain. */ diff --git a/src/bin/lttng-sessiond/ust-app.h b/src/bin/lttng-sessiond/ust-app.h index d6b675bec..567c79e04 100644 --- a/src/bin/lttng-sessiond/ust-app.h +++ b/src/bin/lttng-sessiond/ust-app.h @@ -313,7 +313,8 @@ int ust_app_disable_event_glb(struct ltt_ust_session *usess, struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent); int ust_app_add_ctx_channel_glb(struct ltt_ust_session *usess, struct ltt_ust_channel *uchan, struct ltt_ust_context *uctx); -void ust_app_global_update(struct ltt_ust_session *usess, int sock); +void ust_app_global_update(struct ltt_ust_session *usess, struct ust_app *app); +void ust_app_global_update_all(struct ltt_ust_session *usess); void ust_app_clean_list(void); int ust_app_ht_alloc(void);