Basic hashtable support for UST
authorDavid Goulet <david.goulet@polymtl.ca>
Thu, 27 Oct 2011 12:49:48 +0000 (14:49 +0200)
committerDavid Goulet <david.goulet@polymtl.ca>
Wed, 2 Nov 2011 19:49:33 +0000 (15:49 -0400)
Signed-off-by: David Goulet <david.goulet@polymtl.ca>
21 files changed:
configure.ac
hashtable/rculfhash.c
hashtable/rculfhash.h
include/lttng-sessiond-comm.h
include/lttng-share.h
liblttng-sessiond-comm/lttng-sessiond-comm.c
ltt-sessiond/Makefile.am
ltt-sessiond/channel.c
ltt-sessiond/ltt-sessiond.h
ltt-sessiond/main.c
ltt-sessiond/session.c
ltt-sessiond/session.h
ltt-sessiond/trace-ust.c
ltt-sessiond/trace-ust.h
ltt-sessiond/ust-app.c
ltt-sessiond/ust-app.h
ltt-sessiond/ust-ctl.c [new file with mode: 0644]
ltt-sessiond/ust-ctl.h
lttng/commands/enable_channels.c
tests/Makefile.am
tests/test_sessions.c

index 052c5a33d902cd121f4b5cb88f4dcb118eefcfb1..0ac64700614204c7ea21efe51405343c6017119a 100644 (file)
@@ -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)],
index 2bb26e55034d69f7e7a694802a31856a5d7cfd87..c79bafd42cddbbc21415b058d8a793d7fa6fb251 100644 (file)
 #include <stdint.h>
 #include <string.h>
 
-#include <urcu/config.h>
 #include <urcu.h>
 #include <urcu-call-rcu.h>
 #include <urcu/arch.h>
 #include <urcu/uatomic.h>
 #include <urcu/compiler.h>
-#include "rculfhash.h"
 #include <stdio.h>
 #include <pthread.h>
 
+#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;
index 860ef3d1c2d05e3516ec4a8849c9d47b39f1371f..0a739ee86f7d11b1e9caa4b8bbb9091dbc0ff1b9 100644 (file)
@@ -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);
 
 /*
index 1b2c4b88e85d99515ebc40a5303e629d64a2b6a7..f30bf6673d599610b818adcd6c2c4291f7a8dd6b 100644 (file)
@@ -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 */
index 399de4f6e6f610ee63da83ed72050213dec8deb7..cac819d63467377fbe9bf39f8449595e474249b9 100644 (file)
@@ -23,6 +23,9 @@
 
 #include <lttng/lttng.h>
 
+/* 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 */
index 01851de5f3612cd158deaa433fceb90d0fda0781..9cea3fedea89c3625a225ed2f431fc851d652629 100644 (file)
@@ -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",
index f9301896e5df0f50fd95bd83969cb154989b49aa..f3723016ea083a731e4b79bfd535cc07eeb44789 100644 (file)
@@ -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
index b61e1fb6792b8d1eaa5c1ac79a8f5ce94a7a6420..3870af4beb5ae407fd1d2ee527f41cd54cf2df03 100644 (file)
@@ -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;
index c28572a86ab968c4dcfd6a8aa5924d3a68cf04fa..63de2e12076ac3509f049062b2d7bfd60786d9b1 100644 (file)
@@ -20,6 +20,7 @@
 #define _LTT_SESSIOND_H
 
 #define _LGPL_SOURCE
+#include <urcu.h>
 #include <urcu/wfqueue.h>
 
 #include "ust-app.h"
index c288afbb049f4a078f049756fce9c20094f1d705..081b0c855efa2172f0a7a0dfa5c9eb3bd1dd10f1 100644 (file)
@@ -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:
index b35157bae40c13a381f2b54dea44c825101075bb..c7ce843d71669f3b40609293341dbf8f665a73a1 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <urcu.h>
 
 #include <lttng-sessiond-comm.h>
 #include <lttngerr.h>
 
+#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);
index 7db95ed1d6360b477030d26209c5b518c4d90cf7..41883c60959029dc3f466e14b4e792fcfa627faa 100644 (file)
@@ -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 */
index c2978894ede66ff5ff6b80c764b8ebd54422a7aa..b1066072bf711bbffff2bf87a98bab3b1c359d48 100644 (file)
 #include <lttngerr.h>
 #include <lttng-share.h>
 
+#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();
 }
index e2901a7fa346262eb72db2c96c854ea32f332b36..2b133e8c473239088eacddb637982266447a4df9 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <config.h>
 #include <limits.h>
+#include <urcu.h>
 #include <urcu/list.h>
 #include <lttng/lttng.h>
 
 #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)
index ea062557e56cf60ee471f62921bcdd1082a2e1ee..c8dd848b1dfafe49778ecdeba6c3dcd0b5c81ed5 100644 (file)
 
 #include <lttngerr.h>
 
+#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(&lta->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(&lta->list);
-       /* Sanity check */
-       if (ust_app_list.count > 0) {
-               ust_app_list.count--;
-       }
+       rcu_read_lock();
 
-       cds_list_for_each_entry(chan, &lta->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(&lta->channels.head);
+       hashtable_node_init(&lta->node, (void *)((unsigned long)lta->key.pid),
+                       sizeof(void *));
+       lta->channels = hashtable_new_str(0);
+
+       /* Set sock key map */
+       hashtable_node_init(&lta->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, &lta->node);
+       hashtable_add_unique(ust_app_sock_key_map, &lta->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);
 }
index cc08a4c338b1da77f7f619d1af3ba0b822d5d08a..91be503204c1c6b9e421cd5c90011a874f6234c0 100644 (file)
@@ -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 <stdint.h>
 #include <urcu/list.h>
@@ -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 (file)
index 0000000..6f73bfc
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <lttng-sessiond-comm.h>
+#include <lttngerr.h>
+
+#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;
+}
index a6d4e773ee14ffb8b60e4065566bc6022df935a5..0ceccff454628cf87bcf6c0d0dc7ea971d2d78d4 100644 (file)
 
 #ifdef CONFIG_LTTNG_TOOLS_HAVE_UST
 
-
 #else
 
-
 #endif
 
 #endif /* _LTT_UST_CTL_H */
index c5887d07bf17ac10688e3dbb3b74bc6d57564ddc..715552b5b706a811a853028cfa9953db31e6c9b8 100644 (file)
@@ -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;
index 5ed904b477b59345c7a7833c5abe93017c57820d..e0b3697308e7e844f9defc39c2b6355c7a801a78 100644 (file)
@@ -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
index 3e9bbbbb5ae64307d1c020beee2e529593c48acf..461a33c1e23a852255ff71a65bfc757a45abcf38 100644 (file)
@@ -26,7 +26,8 @@
 #include <time.h>
 
 #include <lttng-sessiond-comm.h>
-#include "ltt-sessiond/session.h"
+
+#include <ltt-sessiond/session.h>
 #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);
This page took 0.051958 seconds and 4 git commands to generate.