/*
* 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)
{
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;
/*
* 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)
{
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;
/*
* Command LTTNG_START_TRACE processed by the client thread.
+ *
+ * Called with session mutex held.
*/
int cmd_start_trace(struct ltt_session *session)
{
/*
* Command LTTNG_DESTROY_SESSION processed by the client thread.
+ *
+ * Called with session lock held.
*/
int cmd_destroy_session(struct ltt_session *session, int wpipe)
{
/* 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);
}
}
#include "buffer-registry.h"
#include "trace-ust.h"
#include "utils.h"
+#include "ust-app.h"
/*
* Match function for the events hash table lookup.
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.
*/
consumer_destroy_output(session->consumer);
consumer_destroy_output(session->tmp_consumer);
+ fini_pid_tracker(&session->pid_tracker);
+
free(session);
}
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 */
*/
char root_shm_path[PATH_MAX];
char shm_path[PATH_MAX];
+
+ struct ust_pid_tracker pid_tracker;
};
/*
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,
{
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 */
*/
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
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);
DBG2("UST trace started for app pid %d", app->pid);
}
-
+end:
/* Everything went well at this point. */
- rcu_read_unlock();
return;
error_unlock:
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.
*/
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);