From f6a9efaa0fe496b7fa4850daa2eae98a240433e1 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 27 Oct 2011 14:49:48 +0200 Subject: [PATCH 1/1] Basic hashtable support for UST Signed-off-by: David Goulet --- configure.ac | 2 + hashtable/rculfhash.c | 51 +++- hashtable/rculfhash.h | 24 +- include/lttng-sessiond-comm.h | 1 + include/lttng-share.h | 3 + liblttng-sessiond-comm/lttng-sessiond-comm.c | 1 + ltt-sessiond/Makefile.am | 6 +- ltt-sessiond/channel.c | 15 +- ltt-sessiond/ltt-sessiond.h | 1 + ltt-sessiond/main.c | 127 ++++++-- ltt-sessiond/session.c | 8 +- ltt-sessiond/session.h | 3 +- ltt-sessiond/trace-ust.c | 290 +++++++++++++------ ltt-sessiond/trace-ust.h | 98 ++++--- ltt-sessiond/ust-app.c | 245 ++++++++++------ ltt-sessiond/ust-app.h | 58 ++-- ltt-sessiond/ust-ctl.c | 226 +++++++++++++++ ltt-sessiond/ust-ctl.h | 2 - lttng/commands/enable_channels.c | 5 + tests/Makefile.am | 5 +- tests/test_sessions.c | 4 +- 21 files changed, 874 insertions(+), 301 deletions(-) create mode 100644 ltt-sessiond/ust-ctl.c diff --git a/configure.ac b/configure.ac index 052c5a33d..0ac647006 100644 --- a/configure.ac +++ b/configure.ac @@ -59,6 +59,8 @@ AC_CHECK_DECL([ustctl_create_session], AM_CONDITIONAL([LTTNG_TOOLS_HAVE_UST], [ test "x$have_ust_test" = "x1" ]) +AC_CHECK_FUNCS([sched_getcpu sysconf]) + # Epoll check. If not present, the build will fallback on poll() API AX_HAVE_EPOLL( [AX_CONFIG_FEATURE_ENABLE(epoll)], diff --git a/hashtable/rculfhash.c b/hashtable/rculfhash.c index 2bb26e550..c79bafd42 100644 --- a/hashtable/rculfhash.c +++ b/hashtable/rculfhash.c @@ -139,16 +139,16 @@ #include #include -#include #include #include #include #include #include -#include "rculfhash.h" #include #include +#include "rculfhash.h" + #ifdef DEBUG #define dbg_printf(fmt, args...) printf("[debug rculfhash] " fmt, ## args) #else @@ -608,7 +608,7 @@ void ht_count_del(struct cds_lfht *ht, unsigned long size) #else /* #if defined(HAVE_SCHED_GETCPU) && defined(HAVE_SYSCONF) */ -static const long nr_cpus_mask = -1; +static const long nr_cpus_mask = -2; static struct ht_items_count *alloc_per_cpu_items_count(void) @@ -1041,8 +1041,12 @@ void partition_resize_helper(struct cds_lfht *ht, unsigned long i, * We spawn just the number of threads we need to satisfy the minimum * partition size, up to the number of CPUs in the system. */ - nr_threads = min(nr_cpus_mask + 1, - len >> MIN_PARTITION_PER_THREAD_ORDER); + if (nr_cpus_mask > 0) { + nr_threads = min(nr_cpus_mask + 1, + len >> MIN_PARTITION_PER_THREAD_ORDER); + } else { + nr_threads = 1; + } partition_len = len >> get_count_order_ulong(nr_threads); work = calloc(nr_threads, sizeof(*work)); thread_id = calloc(nr_threads, sizeof(*thread_id)); @@ -1355,7 +1359,7 @@ void cds_lfht_lookup(struct cds_lfht *ht, void *key, size_t key_len, iter->next = next; } -void cds_lfht_next(struct cds_lfht *ht, struct cds_lfht_iter *iter) +void cds_lfht_next_duplicate(struct cds_lfht *ht, struct cds_lfht_iter *iter) { struct cds_lfht_node *node, *next; unsigned long reverse_hash; @@ -1391,6 +1395,41 @@ void cds_lfht_next(struct cds_lfht *ht, struct cds_lfht_iter *iter) iter->next = next; } +void cds_lfht_next(struct cds_lfht *ht, struct cds_lfht_iter *iter) +{ + struct cds_lfht_node *node, *next; + + node = clear_flag(iter->next); + for (;;) { + if (unlikely(is_end(node))) { + node = next = NULL; + break; + } + next = rcu_dereference(node->p.next); + if (likely(!is_removed(next)) + && !is_dummy(next)) { + break; + } + node = clear_flag(next); + } + assert(!node || !is_dummy(rcu_dereference(node->p.next))); + iter->node = node; + iter->next = next; +} + +void cds_lfht_first(struct cds_lfht *ht, struct cds_lfht_iter *iter) +{ + struct _cds_lfht_node *lookup; + + /* + * Get next after first dummy node. The first dummy node is the + * first node of the linked list. + */ + lookup = &ht->t.tbl[0]->nodes[0]; + iter->next = lookup->next; + cds_lfht_next(ht, iter); +} + void cds_lfht_add(struct cds_lfht *ht, struct cds_lfht_node *node) { unsigned long hash, size; diff --git a/hashtable/rculfhash.h b/hashtable/rculfhash.h index 860ef3d1c..0a739ee86 100644 --- a/hashtable/rculfhash.h +++ b/hashtable/rculfhash.h @@ -42,6 +42,11 @@ struct _cds_lfht_node { unsigned long reverse_hash; } __attribute__((aligned(4))); +/* + * struct cds_lfht_node can be embedded into a structure (as a field). + * caa_container_of() can be used to get the structure from the struct + * cds_lfht_node after a lookup. + */ struct cds_lfht_node { /* cache-hot for iteration */ struct _cds_lfht_node p; /* needs to be first field */ @@ -180,7 +185,7 @@ void cds_lfht_lookup(struct cds_lfht *ht, void *key, size_t key_len, struct cds_lfht_iter *iter); /* - * cds_lfht_next - get the next item with same key (after a lookup). + * cds_lfht_next_duplicate - get the next item with same key (after a lookup). * * Uses an iterator initialized by a lookup. * Sets *iter-node to the following node with same key. @@ -190,6 +195,23 @@ void cds_lfht_lookup(struct cds_lfht *ht, void *key, size_t key_len, * node returned by a previous cds_lfht_next. * Call with rcu_read_lock held. */ +void cds_lfht_next_duplicate(struct cds_lfht *ht, struct cds_lfht_iter *iter); + +/* + * cds_lfht_first - get the first node in the table. + * + * Output in "*iter". *iter->node set to NULL if table is empty. + * Call with rcu_read_lock held. + */ +void cds_lfht_first(struct cds_lfht *ht, struct cds_lfht_iter *iter); + +/* + * cds_lfht_next - get the next node in the table. + * + * Input/Output in "*iter". *iter->node set to NULL if *iter was + * pointing to the last table node. + * Call with rcu_read_lock held. + */ void cds_lfht_next(struct cds_lfht *ht, struct cds_lfht_iter *iter); /* diff --git a/include/lttng-sessiond-comm.h b/include/lttng-sessiond-comm.h index 1b2c4b88e..f30bf6673 100644 --- a/include/lttng-sessiond-comm.h +++ b/include/lttng-sessiond-comm.h @@ -114,6 +114,7 @@ enum lttcomm_return_code { LTTCOMM_KERN_NO_SESSION, /* No kernel session found */ LTTCOMM_KERN_LIST_FAIL, /* Kernel listing events failed */ LTTCOMM_UST_SESS_FAIL, /* UST create session failed */ + LTTCOMM_UST_CHAN_EXIST, /* UST channel already exist */ LTTCOMM_UST_CHAN_FAIL, /* UST create channel failed */ LTTCOMM_UST_CHAN_NOT_FOUND, /* UST channel not found */ LTTCOMM_UST_CHAN_DISABLE_FAIL, /* UST disable channel failed */ diff --git a/include/lttng-share.h b/include/lttng-share.h index 399de4f6e..cac819d63 100644 --- a/include/lttng-share.h +++ b/include/lttng-share.h @@ -23,6 +23,9 @@ #include +/* Default size of a hash table */ +#define DEFAULT_HT_SIZE 32 + /* Default channel attributes */ #define DEFAULT_CHANNEL_NAME "channel0" #define DEFAULT_CHANNEL_OVERWRITE 0 /* usec */ diff --git a/liblttng-sessiond-comm/lttng-sessiond-comm.c b/liblttng-sessiond-comm/lttng-sessiond-comm.c index 01851de5f..9cea3fede 100644 --- a/liblttng-sessiond-comm/lttng-sessiond-comm.c +++ b/liblttng-sessiond-comm/lttng-sessiond-comm.c @@ -75,6 +75,7 @@ static const char *lttcomm_readable_code[] = { [ LTTCOMM_ERR_INDEX(LTTCOMM_KERN_LIST_FAIL) ] = "Listing kernel events failed", [ LTTCOMM_ERR_INDEX(LTTCOMM_UST_SESS_FAIL) ] = "UST create session failed", [ LTTCOMM_ERR_INDEX(LTTCOMM_UST_CHAN_FAIL) ] = "UST create channel failed", + [ LTTCOMM_ERR_INDEX(LTTCOMM_UST_CHAN_EXIST) ] = "UST channel already exist", [ LTTCOMM_ERR_INDEX(LTTCOMM_UST_CHAN_NOT_FOUND) ] = "UST channel not found", [ LTTCOMM_ERR_INDEX(LTTCOMM_UST_CHAN_DISABLE_FAIL) ] = "Disable UST channel failed", [ LTTCOMM_ERR_INDEX(LTTCOMM_UST_CHAN_ENABLE_FAIL) ] = "Enable UST channel failed", diff --git a/ltt-sessiond/Makefile.am b/ltt-sessiond/Makefile.am index f9301896e..f3723016e 100644 --- a/ltt-sessiond/Makefile.am +++ b/ltt-sessiond/Makefile.am @@ -12,6 +12,7 @@ COMPAT=compat/compat-poll.c endif ltt_sessiond_SOURCES = utils.c utils.h \ + hashtable.c hashtable.h \ compat/poll.h $(COMPAT) \ trace-kernel.c trace-kernel.h \ kernel-ctl.c kernel-ctl.h \ @@ -24,7 +25,8 @@ ltt_sessiond_SOURCES = utils.c utils.h \ session.c session.h \ ltt-sessiond.h main.c \ ../hashtable/rculfhash.c \ - ../hashtable/rculfhash.h + ../hashtable/rculfhash.h \ + ../hashtable/hash.c ../hashtable/hash.h if LTTNG_TOOLS_HAVE_UST ltt_sessiond_SOURCES += \ @@ -33,7 +35,7 @@ ltt_sessiond_SOURCES += \ endif # link on liblttngctl for check if sessiond is already alive. -ltt_sessiond_LDADD = -lrt \ +ltt_sessiond_LDADD = -lrt -lurcu-cds -lurcu \ $(top_builddir)/liblttng-sessiond-comm/liblttng-sessiond-comm.la \ $(top_builddir)/libkernelctl/libkernelctl.la \ $(top_builddir)/liblttngctl/liblttngctl.la diff --git a/ltt-sessiond/channel.c b/ltt-sessiond/channel.c index b61e1fb67..3870af4be 100644 --- a/ltt-sessiond/channel.c +++ b/ltt-sessiond/channel.c @@ -30,6 +30,7 @@ #endif #include "channel.h" +#include "hashtable.h" #include "kernel-ctl.h" #include "ust-ctl.h" #include "utils.h" @@ -87,11 +88,12 @@ error_alloc: int channel_ust_copy(struct ltt_ust_channel *dst, struct ltt_ust_channel *src) { - struct ltt_ust_event *uevent, *new_uevent; + //struct ltt_ust_event *uevent, *new_uevent; memcpy(dst, src, sizeof(struct ltt_ust_channel)); - CDS_INIT_LIST_HEAD(&dst->events.head); + dst->events = hashtable_new_str(0); + /* cds_list_for_each_entry(uevent, &src->events.head, list) { new_uevent = malloc(sizeof(struct ltt_ust_event)); if (new_uevent == NULL) { @@ -103,11 +105,12 @@ int channel_ust_copy(struct ltt_ust_channel *dst, cds_list_add(&new_uevent->list, &dst->events.head); dst->events.count++; } + */ return 0; -error: - return -1; +//error: +// return -1; } /* @@ -225,9 +228,10 @@ int channel_ust_create(struct ltt_ust_session *usession, suchan = trace_ust_create_channel(attr, usession->path); if (suchan == NULL) { - ret = LTTCOMM_FATAL; + ret = LTTCOMM_UST_CHAN_FAIL; goto error; } + uattr.overwrite = attr->attr.overwrite; uattr.subbuf_size = attr->attr.subbuf_size; uattr.num_subbuf = attr->attr.num_subbuf; @@ -240,6 +244,7 @@ int channel_ust_create(struct ltt_ust_session *usession, ret = LTTCOMM_UST_CHAN_FAIL; goto error; } + suchan->attr.overwrite = uattr.overwrite; suchan->attr.subbuf_size = uattr.subbuf_size; suchan->attr.num_subbuf = uattr.num_subbuf; diff --git a/ltt-sessiond/ltt-sessiond.h b/ltt-sessiond/ltt-sessiond.h index c28572a86..63de2e120 100644 --- a/ltt-sessiond/ltt-sessiond.h +++ b/ltt-sessiond/ltt-sessiond.h @@ -20,6 +20,7 @@ #define _LTT_SESSIOND_H #define _LGPL_SOURCE +#include #include #include "ust-app.h" diff --git a/ltt-sessiond/main.c b/ltt-sessiond/main.c index c288afbb0..081b0c855 100644 --- a/ltt-sessiond/main.c +++ b/ltt-sessiond/main.c @@ -56,6 +56,7 @@ #include "context.h" #include "event.h" #include "futex.h" +#include "hashtable.h" #include "kernel-ctl.h" #include "ltt-sessiond.h" #include "shm.h" @@ -304,6 +305,17 @@ static void teardown_kernel_session(struct ltt_session *session) } } +/* + * Complete teardown of all UST sessions. This will free everything on his path + * and destroy the core essence of all ust sessions :) + */ +static void teardown_ust_session(struct ltt_session *session) +{ + DBG("Tearing down UST session(s)"); + + trace_ust_destroy_session(session->ust_session); +} + /* * Stop all threads by closing the thread quit pipe. */ @@ -364,7 +376,8 @@ static void cleanup(void) cds_list_for_each_entry_safe(sess, stmp, &session_list_ptr->head, list) { teardown_kernel_session(sess); - // TODO complete session cleanup (including UST) + teardown_ust_session(sess); + free(sess); } } @@ -1131,6 +1144,9 @@ static void *thread_manage_apps(void *data) DBG("[thread] Manage application started"); + rcu_register_thread(); + rcu_thread_online(); + ret = create_thread_poll_set(&events, 2); if (ret < 0) { goto error; @@ -1236,6 +1252,8 @@ error: lttng_poll_clean(&events); + rcu_thread_offline(); + rcu_unregister_thread(); return NULL; } @@ -1838,7 +1856,7 @@ static int create_ust_session(struct ltt_session *session, switch (domain->type) { case LTTNG_DOMAIN_UST_PID: - app = ust_app_get_by_pid(domain->attr.pid); + app = ust_app_find_by_pid(domain->attr.pid); if (app == NULL) { ret = LTTCOMM_APP_NOT_FOUND; goto error; @@ -1867,17 +1885,41 @@ static int create_ust_session(struct ltt_session *session, } } - /* Create session on the UST tracer */ - ret = ustctl_create_session(app->sock); - if (ret < 0) { - ret = LTTCOMM_UST_SESS_FAIL; - goto error; + /* The domain type dictate different actions on session creation */ + switch (domain->type) { + case LTTNG_DOMAIN_UST_PID: + app = ust_app_find_by_pid(domain->attr.pid); + if (app == NULL) { + ret = LTTCOMM_APP_NOT_FOUND; + goto error; + } + /* Create session on the UST tracer */ + ret = ustctl_create_session(app->key.sock, lus); + if (ret < 0) { + ret = LTTCOMM_UST_SESS_FAIL; + goto error; + } + + lus->handle = ret; + break; + case LTTNG_DOMAIN_UST: + /* Create session on the UST tracer */ + ret = ustctl_create_session(app->key.sock, lus); + if (ret < 0) { + ret = LTTCOMM_UST_SESS_FAIL; + goto error; + } + break; + case LTTNG_DOMAIN_UST_EXEC_NAME: + break; + default: + goto error; } lus->handle = ret; lus->sock = app->sock; - cds_list_add(&lus->list, &session->ust_session_list.head); - session->ust_session_list.count++; + session->ust_session = lus; + printf("%p\n", session->ust_session); return LTTCOMM_OK; @@ -2052,13 +2094,14 @@ error: /* * Copy channel from attributes and set it in the application channel list. */ +/* static int copy_ust_channel_to_app(struct ltt_ust_session *usess, struct lttng_channel *attr, struct ust_app *app) { int ret; struct ltt_ust_channel *uchan, *new_chan; - uchan = trace_ust_get_channel_by_name(attr->name, usess); + uchan = trace_ust_get_channel_by_key(usess->channels, attr->name); if (uchan == NULL) { ret = LTTCOMM_FATAL; goto error; @@ -2077,13 +2120,10 @@ static int copy_ust_channel_to_app(struct ltt_ust_session *usess, goto error; } - /* Add channel to the ust app channel list */ - cds_list_add(&new_chan->list, &app->channels.head); - app->channels.count++; - error: return ret; } +*/ /* * Command LTTNG_ENABLE_CHANNEL processed by the client thread. @@ -2092,6 +2132,9 @@ static int cmd_enable_channel(struct ltt_session *session, struct lttng_domain *domain, struct lttng_channel *attr) { int ret; + struct ltt_ust_session *usess = session->ust_session; + + DBG("Enabling channel %s for session %s", session->name, attr->name); switch (domain->type) { case LTTNG_DOMAIN_KERNEL: @@ -2114,8 +2157,35 @@ static int cmd_enable_channel(struct ltt_session *session, kernel_wait_quiescent(kernel_tracer_fd); break; } + case LTTNG_DOMAIN_UST: + { + struct ltt_ust_channel *uchan; + + DBG2("Enabling channel for LTTNG_DOMAIN_UST domain"); + + uchan = trace_ust_find_channel_by_name(usess->domain_global.channels, + attr->name); + if (uchan == NULL) { + uchan = trace_ust_create_channel(attr, usess->path); + if (uchan == NULL) { + ret = LTTCOMM_UST_CHAN_FAIL; + goto error; + } + rcu_read_lock(); + hashtable_add_unique(usess->domain_global.channels, &uchan->node); + rcu_read_unlock(); + } else { + ret = LTTCOMM_UST_CHAN_EXIST; + goto error; + } + + /* TODO: Iterate over trace apps to enable that channel */ + + break; + } case LTTNG_DOMAIN_UST_PID: { + /* int sock; struct ltt_ust_channel *uchan; struct ltt_ust_session *usess; @@ -2153,7 +2223,9 @@ static int cmd_enable_channel(struct ltt_session *session, DBG("UST channel %s created for app sock %d with pid %d", attr->name, app->sock, domain->attr.pid); - break; + */ + ret = LTTCOMM_NOT_IMPLEMENTED; + goto error; } default: ret = LTTCOMM_UNKNOWN_DOMAIN; @@ -2879,7 +2951,7 @@ static ssize_t cmd_list_domains(struct ltt_session *session, nb_dom++; } - nb_dom += session->ust_session_list.count; + /* TODO: User-space tracer domain support */ *domains = malloc(nb_dom * sizeof(struct lttng_domain)); if (*domains == NULL) { @@ -2889,8 +2961,6 @@ static ssize_t cmd_list_domains(struct ltt_session *session, (*domains)[0].type = LTTNG_DOMAIN_KERNEL; - /* TODO: User-space tracer domain support */ - return nb_dom; error: @@ -3070,12 +3140,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx) case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: { struct ltt_ust_session *usess; - if (need_tracing_session) { - usess = trace_ust_get_session_by_pid( - &cmd_ctx->session->ust_session_list, - cmd_ctx->lsm->domain.attr.pid); - if (usess == NULL) { + if (cmd_ctx->session->ust_session == NULL) { ret = create_ust_session(cmd_ctx->session, &cmd_ctx->lsm->domain); if (ret != LTTCOMM_OK) { @@ -3096,7 +3162,6 @@ static int process_client_msg(struct command_ctx *cmd_ctx) pthread_mutex_unlock(&ustconsumer_data.pid_mutex); } break; - } default: break; } @@ -3355,6 +3420,8 @@ static void *thread_manage_clients(void *data) DBG("[thread] Manage client started"); + rcu_register_thread(); + ret = lttcomm_listen_unix_sock(client_sock); if (ret < 0) { goto error; @@ -3455,6 +3522,7 @@ static void *thread_manage_clients(void *data) // TODO: Validate cmd_ctx including sanity check for // security purpose. + rcu_thread_online(); /* * This function dispatch the work to the kernel or userspace tracer * libs and fill the lttcomm_lttng_msg data structure of all the needed @@ -3462,6 +3530,7 @@ static void *thread_manage_clients(void *data) * everything this function may needs. */ ret = process_client_msg(cmd_ctx); + rcu_thread_offline(); if (ret < 0) { /* * TODO: Inform client somehow of the fatal error. At @@ -3494,6 +3563,8 @@ error: lttng_poll_clean(&events); clean_command_ctx(&cmd_ctx); + + rcu_unregister_thread(); return NULL; } @@ -3922,6 +3993,8 @@ int main(int argc, char **argv) void *status; const char *home_path; + rcu_register_thread(); + /* Create thread quit pipe */ if ((ret = init_thread_quit_pipe()) < 0) { goto error; @@ -4064,6 +4137,9 @@ int main(int argc, char **argv) /* Init UST command queue. */ cds_wfq_init(&ust_cmd_queue.queue); + /* Init UST app hash table */ + ust_app_ht_alloc(); + /* * Get session list pointer. This pointer MUST NOT be free(). This list is * statically declared in session.c @@ -4158,7 +4234,10 @@ exit: /* * cleanup() is called when no other thread is running. */ + rcu_thread_online(); cleanup(); + rcu_thread_offline(); + rcu_unregister_thread(); if (!ret) exit(EXIT_SUCCESS); error: diff --git a/ltt-sessiond/session.c b/ltt-sessiond/session.c index b35157bae..c7ce843d7 100644 --- a/ltt-sessiond/session.c +++ b/ltt-sessiond/session.c @@ -21,12 +21,16 @@ #include #include #include +#include #include #include +#include "hashtable.h" #include "session.h" +#include "../hashtable/hash.h" + /* * NOTES: * @@ -204,9 +208,7 @@ int session_create(char *name, char *path) /* Init kernel session */ new_session->kernel_session = NULL; - - /* Init UST session list */ - CDS_INIT_LIST_HEAD(&new_session->ust_session_list.head); + new_session->ust_session = NULL; /* Init lock */ pthread_mutex_init(&new_session->lock, NULL); diff --git a/ltt-sessiond/session.h b/ltt-sessiond/session.h index 7db95ed1d..41883c609 100644 --- a/ltt-sessiond/session.h +++ b/ltt-sessiond/session.h @@ -59,7 +59,7 @@ struct ltt_session { char name[NAME_MAX]; char path[PATH_MAX]; struct ltt_kernel_session *kernel_session; - struct ltt_ust_session_list ust_session_list; + struct ltt_ust_session *ust_session; /* * Protect any read/write on this session data structure. This lock must be * acquired *before* using any public functions declared below. Use @@ -80,5 +80,6 @@ void session_unlock_list(void); struct ltt_session *session_find_by_name(char *name); struct ltt_session_list *session_get_list(void); +unsigned long session_ust_count(struct ltt_session *session); #endif /* _LTT_SESSION_H */ diff --git a/ltt-sessiond/trace-ust.c b/ltt-sessiond/trace-ust.c index c2978894e..b1066072b 100644 --- a/ltt-sessiond/trace-ust.c +++ b/ltt-sessiond/trace-ust.c @@ -24,78 +24,55 @@ #include #include +#include "hashtable.h" #include "trace-ust.h" /* - * Using a ust session list, it will return the session corresponding to the - * pid. Must be a session of domain LTTNG_DOMAIN_UST_PID. + * Find the channel in the hashtable. */ -struct ltt_ust_session *trace_ust_get_session_by_pid( - struct ltt_ust_session_list *session_list, pid_t pid) +struct ltt_ust_channel *trace_ust_find_channel_by_name(struct cds_lfht *ht, + char *name) { - struct ltt_ust_session *sess; + struct cds_lfht_node *node; + struct cds_lfht_iter iter; - if (session_list == NULL) { - ERR("Session list is NULL"); + rcu_read_lock(); + node = hashtable_lookup(ht, (void *) name, strlen(name), &iter); + if (node == NULL) { + rcu_read_unlock(); goto error; } + rcu_read_unlock(); - cds_list_for_each_entry(sess, &session_list->head, list) { - if (sess->domain.type == LTTNG_DOMAIN_UST_PID && - sess->domain.attr.pid == pid) { - DBG2("Trace UST session found by pid %d", pid); - return sess; - } - } - -error: - return NULL; -} + DBG2("Trace UST channel %s found by name", name); -/* - * Find the channel name for the given ust session. - */ -struct ltt_ust_channel *trace_ust_get_channel_by_name( - char *name, struct ltt_ust_session *session) -{ - struct ltt_ust_channel *chan; - - if (session == NULL) { - ERR("Undefine session"); - goto error; - } - - cds_list_for_each_entry(chan, &session->channels.head, list) { - if (strcmp(name, chan->name) == 0) { - DBG2("Found UST channel by name %s", name); - return chan; - } - } + return caa_container_of(node, struct ltt_ust_channel, node); error: + DBG2("Trace UST channel %s not found by name", name); return NULL; } /* - * Find the event name for the given channel. + * Find the event in the hashtable. */ -struct ltt_ust_event *trace_ust_get_event_by_name( - char *name, struct ltt_ust_channel *channel) +struct ltt_ust_event *trace_ust_find_event_by_name(struct cds_lfht *ht, + char *name) { - struct ltt_ust_event *ev; + struct cds_lfht_node *node; + struct cds_lfht_iter iter; - if (channel == NULL) { - ERR("Undefine channel"); + rcu_read_lock(); + node = hashtable_lookup(ht, (void *) name, strlen(name), &iter); + if (node == NULL) { + rcu_read_unlock(); goto error; } + rcu_read_unlock(); - cds_list_for_each_entry(ev, &channel->events.head, list) { - if (strcmp(name, ev->attr.name) == 0) { - DBG("Found UST event by name %s for channel %s", name, - channel->name); - return ev; - } - } + DBG2("Found UST event by name %s", name); + + return caa_container_of(node, struct ltt_ust_event, node); error: return NULL; @@ -124,11 +101,13 @@ struct ltt_ust_session *trace_ust_create_session(char *path, pid_t pid, lus->enabled = 1; lus->consumer_fds_sent = 0; lus->metadata = NULL; - lus->channels.count = 0; - CDS_INIT_LIST_HEAD(&lus->channels.head); - /* Copy lttng_domain */ - memcpy(&lus->domain, domain, sizeof(struct lttng_domain)); + /* Alloc UST domain hash tables */ + lus->domain_pid = hashtable_new(0); + lus->domain_exec = hashtable_new_str(0); + + /* Alloc UST global domain channels' HT */ + lus->domain_global.channels = hashtable_new_str(0); /* Set session path */ ret = snprintf(lus->path, PATH_MAX, "%s/ust_%d", path, pid); @@ -174,15 +153,17 @@ struct ltt_ust_channel *trace_ust_create_channel(struct lttng_channel *chan, luc->handle = -1; luc->enabled = 1; - luc->events.count = 0; - CDS_INIT_LIST_HEAD(&luc->events.head); - - memset(&luc->ctx, 0, sizeof(struct lttng_ust_context)); /* Copy channel name */ strncpy(luc->name, chan->name, sizeof(&luc->name)); luc->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; + /* Init node */ + hashtable_node_init(&luc->node, (void *) luc->name, strlen(luc->name)); + /* Alloc hash tables */ + luc->events = hashtable_new_str(0); + luc->ctx = hashtable_new_str(0); + /* Set trace output path */ ret = snprintf(luc->trace_path, PATH_MAX, "%s", path); if (ret < 0) { @@ -191,6 +172,8 @@ struct ltt_ust_channel *trace_ust_create_channel(struct lttng_channel *chan, } CDS_INIT_LIST_HEAD(&luc->stream_list.head); + DBG2("Trace UST channel %s created", luc->name); + return luc; error: @@ -237,7 +220,12 @@ struct ltt_ust_event *trace_ust_create_event(struct lttng_event *ev) /* Setting up a ust event */ lue->handle = -1; lue->enabled = 1; - memset(&lue->ctx, 0, sizeof(struct lttng_ust_context)); + + /* Init node */ + hashtable_node_init(&lue->node, (void *) lue->attr.name, + strlen(lue->attr.name)); + /* Alloc context hash tables */ + lue->ctx = hashtable_new_str(5); return lue; @@ -271,7 +259,7 @@ struct ltt_ust_metadata *trace_ust_create_metadata(char *path) lum->handle = -1; /* Set metadata trace path */ - ret = asprintf(&lum->pathname, "%s/metadata", path); + ret = snprintf(lum->pathname, PATH_MAX, "%s/metadata", path); if (ret < 0) { perror("asprintf ust metadata"); goto error; @@ -283,35 +271,101 @@ error: return NULL; } +/* + * RCU safe free context structure. + */ +static void destroy_context_rcu(struct rcu_head *head) +{ + struct cds_lfht_node *node = + caa_container_of(head, struct cds_lfht_node, head); + struct ltt_ust_context *ctx = + caa_container_of(node, struct ltt_ust_context, node); + + free(ctx); +} + +/* + * Cleanup UST context hash table. + */ +static void destroy_context(struct cds_lfht *ht) +{ + int ret; + struct cds_lfht_node *node; + struct cds_lfht_iter iter; + + hashtable_get_first(ht, &iter); + while ((node = hashtable_iter_get_node(&iter)) != NULL) { + ret = hashtable_del(ht, &iter); + if (!ret) { + call_rcu(&node->head, destroy_context_rcu); + } + hashtable_get_next(ht, &iter); + } +} + /* * Cleanup ust event structure. */ void trace_ust_destroy_event(struct ltt_ust_event *event) { - DBG("[trace] Destroy ust event %s", event->attr.name); - - /* Remove from event list */ - cds_list_del(&event->list); + DBG2("Trace destroy UST event %s", event->attr.name); + destroy_context(event->ctx); free(event); } +/* + * URCU intermediate call to complete destroy event. + */ +static void destroy_event_rcu(struct rcu_head *head) +{ + struct cds_lfht_node *node = + caa_container_of(head, struct cds_lfht_node, head); + struct ltt_ust_event *event = + caa_container_of(node, struct ltt_ust_event, node); + + trace_ust_destroy_event(event); +} + /* * Cleanup ust channel structure. */ void trace_ust_destroy_channel(struct ltt_ust_channel *channel) { - struct ltt_ust_event *event, *etmp; + int ret; + struct cds_lfht_node *node; + struct cds_lfht_iter iter; - DBG("[trace] Destroy ust channel %d", channel->handle); + DBG2("Trace destroy UST channel %s", channel->name); - /* For each event in the channel list */ - cds_list_for_each_entry_safe(event, etmp, &channel->events.head, list) { - trace_ust_destroy_event(event); + rcu_read_lock(); + + hashtable_get_first(channel->events, &iter); + while ((node = hashtable_iter_get_node(&iter)) != NULL) { + ret = hashtable_del(channel->events, &iter); + if (!ret) { + call_rcu(&node->head, destroy_event_rcu); + } + hashtable_get_next(channel->events, &iter); } - /* Remove from channel list */ - cds_list_del(&channel->list); + free(channel->events); + destroy_context(channel->ctx); free(channel); + + rcu_read_unlock(); +} + +/* + * URCU intermediate call to complete destroy channel. + */ +static void destroy_channel_rcu(struct rcu_head *head) +{ + struct cds_lfht_node *node = + caa_container_of(head, struct cds_lfht_node, head); + struct ltt_ust_channel *channel = + caa_container_of(node, struct ltt_ust_channel, node); + + trace_ust_destroy_channel(channel); } /* @@ -319,38 +373,104 @@ void trace_ust_destroy_channel(struct ltt_ust_channel *channel) */ void trace_ust_destroy_metadata(struct ltt_ust_metadata *metadata) { - DBG("[trace] Destroy ust metadata %d", metadata->handle); + DBG2("Trace UST destroy metadata %d", metadata->handle); - /* Free attributes */ - free(metadata->pathname); free(metadata); } /* - * Cleanup ust session structure + * Iterate over a hash table containing channels and cleanup safely. */ -void trace_ust_destroy_session(struct ltt_ust_session *session) +static void destroy_channels(struct cds_lfht *channels) +{ + int ret; + struct cds_lfht_node *node; + struct cds_lfht_iter iter; + + hashtable_get_first(channels, &iter); + while ((node = hashtable_iter_get_node(&iter)) != NULL) { + ret = hashtable_del(channels, &iter); + if (!ret) { + call_rcu(&node->head, destroy_channel_rcu); + } + hashtable_get_next(channels, &iter); + } +} + +/* + * Cleanup UST pid domain. + */ +static void destroy_domain_pid(struct cds_lfht *ht) +{ + int ret; + struct cds_lfht_node *node; + struct cds_lfht_iter iter; + struct ltt_ust_domain_pid *d; + + hashtable_get_first(ht, &iter); + while ((node = hashtable_iter_get_node(&iter)) != NULL) { + ret = hashtable_del(ht , &iter); + if (!ret) { + d = caa_container_of(node, struct ltt_ust_domain_pid, node); + destroy_channels(d->channels); + } + hashtable_get_next(ht, &iter); + } +} + +/* + * Cleanup UST exec name domain. + */ +static void destroy_domain_exec(struct cds_lfht *ht) { - struct ltt_ust_channel *channel, *ctmp; + int ret; + struct cds_lfht_node *node; + struct cds_lfht_iter iter; + struct ltt_ust_domain_exec *d; + + hashtable_get_first(ht, &iter); + while ((node = hashtable_iter_get_node(&iter)) != NULL) { + ret = hashtable_del(ht , &iter); + if (!ret) { + d = caa_container_of(node, struct ltt_ust_domain_exec, node); + destroy_channels(d->channels); + } + hashtable_get_next(ht, &iter); + } +} - DBG("[trace] Destroy ust session %d", session->handle); +/* + * Cleanup UST global domain. + */ +static void destroy_domain_global(struct ltt_ust_domain_global *dom) +{ + destroy_channels(dom->channels); +} +/* + * Cleanup ust session structure + */ +void trace_ust_destroy_session(struct ltt_ust_session *session) +{ /* Extra safety */ if (session == NULL) { return; } + rcu_read_lock(); + + DBG2("Trace UST destroy session %d", session->handle); + if (session->metadata != NULL) { trace_ust_destroy_metadata(session->metadata); } - cds_list_for_each_entry_safe(channel, ctmp, &session->channels.head, list) { - trace_ust_destroy_channel(channel); - } - - if (session->path) { - free(session->path); - } + /* Cleaning up UST domain */ + destroy_domain_global(&session->domain_global); + destroy_domain_pid(session->domain_pid); + destroy_domain_exec(session->domain_exec); free(session); + + rcu_read_unlock(); } diff --git a/ltt-sessiond/trace-ust.h b/ltt-sessiond/trace-ust.h index e2901a7fa..2b133e8c4 100644 --- a/ltt-sessiond/trace-ust.h +++ b/ltt-sessiond/trace-ust.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -36,19 +37,8 @@ #include "lttng-ust-abi.h" #endif -/* - * UST session list. - */ -struct ltt_ust_session_list { - unsigned int count; - struct cds_list_head head; -}; +#include "../hashtable/rculfhash.h" -/* UST event list */ -struct ltt_ust_event_list { - unsigned int count; - struct cds_list_head head; -}; /* UST Stream list */ struct ltt_ust_stream_list { @@ -56,28 +46,25 @@ struct ltt_ust_stream_list { struct cds_list_head head; }; -/* UST Channel list */ -struct ltt_ust_channel_list { - unsigned int count; - struct cds_list_head head; +/* Context hash table nodes */ +struct ltt_ust_context { + struct lttng_ust_context ctx; + struct cds_lfht_node node; }; /* UST event */ struct ltt_ust_event { int handle; int enabled; - /* - * TODO: need internal representation to support more than a - * single context. - */ - struct lttng_ust_context ctx; - struct lttng_ust_event attr; - struct cds_list_head list; struct object_data *obj; + struct lttng_ust_event attr; + struct cds_lfht *ctx; + struct cds_lfht_node node; }; /* UST stream */ struct ltt_ust_stream { + /* TODO hashtable */ struct object_data *obj; struct cds_list_head list; char *pathname; @@ -89,28 +76,44 @@ struct ltt_ust_channel { int enabled; char name[LTTNG_UST_SYM_NAME_LEN]; char trace_path[PATH_MAX]; /* Trace file path name */ - /* - * TODO: need internal representation to support more than a - * single context. - */ - struct lttng_ust_context ctx; - struct lttng_ust_channel attr; - struct ltt_ust_event_list events; - struct cds_list_head list; struct object_data *obj; + unsigned int stream_count; struct ltt_ust_stream_list stream_list; + struct lttng_ust_channel attr; + struct cds_lfht *ctx; + struct cds_lfht *events; + struct cds_lfht_node node; }; /* UST Metadata */ struct ltt_ust_metadata { int handle; struct object_data *obj; - char *pathname; /* Trace file path name */ + char pathname[PATH_MAX]; /* Trace file path name */ struct lttng_ust_channel attr; struct object_data *stream_obj; }; +/* UST domain global (LTTNG_DOMAIN_UST) */ +struct ltt_ust_domain_global { + struct cds_lfht *channels; +}; + +/* UST domain pid (LTTNG_DOMAIN_UST_PID) */ +struct ltt_ust_domain_pid { + pid_t pid; + struct cds_lfht *channels; + struct cds_lfht_node node; +}; + +/* UST domain exec name (LTTNG_DOMAIN_UST_EXEC_NAME) */ +struct ltt_ust_domain_exec { + char exec_name[LTTNG_UST_SYM_NAME_LEN]; + struct cds_lfht *channels; + struct cds_lfht_node node; +}; + /* UST session */ struct ltt_ust_session { int sock; /* socket to send cmds to app */ @@ -119,11 +122,16 @@ struct ltt_ust_session { int consumer_fds_sent; int consumer_fd; char path[PATH_MAX]; - struct lttng_domain domain; struct ltt_ust_metadata *metadata; - struct ltt_ust_channel_list channels; - struct cds_list_head list; struct object_data *obj; + struct ltt_ust_domain_global domain_global; + /* + * Those two hash tables contains data for a specific UST domain and a HT + * of channels for each. See ltt_ust_domain_exec and ltt_ust_domain_pid + * data structures. + */ + struct cds_lfht *domain_pid; + struct cds_lfht *domain_exec; }; #ifdef CONFIG_LTTNG_TOOLS_HAVE_UST @@ -131,12 +139,10 @@ struct ltt_ust_session { /* * Lookup functions. NULL is returned if not found. */ -struct ltt_ust_event *trace_ust_get_event_by_name( - char *name, struct ltt_ust_channel *channel); -struct ltt_ust_channel *trace_ust_get_channel_by_name( - char *name, struct ltt_ust_session *session); -struct ltt_ust_session *trace_ust_get_session_by_pid( - struct ltt_ust_session_list *session_list, pid_t pid); +struct ltt_ust_event *trace_ust_find_event_by_name(struct cds_lfht *ht, + char *name); +struct ltt_ust_channel *trace_ust_find_channel_by_name(struct cds_lfht *ht, + char *name); /* * Create functions malloc() the data structure. @@ -160,17 +166,19 @@ void trace_ust_destroy_event(struct ltt_ust_event *event); #else static inline -struct ltt_ust_event *trace_ust_get_event_by_name( - char *name, struct ltt_ust_channel *channel) +struct ltt_ust_event *trace_ust_find_event_by_name(struct cds_lfht *ht, + char *name) { return NULL; } + static inline -struct ltt_ust_channel *trace_ust_get_channel_by_name( - char *name, struct ltt_ust_session *session) +struct ltt_ust_channel *trace_ust_find_channel_by_name(struct cds_lfht *ht, + char *name) { return NULL; } + static inline struct ltt_ust_session *trace_ust_get_session_by_pid( struct ltt_ust_session_list *session_list, pid_t pid) diff --git a/ltt-sessiond/ust-app.c b/ltt-sessiond/ust-app.c index ea062557e..c8dd848b1 100644 --- a/ltt-sessiond/ust-app.c +++ b/ltt-sessiond/ust-app.c @@ -26,102 +26,151 @@ #include +#include "hashtable.h" #include "ust-app.h" - -/* Init ust traceable application's list */ -static struct ust_app_list ust_app_list = { - .head = CDS_LIST_HEAD_INIT(ust_app_list.head), - .lock = PTHREAD_MUTEX_INITIALIZER, - .count = 0, -}; - -/* - * Add a traceable application structure to the global list. - */ -static void add_app_to_list(struct ust_app *lta) -{ - cds_list_add(<a->list, &ust_app_list.head); - ust_app_list.count++; -} +#include "../hashtable/hash.h" /* * Delete a traceable application structure from the global list. */ -static void del_app_from_list(struct ust_app *lta) +static void delete_ust_app(struct ust_app *lta) { - struct ltt_ust_channel *chan; + int ret; + struct cds_lfht_node *node; + struct cds_lfht_iter iter; - cds_list_del(<a->list); - /* Sanity check */ - if (ust_app_list.count > 0) { - ust_app_list.count--; - } + rcu_read_lock(); - cds_list_for_each_entry(chan, <a->channels.head, list) { - trace_ust_destroy_channel(chan); + hashtable_get_first(lta->channels, &iter); + while ((node = hashtable_iter_get_node(&iter)) != NULL) { + ret = hashtable_del(lta->channels, &iter); + if (!ret) { + trace_ust_destroy_channel( + caa_container_of(node, struct ltt_ust_channel, node)); + } + hashtable_get_next(lta->channels, &iter); } -} -/* - * Iterate over the traceable apps list and return a pointer or NULL if not - * found. - */ -static struct ust_app *find_app_by_sock(int sock) -{ - struct ust_app *iter; + free(lta->channels); + close(lta->key.sock); - cds_list_for_each_entry(iter, &ust_app_list.head, list) { - if (iter->sock == sock) { - /* Found */ - return iter; + /* Remove from apps hash table */ + node = hashtable_lookup(ust_app_ht, + (void *) ((unsigned long) lta->key.pid), sizeof(void *), &iter); + if (node == NULL) { + ERR("UST app pid %d not found in hash table", lta->key.pid); + } else { + ret = hashtable_del(ust_app_ht, &iter); + if (ret) { + ERR("UST app unable to delete app %d from hash table", + lta->key.pid); + } else { + DBG2("UST app pid %d deleted", lta->key.pid); } } - return NULL; + /* Remove from key hash table */ + node = hashtable_lookup(ust_app_sock_key_map, + (void *) ((unsigned long) lta->key.sock), sizeof(void *), &iter); + if (node == NULL) { + ERR("UST app key %d not found in key hash table", lta->key.sock); + } else { + ret = hashtable_del(ust_app_sock_key_map, &iter); + if (ret) { + ERR("UST app unable to delete app sock %d from key hash table", + lta->key.sock); + } else { + DBG2("UST app pair sock %d key %d deleted", + lta->key.sock, lta->key.pid); + } + } + + free(lta); + + rcu_read_unlock(); } /* - * Return pointer to traceable apps list. + * URCU intermediate call to delete an UST app. */ -struct ust_app_list *ust_app_get_list(void) +static void delete_ust_app_rcu(struct rcu_head *head) { - return &ust_app_list; + struct cds_lfht_node *node = + caa_container_of(head, struct cds_lfht_node, head); + struct ust_app *app = + caa_container_of(node, struct ust_app, node); + + delete_ust_app(app); } /* - * Acquire traceable apps list lock. + * Find an ust_app using the sock and return it. */ -void ust_app_lock_list(void) +static struct ust_app *find_app_by_sock(int sock) { - pthread_mutex_lock(&ust_app_list.lock); + struct cds_lfht_node *node; + struct ust_app_key *key; + struct cds_lfht_iter iter; + //struct ust_app *app; + + rcu_read_lock(); + + node = hashtable_lookup(ust_app_sock_key_map, + (void *)((unsigned long) sock), sizeof(void *), &iter); + if (node == NULL) { + DBG2("UST app find by sock %d key not found", sock); + rcu_read_unlock(); + goto error; + } + + key = caa_container_of(node, struct ust_app_key, node); + + node = hashtable_lookup(ust_app_ht, + (void *)((unsigned long) key->pid), sizeof(void *), &iter); + if (node == NULL) { + DBG2("UST app find by sock %d not found", sock); + rcu_read_unlock(); + goto error; + } + rcu_read_unlock(); + + return caa_container_of(node, struct ust_app, node); + +error: + return NULL; } /* - * Release traceable apps list lock. + * Return pointer to traceable apps list. */ -void ust_app_unlock_list(void) +struct cds_lfht *ust_app_get_ht(void) { - pthread_mutex_unlock(&ust_app_list.lock); + return ust_app_ht; } /* - * Iterate over the traceable apps list and return a pointer or NULL if not - * found. + * Return ust app pointer or NULL if not found. */ -struct ust_app *ust_app_get_by_pid(pid_t pid) +struct ust_app *ust_app_find_by_pid(pid_t pid) { - struct ust_app *iter; + struct cds_lfht_node *node; + struct cds_lfht_iter iter; - cds_list_for_each_entry(iter, &ust_app_list.head, list) { - if (iter->pid == pid) { - /* Found */ - DBG2("Found traceable app by pid %d", pid); - return iter; - } + rcu_read_lock(); + node = hashtable_lookup(ust_app_ht, + (void *)((unsigned long) pid), sizeof(void *), &iter); + if (node == NULL) { + rcu_read_unlock(); + DBG2("UST app no found with pid %d", pid); + goto error; } + rcu_read_unlock(); - DBG2("Traceable app with pid %d not found", pid); + DBG2("Found UST app by pid %d", pid); + return caa_container_of(node, struct ust_app, node); + +error: return NULL; } @@ -143,22 +192,29 @@ int ust_app_register(struct ust_register_msg *msg, int sock) lta->uid = msg->uid; lta->gid = msg->gid; - lta->pid = msg->pid; + lta->key.pid = msg->pid; lta->ppid = msg->ppid; lta->v_major = msg->major; lta->v_minor = msg->minor; - lta->sock = sock; + lta->key.sock = sock; strncpy(lta->name, msg->name, sizeof(lta->name)); lta->name[16] = '\0'; - CDS_INIT_LIST_HEAD(<a->channels.head); + hashtable_node_init(<a->node, (void *)((unsigned long)lta->key.pid), + sizeof(void *)); + lta->channels = hashtable_new_str(0); + + /* Set sock key map */ + hashtable_node_init(<a->key.node, (void *)((unsigned long)lta->key.sock), + sizeof(void *)); - ust_app_lock_list(); - add_app_to_list(lta); - ust_app_unlock_list(); + rcu_read_lock(); + hashtable_add_unique(ust_app_ht, <a->node); + hashtable_add_unique(ust_app_sock_key_map, <a->key.node); + rcu_read_unlock(); DBG("App registered with pid:%d ppid:%d uid:%d gid:%d sock:%d name:%s" - " (version %d.%d)", lta->pid, lta->ppid, lta->uid, lta->gid, - lta->sock, lta->name, lta->v_major, lta->v_minor); + " (version %d.%d)", lta->key.pid, lta->ppid, lta->uid, lta->gid, + lta->key.sock, lta->name, lta->v_major, lta->v_minor); return 0; } @@ -173,27 +229,26 @@ void ust_app_unregister(int sock) { struct ust_app *lta; - ust_app_lock_list(); + DBG2("UST app unregistering sock %d", sock); + lta = find_app_by_sock(sock); if (lta) { - DBG("PID %d unregistered with sock %d", lta->pid, sock); - del_app_from_list(lta); - close(lta->sock); - free(lta); + DBG("PID %d unregistering with sock %d", lta->key.pid, sock); + /* FIXME: Better use a call_rcu here ? */ + delete_ust_app(lta); } - ust_app_unlock_list(); } /* * Return traceable_app_count */ -unsigned int ust_app_list_count(void) +unsigned long ust_app_list_count(void) { - unsigned int count; + unsigned long count; - ust_app_lock_list(); - count = ust_app_list.count; - ust_app_unlock_list(); + rcu_read_lock(); + count = hashtable_get_count(ust_app_ht); + rcu_read_unlock(); return count; } @@ -203,15 +258,31 @@ unsigned int ust_app_list_count(void) */ void ust_app_clean_list(void) { - struct ust_app *iter, *tmp; - - /* - * Don't acquire list lock here. This function should be called from - * cleanup() functions meaning that the program will exit. - */ - cds_list_for_each_entry_safe(iter, tmp, &ust_app_list.head, list) { - del_app_from_list(iter); - close(iter->sock); - free(iter); + int ret; + struct cds_lfht_node *node; + struct cds_lfht_iter iter; + + DBG2("UST app clean hash table"); + + rcu_read_lock(); + + hashtable_get_first(ust_app_ht, &iter); + while ((node = hashtable_iter_get_node(&iter)) != NULL) { + ret = hashtable_del(ust_app_ht, &iter); + if (!ret) { + call_rcu(&node->head, delete_ust_app_rcu); + } + hashtable_get_next(ust_app_ht, &iter); } + + rcu_read_unlock(); +} + +/* + * Init UST app hash table. + */ +void ust_app_ht_alloc(void) +{ + ust_app_ht = hashtable_new(0); + ust_app_sock_key_map = hashtable_new(0); } diff --git a/ltt-sessiond/ust-app.h b/ltt-sessiond/ust-app.h index cc08a4c33..91be50320 100644 --- a/ltt-sessiond/ust-app.h +++ b/ltt-sessiond/ust-app.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _TRACEABLE_APP_H -#define _TRACEABLE_APP_H +#ifndef _LTT_UST_APP_H +#define _LTT_UST_APP_H #include #include @@ -37,56 +37,44 @@ struct ust_register_msg { char name[16]; }; -/* - * Traceable application list. - */ -struct ust_app_list { - /* - * This lock protects any read/write access to the list and count (which is - * basically the list size). All public functions in traceable-app.c - * acquire this lock and release it before returning. If none of those - * functions are used, the lock MUST be acquired in order to iterate or/and - * do any actions on that list. - */ - pthread_mutex_t lock; - - /* - * Number of element in the list. The session list lock MUST be acquired if - * this counter is used when iterating over the session list. - */ - unsigned int count; - - /* Linked list head */ - struct cds_list_head head; +struct cds_lfht *ust_app_ht; + +struct cds_lfht *ust_app_sock_key_map; + +struct ust_app_key { + pid_t pid; + int sock; + struct cds_lfht_node node; }; -/* Registered traceable applications. Libust registers to the session daemon +/* + * Registered traceable applications. Libust registers to the session daemon * and a linked list is kept of all running traceable app. */ struct ust_app { - int sock; /* Communication socket with the application */ - pid_t pid; + //int sock; + //pid_t pid; pid_t ppid; uid_t uid; /* User ID that owns the apps */ gid_t gid; /* Group ID that owns the apps */ uint32_t v_major; /* Verion major number */ uint32_t v_minor; /* Verion minor number */ char name[17]; /* Process name (short) */ - struct ltt_ust_channel_list channels; - struct cds_list_head list; + struct cds_lfht *channels; + struct cds_lfht_node node; + struct ust_app_key key; }; #ifdef CONFIG_LTTNG_TOOLS_HAVE_UST int ust_app_register(struct ust_register_msg *msg, int sock); void ust_app_unregister(int sock); -unsigned int ust_app_list_count(void); +unsigned long ust_app_list_count(void); -void ust_app_lock_list(void); -void ust_app_unlock_list(void); void ust_app_clean_list(void); -struct ust_app_list *ust_app_get_list(void); -struct ust_app *ust_app_get_by_pid(pid_t pid); +void ust_app_ht_alloc(void); +struct cds_lfht *ust_app_get_ht(void); +struct ust_app *ust_app_find_by_pid(pid_t pid); #else @@ -128,8 +116,6 @@ struct ust_app *ust_app_get_by_pid(pid_t pid) return NULL; } - - #endif -#endif /* _TRACEABLE_APP_H */ +#endif /* _LTT_UST_APP_H */ diff --git a/ltt-sessiond/ust-ctl.c b/ltt-sessiond/ust-ctl.c new file mode 100644 index 000000000..6f73bfc66 --- /dev/null +++ b/ltt-sessiond/ust-ctl.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2011 - David Goulet + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; only version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include +#include + +#include "ust-comm.h" +#include "ust-ctl.h" +#include "../hashtable/hash.h" + +/* + * Init command for tracer with cmd type and correct handle. + */ +static void init_command(int cmd, int handle, struct lttcomm_ust_msg *command) +{ + memset(command, 0, sizeof(struct lttcomm_ust_msg)); + + command->cmd = cmd; + command->handle = handle; +} + +/* + * Generic send command to ust tracer. Caller must free reply. + */ +static struct lttcomm_ust_reply *send_command(int sock, + struct lttcomm_ust_msg *command) +{ + struct lttcomm_ust_reply *reply; + + reply = ustcomm_send_command(sock, command); + if (reply == NULL) { + goto error; + } + + if (reply->ret_code != LTTCOMM_OK) { + ERR("Return code (%d): %s", reply->ret_code, + lttcomm_get_readable_code(reply->ret_code)); + goto error; + } + + return reply; + +error: + return NULL; +} + +/* + * Send registration done packet to the application. + */ +int ustctl_register_done(int sock) +{ + struct lttcomm_ust_msg command; + struct lttcomm_ust_reply *reply; + + DBG("Sending register done command to %d", sock); + + command.cmd = LTTNG_UST_REGISTER_DONE; + command.handle = LTTNG_UST_ROOT_HANDLE; + + reply = ustcomm_send_command(sock, &command); + if (reply == NULL) { + goto error; + } + + if (reply->ret_code != LTTCOMM_OK) { + DBG("Return code: %s", lttcomm_get_readable_code(reply->ret_code)); + goto error; + } + + return 0; + +error: + return -1; +} + +/* + * Create an UST session on the tracer. + * + * Return handle if success else negative value. + */ +int ustctl_create_session(int sock, struct ltt_ust_session *session) +{ + int ret; + struct lttcomm_ust_msg command; + struct lttcomm_ust_reply *reply = NULL; + + command.cmd = LTTNG_UST_SESSION; + command.handle = LTTNG_UST_ROOT_HANDLE; + + reply = ustcomm_send_command(sock, &command); + if (reply == NULL) { + goto error; + } + + /* Save session handle */ + ret = reply->ret_val; + free(reply); + + DBG2("ustctl create session command successful with handle %d", ret); + + return ret; + +error: + free(reply); + return -1; +} + +/* + * Create UST channel to the tracer. + * + * Return handle if success else negative value. + */ +int ustctl_create_channel(int sock, struct ltt_ust_session *session, + struct lttng_ust_channel *channel) +{ + int ret; + struct lttcomm_ust_msg command; + struct lttcomm_ust_reply *reply = NULL; + + init_command(LTTNG_UST_CHANNEL, session->handle, &command); + /* Copy channel attributes to command */ + memcpy(&command.u.channel, channel, sizeof(command.u.channel)); + + /* Send command to tracer */ + reply = send_command(sock, &command); + if (reply == NULL) { + goto error; + } + + ret = reply->ret_val; + free(reply); + + return ret; + +error: + free(reply); + return -1; +} + +/* + * Enable UST channel. + */ +int ustctl_enable_channel(int sock, struct ltt_ust_session *session, + struct ltt_ust_channel *chan) +{ + struct lttcomm_ust_msg command; + struct lttcomm_ust_reply *reply = NULL; + + init_command(LTTNG_UST_ENABLE, chan->handle, &command); + + reply = ustcomm_send_command(sock, &command); + if (reply == NULL) { + goto error; + } + + if (reply->handle != chan->handle) { + ERR("Receive wrong handle from UST reply on enable channel"); + goto error; + } + + chan->enabled = 1; + free(reply); + + DBG2("ustctl enable channel successful for sock %d", sock); + return 0; + +error: + free(reply); + return -1; +} + +/* + * Disable UST channel. + */ +int ustctl_disable_channel(int sock, struct ltt_ust_session *session, + struct ltt_ust_channel *chan) +{ + struct lttcomm_ust_msg command; + struct lttcomm_ust_reply *reply = NULL; + + memset(&command, 0, sizeof(command)); + + command.cmd = LTTNG_UST_DISABLE; + command.handle = chan->handle; + + reply = ustcomm_send_command(sock, &command); + if (reply == NULL) { + goto error; + } + + if (reply->handle != chan->handle) { + ERR("Receive wrong handle from UST reply on enable channel"); + goto error; + } + + chan->enabled = 1; + free(reply); + + DBG2("ustctl disable channel successful for sock %d", sock); + return 0; + +error: + free(reply); + return -1; +} diff --git a/ltt-sessiond/ust-ctl.h b/ltt-sessiond/ust-ctl.h index a6d4e773e..0ceccff45 100644 --- a/ltt-sessiond/ust-ctl.h +++ b/ltt-sessiond/ust-ctl.h @@ -26,10 +26,8 @@ #ifdef CONFIG_LTTNG_TOOLS_HAVE_UST - #else - #endif #endif /* _LTT_UST_CTL_H */ diff --git a/lttng/commands/enable_channels.c b/lttng/commands/enable_channels.c index c5887d07b..715552b5b 100644 --- a/lttng/commands/enable_channels.c +++ b/lttng/commands/enable_channels.c @@ -118,6 +118,11 @@ static int enable_channel(char *session_name) dom.type = LTTNG_DOMAIN_UST_PID; dom.attr.pid = opt_pid; DBG("PID %d set to lttng handle", opt_pid); + } else if (opt_userspace && opt_cmd_name == NULL) { + dom.type = LTTNG_DOMAIN_UST; + } else if (opt_userspace && opt_cmd_name != NULL) { + dom.type = LTTNG_DOMAIN_UST_EXEC_NAME; + strncpy(dom.attr.exec_name, opt_cmd_name, NAME_MAX); } else { ERR("Please specify a tracer (--kernel or --userspace)"); ret = CMD_NOT_IMPLEMENTED; diff --git a/tests/Makefile.am b/tests/Makefile.am index 5ed904b47..e0b369730 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,5 @@ AM_CFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/libkernelctl \ - -I$(top_srcdir)/liblttngctl -g -Wall + -I$(top_srcdir)/liblttngctl -g -Wall -lurcu -lurcu-cds EXTRA_DIST = runall.sh lttng/runall.sh lttng/run-kernel-tests.sh @@ -7,7 +7,8 @@ noinst_PROGRAMS = test_sessions test_kernel_data_trace kernel_all_events_basic \ kernel_event_basic UTILS=utils.h -SESSIONS=$(top_srcdir)/ltt-sessiond/session.c +SESSIONS=$(top_srcdir)/ltt-sessiond/session.c $(top_srcdir)/ltt-sessiond/hashtable.c \ + $(top_srcdir)/hashtable/rculfhash.c $(top_srcdir)/hashtable/hash.c KERN_DATA_TRACE=$(top_srcdir)/ltt-sessiond/trace-kernel.c LIBLTTNG=$(top_srcdir)/liblttngctl/lttngctl.c \ $(top_srcdir)/liblttng-sessiond-comm/lttng-sessiond-comm.c diff --git a/tests/test_sessions.c b/tests/test_sessions.c index 3e9bbbbb5..461a33c1e 100644 --- a/tests/test_sessions.c +++ b/tests/test_sessions.c @@ -26,7 +26,8 @@ #include #include -#include "ltt-sessiond/session.h" + +#include #include "utils.h" #define SESSION1 "test1" @@ -263,7 +264,6 @@ int main(int argc, char **argv) } /* Basic init session values */ assert(tmp->kernel_session == NULL); - assert(tmp->ust_session_list.count == 0); assert(strlen(tmp->path)); assert(strlen(tmp->name)); session_lock(tmp); -- 2.34.1