Support per UID buffers
authorDavid Goulet <dgoulet@efficios.com>
Thu, 7 Mar 2013 20:39:10 +0000 (15:39 -0500)
committerDavid Goulet <dgoulet@efficios.com>
Thu, 21 Mar 2013 16:29:43 +0000 (12:29 -0400)
This is a rather large commit. It adds the support for per UID buffers
for the user space tracer.

The --buffers-uid option is added to the lttng enable-channel command
which will set the session to use per UID buffers. So, all other channel
in that session MUST be set with the same buffer type or else an error
will be returned. For instance, here is an invalid use case:

$ lttng create
$ lttng enable-channel -u --buffers-uid chan1
$ lttng enable-channel -u chan2

The default is per PID (--buffers-pid). With no buffer type option, the
per PID is used for the UST tracer and global buffers for the kernel
being the only supported type for it (--buffers-global).

The tracing directory path are also changed to support this. For per UID
buffers, the path is now:

~/lttng-traces/ust/uid/1000/64-bit/*

For per PID buffers:

~/lttng-traces/<session_name>-<date>-<time>/ust/pid/ \
<app-name>-<pid>-<date>-<time>/

So basically, for UID, traces are stored per UID/ABI and for PID is
simply stored with the app name and pid. The kernel traces are untouched
and are still in kernel/.

Tests are also added for per UID buffers.

Acked-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: David Goulet <dgoulet@efficios.com>
55 files changed:
configure.ac
doc/man/lttng.1
include/lttng/lttng-error.h
include/lttng/lttng.h
src/bin/lttng-sessiond/Makefile.am
src/bin/lttng-sessiond/buffer-registry.c [new file with mode: 0644]
src/bin/lttng-sessiond/buffer-registry.h [new file with mode: 0644]
src/bin/lttng-sessiond/channel.c
src/bin/lttng-sessiond/channel.h
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/cmd.h
src/bin/lttng-sessiond/consumer.c
src/bin/lttng-sessiond/consumer.h
src/bin/lttng-sessiond/event.c
src/bin/lttng-sessiond/event.h
src/bin/lttng-sessiond/kernel-consumer.c
src/bin/lttng-sessiond/lttng-ust-abi.h
src/bin/lttng-sessiond/lttng-ust-ctl.h
src/bin/lttng-sessiond/lttng-ust-error.h
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/session.h
src/bin/lttng-sessiond/trace-ust.c
src/bin/lttng-sessiond/trace-ust.h
src/bin/lttng-sessiond/ust-app.c
src/bin/lttng-sessiond/ust-app.h
src/bin/lttng-sessiond/ust-consumer.c
src/bin/lttng-sessiond/ust-consumer.h
src/bin/lttng-sessiond/ust-ctl.h
src/bin/lttng-sessiond/ust-metadata.c
src/bin/lttng-sessiond/ust-registry.c
src/bin/lttng-sessiond/ust-registry.h
src/bin/lttng/commands/enable_channels.c
src/bin/lttng/commands/enable_events.c
src/common/consumer.c
src/common/consumer.h
src/common/defaults.h
src/common/error.c
src/common/hashtable/hashtable.c
src/common/hashtable/hashtable.h
src/common/sessiond-comm/sessiond-comm.h
src/common/ust-consumer/ust-consumer.c
tests/regression/tools/streaming/test_kernel
tests/regression/tools/streaming/test_ust
tests/regression/ust/buffers-uid/Makefile.am [new file with mode: 0644]
tests/regression/ust/buffers-uid/gen-nevents.c [new file with mode: 0644]
tests/regression/ust/buffers-uid/test_buffers_uid [new file with mode: 0755]
tests/regression/ust/buffers-uid/tp.c [new file with mode: 0644]
tests/regression/ust/buffers-uid/ust_gen_nevents.h [new file with mode: 0644]
tests/regression/ust/nprocesses/test_nprocesses
tests/regression/ust/overlap/test_overlap
tests/regression/ust/run.sh
tests/unit/Makefile.am
tests/unit/test_kernel_data.c
tests/unit/test_session.c
tests/unit/test_ust_data.c

index 7e35c06458fc081340b448c85d75b9c18bc94bae..b9ee7ec3f5703bec8be408277cea1f085d5aeeeb 100644 (file)
@@ -320,6 +320,7 @@ AC_CONFIG_FILES([
        tests/regression/ust/high-throughput/Makefile
        tests/regression/ust/low-throughput/Makefile
        tests/regression/ust/before-after/Makefile
+       tests/regression/ust/buffers-uid/Makefile
        tests/regression/ust/multi-session/Makefile
        tests/regression/ust/overlap/Makefile
        tests/regression/ust/overlap/demo/Makefile
index 814e1c64fad9bb62fa4b24088f8ba2baf20a8eb9..0de06d7cbec62ede56a73a24b40bf452ae486269 100644 (file)
@@ -301,6 +301,10 @@ To enable event, you must first enable a channel which contains event(s).
 
 If \fB\-s, \-\-session\fP is omitted, the session name is taken from the .lttngrc
 file.
+
+It is important to note that if a certain type of buffers is used, the session
+will be set with that type and all other subsequent channel need to have the
+same type.
 .fi
 
 .B OPTIONS:
@@ -333,6 +337,13 @@ file.
         Read timer interval in usec (default: 200)
 \-\-output TYPE
         Channel output type. Possible values: mmap, splice
+\-\-buffers-uid
+        Use per UID buffer (\-u only). Buffers are shared between applications
+        that have the same UID.
+\-\-buffers-pid
+        Use per PID buffer (\-u only). Each application has its own buffers.
+\-\-buffers-global
+        Use shared buffer for the whole system (\-k only)
 .fi
 
 .IP
index 2bcc2c365436efda24e18440c111a7458fbb2a20..4e9b37f6c738eb86569fd500957c9909ee0489b8 100644 (file)
@@ -52,9 +52,9 @@ enum lttng_error_code {
        LTTNG_ERR_NO_SESSIOND            = 19,  /* No session daemon available */
        LTTNG_ERR_SET_URL                = 20,  /* Error setting URL */
        LTTNG_ERR_URL_EXIST              = 21,  /* URL already exists. */
-       /* 22 */
+       LTTNG_ERR_BUFFER_NOT_SUPPORTED   = 22,  /* Buffer type not supported. */
        LTTNG_ERR_SESS_NOT_FOUND         = 23,  /* Session by name not found */
-       /* 24 */
+       LTTNG_ERR_BUFFER_TYPE_MISMATCH   = 24,  /* Buffer type mismatched. */
        LTTNG_ERR_FATAL                  = 25,  /* Fatal error */
        /* 26 */
        LTTNG_ERR_SELECT_SESS            = 27,  /* Must select a session */
index 6077047642fe628530a1b7803f40b69dcb9be3f0..8566deabe61d91dea58337e94bb74f5075c970e2 100644 (file)
@@ -142,13 +142,21 @@ enum lttng_health_component {
        LTTNG_HEALTH_ALL,
 };
 
+/* Buffer type for a specific domain. */
+enum lttng_buffer_type {
+       LTTNG_BUFFER_PER_PID,   /* Only supported by UST being the default. */
+       LTTNG_BUFFER_PER_UID,   /* Only supported by UST. */
+       LTTNG_BUFFER_GLOBAL,    /* Only supported by the Kernel. */
+};
+
 /*
  * The structures should be initialized to zero before use.
  */
-#define LTTNG_DOMAIN_PADDING1              16
+#define LTTNG_DOMAIN_PADDING1              12
 #define LTTNG_DOMAIN_PADDING2              LTTNG_SYMBOL_NAME_LEN + 32
 struct lttng_domain {
        enum lttng_domain_type type;
+       enum lttng_buffer_type buf_type;
        char padding[LTTNG_DOMAIN_PADDING1];
 
        union {
index 26a2d13a0cac2be8fb7438297ceac88434e33684..244bc70ebfd0a2a5d61a3777fe75afed2f968fcc 100644 (file)
@@ -10,6 +10,7 @@ lttng_sessiond_SOURCES = utils.c utils.h \
                        trace-kernel.c trace-kernel.h \
                        kernel.c kernel.h \
                        ust-ctl.h ust-app.h trace-ust.h ust-thread.h \
+                       ust-registry.h \
                        context.c context.h \
                        channel.c channel.h \
                        event.c event.h \
@@ -23,10 +24,11 @@ lttng_sessiond_SOURCES = utils.c utils.h \
                        consumer.h \
                        health.c health.h \
                        cmd.c cmd.h \
+                       buffer-registry.c buffer-registry.h \
                        testpoint.h
 
 if HAVE_LIBLTTNG_UST_CTL
-lttng_sessiond_SOURCES += trace-ust.c ust-registry.c ust-registry.h ust-app.c \
+lttng_sessiond_SOURCES += trace-ust.c ust-registry.c ust-app.c \
                        ust-consumer.c ust-consumer.h ust-thread.c \
                        ust-metadata.c ust-clock.h
 endif
diff --git a/src/bin/lttng-sessiond/buffer-registry.c b/src/bin/lttng-sessiond/buffer-registry.c
new file mode 100644 (file)
index 0000000..765294f
--- /dev/null
@@ -0,0 +1,686 @@
+/*
+ * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include <inttypes.h>
+
+#include <common/common.h>
+#include <common/hashtable/utils.h>
+
+#include "buffer-registry.h"
+#include "fd-limit.h"
+#include "ust-consumer.h"
+#include "ust-ctl.h"
+
+/*
+ * Set in main.c during initialization process of the daemon. This contains
+ * buffer_reg_uid object which are global registry for per UID buffer. Object
+ * are indexed by session id and matched by the triplet
+ * <session_id/bits_per_long/uid>.
+ */
+static struct lttng_ht *buffer_registry_uid;
+
+/*
+ * Initialized at the daemon start. This contains buffer_reg_pid object and
+ * indexed by session id.
+ */
+static struct lttng_ht *buffer_registry_pid;
+
+/*
+ * Match function for the per UID registry hash table. It matches a registry
+ * uid object with the triplet <session_id/abi/uid>.
+ */
+static int ht_match_reg_uid(struct cds_lfht_node *node, const void *_key)
+{
+       struct buffer_reg_uid *reg;
+       const struct buffer_reg_uid *key;
+
+       assert(node);
+       assert(_key);
+
+       reg = caa_container_of(node, struct buffer_reg_uid, node.node);
+       assert(reg);
+       key = _key;
+
+       if (key->session_id != reg->session_id ||
+                       key->bits_per_long != reg->bits_per_long ||
+                       key->uid != reg->uid) {
+               goto no_match;
+       }
+
+       /* Match */
+       return 1;
+no_match:
+       return 0;
+}
+
+/*
+ * Hash function for the per UID registry hash table. This XOR the triplet
+ * together.
+ */
+static unsigned long ht_hash_reg_uid(void *_key, unsigned long seed)
+{
+       uint64_t xored_key;
+       struct buffer_reg_uid *key = _key;
+
+       assert(key);
+
+       xored_key = (uint64_t)(key->session_id ^ key->bits_per_long ^ key->uid);
+       return hash_key_u64(&xored_key, seed);
+}
+
+/*
+ * Initialize global buffer per UID registry. Should only be called ONCE!.
+ */
+void buffer_reg_init_uid_registry(void)
+{
+       /* Should be called once. */
+       assert(!buffer_registry_uid);
+       buffer_registry_uid = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
+       assert(buffer_registry_uid);
+       buffer_registry_uid->match_fct = ht_match_reg_uid;
+       buffer_registry_uid->hash_fct = ht_hash_reg_uid;
+
+       DBG3("Global buffer per UID registry initialized");
+}
+
+/*
+ * Allocate and initialize object. Set regp with the object pointer.
+ *
+ * Return 0 on success else a negative value and regp is untouched.
+ */
+int buffer_reg_uid_create(int session_id, uint32_t bits_per_long, uid_t uid,
+               enum lttng_domain_type domain, struct buffer_reg_uid **regp)
+{
+       int ret = 0;
+       struct buffer_reg_uid *reg = NULL;
+
+       assert(regp);
+
+       reg = zmalloc(sizeof(*reg));
+       if (!reg) {
+               PERROR("zmalloc buffer registry uid");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       reg->registry = zmalloc(sizeof(struct buffer_reg_session));
+       if (!reg) {
+               PERROR("zmalloc buffer registry uid session");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       reg->session_id = session_id;
+       reg->bits_per_long = bits_per_long;
+       reg->uid = uid;
+       reg->domain = domain;
+
+       reg->registry->channels = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
+       if (!reg->registry->channels) {
+               ret = -ENOMEM;
+               goto error_session;
+       }
+
+       cds_lfht_node_init(&reg->node.node);
+       *regp = reg;
+
+       DBG3("Buffer registry per UID created id: %d, ABI: %u, uid: %d, domain: %d",
+                       session_id, bits_per_long, uid, domain);
+
+       return 0;
+
+error_session:
+       free(reg->registry);
+error:
+       free(reg);
+       return ret;
+}
+
+/*
+ * Add a buffer registry per UID object to the global registry.
+ */
+void buffer_reg_uid_add(struct buffer_reg_uid *reg)
+{
+       struct cds_lfht_node *nodep;
+       struct lttng_ht *ht = buffer_registry_uid;
+
+       assert(reg);
+
+       DBG3("Buffer registry per UID adding to global registry with id: %d",
+                       reg->session_id);
+
+       rcu_read_lock();
+       nodep = cds_lfht_add_unique(ht->ht, ht->hash_fct(reg, lttng_ht_seed),
+                       ht->match_fct, reg, &reg->node.node);
+       assert(nodep == &reg->node.node);
+       rcu_read_unlock();
+}
+
+/*
+ * Find a buffer registry per UID object with given params. RCU read side lock
+ * MUST be acquired before calling this and hold on to protect the object.
+ *
+ * Return the object pointer or NULL on error.
+ */
+struct buffer_reg_uid *buffer_reg_uid_find(int session_id,
+               uint32_t bits_per_long, uid_t uid)
+{
+       struct lttng_ht_node_u64 *node;
+       struct lttng_ht_iter iter;
+       struct buffer_reg_uid *reg = NULL, key;
+       struct lttng_ht *ht = buffer_registry_uid;
+
+       /* Setup key we are looking for. */
+       key.session_id = session_id;
+       key.bits_per_long = bits_per_long;
+       key.uid = uid;
+
+       DBG3("Buffer registry per UID find id: %d, ABI: %u, uid: %d",
+                       session_id, bits_per_long, uid);
+
+       /* Custom lookup function since it's a different key. */
+       cds_lfht_lookup(ht->ht, ht->hash_fct(&key, lttng_ht_seed), ht->match_fct,
+                       &key, &iter.iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
+       if (!node) {
+               goto end;
+       }
+       reg = caa_container_of(node, struct buffer_reg_uid, node);
+
+end:
+       return reg;
+}
+
+/*
+ * Initialize global buffer per PID registry. Should only be called ONCE!.
+ */
+void buffer_reg_init_pid_registry(void)
+{
+       /* Should be called once. */
+       assert(!buffer_registry_pid);
+       buffer_registry_pid = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+       assert(buffer_registry_pid);
+
+       DBG3("Global buffer per PID registry initialized");
+}
+
+/*
+ * Allocate and initialize object. Set regp with the object pointer.
+ *
+ * Return 0 on success else a negative value and regp is untouched.
+ */
+int buffer_reg_pid_create(int session_id, struct buffer_reg_pid **regp)
+{
+       int ret = 0;
+       struct buffer_reg_pid *reg = NULL;
+
+       assert(regp);
+
+       reg = zmalloc(sizeof(*reg));
+       if (!reg) {
+               PERROR("zmalloc buffer registry pid");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       reg->registry = zmalloc(sizeof(struct buffer_reg_session));
+       if (!reg) {
+               PERROR("zmalloc buffer registry pid session");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       /* A cast is done here so we can use the session ID as a u64 ht node. */
+       reg->session_id = session_id;
+
+       reg->registry->channels = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
+       if (!reg->registry->channels) {
+               ret = -ENOMEM;
+               goto error_session;
+       }
+
+       lttng_ht_node_init_ulong(&reg->node, reg->session_id);
+       *regp = reg;
+
+       DBG3("Buffer registry per PID created with session id: %d", session_id);
+
+       return 0;
+
+error_session:
+       free(reg->registry);
+error:
+       free(reg);
+       return ret;
+}
+
+/*
+ * Add a buffer registry per PID object to the global registry.
+ */
+void buffer_reg_pid_add(struct buffer_reg_pid *reg)
+{
+       assert(reg);
+
+       DBG3("Buffer registry per PID adding to global registry with id: %d",
+                       reg->session_id);
+
+       rcu_read_lock();
+       lttng_ht_add_unique_ulong(buffer_registry_pid, &reg->node);
+       rcu_read_unlock();
+}
+
+/*
+ * Find a buffer registry per PID object with given params. RCU read side lock
+ * MUST be acquired before calling this and hold on to protect the object.
+ *
+ * Return the object pointer or NULL on error.
+ */
+struct buffer_reg_pid *buffer_reg_pid_find(int session_id)
+{
+       struct lttng_ht_node_ulong *node;
+       struct lttng_ht_iter iter;
+       struct buffer_reg_pid *reg = NULL;
+       struct lttng_ht *ht = buffer_registry_pid;
+
+       DBG3("Buffer registry per PID find id: %d", session_id);
+
+       lttng_ht_lookup(ht, (void *)((unsigned long) session_id), &iter);
+       node = lttng_ht_iter_get_node_ulong(&iter);
+       if (!node) {
+               goto end;
+       }
+       reg = caa_container_of(node, struct buffer_reg_pid, node);
+
+end:
+       return reg;
+}
+
+/*
+ * Allocate and initialize a buffer registry channel with the given key. Set
+ * regp with the object pointer.
+ *
+ * Return 0 on success or else a negative value keeping regp untouched.
+ */
+int buffer_reg_channel_create(uint64_t key, struct buffer_reg_channel **regp)
+{
+       struct buffer_reg_channel *reg;
+
+       assert(regp);
+
+       DBG3("Buffer registry channel create with key: %" PRIu64, key);
+
+       reg = zmalloc(sizeof(*reg));
+       if (!reg) {
+               PERROR("zmalloc buffer registry channel");
+               return -ENOMEM;
+       }
+
+       reg->key = key;
+       CDS_INIT_LIST_HEAD(&reg->streams);
+       pthread_mutex_init(&reg->stream_list_lock, NULL);
+
+       lttng_ht_node_init_u64(&reg->node, key);
+       *regp = reg;
+
+       return 0;
+}
+
+/*
+ * Allocate and initialize a buffer registry stream. Set regp with the object
+ * pointer.
+ *
+ * Return 0 on success or else a negative value keeping regp untouched.
+ */
+int buffer_reg_stream_create(struct buffer_reg_stream **regp)
+{
+       struct buffer_reg_stream *reg;
+
+       assert(regp);
+
+       DBG3("Buffer registry creating stream");
+
+       reg = zmalloc(sizeof(*reg));
+       if (!reg) {
+               PERROR("zmalloc buffer registry stream");
+               return -ENOMEM;
+       }
+
+       *regp = reg;
+
+       return 0;
+}
+
+/*
+ * Add stream to the list in the channel.
+ */
+void buffer_reg_stream_add(struct buffer_reg_stream *stream,
+               struct buffer_reg_channel *channel)
+{
+       assert(stream);
+       assert(channel);
+
+       pthread_mutex_lock(&channel->stream_list_lock);
+       cds_list_add_tail(&stream->lnode, &channel->streams);
+       pthread_mutex_unlock(&channel->stream_list_lock);
+}
+
+/*
+ * Add a buffer registry channel object to the given session.
+ */
+void buffer_reg_channel_add(struct buffer_reg_session *session,
+               struct buffer_reg_channel *channel)
+{
+       assert(session);
+       assert(channel);
+
+       rcu_read_lock();
+       lttng_ht_add_unique_u64(session->channels, &channel->node);
+       rcu_read_unlock();
+}
+
+/*
+ * Find a buffer registry channel object with the given key. RCU read side lock
+ * MUST be acquired and hold on until the object reference is not needed
+ * anymore.
+ *
+ * Return the object pointer or NULL on error.
+ */
+struct buffer_reg_channel *buffer_reg_channel_find(uint64_t key,
+               struct buffer_reg_uid *reg)
+{
+       struct lttng_ht_node_u64 *node;
+       struct lttng_ht_iter iter;
+       struct buffer_reg_channel *chan = NULL;
+       struct lttng_ht *ht;
+
+       assert(reg);
+
+       switch (reg->domain) {
+       case LTTNG_DOMAIN_UST:
+               ht = reg->registry->channels;
+               break;
+       default:
+               assert(0);
+               goto end;
+       }
+
+       lttng_ht_lookup(ht, &key, &iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
+       if (!node) {
+               goto end;
+       }
+       chan = caa_container_of(node, struct buffer_reg_channel, node);
+
+end:
+       return chan;
+}
+
+/*
+ * Destroy a buffer registry stream with the given domain.
+ */
+void buffer_reg_stream_destroy(struct buffer_reg_stream *regp,
+               enum lttng_domain_type domain)
+{
+       if (!regp) {
+               return;
+       }
+
+       DBG3("Buffer registry stream destroy with handle %d",
+                       regp->obj.ust->handle);
+
+       switch (domain) {
+       case LTTNG_DOMAIN_UST:
+       {
+               int ret;
+
+               ret = ust_ctl_release_object(-1, regp->obj.ust);
+               if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       ERR("Buffer reg stream release obj handle %d failed with ret %d",
+                                       regp->obj.ust->handle, ret);
+               }
+               free(regp->obj.ust);
+               lttng_fd_put(LTTNG_FD_APPS, 2);
+               break;
+       }
+       default:
+               assert(0);
+       }
+
+       free(regp);
+       return;
+}
+
+/*
+ * Remove buffer registry channel object from the session hash table. RCU read
+ * side lock MUST be acquired before calling this.
+ */
+void buffer_reg_channel_remove(struct buffer_reg_session *session,
+               struct buffer_reg_channel *regp)
+{
+       int ret;
+       struct lttng_ht_iter iter;
+
+       assert(session);
+       assert(regp);
+
+       iter.iter.node = &regp->node.node;
+       ret = lttng_ht_del(session->channels, &iter);
+       assert(!ret);
+}
+
+/*
+ * Destroy a buffer registry channel with the given domain.
+ */
+void buffer_reg_channel_destroy(struct buffer_reg_channel *regp,
+               enum lttng_domain_type domain)
+{
+       if (!regp) {
+               return;
+       }
+
+       DBG3("Buffer registry channel destroy with key %" PRIu32 " and handle %d",
+                       regp->key, regp->obj.ust->handle);
+
+       switch (domain) {
+       case LTTNG_DOMAIN_UST:
+       {
+               int ret;
+               struct buffer_reg_stream *sreg, *stmp;
+               /* Wipe stream */
+               cds_list_for_each_entry_safe(sreg, stmp, &regp->streams, lnode) {
+                       cds_list_del(&sreg->lnode);
+                       buffer_reg_stream_destroy(sreg, domain);
+               }
+
+               ret = ust_ctl_release_object(-1, regp->obj.ust);
+               if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       ERR("Buffer reg channel release obj handle %d failed with ret %d",
+                                       regp->obj.ust->handle, ret);
+               }
+               free(regp->obj.ust);
+               lttng_fd_put(LTTNG_FD_APPS, 1);
+               break;
+       }
+       default:
+               assert(0);
+       }
+
+       free(regp);
+       return;
+}
+
+/*
+ * Destroy a buffer registry session with the given domain.
+ */
+void buffer_reg_session_destroy(struct buffer_reg_session *regp,
+               enum lttng_domain_type domain)
+{
+       int ret;
+       struct lttng_ht_iter iter;
+       struct buffer_reg_channel *reg_chan;
+
+       DBG3("Buffer registry session destroy");
+
+       /* Destroy all channels. */
+       rcu_read_lock();
+       cds_lfht_for_each_entry(regp->channels->ht, &iter.iter, reg_chan,
+                       node.node) {
+               ret = lttng_ht_del(regp->channels, &iter);
+               assert(!ret);
+               buffer_reg_channel_destroy(reg_chan, domain);
+       }
+       lttng_ht_destroy(regp->channels);
+       rcu_read_unlock();
+
+       switch (domain) {
+       case LTTNG_DOMAIN_UST:
+               ust_registry_session_destroy(regp->reg.ust);
+               free(regp->reg.ust);
+               break;
+       default:
+               assert(0);
+       }
+
+       free(regp);
+       return;
+}
+
+/*
+ * Remove buffer registry UID object from the global hash table. RCU read side
+ * lock MUST be acquired before calling this.
+ */
+void buffer_reg_uid_remove(struct buffer_reg_uid *regp)
+{
+       int ret;
+       struct lttng_ht_iter iter;
+
+       assert(regp);
+
+       iter.iter.node = &regp->node.node;
+       ret = lttng_ht_del(buffer_registry_uid, &iter);
+       assert(!ret);
+}
+
+static void rcu_free_buffer_reg_uid(struct rcu_head *head)
+{
+       struct lttng_ht_node_u64 *node =
+               caa_container_of(head, struct lttng_ht_node_u64, head);
+       struct buffer_reg_uid *reg =
+               caa_container_of(node, struct buffer_reg_uid, node);
+
+       buffer_reg_session_destroy(reg->registry, reg->domain);
+       free(reg);
+}
+
+static void rcu_free_buffer_reg_pid(struct rcu_head *head)
+{
+       struct lttng_ht_node_ulong *node =
+               caa_container_of(head, struct lttng_ht_node_ulong, head);
+       struct buffer_reg_pid *reg =
+               caa_container_of(node, struct buffer_reg_pid, node);
+
+       buffer_reg_session_destroy(reg->registry, LTTNG_DOMAIN_UST);
+       free(reg);
+}
+
+/*
+ * Destroy buffer registry per UID. The given pointer is NOT removed from any
+ * list or hash table. Use buffer_reg_pid_remove() before calling this function
+ * for the case that the object is in the global hash table.
+ */
+void buffer_reg_uid_destroy(struct buffer_reg_uid *regp,
+               struct consumer_output *consumer)
+{
+       struct consumer_socket *socket;
+
+       if (!regp) {
+               return;
+       }
+
+       DBG3("Buffer registry per UID destroy with id: %d, ABI: %u, uid: %d",
+                       regp->session_id, regp->bits_per_long, regp->uid);
+
+       if (!consumer) {
+               goto destroy;
+       }
+
+       /* Get the right socket from the consumer object. */
+       socket = consumer_find_socket_by_bitness(regp->bits_per_long,
+                       consumer);
+       if (!socket) {
+               goto destroy;
+       }
+
+       switch (regp->domain) {
+       case LTTNG_DOMAIN_UST:
+               if (regp->registry->reg.ust->metadata_key) {
+                       /* Return value does not matter. This call will print errors. */
+                       (void) consumer_close_metadata(socket,
+                                       regp->registry->reg.ust->metadata_key);
+               }
+               break;
+       default:
+               assert(0);
+               return;
+       }
+
+destroy:
+       call_rcu(&regp->node.head, rcu_free_buffer_reg_uid);
+}
+
+/*
+ * Remove buffer registry UID object from the global hash table. RCU read side
+ * lock MUST be acquired before calling this.
+ */
+void buffer_reg_pid_remove(struct buffer_reg_pid *regp)
+{
+       int ret;
+       struct lttng_ht_iter iter;
+
+       assert(regp);
+
+       iter.iter.node = &regp->node.node;
+       ret = lttng_ht_del(buffer_registry_pid, &iter);
+       assert(!ret);
+}
+
+/*
+ * Destroy buffer registry per PID. The pointer is NOT removed from the global
+ * hash table. Call buffer_reg_pid_remove() before that if the object was
+ * previously added to the global hash table.
+ */
+void buffer_reg_pid_destroy(struct buffer_reg_pid *regp)
+{
+       if (!regp) {
+               return;
+       }
+
+       DBG3("Buffer registry per PID destroy with id: %d", regp->session_id);
+
+       /* This registry is only used by UST. */
+       call_rcu(&regp->node.head, rcu_free_buffer_reg_pid);
+}
+
+/*
+ * Destroy per PID and UID registry hash table.
+ */
+void buffer_reg_destroy_registries(void)
+{
+       DBG3("Buffer registry destroy all registry");
+       lttng_ht_destroy(buffer_registry_uid);
+       lttng_ht_destroy(buffer_registry_pid);
+}
diff --git a/src/bin/lttng-sessiond/buffer-registry.h b/src/bin/lttng-sessiond/buffer-registry.h
new file mode 100644 (file)
index 0000000..4b19f71
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef LTTNG_BUFFER_REGISTRY_H
+#define LTTNG_BUFFER_REGISTRY_H
+
+#include <stdint.h>
+#include <lttng/ust-ctl.h>
+#include <urcu/list.h>
+
+#include <lttng/lttng.h>
+#include <common/hashtable/hashtable.h>
+
+#include "consumer.h"
+#include "ust-registry.h"
+
+struct buffer_reg_stream {
+       struct cds_list_head lnode;
+       union {
+               /* Original object data that MUST be copied over. */
+               struct lttng_ust_object_data *ust;
+       } obj;
+};
+
+struct buffer_reg_channel {
+       /* This key is the same as a tracing channel key. */
+       uint32_t key;
+       /* Key of the channel on the consumer side. */
+       uint64_t consumer_key;
+       /* Stream registry object of this channel registry. */
+       struct cds_list_head streams;
+       /* Used to ensure mutual exclusion to the stream's list. */
+       pthread_mutex_t stream_list_lock;
+       /* Node for hash table usage. */
+       struct lttng_ht_node_u64 node;
+       union {
+               /* Original object data that MUST be copied over. */
+               struct lttng_ust_object_data *ust;
+       } obj;
+};
+
+struct buffer_reg_session {
+       /* Registry per domain. */
+       union {
+               struct ust_registry_session *ust;
+       } reg;
+
+       /* Contains buffer registry channel indexed by tracing channel key. */
+       struct lttng_ht *channels;
+};
+
+/*
+ * Registry object for per UID buffers.
+ */
+struct buffer_reg_uid {
+       /*
+        * Keys to match this object in a hash table. The following three variables
+        * identify a unique per UID buffer registry.
+        */
+       int session_id;         /* Unique tracing session id. */
+       int bits_per_long;      /* ABI */
+       uid_t uid;                      /* Owner. */
+
+       enum lttng_domain_type domain;
+       struct buffer_reg_session *registry;
+
+       /* Indexed by session id. */
+       struct lttng_ht_node_u64 node;
+       /* Node of a linked list used to teardown object at a destroy session. */
+       struct cds_list_head lnode;
+};
+
+/*
+ * Registry object for per PID buffers.
+ */
+struct buffer_reg_pid {
+       int session_id;
+
+       struct buffer_reg_session *registry;
+
+       /* Indexed by session id. */
+       struct lttng_ht_node_ulong node;
+};
+
+/* Buffer registry per UID. */
+void buffer_reg_init_uid_registry(void);
+int buffer_reg_uid_create(int session_id, uint32_t bits_per_long, uid_t uid,
+               enum lttng_domain_type domain, struct buffer_reg_uid **regp);
+void buffer_reg_uid_add(struct buffer_reg_uid *reg);
+struct buffer_reg_uid *buffer_reg_uid_find(int session_id,
+               uint32_t bits_per_long, uid_t uid);
+void buffer_reg_uid_remove(struct buffer_reg_uid *regp);
+void buffer_reg_uid_destroy(struct buffer_reg_uid *regp,
+               struct consumer_output *consumer);
+
+/* Buffer registry per PID. */
+void buffer_reg_init_pid_registry(void);
+int buffer_reg_pid_create(int session_id, struct buffer_reg_pid **regp);
+void buffer_reg_pid_add(struct buffer_reg_pid *reg);
+struct buffer_reg_pid *buffer_reg_pid_find(int session_id);
+void buffer_reg_pid_remove(struct buffer_reg_pid *regp);
+void buffer_reg_pid_destroy(struct buffer_reg_pid *regp);
+
+/* Channel */
+int buffer_reg_channel_create(uint64_t key, struct buffer_reg_channel **regp);
+void buffer_reg_channel_add(struct buffer_reg_session *session,
+               struct buffer_reg_channel *channel);
+struct buffer_reg_channel *buffer_reg_channel_find(uint64_t key,
+               struct buffer_reg_uid *reg);
+void buffer_reg_channel_remove(struct buffer_reg_session *session,
+               struct buffer_reg_channel *regp);
+void buffer_reg_channel_destroy(struct buffer_reg_channel *regp,
+               enum lttng_domain_type domain);
+
+/* Stream */
+int buffer_reg_stream_create(struct buffer_reg_stream **regp);
+void buffer_reg_stream_add(struct buffer_reg_stream *stream,
+               struct buffer_reg_channel *channel);
+void buffer_reg_stream_destroy(struct buffer_reg_stream *regp,
+               enum lttng_domain_type domain);
+
+/* Session */
+void buffer_reg_session_destroy(struct buffer_reg_session *regp,
+               enum lttng_domain_type domain);
+
+/* Global registry. */
+void buffer_reg_destroy_registries(void);
+
+#endif /* LTTNG_BUFFER_REGISTRY_H */
index 91be4f41c8ff559296692d04decd0f7bdf4930ff..6c7422b292dcb3ffd21665468c0f15cc6a728180 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #define _GNU_SOURCE
+#include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
 
@@ -188,7 +189,7 @@ error:
 /*
  * Enable UST channel for session and domain.
  */
-int channel_ust_enable(struct ltt_ust_session *usess, int domain,
+int channel_ust_enable(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan)
 {
        int ret = LTTNG_OK;
@@ -203,43 +204,30 @@ int channel_ust_enable(struct ltt_ust_session *usess, int domain,
                goto end;
        }
 
-       switch (domain) {
-       case LTTNG_DOMAIN_UST:
-               DBG2("Channel %s being enabled in UST global domain", uchan->name);
-
-               /*
-                * Enable channel for UST global domain on all applications. Ignore
-                * return value here since whatever error we got, it means that the
-                * channel was not created on one or many registered applications and
-                * we can not report this to the user yet. However, at this stage, the
-                * channel was successfully created on the session daemon side so the
-                * enable-channel command is a success.
-                */
-               (void) ust_app_create_channel_glb(usess, uchan);
-               break;
-#if 0
-       case LTTNG_DOMAIN_UST_PID:
-       case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
-       case LTTNG_DOMAIN_UST_EXEC_NAME:
-#endif
-       default:
-               ret = LTTNG_ERR_UND;
-               goto error;
-       }
+       DBG2("Channel %s being enabled in UST domain", uchan->name);
+
+       /*
+        * Enable channel for UST global domain on all applications. Ignore return
+        * value here since whatever error we got, it means that the channel was
+        * not created on one or many registered applications and we can not report
+        * this to the user yet. However, at this stage, the channel was
+        * successfully created on the session daemon side so the enable-channel
+        * command is a success.
+        */
+       (void) ust_app_create_channel_glb(usess, uchan);
 
        uchan->enabled = 1;
        DBG2("Channel %s enabled successfully", uchan->name);
 
 end:
-error:
        return ret;
 }
 
 /*
  * Create UST channel for session and domain.
  */
-int channel_ust_create(struct ltt_ust_session *usess, int domain,
-               struct lttng_channel *attr)
+int channel_ust_create(struct ltt_ust_session *usess,
+               struct lttng_channel *attr, enum lttng_buffer_type type)
 {
        int ret = LTTNG_OK;
        struct ltt_ust_channel *uchan = NULL;
@@ -249,7 +237,7 @@ int channel_ust_create(struct ltt_ust_session *usess, int domain,
 
        /* Creating channel attributes if needed */
        if (attr == NULL) {
-               defattr = channel_new_default_attr(domain);
+               defattr = channel_new_default_attr(LTTNG_DOMAIN_UST);
                if (defattr == NULL) {
                        ret = LTTNG_ERR_FATAL;
                        goto error;
@@ -291,24 +279,27 @@ int channel_ust_create(struct ltt_ust_session *usess, int domain,
                goto error;
        }
        uchan->enabled = 1;
-
-       switch (domain) {
-       case LTTNG_DOMAIN_UST:
-               DBG2("Channel %s being created in UST global domain", uchan->name);
-
-               /* Enable channel for global domain */
-               ret = ust_app_create_channel_glb(usess, uchan);
-               break;
-#if 0
-       case LTTNG_DOMAIN_UST_PID:
-       case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
-       case LTTNG_DOMAIN_UST_EXEC_NAME:
-#endif
-       default:
-               ret = LTTNG_ERR_UND;
+       if (trace_ust_is_max_id(usess->used_channel_id)) {
+               ret = LTTNG_ERR_UST_CHAN_FAIL;
+               goto error;
+       }
+       uchan->id = trace_ust_get_next_chan_id(usess);
+
+       DBG2("Channel %s is being created for UST with buffer %d and id %" PRIu64,
+                       uchan->name, type, uchan->id);
+
+       /* Flag session buffer type. */
+       if (!usess->buffer_type_changed) {
+               usess->buffer_type = type;
+               usess->buffer_type_changed = 1;
+       } else if (usess->buffer_type != type) {
+               /* Buffer type was already set. Refuse to create channel. */
+               ret = LTTNG_ERR_BUFFER_TYPE_MISMATCH;
                goto error_free_chan;
        }
 
+       /* Enable channel for global domain */
+       ret = ust_app_create_channel_glb(usess, uchan);
        if (ret < 0 && ret != -LTTNG_UST_ERR_EXIST) {
                ret = LTTNG_ERR_UST_CHAN_FAIL;
                goto error_free_chan;
@@ -338,7 +329,7 @@ error:
 /*
  * Disable UST channel for session and domain.
  */
-int channel_ust_disable(struct ltt_ust_session *usess, int domain,
+int channel_ust_disable(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan)
 {
        int ret = LTTNG_OK;
@@ -352,23 +343,9 @@ int channel_ust_disable(struct ltt_ust_session *usess, int domain,
                goto end;
        }
 
-       /* Get the right channel's hashtable */
-       switch (domain) {
-       case LTTNG_DOMAIN_UST:
-               DBG2("Channel %s being disabled in UST global domain", uchan->name);
-               /* Disable channel for global domain */
-               ret = ust_app_disable_channel_glb(usess, uchan);
-               break;
-#if 0
-       case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
-       case LTTNG_DOMAIN_UST_EXEC_NAME:
-       case LTTNG_DOMAIN_UST_PID:
-#endif
-       default:
-               ret = LTTNG_ERR_UND;
-               goto error;
-       }
-
+       DBG2("Channel %s being disabled in UST global domain", uchan->name);
+       /* Disable channel for global domain */
+       ret = ust_app_disable_channel_glb(usess, uchan);
        if (ret < 0 && ret != -LTTNG_UST_ERR_EXIST) {
                ret = LTTNG_ERR_UST_CHAN_DISABLE_FAIL;
                goto error;
index 75953a88ce7f615dd83a84b8c11ee2fdba32ddfc..7fbbb4c154fbc4a3da25f5884022dd75e86f704a 100644 (file)
@@ -32,11 +32,11 @@ int channel_kernel_create(struct ltt_kernel_session *ksession,
 
 struct lttng_channel *channel_new_default_attr(int domain);
 
-int channel_ust_create(struct ltt_ust_session *usess, int domain,
-               struct lttng_channel *attr);
-int channel_ust_enable(struct ltt_ust_session *usess, int domain,
+int channel_ust_create(struct ltt_ust_session *usess,
+               struct lttng_channel *attr, enum lttng_buffer_type type);
+int channel_ust_enable(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan);
-int channel_ust_disable(struct ltt_ust_session *usess, int domain,
+int channel_ust_disable(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan);
 
 #endif /* _LTT_CHANNEL_H */
index 1a8fbba1eea75f30f4559274a3790f1e1ba599cc..80834941d9c278e181d129e9959489a518c4d938 100644 (file)
@@ -28,6 +28,7 @@
 #include "channel.h"
 #include "consumer.h"
 #include "event.h"
+#include "health.h"
 #include "kernel.h"
 #include "kernel-consumer.h"
 #include "lttng-sessiond.h"
@@ -816,7 +817,7 @@ int cmd_disable_channel(struct ltt_session *session, int domain,
                        goto error;
                }
 
-               ret = channel_ust_disable(usess, domain, uchan);
+               ret = channel_ust_disable(usess, uchan);
                if (ret != LTTNG_OK) {
                        goto error;
                }
@@ -845,7 +846,7 @@ error:
  * The wpipe arguments is used as a notifier for the kernel thread.
  */
 int cmd_enable_channel(struct ltt_session *session,
-               int domain, struct lttng_channel *attr, int wpipe)
+               struct lttng_domain *domain, struct lttng_channel *attr, int wpipe)
 {
        int ret;
        struct ltt_ust_session *usess = session->ust_session;
@@ -853,12 +854,13 @@ int cmd_enable_channel(struct ltt_session *session,
 
        assert(session);
        assert(attr);
+       assert(domain);
 
        DBG("Enabling channel %s for session %s", attr->name, session->name);
 
        rcu_read_lock();
 
-       switch (domain) {
+       switch (domain->type) {
        case LTTNG_DOMAIN_KERNEL:
        {
                struct ltt_kernel_channel *kchan;
@@ -898,9 +900,9 @@ int cmd_enable_channel(struct ltt_session *session,
 
                uchan = trace_ust_find_channel_by_name(chan_ht, attr->name);
                if (uchan == NULL) {
-                       ret = channel_ust_create(usess, domain, attr);
+                       ret = channel_ust_create(usess, attr, domain->buf_type);
                } else {
-                       ret = channel_ust_enable(usess, domain, uchan);
+                       ret = channel_ust_enable(usess, uchan);
                }
 
                /* Start the UST session if the session was already started. */
@@ -915,11 +917,6 @@ int cmd_enable_channel(struct ltt_session *session,
                }
                break;
        }
-#if 0
-       case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
-       case LTTNG_DOMAIN_UST_EXEC_NAME:
-       case LTTNG_DOMAIN_UST_PID:
-#endif
        default:
                ret = LTTNG_ERR_UNKNOWN_DOMAIN;
                goto error;
@@ -977,7 +974,7 @@ int cmd_disable_event(struct ltt_session *session, int domain,
                        goto error;
                }
 
-               ret = event_ust_disable_tracepoint(usess, domain, uchan, event_name);
+               ret = event_ust_disable_tracepoint(usess, uchan, event_name);
                if (ret != LTTNG_OK) {
                        goto error;
                }
@@ -1049,7 +1046,7 @@ int cmd_disable_event_all(struct ltt_session *session, int domain,
                        goto error;
                }
 
-               ret = event_ust_disable_all_tracepoints(usess, domain, uchan);
+               ret = event_ust_disable_all_tracepoints(usess, uchan);
                if (ret != 0) {
                        goto error;
                }
@@ -1117,7 +1114,7 @@ int cmd_add_context(struct ltt_session *session, int domain,
                                goto error;
                        }
 
-                       ret = channel_ust_create(usess, domain, attr);
+                       ret = channel_ust_create(usess, attr, usess->buffer_type);
                        if (ret != LTTNG_OK) {
                                free(attr);
                                goto error;
@@ -1150,7 +1147,7 @@ error:
 /*
  * Command LTTNG_ENABLE_EVENT processed by the client thread.
  */
-int cmd_enable_event(struct ltt_session *session, int domain,
+int cmd_enable_event(struct ltt_session *session, struct lttng_domain *domain,
                char *channel_name, struct lttng_event *event,
                struct lttng_filter_bytecode *filter, int wpipe)
 {
@@ -1163,7 +1160,7 @@ int cmd_enable_event(struct ltt_session *session, int domain,
 
        rcu_read_lock();
 
-       switch (domain) {
+       switch (domain->type) {
        case LTTNG_DOMAIN_KERNEL:
        {
                struct ltt_kernel_channel *kchan;
@@ -1171,7 +1168,7 @@ int cmd_enable_event(struct ltt_session *session, int domain,
                kchan = trace_kernel_get_channel_by_name(channel_name,
                                session->kernel_session);
                if (kchan == NULL) {
-                       attr = channel_new_default_attr(domain);
+                       attr = channel_new_default_attr(LTTNG_DOMAIN_KERNEL);
                        if (attr == NULL) {
                                ret = LTTNG_ERR_FATAL;
                                goto error;
@@ -1221,7 +1218,7 @@ int cmd_enable_event(struct ltt_session *session, int domain,
                                channel_name);
                if (uchan == NULL) {
                        /* Create default channel */
-                       attr = channel_new_default_attr(domain);
+                       attr = channel_new_default_attr(LTTNG_DOMAIN_UST);
                        if (attr == NULL) {
                                ret = LTTNG_ERR_FATAL;
                                goto error;
@@ -1242,7 +1239,7 @@ int cmd_enable_event(struct ltt_session *session, int domain,
                }
 
                /* At this point, the session and channel exist on the tracer */
-               ret = event_ust_enable_tracepoint(usess, domain, uchan, event, filter);
+               ret = event_ust_enable_tracepoint(usess, uchan, event, filter);
                if (ret != LTTNG_OK) {
                        goto error;
                }
@@ -1268,8 +1265,8 @@ error:
 /*
  * Command LTTNG_ENABLE_ALL_EVENT processed by the client thread.
  */
-int cmd_enable_event_all(struct ltt_session *session, int domain,
-               char *channel_name, int event_type,
+int cmd_enable_event_all(struct ltt_session *session,
+               struct lttng_domain *domain, char *channel_name, int event_type,
                struct lttng_filter_bytecode *filter, int wpipe)
 {
        int ret;
@@ -1280,7 +1277,7 @@ int cmd_enable_event_all(struct ltt_session *session, int domain,
 
        rcu_read_lock();
 
-       switch (domain) {
+       switch (domain->type) {
        case LTTNG_DOMAIN_KERNEL:
        {
                struct ltt_kernel_channel *kchan;
@@ -1291,7 +1288,7 @@ int cmd_enable_event_all(struct ltt_session *session, int domain,
                                session->kernel_session);
                if (kchan == NULL) {
                        /* Create default channel */
-                       attr = channel_new_default_attr(domain);
+                       attr = channel_new_default_attr(LTTNG_DOMAIN_KERNEL);
                        if (attr == NULL) {
                                ret = LTTNG_ERR_FATAL;
                                goto error;
@@ -1355,7 +1352,7 @@ int cmd_enable_event_all(struct ltt_session *session, int domain,
                                channel_name);
                if (uchan == NULL) {
                        /* Create default channel */
-                       attr = channel_new_default_attr(domain);
+                       attr = channel_new_default_attr(LTTNG_DOMAIN_UST);
                        if (attr == NULL) {
                                ret = LTTNG_ERR_FATAL;
                                goto error;
@@ -1380,8 +1377,7 @@ int cmd_enable_event_all(struct ltt_session *session, int domain,
                switch (event_type) {
                case LTTNG_EVENT_ALL:
                case LTTNG_EVENT_TRACEPOINT:
-                       ret = event_ust_enable_all_tracepoints(usess, domain, uchan,
-                                       filter);
+                       ret = event_ust_enable_all_tracepoints(usess, uchan, filter);
                        if (ret != LTTNG_OK) {
                                goto error;
                        }
index 96a6507b5a0c0d7762d027a9a8eef375125a0c2c..d997f85cddbcb634e3511b9418df7492ac7d8fbb 100644 (file)
@@ -35,8 +35,9 @@ int cmd_destroy_session(struct ltt_session *session, int wpipe);
 /* Channel commands */
 int cmd_disable_channel(struct ltt_session *session, int domain,
                char *channel_name);
-int cmd_enable_channel(struct ltt_session *session, int domain,
-               struct lttng_channel *attr, int wpipe);
+
+int cmd_enable_channel(struct ltt_session *session,
+               struct lttng_domain *domain, struct lttng_channel *attr, int wpipe);
 
 /* Event commands */
 int cmd_disable_event(struct ltt_session *session, int domain,
@@ -48,11 +49,11 @@ int cmd_add_context(struct ltt_session *session, int domain,
 int cmd_set_filter(struct ltt_session *session, int domain,
                char *channel_name, struct lttng_event *event,
                struct lttng_filter_bytecode *bytecode);
-int cmd_enable_event(struct ltt_session *session, int domain,
+int cmd_enable_event(struct ltt_session *session, struct lttng_domain *domain,
                char *channel_name, struct lttng_event *event,
                struct lttng_filter_bytecode *filter, int wpipe);
-int cmd_enable_event_all(struct ltt_session *session, int domain,
-               char *channel_name, int event_type,
+int cmd_enable_event_all(struct ltt_session *session,
+               struct lttng_domain *domain, char *channel_name, int event_type,
                struct lttng_filter_bytecode *filter, int wpipe);
 
 /* Trace session action commands */
index 92abcf21d07257ce4cfa83ad44dbf79bd833508d..57b5b19d17db507b6b42d5407be7535512236e1e 100644 (file)
@@ -30,6 +30,8 @@
 #include <common/uri.h>
 
 #include "consumer.h"
+#include "health.h"
+#include "ust-app.h"
 
 /*
  * Receive a reply command status message from the consumer. Consumer socket
@@ -230,6 +232,41 @@ error:
        return ret;
 }
 
+/*
+ * Return the consumer socket from the given consumer output with the right
+ * bitness. On error, returns NULL.
+ *
+ * The caller MUST acquire a rcu read side lock and keep it until the socket
+ * object reference is not needed anymore.
+ */
+struct consumer_socket *consumer_find_socket_by_bitness(int bits,
+               struct consumer_output *consumer)
+{
+       int consumer_fd;
+       struct consumer_socket *socket = NULL;
+
+       switch (bits) {
+       case 64:
+               consumer_fd = uatomic_read(&ust_consumerd64_fd);
+               break;
+       case 32:
+               consumer_fd = uatomic_read(&ust_consumerd32_fd);
+               break;
+       default:
+               assert(0);
+               goto end;
+       }
+
+       socket = consumer_find_socket(consumer_fd, consumer);
+       if (!socket) {
+               ERR("Consumer socket fd %d not found in consumer obj %p",
+                               consumer_fd, consumer);
+       }
+
+end:
+       return socket;
+}
+
 /*
  * Find a consumer_socket in a consumer_output hashtable. Read side lock must
  * be acquired before calling this function and across use of the
@@ -625,7 +662,8 @@ void consumer_init_ask_channel_comm_msg(struct lttcomm_consumer_msg *msg,
                gid_t gid,
                uint64_t relayd_id,
                uint64_t key,
-               unsigned char *uuid)
+               unsigned char *uuid,
+               uint32_t chan_id)
 {
        assert(msg);
 
@@ -645,6 +683,7 @@ void consumer_init_ask_channel_comm_msg(struct lttcomm_consumer_msg *msg,
        msg->u.ask_channel.gid = gid;
        msg->u.ask_channel.relayd_id = relayd_id;
        msg->u.ask_channel.key = key;
+       msg->u.ask_channel.chan_id = chan_id;
 
        memcpy(msg->u.ask_channel.uuid, uuid, sizeof(msg->u.ask_channel.uuid));
 
@@ -933,3 +972,158 @@ error_unlock:
        rcu_read_unlock();
        return -1;
 }
+
+/*
+ * Send a flush command to consumer using the given channel key.
+ *
+ * Return 0 on success else a negative value.
+ */
+int consumer_flush_channel(struct consumer_socket *socket, uint64_t key)
+{
+       int ret;
+       struct lttcomm_consumer_msg msg;
+
+       assert(socket);
+       assert(socket->fd >= 0);
+
+       DBG2("Consumer flush channel key %" PRIu64, key);
+
+       msg.cmd_type = LTTNG_CONSUMER_FLUSH_CHANNEL;
+       msg.u.flush_channel.key = key;
+
+       pthread_mutex_lock(socket->lock);
+       health_code_update();
+
+       ret = consumer_send_msg(socket, &msg);
+       if (ret < 0) {
+               goto end;
+       }
+
+end:
+       health_code_update();
+       pthread_mutex_unlock(socket->lock);
+       return ret;
+}
+
+/*
+ * Send a close metdata command to consumer using the given channel key.
+ *
+ * Return 0 on success else a negative value.
+ */
+int consumer_close_metadata(struct consumer_socket *socket,
+               uint64_t metadata_key)
+{
+       int ret;
+       struct lttcomm_consumer_msg msg;
+
+       assert(socket);
+       assert(socket->fd >= 0);
+
+       DBG2("Consumer close metadata channel key %" PRIu64, metadata_key);
+
+       msg.cmd_type = LTTNG_CONSUMER_CLOSE_METADATA;
+       msg.u.close_metadata.key = metadata_key;
+
+       pthread_mutex_lock(socket->lock);
+       health_code_update();
+
+       ret = consumer_send_msg(socket, &msg);
+       if (ret < 0) {
+               goto end;
+       }
+
+end:
+       health_code_update();
+       pthread_mutex_unlock(socket->lock);
+       return ret;
+}
+
+/*
+ * Send a setup metdata command to consumer using the given channel key.
+ *
+ * Return 0 on success else a negative value.
+ */
+int consumer_setup_metadata(struct consumer_socket *socket,
+               uint64_t metadata_key)
+{
+       int ret;
+       struct lttcomm_consumer_msg msg;
+
+       assert(socket);
+       assert(socket->fd >= 0);
+
+       DBG2("Consumer setup metadata channel key %" PRIu64, metadata_key);
+
+       msg.cmd_type = LTTNG_CONSUMER_SETUP_METADATA;
+       msg.u.setup_metadata.key = metadata_key;
+
+       pthread_mutex_lock(socket->lock);
+       health_code_update();
+
+       ret = consumer_send_msg(socket, &msg);
+       if (ret < 0) {
+               goto end;
+       }
+
+end:
+       health_code_update();
+       pthread_mutex_unlock(socket->lock);
+       return ret;
+}
+
+/*
+ * Send metadata string to consumer.
+ *
+ * Return 0 on success else a negative value.
+ */
+int consumer_push_metadata(struct consumer_socket *socket,
+               uint64_t metadata_key, char *metadata_str, size_t len,
+               size_t target_offset)
+{
+       int ret;
+       struct lttcomm_consumer_msg msg;
+
+       assert(socket);
+       assert(socket->fd >= 0);
+
+       DBG2("Consumer push metadata to consumer socket %d", socket->fd);
+
+       msg.cmd_type = LTTNG_CONSUMER_PUSH_METADATA;
+       msg.u.push_metadata.key = metadata_key;
+       msg.u.push_metadata.target_offset = target_offset;
+       msg.u.push_metadata.len = len;
+
+       /*
+        * TODO: reenable these locks when the consumerd gets the ability to
+        * reorder the metadata it receives. This fits with locking in
+        * src/bin/lttng-sessiond/ust-app.c:push_metadata()
+        *
+        * pthread_mutex_lock(socket->lock);
+        */
+
+       health_code_update();
+       ret = consumer_send_msg(socket, &msg);
+       if (ret < 0) {
+               goto end;
+       }
+
+       DBG3("Consumer pushing metadata on sock %d of len %lu", socket->fd, len);
+
+       ret = lttcomm_send_unix_sock(socket->fd, metadata_str, len);
+       if (ret < 0) {
+               goto end;
+       }
+
+       health_code_update();
+       ret = consumer_recv_status_reply(socket);
+       if (ret < 0) {
+               goto end;
+       }
+
+end:
+       health_code_update();
+       /*
+        * pthread_mutex_unlock(socket->lock);
+        */
+       return ret;
+}
index 3616d467cd4e76e65246ce5c2e07cbf80e75434e..cde2d0d060be09375c0dabcdfda5c4e1b15afccc 100644 (file)
@@ -22,8 +22,6 @@
 #include <common/hashtable/hashtable.h>
 #include <lttng/lttng.h>
 
-#include "health.h"
-
 enum consumer_dst_type {
        CONSUMER_DST_LOCAL,
        CONSUMER_DST_NET,
@@ -148,6 +146,8 @@ struct consumer_output {
 
 struct consumer_socket *consumer_find_socket(int key,
                struct consumer_output *consumer);
+struct consumer_socket *consumer_find_socket_by_bitness(int bits,
+               struct consumer_output *consumer);
 struct consumer_socket *consumer_allocate_socket(int fd);
 void consumer_add_socket(struct consumer_socket *sock,
                struct consumer_output *consumer);
@@ -197,7 +197,8 @@ void consumer_init_ask_channel_comm_msg(struct lttcomm_consumer_msg *msg,
                gid_t gid,
                uint64_t relayd_id,
                uint64_t key,
-               unsigned char *uuid);
+               unsigned char *uuid,
+               uint32_t chan_id);
 void consumer_init_stream_comm_msg(struct lttcomm_consumer_msg *msg,
                enum lttng_consumer_command cmd,
                uint64_t channel_key,
@@ -217,5 +218,13 @@ void consumer_init_channel_comm_msg(struct lttcomm_consumer_msg *msg,
                int type);
 int consumer_is_data_pending(uint64_t session_id,
                struct consumer_output *consumer);
+int consumer_close_metadata(struct consumer_socket *socket,
+               uint64_t metadata_key);
+int consumer_setup_metadata(struct consumer_socket *socket,
+               uint64_t metadata_key);
+int consumer_push_metadata(struct consumer_socket *socket,
+               uint64_t metadata_key, char *metadata_str, size_t len,
+               size_t target_offset);
+int consumer_flush_channel(struct consumer_socket *socket, uint64_t key);
 
 #endif /* _CONSUMER_H */
index 5acb4790b3ca8dcf3fab4cfa02fbda91066be7be..0af7b4cb2f944288a1107b7b6ea50ff2383dcf76 100644 (file)
@@ -312,7 +312,7 @@ end:
 /*
  * Enable all UST tracepoints for a channel from a UST session.
  */
-int event_ust_enable_all_tracepoints(struct ltt_ust_session *usess, int domain,
+int event_ust_enable_all_tracepoints(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct lttng_filter_bytecode *filter)
 {
        int ret, i, size;
@@ -325,86 +325,71 @@ int event_ust_enable_all_tracepoints(struct ltt_ust_session *usess, int domain,
 
        rcu_read_lock();
 
-       switch (domain) {
-       case LTTNG_DOMAIN_UST:
-       {
-               /* Enable existing events */
-               cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent,
-                               node.node) {
-                       if (uevent->enabled == 0) {
-                               ret = ust_app_enable_event_glb(usess, uchan, uevent);
-                               if (ret < 0) {
-                                       continue;
-                               }
-                               uevent->enabled = 1;
-                       }
-               }
-
-               /* Get all UST available events */
-               size = ust_app_list_events(&events);
-               if (size < 0) {
-                       ret = LTTNG_ERR_UST_LIST_FAIL;
-                       goto error;
-               }
-
-               for (i = 0; i < size; i++) {
-                       /*
-                        * Check if event exist and if so, continue since it was enable
-                        * previously.
-                        */
-                       uevent = trace_ust_find_event(uchan->events, events[i].name, filter,
-                                       events[i].loglevel);
-                       if (uevent != NULL) {
-                               ret = ust_app_enable_event_pid(usess, uchan, uevent,
-                                               events[i].pid);
-                               if (ret < 0) {
-                                       if (ret != -LTTNG_UST_ERR_EXIST) {
-                                               ret = LTTNG_ERR_UST_ENABLE_FAIL;
-                                               goto error;
-                                       }
-                               }
+       /* Enable existing events */
+       cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent,
+                       node.node) {
+               if (uevent->enabled == 0) {
+                       ret = ust_app_enable_event_glb(usess, uchan, uevent);
+                       if (ret < 0) {
                                continue;
                        }
+                       uevent->enabled = 1;
+               }
+       }
 
-                       /* Create ust event */
-                       uevent = trace_ust_create_event(&events[i], filter);
-                       if (uevent == NULL) {
-                               ret = LTTNG_ERR_FATAL;
-                               goto error_destroy;
-                       }
+       /* Get all UST available events */
+       size = ust_app_list_events(&events);
+       if (size < 0) {
+               ret = LTTNG_ERR_UST_LIST_FAIL;
+               goto error;
+       }
 
-                       /* Create event for the specific PID */
+       for (i = 0; i < size; i++) {
+               /*
+                * Check if event exist and if so, continue since it was enable
+                * previously.
+                */
+               uevent = trace_ust_find_event(uchan->events, events[i].name, filter,
+                               events[i].loglevel);
+               if (uevent != NULL) {
                        ret = ust_app_enable_event_pid(usess, uchan, uevent,
                                        events[i].pid);
                        if (ret < 0) {
-                               if (ret == -LTTNG_UST_ERR_EXIST) {
-                                       ret = LTTNG_ERR_UST_EVENT_EXIST;
-                                       goto error;
-                               } else {
+                               if (ret != -LTTNG_UST_ERR_EXIST) {
                                        ret = LTTNG_ERR_UST_ENABLE_FAIL;
-                                       goto error_destroy;
+                                       goto error;
                                }
                        }
+                       continue;
+               }
 
-                       uevent->enabled = 1;
-                       /* Add ltt ust event to channel */
-                       rcu_read_lock();
-                       add_unique_ust_event(uchan->events, uevent);
-                       rcu_read_unlock();
+               /* Create ust event */
+               uevent = trace_ust_create_event(&events[i], filter);
+               if (uevent == NULL) {
+                       ret = LTTNG_ERR_FATAL;
+                       goto error_destroy;
                }
 
-               free(events);
-               break;
-       }
-#if 0
-       case LTTNG_DOMAIN_UST_EXEC_NAME:
-       case LTTNG_DOMAIN_UST_PID:
-       case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
-#endif
-       default:
-               ret = LTTNG_ERR_UND;
-               goto error;
+               /* Create event for the specific PID */
+               ret = ust_app_enable_event_pid(usess, uchan, uevent,
+                               events[i].pid);
+               if (ret < 0) {
+                       if (ret == -LTTNG_UST_ERR_EXIST) {
+                               ret = LTTNG_ERR_UST_EVENT_EXIST;
+                               goto error;
+                       } else {
+                               ret = LTTNG_ERR_UST_ENABLE_FAIL;
+                               goto error_destroy;
+                       }
+               }
+
+               uevent->enabled = 1;
+               /* Add ltt ust event to channel */
+               rcu_read_lock();
+               add_unique_ust_event(uchan->events, uevent);
+               rcu_read_unlock();
        }
+       free(events);
 
        rcu_read_unlock();
        return LTTNG_OK;
@@ -421,7 +406,7 @@ error:
 /*
  * Enable UST tracepoint event for a channel from a UST session.
  */
-int event_ust_enable_tracepoint(struct ltt_ust_session *usess, int domain,
+int event_ust_enable_tracepoint(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct lttng_event *event,
                struct lttng_filter_bytecode *filter)
 {
@@ -455,36 +440,22 @@ int event_ust_enable_tracepoint(struct ltt_ust_session *usess, int domain,
 
        uevent->enabled = 1;
 
-       switch (domain) {
-       case LTTNG_DOMAIN_UST:
-       {
-               if (to_create) {
-                       /* Create event on all UST registered apps for session */
-                       ret = ust_app_create_event_glb(usess, uchan, uevent);
-               } else {
-                       /* Enable event on all UST registered apps for session */
-                       ret = ust_app_enable_event_glb(usess, uchan, uevent);
-               }
+       if (to_create) {
+               /* Create event on all UST registered apps for session */
+               ret = ust_app_create_event_glb(usess, uchan, uevent);
+       } else {
+               /* Enable event on all UST registered apps for session */
+               ret = ust_app_enable_event_glb(usess, uchan, uevent);
+       }
 
-               if (ret < 0) {
-                       if (ret == -LTTNG_UST_ERR_EXIST) {
-                               ret = LTTNG_ERR_UST_EVENT_EXIST;
-                               goto end;
-                       } else {
-                               ret = LTTNG_ERR_UST_ENABLE_FAIL;
-                               goto error;
-                       }
+       if (ret < 0) {
+               if (ret == -LTTNG_UST_ERR_EXIST) {
+                       ret = LTTNG_ERR_UST_EVENT_EXIST;
+                       goto end;
+               } else {
+                       ret = LTTNG_ERR_UST_ENABLE_FAIL;
+                       goto error;
                }
-               break;
-       }
-#if 0
-       case LTTNG_DOMAIN_UST_EXEC_NAME:
-       case LTTNG_DOMAIN_UST_PID:
-       case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
-#endif
-       default:
-               ret = LTTNG_ERR_UND;
-               goto end;
        }
 
        if (to_create) {
@@ -520,7 +491,7 @@ error:
 /*
  * Disable UST tracepoint of a channel from a UST session.
  */
-int event_ust_disable_tracepoint(struct ltt_ust_session *usess, int domain,
+int event_ust_disable_tracepoint(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, char *event_name)
 {
        int ret;
@@ -560,24 +531,11 @@ int event_ust_disable_tracepoint(struct ltt_ust_session *usess, int domain,
                        continue;
                }
 
-               switch (domain) {
-               case LTTNG_DOMAIN_UST:
-                       ret = ust_app_disable_event_glb(usess, uchan, uevent);
-                       if (ret < 0 && ret != -LTTNG_UST_ERR_EXIST) {
-                               ret = LTTNG_ERR_UST_DISABLE_FAIL;
-                               goto error;
-                       }
-                       break;
-#if 0
-               case LTTNG_DOMAIN_UST_EXEC_NAME:
-               case LTTNG_DOMAIN_UST_PID:
-               case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
-#endif
-               default:
-                       ret = LTTNG_ERR_UND;
+               ret = ust_app_disable_event_glb(usess, uchan, uevent);
+               if (ret < 0 && ret != -LTTNG_UST_ERR_EXIST) {
+                       ret = LTTNG_ERR_UST_DISABLE_FAIL;
                        goto error;
                }
-
                uevent->enabled = 0;
 
                DBG2("Event UST %s disabled in channel %s", uevent->attr.name,
@@ -599,7 +557,7 @@ error:
 /*
  * Disable all UST tracepoints for a channel from a UST session.
  */
-int event_ust_disable_all_tracepoints(struct ltt_ust_session *usess, int domain,
+int event_ust_disable_all_tracepoints(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan)
 {
        int ret, i, size;
@@ -612,50 +570,35 @@ int event_ust_disable_all_tracepoints(struct ltt_ust_session *usess, int domain,
 
        rcu_read_lock();
 
-       switch (domain) {
-       case LTTNG_DOMAIN_UST:
-       {
-               /* Disabling existing events */
-               cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent,
-                               node.node) {
-                       if (uevent->enabled == 1) {
-                               ret = event_ust_disable_tracepoint(usess, domain, uchan,
-                                               uevent->attr.name);
-                               if (ret < 0) {
-                                       continue;
-                               }
-                       }
-               }
-
-               /* Get all UST available events */
-               size = ust_app_list_events(&events);
-               if (size < 0) {
-                       ret = LTTNG_ERR_UST_LIST_FAIL;
-                       goto error;
-               }
-
-               for (i = 0; i < size; i++) {
-                       ret = event_ust_disable_tracepoint(usess, domain, uchan,
-                                       events[i].name);
-                       if (ret != LTTNG_OK) {
-                               /* Continue to disable the rest... */
+       /* Disabling existing events */
+       cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent,
+                       node.node) {
+               if (uevent->enabled == 1) {
+                       ret = event_ust_disable_tracepoint(usess, uchan,
+                                       uevent->attr.name);
+                       if (ret < 0) {
                                continue;
                        }
                }
-
-               free(events);
-               break;
        }
-#if 0
-       case LTTNG_DOMAIN_UST_EXEC_NAME:
-       case LTTNG_DOMAIN_UST_PID:
-       case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
-#endif
-       default:
-               ret = LTTNG_ERR_UND;
+
+       /* Get all UST available events */
+       size = ust_app_list_events(&events);
+       if (size < 0) {
+               ret = LTTNG_ERR_UST_LIST_FAIL;
                goto error;
        }
 
+       for (i = 0; i < size; i++) {
+               ret = event_ust_disable_tracepoint(usess, uchan,
+                               events[i].name);
+               if (ret != LTTNG_OK) {
+                       /* Continue to disable the rest... */
+                       continue;
+               }
+       }
+       free(events);
+
        rcu_read_unlock();
        return LTTNG_OK;
 
index a8b75192fd2dd719e230f46adb73a5feb4e9313f..819111599c15da37b2d75bd0e11ce2f3fcc464bd 100644 (file)
@@ -35,14 +35,14 @@ int event_kernel_enable_all_syscalls(struct ltt_kernel_channel *kchan,
 int event_kernel_enable_all(struct ltt_kernel_channel *kchan,
                int kernel_tracer_fd);
 
-int event_ust_enable_tracepoint(struct ltt_ust_session *usess, int domain,
+int event_ust_enable_tracepoint(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct lttng_event *event,
                struct lttng_filter_bytecode *filter);
-int event_ust_disable_tracepoint(struct ltt_ust_session *usess, int domain,
+int event_ust_disable_tracepoint(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, char *event_name);
-int event_ust_enable_all_tracepoints(struct ltt_ust_session *usess, int domain,
+int event_ust_enable_all_tracepoints(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct lttng_filter_bytecode *filter);
-int event_ust_disable_all_tracepoints(struct ltt_ust_session *usess, int domain,
+int event_ust_disable_all_tracepoints(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan);
 
 #endif /* _LTT_EVENT_H */
index 837afdc8333faf71de79dfe56bbff31ae44a236a..3368da6c1ba8a5d6e2c89ac09d0679793fc04867 100644 (file)
@@ -26,6 +26,7 @@
 #include <common/defaults.h>
 
 #include "consumer.h"
+#include "health.h"
 #include "kernel-consumer.h"
 
 /*
index 4ef04653cc517bebc3ec87890f03bc9dcc975622..df61cde57c5c0005bb6e72c7d2ccdcbea4d19c2d 100644 (file)
 #include <stdint.h>
 #include <lttng/ust-compiler.h>
 
-#define LTTNG_UST_SYM_NAME_LEN 256
+#ifndef __ust_stringify
+#define __ust_stringify1(x)    #x
+#define __ust_stringify(x)     __ust_stringify1(x)
+#endif /* __ust_stringify */
 
-/* Version for comm protocol between sessiond and ust */
-#define LTTNG_UST_COMM_VERSION_MAJOR           2
-#define LTTNG_UST_COMM_VERSION_MINOR           1
+#define LTTNG_UST_SYM_NAME_LEN                 256
+#define LTTNG_UST_ABI_PROCNAME_LEN             16
+
+/* UST comm magic number, used to validate protocol and endianness. */
+#define LTTNG_UST_COMM_MAGIC                   0xC57C57C5
 
 /* Version for ABI between liblttng-ust, sessiond, consumerd */
-#define LTTNG_UST_INTERNAL_MAJOR_VERSION       3
-#define LTTNG_UST_INTERNAL_MINOR_VERSION       0
-#define LTTNG_UST_INTERNAL_PATCHLEVEL_VERSION  0
+#define LTTNG_UST_ABI_MAJOR_VERSION            4
+#define LTTNG_UST_ABI_MINOR_VERSION            0
 
 enum lttng_ust_instrumentation {
        LTTNG_UST_TRACEPOINT            = 0,
@@ -68,7 +72,7 @@ struct lttng_ust_tracer_version {
        uint32_t patchlevel;
 } LTTNG_PACKED;
 
-#define LTTNG_UST_CHANNEL_PADDING      LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_CHANNEL_PADDING      (LTTNG_UST_SYM_NAME_LEN + 32)
 /*
  * Given that the consumerd is limited to 64k file descriptors, we
  * cannot expect much more than 1MB channel structure size. This size is
@@ -83,7 +87,7 @@ struct lttng_ust_channel {
        char data[];    /* variable sized data */
 } LTTNG_PACKED;
 
-#define LTTNG_UST_STREAM_PADDING1      LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_STREAM_PADDING1      (LTTNG_UST_SYM_NAME_LEN + 32)
 struct lttng_ust_stream {
        uint64_t len;           /* shm len */
        uint32_t stream_nr;     /* stream number */
@@ -95,7 +99,7 @@ struct lttng_ust_stream {
 } LTTNG_PACKED;
 
 #define LTTNG_UST_EVENT_PADDING1       16
-#define LTTNG_UST_EVENT_PADDING2       LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_EVENT_PADDING2       (LTTNG_UST_SYM_NAME_LEN + 32)
 struct lttng_ust_event {
        enum lttng_ust_instrumentation instrumentation;
        char name[LTTNG_UST_SYM_NAME_LEN];      /* event name */
@@ -118,7 +122,7 @@ enum lttng_ust_field_type {
        LTTNG_UST_FIELD_STRING                  = 4,
 };
 
-#define LTTNG_UST_FIELD_ITER_PADDING           LTTNG_UST_SYM_NAME_LEN + 28
+#define LTTNG_UST_FIELD_ITER_PADDING   (LTTNG_UST_SYM_NAME_LEN + 28)
 struct lttng_ust_field_iter {
        char event_name[LTTNG_UST_SYM_NAME_LEN];
        char field_name[LTTNG_UST_SYM_NAME_LEN];
@@ -136,7 +140,7 @@ enum lttng_ust_context_type {
 };
 
 #define LTTNG_UST_CONTEXT_PADDING1     16
-#define LTTNG_UST_CONTEXT_PADDING2     LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_CONTEXT_PADDING2     (LTTNG_UST_SYM_NAME_LEN + 32)
 struct lttng_ust_context {
        enum lttng_ust_context_type ctx;
        char padding[LTTNG_UST_CONTEXT_PADDING1];
@@ -149,7 +153,7 @@ struct lttng_ust_context {
 /*
  * Tracer channel attributes.
  */
-#define LTTNG_UST_CHANNEL_ATTR_PADDING LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_CHANNEL_ATTR_PADDING (LTTNG_UST_SYM_NAME_LEN + 32)
 struct lttng_ust_channel_attr {
        uint64_t subbuf_size;                   /* bytes */
        uint64_t num_subbuf;                    /* power of 2 */
@@ -171,10 +175,12 @@ enum lttng_ust_object_type {
        LTTNG_UST_OBJECT_TYPE_UNKNOWN = -1,
        LTTNG_UST_OBJECT_TYPE_CHANNEL = 0,
        LTTNG_UST_OBJECT_TYPE_STREAM = 1,
+       LTTNG_UST_OBJECT_TYPE_EVENT = 2,
+       LTTNG_UST_OBJECT_TYPE_CONTEXT = 3,
 };
 
-#define LTTNG_UST_OBJECT_DATA_PADDING1         32
-#define LTTNG_UST_OBJECT_DATA_PADDING2         LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_OBJECT_DATA_PADDING1 32
+#define LTTNG_UST_OBJECT_DATA_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32)
 
 struct lttng_ust_object_data {
        enum lttng_ust_object_type type;
@@ -185,6 +191,7 @@ struct lttng_ust_object_data {
                struct {
                        void *data;
                        enum lttng_ust_chan_type type;
+                       int wakeup_fd;
                } channel;
                struct {
                        int shm_fd;
@@ -200,7 +207,7 @@ enum lttng_ust_calibrate_type {
 };
 
 #define LTTNG_UST_CALIBRATE_PADDING1   16
-#define LTTNG_UST_CALIBRATE_PADDING2   LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_CALIBRATE_PADDING2   (LTTNG_UST_SYM_NAME_LEN + 32)
 struct lttng_ust_calibrate {
        enum lttng_ust_calibrate_type type;     /* type (input) */
        char padding[LTTNG_UST_CALIBRATE_PADDING1];
@@ -239,8 +246,6 @@ struct lttng_ust_filter_bytecode {
 #define LTTNG_UST_TRACEPOINT_FIELD_LIST                _UST_CMD(0x45)
 
 /* Session FD commands */
-#define LTTNG_UST_METADATA                     \
-       _UST_CMDW(0x50, struct lttng_ust_channel)
 #define LTTNG_UST_CHANNEL                      \
        _UST_CMDW(0x51, struct lttng_ust_channel)
 #define LTTNG_UST_SESSION_START                        _UST_CMD(0x52)
@@ -275,6 +280,7 @@ struct lttng_ust_obj;
 union ust_args {
        struct {
                void *chan_data;
+               int wakeup_fd;
        } channel;
        struct {
                int shm_fd;
@@ -295,7 +301,7 @@ struct lttng_ust_objd_ops {
 int lttng_abi_create_root_handle(void);
 
 const struct lttng_ust_objd_ops *objd_ops(int id);
-int lttng_ust_objd_unref(int id);
+int lttng_ust_objd_unref(int id, int is_owner);
 
 void lttng_ust_abi_exit(void);
 void lttng_ust_events_exit(void);
index 7dd36a93cc591d20c2d89764e5e13e57d88f6a7c..fc5c794743646f5b38fb0b0b4eb5014732fdbd64 100644 (file)
 #define _LTTNG_UST_CTL_H
 
 #include <lttng/ust-abi.h>
-
-#ifndef LTTNG_PACKED
-#define LTTNG_PACKED __attribute__((packed))
-#endif
+#include <sys/types.h>
 
 #ifndef LTTNG_UST_UUID_LEN
 #define LTTNG_UST_UUID_LEN     16
 #endif
 
+/* Default unix socket path */
+#define LTTNG_UST_SOCK_FILENAME                                        \
+       "lttng-ust-sock-"                                       \
+       __ust_stringify(LTTNG_UST_ABI_MAJOR_VERSION)
+
+/*
+ * Shared memory files path are automatically related to shm root, e.g.
+ * /dev/shm under linux.
+ */
+#define LTTNG_UST_WAIT_FILENAME                                        \
+       "lttng-ust-wait-"                                       \
+       __ust_stringify(LTTNG_UST_ABI_MAJOR_VERSION)
+
 struct lttng_ust_shm_handle;
 struct lttng_ust_lib_ring_buffer;
 
@@ -40,6 +50,7 @@ struct ustctl_consumer_channel_attr {
        unsigned int switch_timer_interval;     /* usec */
        unsigned int read_timer_interval;       /* usec */
        enum lttng_ust_output output;           /* splice, mmap */
+       uint32_t chan_id;           /* channel ID */
        unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */
 } LTTNG_PACKED;
 
@@ -118,6 +129,14 @@ int ustctl_send_stream_to_ust(int sock,
                struct lttng_ust_object_data *channel_data,
                struct lttng_ust_object_data *stream_data);
 
+/*
+ * ustctl_duplicate_ust_object_data allocated a new object in "dest" if
+ * it succeeds (returns 0). It must be released using
+ * ustctl_release_object() and then freed with free().
+ */
+int ustctl_duplicate_ust_object_data(struct lttng_ust_object_data **dest,
+               struct lttng_ust_object_data *src);
+
 /*
  * API used by consumer.
  */
@@ -141,6 +160,11 @@ int ustctl_channel_close_wakeup_fd(struct ustctl_consumer_channel *consumer_chan
 int ustctl_channel_get_wait_fd(struct ustctl_consumer_channel *consumer_chan);
 int ustctl_channel_get_wakeup_fd(struct ustctl_consumer_channel *consumer_chan);
 
+int ustctl_write_metadata_to_channel(
+               struct ustctl_consumer_channel *channel,
+               const char *metadata_str,       /* NOT null-terminated */
+               size_t len);                    /* metadata length */
+
 /*
  * Send a NULL stream to finish iteration over all streams of a given
  * channel.
@@ -192,4 +216,179 @@ int ustctl_put_subbuf(struct ustctl_consumer_stream *stream);
 void ustctl_flush_buffer(struct ustctl_consumer_stream *stream,
                int producer_active);
 
+/* event registry management */
+
+enum ustctl_socket_type {
+       USTCTL_SOCKET_CMD = 0,
+       USTCTL_SOCKET_NOTIFY = 1,
+};
+
+enum ustctl_notify_cmd {
+       USTCTL_NOTIFY_CMD_EVENT = 0,
+       USTCTL_NOTIFY_CMD_CHANNEL = 1,
+};
+
+enum ustctl_channel_header {
+       USTCTL_CHANNEL_HEADER_UNKNOWN = 0,
+       USTCTL_CHANNEL_HEADER_COMPACT = 1,
+       USTCTL_CHANNEL_HEADER_LARGE = 2,
+};
+
+/* event type structures */
+
+enum ustctl_abstract_types {
+       ustctl_atype_integer,
+       ustctl_atype_enum,
+       ustctl_atype_array,
+       ustctl_atype_sequence,
+       ustctl_atype_string,
+       ustctl_atype_float,
+       NR_USTCTL_ABSTRACT_TYPES,
+};
+
+enum ustctl_string_encodings {
+       ustctl_encode_none = 0,
+       ustctl_encode_UTF8 = 1,
+       ustctl_encode_ASCII = 2,
+       NR_USTCTL_STRING_ENCODINGS,
+};
+
+#define USTCTL_UST_INTEGER_TYPE_PADDING        24
+struct ustctl_integer_type {
+       uint32_t size;          /* in bits */
+       uint32_t signedness;
+       uint32_t reverse_byte_order;
+       uint32_t base;          /* 2, 8, 10, 16, for pretty print */
+       enum ustctl_string_encodings encoding;
+       uint16_t alignment;     /* in bits */
+       char padding[USTCTL_UST_INTEGER_TYPE_PADDING];
+} LTTNG_PACKED;
+
+#define USTCTL_UST_FLOAT_TYPE_PADDING  24
+struct ustctl_float_type {
+       uint32_t exp_dig;               /* exponent digits, in bits */
+       uint32_t mant_dig;              /* mantissa digits, in bits */
+       uint32_t reverse_byte_order;
+       uint16_t alignment;     /* in bits */
+       char padding[USTCTL_UST_FLOAT_TYPE_PADDING];
+} LTTNG_PACKED;
+
+#define USTCTL_UST_BASIC_TYPE_PADDING  296
+union _ustctl_basic_type {
+       struct ustctl_integer_type integer;
+       struct {
+               enum ustctl_string_encodings encoding;
+       } string;
+       struct ustctl_float_type _float;
+       char padding[USTCTL_UST_BASIC_TYPE_PADDING];
+} LTTNG_PACKED;
+
+struct ustctl_basic_type {
+       enum ustctl_abstract_types atype;
+       union {
+               union _ustctl_basic_type basic;
+       } u;
+} LTTNG_PACKED;
+
+#define USTCTL_UST_TYPE_PADDING        128
+struct ustctl_type {
+       enum ustctl_abstract_types atype;
+       union {
+               union _ustctl_basic_type basic;
+               struct {
+                       struct ustctl_basic_type elem_type;
+                       uint32_t length;                /* num. elems. */
+               } array;
+               struct {
+                       struct ustctl_basic_type length_type;
+                       struct ustctl_basic_type elem_type;
+               } sequence;
+               char padding[USTCTL_UST_TYPE_PADDING];
+       } u;
+} LTTNG_PACKED;
+
+#define USTCTL_UST_FIELD_PADDING       28
+struct ustctl_field {
+       char name[LTTNG_UST_SYM_NAME_LEN];
+       struct ustctl_type type;
+       char padding[USTCTL_UST_FIELD_PADDING];
+} LTTNG_PACKED;
+
+/*
+ * Returns 0 on success, negative error value on error.
+ * If an error other than -LTTNG_UST_ERR_UNSUP_MAJOR is returned,
+ * the output fields are not populated.
+ */
+int ustctl_recv_reg_msg(int sock,
+       enum ustctl_socket_type *type,
+       uint32_t *major,
+       uint32_t *minor,
+       uint32_t *pid,
+       uint32_t *ppid,
+       uint32_t *uid,
+       uint32_t *gid,
+       uint32_t *bits_per_long,
+       uint32_t *uint8_t_alignment,
+       uint32_t *uint16_t_alignment,
+       uint32_t *uint32_t_alignment,
+       uint32_t *uint64_t_alignment,
+       uint32_t *long_alignment,
+       int *byte_order,
+       char *name);    /* size LTTNG_UST_ABI_PROCNAME_LEN */
+
+/*
+ * Returns 0 on success, negative UST or system error value on error.
+ * Receive the notification command. The "notify_cmd" can then be used
+ * by the caller to find out which ustctl_recv_* function should be
+ * called to receive the notification, and which ustctl_reply_* is
+ * appropriate.
+ */
+int ustctl_recv_notify(int sock, enum ustctl_notify_cmd *notify_cmd);
+
+/*
+ * Returns 0 on success, negative UST or system error value on error.
+ */
+int ustctl_recv_register_event(int sock,
+       int *session_objd,              /* session descriptor (output) */
+       int *channel_objd,              /* channel descriptor (output) */
+       char *event_name,               /*
+                                        * event name (output,
+                                        * size LTTNG_UST_SYM_NAME_LEN)
+                                        */
+       int *loglevel,
+       char **signature,               /*
+                                        * event signature
+                                        * (output, dynamically
+                                        * allocated, must be free(3)'d
+                                        * by the caller if function
+                                        * returns success.)
+                                        */
+       size_t *nr_fields,
+       struct ustctl_field **fields,
+       char **model_emf_uri);
+
+/*
+ * Returns 0 on success, negative error value on error.
+ */
+int ustctl_reply_register_event(int sock,
+       uint32_t id,                    /* event id (input) */
+       int ret_code);                  /* return code. 0 ok, negative error */
+
+/*
+ * Returns 0 on success, negative UST or system error value on error.
+ */
+int ustctl_recv_register_channel(int sock,
+       int *session_objd,              /* session descriptor (output) */
+       int *channel_objd,              /* channel descriptor (output) */
+       size_t *nr_fields,              /* context fields */
+       struct ustctl_field **fields);
+
+/*
+ * Returns 0 on success, negative error value on error.
+ */
+int ustctl_reply_register_channel(int sock,
+       uint32_t chan_id,
+       enum ustctl_channel_header header_type,
+       int ret_code);                  /* return code. 0 ok, negative error */
+
 #endif /* _LTTNG_UST_CTL_H */
index d83ecb8c00718aec0a7daac582eff193c2a29cec..05cc3bee65e2dd61a87c3907bda010e444c85680 100644 (file)
@@ -28,8 +28,7 @@
 
 #include <limits.h>
 #include <unistd.h>
-
-#include "lttng-ust-abi.h"
+#include <lttng/ust-abi.h>
 
 /*
  * ustcomm error code.
@@ -38,10 +37,15 @@ enum lttng_ust_error_code {
        LTTNG_UST_OK = 0,                       /* Ok */
        LTTNG_UST_ERR = 1024,                   /* Unknown Error */
        LTTNG_UST_ERR_NOENT = 1025,             /* No entry */
-       LTTNG_UST_ERR_EXIST = 1026,     /* Object exists */
-       LTTNG_UST_ERR_INVAL = 1027,     /* Invalid argument */
-       LTTNG_UST_ERR_PERM  = 1028,     /* Permission denied */
-       LTTNG_UST_ERR_NOSYS = 1029,     /* Not implemented */
+       LTTNG_UST_ERR_EXIST = 1026,             /* Object exists */
+       LTTNG_UST_ERR_INVAL = 1027,             /* Invalid argument */
+       LTTNG_UST_ERR_PERM  = 1028,             /* Permission denied */
+       LTTNG_UST_ERR_NOSYS = 1029,             /* Not implemented */
+       LTTNG_UST_ERR_EXITING = 1030,           /* Process is exiting */
+
+       LTTNG_UST_ERR_INVAL_MAGIC = 1031,       /* Invalid magic number */
+       LTTNG_UST_ERR_INVAL_SOCKET_TYPE = 1032, /* Invalid socket type */
+       LTTNG_UST_ERR_UNSUP_MAJOR = 1033,       /* Unsupported major version */
 
        /* MUST be last element */
        LTTNG_UST_ERR_NR,                       /* Last element */
index f7bb53ef7ead038e479964b6e11bb2259eeb1cd7..f57a5c911d11095a7efbdc1a5ad8a87d400f3d9f 100644 (file)
@@ -45,6 +45,7 @@
 #include <common/utils.h>
 
 #include "lttng-sessiond.h"
+#include "buffer-registry.h"
 #include "channel.h"
 #include "cmd.h"
 #include "consumer.h"
@@ -435,6 +436,7 @@ static void cleanup(void)
 
        DBG("Closing all UST sockets");
        ust_app_clean_list();
+       buffer_reg_destroy_registries();
 
        if (is_root && !opt_no_kernel) {
                DBG2("Closing kernel fd");
@@ -1299,6 +1301,7 @@ static void *thread_dispatch_ust_registration(void *data)
 
                do {
                        struct ust_app *app = NULL;
+                       ust_cmd = NULL;
 
                        /* Dequeue command for registration */
                        node = cds_wfq_dequeue_blocking(&ust_cmd_queue.queue);
@@ -1321,6 +1324,7 @@ static void *thread_dispatch_ust_registration(void *data)
                                wait_node = zmalloc(sizeof(*wait_node));
                                if (!wait_node) {
                                        PERROR("zmalloc wait_node dispatch");
+                                       free(ust_cmd);
                                        goto error;
                                }
                                CDS_INIT_LIST_HEAD(&wait_node->head);
@@ -1335,6 +1339,7 @@ static void *thread_dispatch_ust_registration(void *data)
                                        }
                                        lttng_fd_put(1, LTTNG_FD_APPS);
                                        free(wait_node);
+                                       free(ust_cmd);
                                        continue;
                                }
                                /*
@@ -1343,6 +1348,7 @@ static void *thread_dispatch_ust_registration(void *data)
                                 */
                                cds_list_add(&wait_node->head, &wait_queue);
 
+                               free(ust_cmd);
                                /*
                                 * We have to continue here since we don't have the notify
                                 * socket and the application MUST be added to the hash table
@@ -1365,6 +1371,7 @@ static void *thread_dispatch_ust_registration(void *data)
                                                break;
                                        }
                                }
+                               free(ust_cmd);
                        }
 
                        if (app) {
@@ -1433,7 +1440,6 @@ static void *thread_dispatch_ust_registration(void *data)
                                }
                                lttng_fd_put(1, LTTNG_FD_APPS);
                        }
-                       free(ust_cmd);
                } while (node != NULL);
 
                /* Futex wait on queue. Blocking call on futex() */
@@ -2610,13 +2616,13 @@ skip_domain:
        }
        case LTTNG_ENABLE_CHANNEL:
        {
-               ret = cmd_enable_channel(cmd_ctx->session, cmd_ctx->lsm->domain.type,
+               ret = cmd_enable_channel(cmd_ctx->session, &cmd_ctx->lsm->domain,
                                &cmd_ctx->lsm->u.channel.chan, kernel_poll_pipe[1]);
                break;
        }
        case LTTNG_ENABLE_EVENT:
        {
-               ret = cmd_enable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type,
+               ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain,
                                cmd_ctx->lsm->u.enable.channel_name,
                                &cmd_ctx->lsm->u.enable.event, NULL, kernel_poll_pipe[1]);
                break;
@@ -2625,7 +2631,7 @@ skip_domain:
        {
                DBG("Enabling all events");
 
-               ret = cmd_enable_event_all(cmd_ctx->session, cmd_ctx->lsm->domain.type,
+               ret = cmd_enable_event_all(cmd_ctx->session, &cmd_ctx->lsm->domain,
                                cmd_ctx->lsm->u.enable.channel_name,
                                cmd_ctx->lsm->u.enable.event.type, NULL, kernel_poll_pipe[1]);
                break;
@@ -2974,7 +2980,7 @@ skip_domain:
                        goto error;
                }
 
-               ret = cmd_enable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type,
+               ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain,
                                cmd_ctx->lsm->u.enable.channel_name,
                                &cmd_ctx->lsm->u.enable.event, bytecode, kernel_poll_pipe[1]);
                break;
@@ -4217,6 +4223,10 @@ int main(int argc, char **argv)
                goto exit;
        }
 
+       /* Initialize global buffer per UID and PID registry. */
+       buffer_reg_init_uid_registry();
+       buffer_reg_init_pid_registry();
+
        /* Init UST command queue. */
        cds_wfq_init(&ust_cmd_queue.queue);
 
index d49cf430ac627379459911928f4dc40d63add329..fd23ab05ed90bb422779446d7dd3961bc862f1da 100644 (file)
@@ -21,7 +21,8 @@
 #include <urcu/list.h>
 
 #include "trace-kernel.h"
-#include "trace-ust.h"
+
+struct ltt_ust_session;
 
 /*
  * Tracing session list
index 97a9c77e81f6974625877c67b4e125fde692d9e4..8f15a1576a68375277609e0ffd50642d0fd4eb3c 100644 (file)
@@ -24,6 +24,7 @@
 #include <common/common.h>
 #include <common/defaults.h>
 
+#include "buffer-registry.h"
 #include "trace-ust.h"
 
 /*
@@ -195,9 +196,17 @@ struct ltt_ust_session *trace_ust_create_session(char *path,
        lus->id = session_id;
        lus->start_trace = 0;
 
-       /* Alloc UST domain hash tables */
-       lus->domain_pid = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
-       lus->domain_exec = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+       /*
+        * Default buffer type. This can be changed through an enable channel
+        * requesting a different type. Note that this can only be changed once
+        * during the session lifetime which is at the first enable channel and
+        * only before start. The flag buffer_type_changed indicates the status.
+        */
+       lus->buffer_type = LTTNG_BUFFER_PER_PID;
+       /* Once set to 1, the buffer_type is immutable for the session. */
+       lus->buffer_type_changed = 0;
+       /* Init it in case it get used after allocation. */
+       CDS_INIT_LIST_HEAD(&lus->buffer_reg_uid_list);
 
        /* Alloc UST global domain channels' HT */
        lus->domain_global.channels = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
@@ -225,14 +234,6 @@ struct ltt_ust_session *trace_ust_create_session(char *path,
                        PERROR("snprintf UST consumer trace path");
                        goto error_path;
                }
-
-               /* Set session path */
-               ret = snprintf(lus->pathname, PATH_MAX, "%s" DEFAULT_UST_TRACE_DIR,
-                               path);
-               if (ret < 0) {
-                       PERROR("snprintf kernel traces path");
-                       goto error_path;
-               }
        }
 
        DBG2("UST trace session create successful");
@@ -243,8 +244,6 @@ error_path:
        consumer_destroy_output(lus->consumer);
 error_consumer:
        lttng_ht_destroy(lus->domain_global.channels);
-       lttng_ht_destroy(lus->domain_exec);
-       lttng_ht_destroy(lus->domain_pid);
        free(lus);
 error:
        return NULL;
@@ -258,7 +257,6 @@ error:
 struct ltt_ust_channel *trace_ust_create_channel(struct lttng_channel *chan,
                char *path)
 {
-       int ret;
        struct ltt_ust_channel *luc;
 
        assert(chan);
@@ -295,23 +293,10 @@ struct ltt_ust_channel *trace_ust_create_channel(struct lttng_channel *chan,
        luc->events = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
        luc->ctx = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
 
-       /* Set trace output path */
-       ret = snprintf(luc->pathname, PATH_MAX, "%s", path);
-       if (ret < 0) {
-               PERROR("asprintf ust create channel");
-               goto error_free_channel;
-       }
-
        DBG2("Trace UST channel %s created", luc->name);
 
-       return luc;
-
-error_free_channel:
-       lttng_ht_destroy(luc->ctx);
-       lttng_ht_destroy(luc->events);
-       free(luc);
 error:
-       return NULL;
+       return luc;
 }
 
 /*
@@ -629,46 +614,6 @@ static void destroy_channels(struct lttng_ht *channels)
        rcu_read_unlock();
 }
 
-/*
- * Cleanup UST pid domain.
- */
-static void destroy_domain_pid(struct lttng_ht *ht)
-{
-       int ret;
-       struct lttng_ht_iter iter;
-       struct ltt_ust_domain_pid *dpid;
-
-       assert(ht);
-
-       cds_lfht_for_each_entry(ht->ht, &iter.iter, dpid, node.node) {
-               ret = lttng_ht_del(ht , &iter);
-               assert(!ret);
-               destroy_channels(dpid->channels);
-       }
-
-       lttng_ht_destroy(ht);
-}
-
-/*
- * Cleanup UST exec name domain.
- */
-static void destroy_domain_exec(struct lttng_ht *ht)
-{
-       int ret;
-       struct lttng_ht_iter iter;
-       struct ltt_ust_domain_exec *dexec;
-
-       assert(ht);
-
-       cds_lfht_for_each_entry(ht->ht, &iter.iter, dexec, node.node) {
-               ret = lttng_ht_del(ht , &iter);
-               assert(!ret);
-               destroy_channels(dexec->channels);
-       }
-
-       lttng_ht_destroy(ht);
-}
-
 /*
  * Cleanup UST global domain.
  */
@@ -684,6 +629,8 @@ static void destroy_domain_global(struct ltt_ust_domain_global *dom)
  */
 void trace_ust_destroy_session(struct ltt_ust_session *session)
 {
+       struct buffer_reg_uid *reg, *sreg;
+
        assert(session);
 
        rcu_read_lock();
@@ -692,8 +639,14 @@ void trace_ust_destroy_session(struct ltt_ust_session *session)
 
        /* Cleaning up UST domain */
        destroy_domain_global(&session->domain_global);
-       destroy_domain_pid(session->domain_pid);
-       destroy_domain_exec(session->domain_exec);
+
+       /* Cleanup UID buffer registry object(s). */
+       cds_list_for_each_entry_safe(reg, sreg, &session->buffer_reg_uid_list,
+                       lnode) {
+               cds_list_del(&reg->lnode);
+               buffer_reg_uid_remove(reg);
+               buffer_reg_uid_destroy(reg, session->consumer);
+       }
 
        consumer_destroy_output(session->consumer);
        consumer_destroy_output(session->tmp_consumer);
index f5fa092629d60e7030ac0b92aba0d943228268ab..87fe412d6b862ed0c5eed27af988c55affbdabbd 100644 (file)
@@ -51,6 +51,7 @@ struct ltt_ust_event {
 
 /* UST channel */
 struct ltt_ust_channel {
+       uint64_t id;    /* unique id per session. */
        unsigned int enabled;
        char name[LTTNG_UST_SYM_NAME_LEN];
        char pathname[PATH_MAX];
@@ -72,20 +73,7 @@ struct ltt_ust_metadata {
 /* UST domain global (LTTNG_DOMAIN_UST) */
 struct ltt_ust_domain_global {
        struct lttng_ht *channels;
-};
-
-/* UST domain pid (LTTNG_DOMAIN_UST_PID) */
-struct ltt_ust_domain_pid {
-       pid_t pid;
-       struct lttng_ht *channels;
-       struct lttng_ht_node_ulong node;
-};
-
-/* UST domain exec name (LTTNG_DOMAIN_UST_EXEC_NAME) */
-struct ltt_ust_domain_exec {
-       char exec_name[LTTNG_UST_SYM_NAME_LEN];
-       struct lttng_ht *channels;
-       struct lttng_ht_node_str node;
+       struct cds_list_head registry_buffer_uid_list;
 };
 
 /* UST session */
@@ -94,13 +82,6 @@ struct ltt_ust_session {
        int start_trace;
        char pathname[PATH_MAX];
        struct ltt_ust_domain_global domain_global;
-       /*
-        * Those two hash tables contains data for a specific UST domain and each
-        * contains a HT of channels. See ltt_ust_domain_exec and
-        * ltt_ust_domain_pid data structures.
-        */
-       struct lttng_ht *domain_pid;
-       struct lttng_ht *domain_exec;
        /* UID/GID of the user owning the session */
        uid_t uid;
        gid_t gid;
@@ -114,8 +95,47 @@ struct ltt_ust_session {
        struct consumer_output *tmp_consumer;
        /* Sequence number for filters so the tracer knows the ordering. */
        uint64_t filter_seq_num;
+       /* This indicates which type of buffer this session is set for. */
+       enum lttng_buffer_type buffer_type;
+       /* If set to 1, the buffer_type can not be changed anymore. */
+       int buffer_type_changed;
+       /* For per UID buffer, every buffer reg object is kept of this session */
+       struct cds_list_head buffer_reg_uid_list;
+       /* Next channel ID available for a newly registered channel. */
+       uint64_t next_channel_id;
+       /* Once this value reaches UINT32_MAX, no more id can be allocated. */
+       uint64_t used_channel_id;
 };
 
+/*
+ * Validate that the id has reached the maximum allowed or not.
+ *
+ * Return 0 if NOT else 1.
+ */
+static inline int trace_ust_is_max_id(uint64_t id)
+{
+       return (id == UINT64_MAX) ? 1 : 0;
+}
+
+/*
+ * Return next available channel id and increment the used counter. The
+ * trace_ust_is_max_id function MUST be called before in order to validate if
+ * the maximum number of IDs have been reached. If not, it is safe to call this
+ * function.
+ *
+ * Return a unique channel ID. If max is reached, the used_channel_id counter
+ * is returned.
+ */
+static inline uint64_t trace_ust_get_next_chan_id(struct ltt_ust_session *s)
+{
+       if (trace_ust_is_max_id(s->used_channel_id)) {
+               return s->used_channel_id;
+       }
+
+       s->used_channel_id++;
+       return s->next_channel_id++;
+}
+
 #ifdef HAVE_LIBLTTNG_UST_CTL
 
 int trace_ust_ht_match_event(struct cds_lfht_node *node, const void *_key);
index cef02ae298ce368780c4bf1b64ed72f64ff73783..9250433ab1573b4d3534caf677e0bf817fe0c658 100644 (file)
@@ -17,6 +17,7 @@
 
 #define _GNU_SOURCE
 #include <errno.h>
+#include <inttypes.h>
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -30,6 +31,7 @@
 #include <common/common.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 
+#include "buffer-registry.h"
 #include "fd-limit.h"
 #include "health.h"
 #include "ust-app.h"
@@ -38,6 +40,7 @@
 
 /* Next available channel key. */
 static unsigned long next_channel_key;
+static unsigned long next_session_id;
 
 /*
  * Return the atomically incremented value of next_channel_key.
@@ -48,38 +51,11 @@ static inline unsigned long get_next_channel_key(void)
 }
 
 /*
- * Return the consumer socket from the given consumer output with the right
- * bitness. On error, returns NULL.
- *
- * The caller MUST acquire a rcu read side lock and keep it until the socket
- * object reference is not needed anymore.
+ * Return the atomically incremented value of next_session_id.
  */
-static struct consumer_socket *find_consumer_socket_by_bitness(int bits,
-               struct consumer_output *consumer)
+static inline unsigned long get_next_session_id(void)
 {
-       int consumer_fd;
-       struct consumer_socket *socket = NULL;
-
-       switch (bits) {
-       case 64:
-               consumer_fd = uatomic_read(&ust_consumerd64_fd);
-               break;
-       case 32:
-               consumer_fd = uatomic_read(&ust_consumerd32_fd);
-               break;
-       default:
-               assert(0);
-               goto end;
-       }
-
-       socket = consumer_find_socket(consumer_fd, consumer);
-       if (!socket) {
-               ERR("Consumer socket fd %d not found in consumer obj %p",
-                               consumer_fd, consumer);
-       }
-
-end:
-       return socket;
+       return uatomic_add_return(&next_session_id, 1);
 }
 
 /*
@@ -190,6 +166,48 @@ static void close_notify_sock_rcu(struct rcu_head *head)
        free(obj);
 }
 
+/*
+ * Return the session registry according to the buffer type of the given
+ * session.
+ *
+ * A registry per UID object MUST exists before calling this function or else
+ * it assert() if not found. RCU read side lock must be acquired.
+ */
+static struct ust_registry_session *get_session_registry(
+               struct ust_app_session *ua_sess)
+{
+       struct ust_registry_session *registry = NULL;
+
+       assert(ua_sess);
+
+       switch (ua_sess->buffer_type) {
+       case LTTNG_BUFFER_PER_PID:
+       {
+               struct buffer_reg_pid *reg_pid = buffer_reg_pid_find(ua_sess->id);
+               if (!reg_pid) {
+                       goto error;
+               }
+               registry = reg_pid->registry->reg.ust;
+               break;
+       }
+       case LTTNG_BUFFER_PER_UID:
+       {
+               struct buffer_reg_uid *reg_uid = buffer_reg_uid_find(
+                               ua_sess->tracing_id, ua_sess->bits_per_long, ua_sess->uid);
+               if (!reg_uid) {
+                       goto error;
+               }
+               registry = reg_uid->registry->reg.ust;
+               break;
+       }
+       default:
+               assert(0);
+       };
+
+error:
+       return registry;
+}
+
 /*
  * Delete ust context safely. RCU read lock must be held before calling
  * this function.
@@ -237,13 +255,13 @@ void delete_ust_app_event(int sock, struct ust_app_event *ua_event)
 }
 
 /*
- * Delete ust app stream safely. RCU read lock must be held before calling
- * this function.
+ * Release ust data object of the given stream.
+ *
+ * Return 0 on success or else a negative value.
  */
-static
-void delete_ust_app_stream(int sock, struct ust_app_stream *stream)
+static int release_ust_app_stream(int sock, struct ust_app_stream *stream)
 {
-       int ret;
+       int ret = 0;
 
        assert(stream);
 
@@ -256,6 +274,20 @@ void delete_ust_app_stream(int sock, struct ust_app_stream *stream)
                lttng_fd_put(LTTNG_FD_APPS, 2);
                free(stream->obj);
        }
+
+       return ret;
+}
+
+/*
+ * Delete ust app stream safely. RCU read lock must be held before calling
+ * this function.
+ */
+static
+void delete_ust_app_stream(int sock, struct ust_app_stream *stream)
+{
+       assert(stream);
+
+       (void) release_ust_app_stream(sock, stream);
        free(stream);
 }
 
@@ -272,6 +304,7 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan,
        struct ust_app_event *ua_event;
        struct ust_app_ctx *ua_ctx;
        struct ust_app_stream *stream, *stmp;
+       struct ust_registry_session *registry;
 
        assert(ua_chan);
 
@@ -301,7 +334,10 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan,
        lttng_ht_destroy(ua_chan->events);
 
        /* Wipe and free registry from session registry. */
-       ust_registry_channel_del_free(ua_chan->session->registry, ua_chan->key);
+       registry = get_session_registry(ua_chan->session);
+       if (registry) {
+               ust_registry_channel_del_free(registry, ua_chan->key);
+       }
 
        if (ua_chan->obj != NULL) {
                /* Remove channel from application UST object descriptor. */
@@ -312,7 +348,7 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan,
                        ERR("UST app sock %d release channel obj failed with ret %d",
                                        sock, ret);
                }
-               lttng_fd_put(LTTNG_FD_APPS, 2);
+               lttng_fd_put(LTTNG_FD_APPS, 1);
                free(ua_chan->obj);
        }
        free(ua_chan);
@@ -324,27 +360,31 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan,
  *
  * Return 0 on success else a negative error.
  */
-static int push_metadata(struct ust_app *app, struct ust_app_session *ua_sess)
+static int push_metadata(struct ust_registry_session *registry,
+               struct consumer_output *consumer)
 {
        int ret;
        char *metadata_str = NULL;
        size_t len, offset;
        struct consumer_socket *socket;
 
-       assert(app);
-       assert(ua_sess);
+       assert(registry);
+       assert(consumer);
+
+       rcu_read_lock();
 
-       if (!ua_sess->consumer || !ua_sess->metadata) {
-               /* No consumer means no stream associated so just return gracefully. */
+       /*
+        * Means that no metadata was assigned to the session. This can happens if
+        * no start has been done previously.
+        */
+       if (!registry->metadata_key) {
                ret = 0;
-               goto end;
+               goto error_rcu_unlock;
        }
 
-       rcu_read_lock();
-
        /* Get consumer socket to use to push the metadata.*/
-       socket = find_consumer_socket_by_bitness(app->bits_per_long,
-                       ua_sess->consumer);
+       socket = consumer_find_socket_by_bitness(registry->bits_per_long,
+                       consumer);
        if (!socket) {
                ret = -1;
                goto error_rcu_unlock;
@@ -361,13 +401,13 @@ static int push_metadata(struct ust_app *app, struct ust_app_session *ua_sess)
         * ability to reorder the metadata it receives.
         */
        pthread_mutex_lock(socket->lock);
-       pthread_mutex_lock(&ua_sess->registry->lock);
+       pthread_mutex_lock(&registry->lock);
 
-       offset = ua_sess->registry->metadata_len_sent;
-       len = ua_sess->registry->metadata_len -
-               ua_sess->registry->metadata_len_sent;
+       offset = registry->metadata_len_sent;
+       len = registry->metadata_len - registry->metadata_len_sent;
        if (len == 0) {
-               DBG3("No metadata to push for session id %d", ua_sess->id);
+               DBG3("No metadata to push for metadata key %" PRIu64,
+                               registry->metadata_key);
                ret = 0;
                goto error_reg_unlock;
        }
@@ -381,21 +421,21 @@ static int push_metadata(struct ust_app *app, struct ust_app_session *ua_sess)
                goto error_reg_unlock;
        }
        /* Copy what we haven't send out. */
-       memcpy(metadata_str, ua_sess->registry->metadata + offset, len);
+       memcpy(metadata_str, registry->metadata + offset, len);
 
-       pthread_mutex_unlock(&ua_sess->registry->lock);
+       pthread_mutex_unlock(&registry->lock);
 
-       ret = ust_consumer_push_metadata(socket, ua_sess, metadata_str, len,
-                       offset);
+       ret = consumer_push_metadata(socket, registry->metadata_key,
+                       metadata_str, len, offset);
        if (ret < 0) {
                pthread_mutex_unlock(socket->lock);
                goto error_rcu_unlock;
        }
 
        /* Update len sent of the registry. */
-       pthread_mutex_lock(&ua_sess->registry->lock);
-       ua_sess->registry->metadata_len_sent += len;
-       pthread_mutex_unlock(&ua_sess->registry->lock);
+       pthread_mutex_lock(&registry->lock);
+       registry->metadata_len_sent += len;
+       pthread_mutex_unlock(&registry->lock);
        pthread_mutex_unlock(socket->lock);
 
        rcu_read_unlock();
@@ -403,12 +443,11 @@ static int push_metadata(struct ust_app *app, struct ust_app_session *ua_sess)
        return 0;
 
 error_reg_unlock:
-       pthread_mutex_unlock(&ua_sess->registry->lock);
+       pthread_mutex_unlock(&registry->lock);
        pthread_mutex_unlock(socket->lock);
 error_rcu_unlock:
        rcu_read_unlock();
        free(metadata_str);
-end:
        return ret;
 }
 
@@ -420,42 +459,40 @@ end:
  *
  * Return 0 on success else a negative value.
  */
-static int close_metadata(struct ust_app *app, struct ust_app_session *ua_sess)
+static int close_metadata(struct ust_registry_session *registry,
+               struct consumer_output *consumer)
 {
        int ret;
        struct consumer_socket *socket;
 
-       assert(app);
-       assert(ua_sess);
+       assert(registry);
+       assert(consumer);
+
+       rcu_read_lock();
 
-       /* Ignore if no metadata. Valid since it can be called on unregister. */
-       if (!ua_sess->metadata) {
+       if (!registry->metadata_key || registry->metadata_closed) {
                ret = 0;
                goto error;
        }
 
-       rcu_read_lock();
-
        /* Get consumer socket to use to push the metadata.*/
-       socket = find_consumer_socket_by_bitness(app->bits_per_long,
-                       ua_sess->consumer);
+       socket = consumer_find_socket_by_bitness(registry->bits_per_long,
+                       consumer);
        if (!socket) {
                ret = -1;
-               goto error_rcu_unlock;
+               goto error;
        }
 
-       ret = ust_consumer_close_metadata(socket, ua_sess->metadata);
+       ret = consumer_close_metadata(socket, registry->metadata_key);
        if (ret < 0) {
-               goto error_rcu_unlock;
+               goto error;
        }
 
-error_rcu_unlock:
-       /* Destroy metadata on our side since we must not use it anymore. */
-       delete_ust_app_channel(-1, ua_sess->metadata, app);
-       ua_sess->metadata = NULL;
+       /* Metadata successfully closed. Flag the registry. */
+       registry->metadata_closed = 1;
 
-       rcu_read_unlock();
 error:
+       rcu_read_unlock();
        return ret;
 }
 
@@ -470,15 +507,23 @@ void delete_ust_app_session(int sock, struct ust_app_session *ua_sess,
        int ret;
        struct lttng_ht_iter iter;
        struct ust_app_channel *ua_chan;
+       struct ust_registry_session *registry;
 
        assert(ua_sess);
 
-       if (ua_sess->metadata) {
+       registry = get_session_registry(ua_sess);
+       if (registry) {
                /* Push metadata for application before freeing the application. */
-               (void) push_metadata(app, ua_sess);
+               (void) push_metadata(registry, ua_sess->consumer);
 
-               /* And ask to close it for this session. */
-               (void) close_metadata(app, ua_sess);
+               /*
+                * Don't ask to close metadata for global per UID buffers. Close
+                * metadata only on destroy trace session in this case.
+                */
+               if (ua_sess->buffer_type != LTTNG_BUFFER_PER_UID) {
+                       /* And ask to close it for this session registry. */
+                       (void) close_metadata(registry, ua_sess->consumer);
+               }
        }
 
        cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, ua_chan,
@@ -489,8 +534,14 @@ void delete_ust_app_session(int sock, struct ust_app_session *ua_sess,
        }
        lttng_ht_destroy(ua_sess->channels);
 
-       ust_registry_session_destroy(ua_sess->registry);
-       free(ua_sess->registry);
+       /* In case of per PID, the registry is kept in the session. */
+       if (ua_sess->buffer_type == LTTNG_BUFFER_PER_PID) {
+               struct buffer_reg_pid *reg_pid = buffer_reg_pid_find(ua_sess->id);
+               if (reg_pid) {
+                       buffer_reg_pid_remove(reg_pid);
+                       buffer_reg_pid_destroy(reg_pid);
+               }
+       }
 
        if (ua_sess->handle != -1) {
                ret = ustctl_release_handle(sock, ua_sess->handle);
@@ -526,6 +577,7 @@ void delete_ust_app(struct ust_app *app)
                /* Free every object in the session and the session. */
                delete_ust_app_session(sock, ua_sess, app);
        }
+       lttng_ht_destroy(app->ust_objd);
 
        /*
         * Wait until we have deleted the application from the sock hash table
@@ -612,21 +664,9 @@ struct ust_app_session *alloc_ust_app_session(struct ust_app *app)
        ua_sess->handle = -1;
        ua_sess->channels = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
        pthread_mutex_init(&ua_sess->lock, NULL);
-       if (ust_registry_session_init(&ua_sess->registry, app,
-                       app->bits_per_long,
-                       app->uint8_t_alignment,
-                       app->uint16_t_alignment,
-                       app->uint32_t_alignment,
-                       app->uint64_t_alignment,
-                       app->long_alignment,
-                       app->byte_order)) {
-               goto error;
-       }
 
        return ua_sess;
 
-error:
-       free(ua_sess);
 error_free:
        return NULL;
 }
@@ -662,11 +702,6 @@ struct ust_app_channel *alloc_ust_app_channel(char *name,
 
        CDS_INIT_LIST_HEAD(&ua_chan->streams.head);
 
-       /* Add a channel registry to session. */
-       if (ust_registry_channel_add(ua_sess->registry, ua_chan->key) < 0) {
-               goto error;
-       }
-
        /* Copy attributes */
        if (attr) {
                /* Translate from lttng_ust_channel to ustctl_consumer_channel_attr. */
@@ -1065,69 +1100,24 @@ error:
 }
 
 /*
- * Create the specified channel onto the UST tracer for a UST session. This
- * MUST be called with UST app session lock held.
+ * Send channel and stream buffer to application.
  *
  * Return 0 on success. On error, a negative value is returned.
  */
-static int create_ust_channel(struct ust_app *app,
-               struct ust_app_session *ua_sess, struct ust_app_channel *ua_chan,
-               struct consumer_output *consumer)
+static int send_channel_pid_to_ust(struct ust_app *app,
+               struct ust_app_session *ua_sess, struct ust_app_channel *ua_chan)
 {
        int ret;
-       unsigned int nb_fd = 0;
-       struct consumer_socket *socket;
        struct ust_app_stream *stream, *stmp;
 
        assert(app);
        assert(ua_sess);
        assert(ua_chan);
-       assert(consumer);
-
-       rcu_read_lock();
-       health_code_update();
-
-       /* Get the right consumer socket for the application. */
-       socket = find_consumer_socket_by_bitness(app->bits_per_long, consumer);
-       if (!socket) {
-               ret = -1;
-               goto error;
-       }
-
-       health_code_update();
-
-       /*
-        * Ask consumer to create channel. The consumer will return the number of
-        * stream we have to expect.
-        */
-       ret = ust_consumer_ask_channel(ua_sess, ua_chan, consumer, socket);
-       if (ret < 0) {
-               goto error;
-       }
-
-       /*
-        * Compute the number of fd needed before receiving them. It must be 2 per
-        * stream (2 being the default value here).
-        */
-       nb_fd = DEFAULT_UST_STREAM_FD_NUM * ua_chan->expected_stream_count;
-
-       /* Reserve the amount of file descriptor we need. */
-       ret = lttng_fd_get(LTTNG_FD_APPS, nb_fd);
-       if (ret < 0) {
-               ERR("Exhausted number of available FD upon create channel");
-               goto error_fd_get;
-       }
 
        health_code_update();
 
-       /*
-        * Now get the channel from the consumer. This call wil populate the stream
-        * list of that channel and set the ust object.
-        */
-       ret = ust_consumer_get_channel(socket, ua_chan);
-       if (ret < 0) {
-               goto error_destroy;
-       }
+       DBG("UST app sending channel %s to UST app sock %d", ua_chan->name,
+                       app->sock);
 
        /* Send channel to the application. */
        ret = ust_consumer_send_channel_to_ust(app, ua_sess, ua_chan);
@@ -1147,39 +1137,11 @@ static int create_ust_channel(struct ust_app *app,
                cds_list_del(&stream->list);
                delete_ust_app_stream(-1, stream);
        }
-
        /* Flag the channel that it is sent to the application. */
        ua_chan->is_sent = 1;
-       /* Initialize ust objd object using the received handle and add it. */
-       lttng_ht_node_init_ulong(&ua_chan->ust_objd_node, ua_chan->handle);
-       lttng_ht_add_unique_ulong(app->ust_objd, &ua_chan->ust_objd_node);
-
-       health_code_update();
-
-       /* If channel is not enabled, disable it on the tracer */
-       if (!ua_chan->enabled) {
-               ret = disable_ust_channel(app, ua_sess, ua_chan);
-               if (ret < 0) {
-                       goto error;
-               }
-       }
 
-       rcu_read_unlock();
-       return 0;
-
-error_destroy:
-       lttng_fd_put(LTTNG_FD_APPS, nb_fd);
-error_fd_get:
-       /*
-        * Initiate a destroy channel on the consumer since we had an error
-        * handling it on our side. The return value is of no importance since we
-        * already have a ret value set by the previous error that we need to
-        * return.
-        */
-       (void) ust_consumer_destroy_channel(socket, ua_chan);
 error:
        health_code_update();
-       rcu_read_unlock();
        return ret;
 }
 
@@ -1304,6 +1266,7 @@ static void shadow_copy_channel(struct ust_app_channel *ua_chan,
         */
 
        ua_chan->enabled = uchan->enabled;
+       ua_chan->tracing_channel_id = uchan->id;
 
        cds_lfht_for_each_entry(uchan->ctx->ht, &iter.iter, uctx, node.node) {
                ua_ctx = alloc_ust_app_ctx(&uctx->ctx);
@@ -1356,20 +1319,37 @@ static void shadow_copy_session(struct ust_app_session *ua_sess,
 
        DBG2("Shadow copy of session handle %d", ua_sess->handle);
 
-       ua_sess->id = usess->id;
-       ua_sess->uid = usess->uid;
-       ua_sess->gid = usess->gid;
-
-       ret = snprintf(ua_sess->path, PATH_MAX, "%s-%d-%s/", app->name, app->pid,
-                       datetime);
+       ua_sess->tracing_id = usess->id;
+       ua_sess->id = get_next_session_id();
+       ua_sess->uid = app->uid;
+       ua_sess->gid = app->gid;
+       ua_sess->euid = usess->uid;
+       ua_sess->egid = usess->gid;
+       ua_sess->buffer_type = usess->buffer_type;
+       ua_sess->bits_per_long = app->bits_per_long;
+       /* There is only one consumer object per session possible. */
+       ua_sess->consumer = usess->consumer;
+
+       switch (ua_sess->buffer_type) {
+       case LTTNG_BUFFER_PER_PID:
+               ret = snprintf(ua_sess->path, sizeof(ua_sess->path),
+                               DEFAULT_UST_TRACE_PID_PATH "/%s-%d-%s/", app->name, app->pid,
+                               datetime);
+               break;
+       case LTTNG_BUFFER_PER_UID:
+               ret = snprintf(ua_sess->path, sizeof(ua_sess->path),
+                               DEFAULT_UST_TRACE_UID_PATH, ua_sess->uid, app->bits_per_long);
+               break;
+       default:
+               assert(0);
+               goto error;
+       }
        if (ret < 0) {
                PERROR("asprintf UST shadow copy session");
-               /* TODO: We cannot return an error from here.. */
                assert(0);
+               goto error;
        }
 
-       /* TODO: support all UST domain */
-
        /* Iterate over all channels in global domain. */
        cds_lfht_for_each_entry(usess->domain_global.channels->ht, &iter.iter,
                        uchan, node.node) {
@@ -1399,6 +1379,9 @@ static void shadow_copy_session(struct ust_app_session *ua_sess,
 
                lttng_ht_add_unique_str(ua_sess->channels, &ua_chan->node);
        }
+
+error:
+       return;
 }
 
 /*
@@ -1434,6 +1417,115 @@ error:
        return NULL;
 }
 
+/*
+ * Setup buffer registry per PID for the given session and application. If none
+ * is found, a new one is created, added to the global registry and
+ * initialized. If regp is valid, it's set with the newly created object.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int setup_buffer_reg_pid(struct ust_app_session *ua_sess,
+               struct ust_app *app, struct buffer_reg_pid **regp)
+{
+       int ret = 0;
+       struct buffer_reg_pid *reg_pid;
+
+       assert(ua_sess);
+       assert(app);
+
+       rcu_read_lock();
+
+       reg_pid = buffer_reg_pid_find(ua_sess->id);
+       if (!reg_pid) {
+               /*
+                * This is the create channel path meaning that if there is NO
+                * registry available, we have to create one for this session.
+                */
+               ret = buffer_reg_pid_create(ua_sess->id, &reg_pid);
+               if (ret < 0) {
+                       goto error;
+               }
+               buffer_reg_pid_add(reg_pid);
+       } else {
+               goto end;
+       }
+
+       /* Initialize registry. */
+       ret = ust_registry_session_init(&reg_pid->registry->reg.ust, app,
+                       app->bits_per_long, app->uint8_t_alignment,
+                       app->uint16_t_alignment, app->uint32_t_alignment,
+                       app->uint64_t_alignment, app->long_alignment, app->byte_order);
+       if (ret < 0) {
+               goto error;
+       }
+
+       DBG3("UST app buffer registry per PID created successfully");
+
+end:
+       if (regp) {
+               *regp = reg_pid;
+       }
+error:
+       rcu_read_unlock();
+       return ret;
+}
+
+/*
+ * Setup buffer registry per UID for the given session and application. If none
+ * is found, a new one is created, added to the global registry and
+ * initialized. If regp is valid, it's set with the newly created object.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int setup_buffer_reg_uid(struct ltt_ust_session *usess,
+               struct ust_app *app, struct buffer_reg_uid **regp)
+{
+       int ret = 0;
+       struct buffer_reg_uid *reg_uid;
+
+       assert(usess);
+       assert(app);
+
+       rcu_read_lock();
+
+       reg_uid = buffer_reg_uid_find(usess->id, app->bits_per_long, app->uid);
+       if (!reg_uid) {
+               /*
+                * This is the create channel path meaning that if there is NO
+                * registry available, we have to create one for this session.
+                */
+               ret = buffer_reg_uid_create(usess->id, app->bits_per_long, app->uid,
+                               LTTNG_DOMAIN_UST, &reg_uid);
+               if (ret < 0) {
+                       goto error;
+               }
+               buffer_reg_uid_add(reg_uid);
+       } else {
+               goto end;
+       }
+
+       /* Initialize registry. */
+       ret = ust_registry_session_init(&reg_uid->registry->reg.ust, app,
+                       app->bits_per_long, app->uint8_t_alignment,
+                       app->uint16_t_alignment, app->uint32_t_alignment,
+                       app->uint64_t_alignment, app->long_alignment, app->byte_order);
+       if (ret < 0) {
+               goto error;
+       }
+       /* Add node to teardown list of the session. */
+       cds_list_add(&reg_uid->lnode, &usess->buffer_reg_uid_list);
+
+       DBG3("UST app buffer registry per UID created successfully");
+
+end:
+       if (regp) {
+               *regp = reg_uid;
+       }
+error:
+       rcu_read_unlock();
+       return ret;
+}
+
 /*
  * Create a session on the tracer side for the given app.
  *
@@ -1472,10 +1564,31 @@ static int create_ust_app_session(struct ltt_ust_session *usess,
                created = 1;
        }
 
-       health_code_update();
-
-       if (ua_sess->handle == -1) {
-               ret = ustctl_create_session(app->sock);
+       switch (usess->buffer_type) {
+       case LTTNG_BUFFER_PER_PID:
+               /* Init local registry. */
+               ret = setup_buffer_reg_pid(ua_sess, app, NULL);
+               if (ret < 0) {
+                       goto error;
+               }
+               break;
+       case LTTNG_BUFFER_PER_UID:
+               /* Look for a global registry. If none exists, create one. */
+               ret = setup_buffer_reg_uid(usess, app, NULL);
+               if (ret < 0) {
+                       goto error;
+               }
+               break;
+       default:
+               assert(0);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       health_code_update();
+
+       if (ua_sess->handle == -1) {
+               ret = ustctl_create_session(app->sock);
                if (ret < 0) {
                        if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
                                ERR("Creating session for app pid %d with ret %d",
@@ -1494,164 +1607,684 @@ static int create_ust_app_session(struct ltt_ust_session *usess,
                        goto error;
                }
 
-               ua_sess->handle = ret;
+               ua_sess->handle = ret;
+
+               /* Add ust app session to app's HT */
+               lttng_ht_node_init_ulong(&ua_sess->node,
+                               (unsigned long) ua_sess->tracing_id);
+               lttng_ht_add_unique_ulong(app->sessions, &ua_sess->node);
+
+               DBG2("UST app session created successfully with handle %d", ret);
+       }
+
+       *ua_sess_ptr = ua_sess;
+       if (is_created) {
+               *is_created = created;
+       }
+
+       /* Everything went well. */
+       ret = 0;
+
+error:
+       health_code_update();
+       return ret;
+}
+
+/*
+ * Create a context for the channel on the tracer.
+ *
+ * Called with UST app session lock held and a RCU read side lock.
+ */
+static
+int create_ust_app_channel_context(struct ust_app_session *ua_sess,
+               struct ust_app_channel *ua_chan, struct lttng_ust_context *uctx,
+               struct ust_app *app)
+{
+       int ret = 0;
+       struct lttng_ht_iter iter;
+       struct lttng_ht_node_ulong *node;
+       struct ust_app_ctx *ua_ctx;
+
+       DBG2("UST app adding context to channel %s", ua_chan->name);
+
+       lttng_ht_lookup(ua_chan->ctx, (void *)((unsigned long)uctx->ctx), &iter);
+       node = lttng_ht_iter_get_node_ulong(&iter);
+       if (node != NULL) {
+               ret = -EEXIST;
+               goto error;
+       }
+
+       ua_ctx = alloc_ust_app_ctx(uctx);
+       if (ua_ctx == NULL) {
+               /* malloc failed */
+               ret = -1;
+               goto error;
+       }
+
+       lttng_ht_node_init_ulong(&ua_ctx->node, (unsigned long) ua_ctx->ctx.ctx);
+       lttng_ht_add_unique_ulong(ua_chan->ctx, &ua_ctx->node);
+
+       ret = create_ust_channel_context(ua_chan, ua_ctx, app);
+       if (ret < 0) {
+               goto error;
+       }
+
+error:
+       return ret;
+}
+
+/*
+ * Enable on the tracer side a ust app event for the session and channel.
+ *
+ * Called with UST app session lock held.
+ */
+static
+int enable_ust_app_event(struct ust_app_session *ua_sess,
+               struct ust_app_event *ua_event, struct ust_app *app)
+{
+       int ret;
+
+       ret = enable_ust_event(app, ua_sess, ua_event);
+       if (ret < 0) {
+               goto error;
+       }
+
+       ua_event->enabled = 1;
+
+error:
+       return ret;
+}
+
+/*
+ * Disable on the tracer side a ust app event for the session and channel.
+ */
+static int disable_ust_app_event(struct ust_app_session *ua_sess,
+               struct ust_app_event *ua_event, struct ust_app *app)
+{
+       int ret;
+
+       ret = disable_ust_event(app, ua_sess, ua_event);
+       if (ret < 0) {
+               goto error;
+       }
+
+       ua_event->enabled = 0;
+
+error:
+       return ret;
+}
+
+/*
+ * Lookup ust app channel for session and disable it on the tracer side.
+ */
+static
+int disable_ust_app_channel(struct ust_app_session *ua_sess,
+               struct ust_app_channel *ua_chan, struct ust_app *app)
+{
+       int ret;
+
+       ret = disable_ust_channel(app, ua_sess, ua_chan);
+       if (ret < 0) {
+               goto error;
+       }
+
+       ua_chan->enabled = 0;
+
+error:
+       return ret;
+}
+
+/*
+ * Lookup ust app channel for session and enable it on the tracer side. This
+ * MUST be called with a RCU read side lock acquired.
+ */
+static int enable_ust_app_channel(struct ust_app_session *ua_sess,
+               struct ltt_ust_channel *uchan, struct ust_app *app)
+{
+       int ret = 0;
+       struct lttng_ht_iter iter;
+       struct lttng_ht_node_str *ua_chan_node;
+       struct ust_app_channel *ua_chan;
+
+       lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &iter);
+       ua_chan_node = lttng_ht_iter_get_node_str(&iter);
+       if (ua_chan_node == NULL) {
+               DBG2("Unable to find channel %s in ust session id %u",
+                               uchan->name, ua_sess->tracing_id);
+               goto error;
+       }
+
+       ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+
+       ret = enable_ust_channel(app, ua_sess, ua_chan);
+       if (ret < 0) {
+               goto error;
+       }
+
+error:
+       return ret;
+}
+
+/*
+ * Ask the consumer to create a channel and get it if successful.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int do_consumer_create_channel(struct ltt_ust_session *usess,
+               struct ust_app_session *ua_sess, struct ust_app_channel *ua_chan,
+               int bitness, struct ust_registry_session *registry)
+{
+       int ret;
+       unsigned int nb_fd = 0;
+       struct consumer_socket *socket;
+
+       assert(usess);
+       assert(ua_sess);
+       assert(ua_chan);
+       assert(registry);
+
+       rcu_read_lock();
+       health_code_update();
+
+       /* Get the right consumer socket for the application. */
+       socket = consumer_find_socket_by_bitness(bitness, usess->consumer);
+       if (!socket) {
+               ret = -EINVAL;
+               goto error;
+       }
+
+       health_code_update();
+
+       /* Need one fd for the channel. */
+       ret = lttng_fd_get(LTTNG_FD_APPS, 1);
+       if (ret < 0) {
+               ERR("Exhausted number of available FD upon create channel");
+               goto error;
+       }
+
+       /*
+        * Ask consumer to create channel. The consumer will return the number of
+        * stream we have to expect.
+        */
+       ret = ust_consumer_ask_channel(ua_sess, ua_chan, usess->consumer, socket,
+                       registry);
+       if (ret < 0) {
+               goto error_ask;
+       }
+
+       /*
+        * Compute the number of fd needed before receiving them. It must be 2 per
+        * stream (2 being the default value here).
+        */
+       nb_fd = DEFAULT_UST_STREAM_FD_NUM * ua_chan->expected_stream_count;
+
+       /* Reserve the amount of file descriptor we need. */
+       ret = lttng_fd_get(LTTNG_FD_APPS, nb_fd);
+       if (ret < 0) {
+               ERR("Exhausted number of available FD upon create channel");
+               goto error_fd_get_stream;
+       }
+
+       health_code_update();
+
+       /*
+        * Now get the channel from the consumer. This call wil populate the stream
+        * list of that channel and set the ust objects.
+        */
+       ret = ust_consumer_get_channel(socket, ua_chan);
+       if (ret < 0) {
+               goto error_destroy;
+       }
+
+       rcu_read_unlock();
+       return 0;
+
+error_destroy:
+       lttng_fd_put(LTTNG_FD_APPS, nb_fd);
+error_fd_get_stream:
+       /*
+        * Initiate a destroy channel on the consumer since we had an error
+        * handling it on our side. The return value is of no importance since we
+        * already have a ret value set by the previous error that we need to
+        * return.
+        */
+       (void) ust_consumer_destroy_channel(socket, ua_chan);
+error_ask:
+       lttng_fd_put(LTTNG_FD_APPS, 1);
+error:
+       health_code_update();
+       rcu_read_unlock();
+       return ret;
+}
+
+/*
+ * Duplicate the ust data object of the ust app stream and save it in the
+ * buffer registry stream.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int duplicate_stream_object(struct buffer_reg_stream *reg_stream,
+               struct ust_app_stream *stream)
+{
+       int ret;
+
+       assert(reg_stream);
+       assert(stream);
+
+       /* Reserve the amount of file descriptor we need. */
+       ret = lttng_fd_get(LTTNG_FD_APPS, 2);
+       if (ret < 0) {
+               ERR("Exhausted number of available FD upon duplicate stream");
+               goto error;
+       }
+
+       /* Duplicate object for stream once the original is in the registry. */
+       ret = ustctl_duplicate_ust_object_data(&stream->obj,
+                       reg_stream->obj.ust);
+       if (ret < 0) {
+               ERR("Duplicate stream obj from %p to %p failed with ret %d",
+                               reg_stream->obj.ust, stream->obj, ret);
+               lttng_fd_put(LTTNG_FD_APPS, 2);
+               goto error;
+       }
+       stream->handle = stream->obj->handle;
+
+error:
+       return ret;
+}
+
+/*
+ * Duplicate the ust data object of the ust app. channel and save it in the
+ * buffer registry channel.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int duplicate_channel_object(struct buffer_reg_channel *reg_chan,
+               struct ust_app_channel *ua_chan)
+{
+       int ret;
+
+       assert(reg_chan);
+       assert(ua_chan);
+
+       /* Need two fds for the channel. */
+       ret = lttng_fd_get(LTTNG_FD_APPS, 1);
+       if (ret < 0) {
+               ERR("Exhausted number of available FD upon duplicate channel");
+               goto error_fd_get;
+       }
+
+       /* Duplicate object for stream once the original is in the registry. */
+       ret = ustctl_duplicate_ust_object_data(&ua_chan->obj, reg_chan->obj.ust);
+       if (ret < 0) {
+               ERR("Duplicate channel obj from %p to %p failed with ret: %d",
+                               reg_chan->obj.ust, ua_chan->obj, ret);
+               goto error;
+       }
+       ua_chan->handle = ua_chan->obj->handle;
+
+       return 0;
+
+error:
+       lttng_fd_put(LTTNG_FD_APPS, 1);
+error_fd_get:
+       return ret;
+}
+
+/*
+ * For a given channel buffer registry, setup all streams of the given ust
+ * application channel.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int setup_buffer_reg_streams(struct buffer_reg_channel *reg_chan,
+               struct ust_app_channel *ua_chan)
+{
+       int ret = 0;
+       struct ust_app_stream *stream, *stmp;
+
+       assert(reg_chan);
+       assert(ua_chan);
+
+       DBG2("UST app setup buffer registry stream");
+
+       /* Send all streams to application. */
+       cds_list_for_each_entry_safe(stream, stmp, &ua_chan->streams.head, list) {
+               struct buffer_reg_stream *reg_stream;
+
+               ret = buffer_reg_stream_create(&reg_stream);
+               if (ret < 0) {
+                       goto error;
+               }
+
+               /*
+                * Keep original pointer and nullify it in the stream so the delete
+                * stream call does not release the object.
+                */
+               reg_stream->obj.ust = stream->obj;
+               stream->obj = NULL;
+               buffer_reg_stream_add(reg_stream, reg_chan);
+
+               /* We don't need the streams anymore. */
+               cds_list_del(&stream->list);
+               delete_ust_app_stream(-1, stream);
+       }
 
-               /* Add ust app session to app's HT */
-               lttng_ht_node_init_ulong(&ua_sess->node, (unsigned long) ua_sess->id);
-               lttng_ht_add_unique_ulong(app->sessions, &ua_sess->node);
+error:
+       return ret;
+}
 
-               DBG2("UST app session created successfully with handle %d", ret);
+/*
+ * Create a buffer registry channel for the given session registry and
+ * application channel object. If regp pointer is valid, it's set with the
+ * created object. Important, the created object is NOT added to the session
+ * registry hash table.
+ *
+ * Return 0 on success else a negative value.
+ */
+static int create_buffer_reg_channel(struct buffer_reg_session *reg_sess,
+               struct ust_app_channel *ua_chan, struct buffer_reg_channel **regp)
+{
+       int ret;
+       struct buffer_reg_channel *reg_chan = NULL;
+
+       assert(reg_sess);
+       assert(ua_chan);
+
+       DBG2("UST app creating buffer registry channel for %s", ua_chan->name);
+
+       /* Create buffer registry channel. */
+       ret = buffer_reg_channel_create(ua_chan->tracing_channel_id, &reg_chan);
+       if (ret < 0) {
+               goto error_create;
        }
+       assert(reg_chan);
+       reg_chan->consumer_key = ua_chan->key;
 
-       /*
-        * Assign consumer if not already set. For one application, there is only
-        * one possible consumer has of now.
-        */
-       if (!ua_sess->consumer) {
-               ua_sess->consumer = usess->consumer;
+       /* Create and add a channel registry to session. */
+       ret = ust_registry_channel_add(reg_sess->reg.ust,
+                       ua_chan->tracing_channel_id);
+       if (ret < 0) {
+               goto error;
        }
+       buffer_reg_channel_add(reg_sess, reg_chan);
 
-       *ua_sess_ptr = ua_sess;
-       if (is_created) {
-               *is_created = created;
+       if (regp) {
+               *regp = reg_chan;
        }
 
-       /* Everything went well. */
-       ret = 0;
+       return 0;
 
 error:
-       health_code_update();
+       /* Safe because the registry channel object was not added to any HT. */
+       buffer_reg_channel_destroy(reg_chan, LTTNG_DOMAIN_UST);
+error_create:
        return ret;
 }
 
 /*
- * Create a context for the channel on the tracer.
+ * Setup buffer registry channel for the given session registry and application
+ * channel object. If regp pointer is valid, it's set with the created object.
  *
- * Called with UST app session lock held.
+ * Return 0 on success else a negative value.
  */
-static
-int create_ust_app_channel_context(struct ust_app_session *ua_sess,
-               struct ust_app_channel *ua_chan, struct lttng_ust_context *uctx,
-               struct ust_app *app)
+static int setup_buffer_reg_channel(struct buffer_reg_session *reg_sess,
+               struct ust_app_channel *ua_chan, struct buffer_reg_channel *reg_chan)
 {
-       int ret = 0;
-       struct lttng_ht_iter iter;
-       struct lttng_ht_node_ulong *node;
-       struct ust_app_ctx *ua_ctx;
+       int ret;
 
-       DBG2("UST app adding context to channel %s", ua_chan->name);
+       assert(reg_sess);
+       assert(reg_chan);
+       assert(ua_chan);
+       assert(ua_chan->obj);
 
-       lttng_ht_lookup(ua_chan->ctx, (void *)((unsigned long)uctx->ctx), &iter);
-       node = lttng_ht_iter_get_node_ulong(&iter);
-       if (node != NULL) {
-               ret = -EEXIST;
-               goto error;
-       }
+       DBG2("UST app setup buffer registry channel for %s", ua_chan->name);
 
-       ua_ctx = alloc_ust_app_ctx(uctx);
-       if (ua_ctx == NULL) {
-               /* malloc failed */
-               ret = -1;
+       /* Setup all streams for the registry. */
+       ret = setup_buffer_reg_streams(reg_chan, ua_chan);
+       if (ret < 0) {
                goto error;
        }
 
-       lttng_ht_node_init_ulong(&ua_ctx->node, (unsigned long) ua_ctx->ctx.ctx);
-       lttng_ht_add_unique_ulong(ua_chan->ctx, &ua_ctx->node);
+       reg_chan->obj.ust = ua_chan->obj;
+       ua_chan->obj = NULL;
 
-       ret = create_ust_channel_context(ua_chan, ua_ctx, app);
-       if (ret < 0) {
-               goto error;
-       }
+       return 0;
 
 error:
+       buffer_reg_channel_remove(reg_sess, reg_chan);
+       buffer_reg_channel_destroy(reg_chan, LTTNG_DOMAIN_UST);
        return ret;
 }
 
 /*
- * Enable on the tracer side a ust app event for the session and channel.
+ * Send buffer registry channel to the application.
  *
- * Called with UST app session lock held.
+ * Return 0 on success else a negative value.
  */
-static
-int enable_ust_app_event(struct ust_app_session *ua_sess,
-               struct ust_app_event *ua_event, struct ust_app *app)
+static int send_channel_uid_to_ust(struct buffer_reg_channel *reg_chan,
+               struct ust_app *app, struct ust_app_session *ua_sess,
+               struct ust_app_channel *ua_chan)
 {
        int ret;
+       struct buffer_reg_stream *reg_stream;
 
-       ret = enable_ust_event(app, ua_sess, ua_event);
+       assert(reg_chan);
+       assert(app);
+       assert(ua_sess);
+       assert(ua_chan);
+
+       DBG("UST app sending buffer registry channel to ust sock %d", app->sock);
+
+       ret = duplicate_channel_object(reg_chan, ua_chan);
        if (ret < 0) {
                goto error;
        }
 
-       ua_event->enabled = 1;
+       /* Send channel to the application. */
+       ret = ust_consumer_send_channel_to_ust(app, ua_sess, ua_chan);
+       if (ret < 0) {
+               goto error;
+       }
+
+       health_code_update();
+
+       /* Send all streams to application. */
+       pthread_mutex_lock(&reg_chan->stream_list_lock);
+       cds_list_for_each_entry(reg_stream, &reg_chan->streams, lnode) {
+               struct ust_app_stream stream;
+
+               ret = duplicate_stream_object(reg_stream, &stream);
+               if (ret < 0) {
+                       goto error_stream_unlock;
+               }
+
+               ret = ust_consumer_send_stream_to_ust(app, ua_chan, &stream);
+               if (ret < 0) {
+                       goto error_stream_unlock;
+               }
+
+               /*
+                * The return value is not important here. This function will output an
+                * error if needed.
+                */
+               (void) release_ust_app_stream(-1, &stream);
+       }
+       ua_chan->is_sent = 1;
 
+error_stream_unlock:
+       pthread_mutex_unlock(&reg_chan->stream_list_lock);
 error:
        return ret;
 }
 
 /*
- * Disable on the tracer side a ust app event for the session and channel.
+ * Create and send to the application the created buffers with per UID buffers.
+ *
+ * Return 0 on success else a negative value.
  */
-static int disable_ust_app_event(struct ust_app_session *ua_sess,
-               struct ust_app_event *ua_event, struct ust_app *app)
+static int create_channel_per_uid(struct ust_app *app,
+               struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
+               struct ust_app_channel *ua_chan)
 {
        int ret;
+       struct buffer_reg_uid *reg_uid;
+       struct buffer_reg_channel *reg_chan;
 
-       ret = disable_ust_event(app, ua_sess, ua_event);
+       assert(app);
+       assert(usess);
+       assert(ua_sess);
+       assert(ua_chan);
+
+       DBG("UST app creating channel %s with per UID buffers", ua_chan->name);
+
+       reg_uid = buffer_reg_uid_find(usess->id, app->bits_per_long, app->uid);
+       /*
+        * The session creation handles the creation of this global registry
+        * object. If none can be find, there is a code flow problem or a
+        * teardown race.
+        */
+       assert(reg_uid);
+
+       reg_chan = buffer_reg_channel_find(ua_chan->tracing_channel_id,
+                       reg_uid);
+       if (!reg_chan) {
+               /* Create the buffer registry channel object. */
+               ret = create_buffer_reg_channel(reg_uid->registry, ua_chan, &reg_chan);
+               if (ret < 0) {
+                       goto error;
+               }
+               assert(reg_chan);
+
+               /*
+                * Create the buffers on the consumer side. This call populates the
+                * ust app channel object with all streams and data object.
+                */
+               ret = do_consumer_create_channel(usess, ua_sess, ua_chan,
+                               app->bits_per_long, reg_uid->registry->reg.ust);
+               if (ret < 0) {
+                       goto error;
+               }
+
+               /*
+                * Setup the streams and add it to the session registry.
+                */
+               ret = setup_buffer_reg_channel(reg_uid->registry, ua_chan, reg_chan);
+               if (ret < 0) {
+                       goto error;
+               }
+
+       }
+
+       /* Send buffers to the application. */
+       ret = send_channel_uid_to_ust(reg_chan, app, ua_sess, ua_chan);
        if (ret < 0) {
                goto error;
        }
 
-       ua_event->enabled = 0;
-
 error:
        return ret;
 }
 
 /*
- * Lookup ust app channel for session and disable it on the tracer side.
+ * Create and send to the application the created buffers with per PID buffers.
+ *
+ * Return 0 on success else a negative value.
  */
-static
-int disable_ust_app_channel(struct ust_app_session *ua_sess,
-               struct ust_app_channel *ua_chan, struct ust_app *app)
+static int create_channel_per_pid(struct ust_app *app,
+               struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
+               struct ust_app_channel *ua_chan)
 {
        int ret;
+       struct ust_registry_session *registry;
 
-       ret = disable_ust_channel(app, ua_sess, ua_chan);
+       assert(app);
+       assert(usess);
+       assert(ua_sess);
+       assert(ua_chan);
+
+       DBG("UST app creating channel %s with per PID buffers", ua_chan->name);
+
+       rcu_read_lock();
+
+       registry = get_session_registry(ua_sess);
+       assert(registry);
+
+       /* Create and add a new channel registry to session. */
+       ret = ust_registry_channel_add(registry, ua_chan->key);
        if (ret < 0) {
                goto error;
        }
 
-       ua_chan->enabled = 0;
+       /* Create and get channel on the consumer side. */
+       ret = do_consumer_create_channel(usess, ua_sess, ua_chan,
+                       app->bits_per_long, registry);
+       if (ret < 0) {
+               goto error;
+       }
+
+       ret = send_channel_pid_to_ust(app, ua_sess, ua_chan);
+       if (ret < 0) {
+               goto error;
+       }
 
 error:
+       rcu_read_unlock();
        return ret;
 }
 
 /*
- * Lookup ust app channel for session and enable it on the tracer side.
+ * From an already allocated ust app channel, create the channel buffers if
+ * need and send it to the application. This MUST be called with a RCU read
+ * side lock acquired.
+ *
+ * Return 0 on success or else a negative value.
  */
-static int enable_ust_app_channel(struct ust_app_session *ua_sess,
-               struct ltt_ust_channel *uchan, struct ust_app *app)
+static int do_create_channel(struct ust_app *app,
+               struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
+               struct ust_app_channel *ua_chan)
 {
-       int ret = 0;
-       struct lttng_ht_iter iter;
-       struct lttng_ht_node_str *ua_chan_node;
-       struct ust_app_channel *ua_chan;
+       int ret;
 
-       lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &iter);
-       ua_chan_node = lttng_ht_iter_get_node_str(&iter);
-       if (ua_chan_node == NULL) {
-               DBG2("Unable to find channel %s in ust session id %u",
-                               uchan->name, ua_sess->id);
+       assert(app);
+       assert(usess);
+       assert(ua_sess);
+       assert(ua_chan);
+
+       /* Handle buffer type before sending the channel to the application. */
+       switch (usess->buffer_type) {
+       case LTTNG_BUFFER_PER_UID:
+       {
+               ret = create_channel_per_uid(app, usess, ua_sess, ua_chan);
+               if (ret < 0) {
+                       goto error;
+               }
+               break;
+       }
+       case LTTNG_BUFFER_PER_PID:
+       {
+               ret = create_channel_per_pid(app, usess, ua_sess, ua_chan);
+               if (ret < 0) {
+                       goto error;
+               }
+               break;
+       }
+       default:
+               assert(0);
+               ret = -EINVAL;
                goto error;
        }
 
-       ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+       /* Initialize ust objd object using the received handle and add it. */
+       lttng_ht_node_init_ulong(&ua_chan->ust_objd_node, ua_chan->handle);
+       lttng_ht_add_unique_ulong(app->ust_objd, &ua_chan->ust_objd_node);
 
-       ret = enable_ust_channel(app, ua_sess, ua_chan);
-       if (ret < 0) {
-               goto error;
+       /* If channel is not enabled, disable it on the tracer */
+       if (!ua_chan->enabled) {
+               ret = disable_ust_channel(app, ua_sess, ua_chan);
+               if (ret < 0) {
+                       goto error;
+               }
        }
 
 error:
@@ -1663,10 +2296,12 @@ error:
  * newly created channel if not NULL.
  *
  * Called with UST app session lock held.
+ *
+ * Return 0 on success or else a negative value.
  */
 static int create_ust_app_channel(struct ust_app_session *ua_sess,
                struct ltt_ust_channel *uchan, struct ust_app *app,
-               struct consumer_output *consumer, enum lttng_ust_chan_type type,
+               enum lttng_ust_chan_type type, struct ltt_ust_session *usess,
                struct ust_app_channel **ua_chanp)
 {
        int ret = 0;
@@ -1693,7 +2328,7 @@ static int create_ust_app_channel(struct ust_app_session *ua_sess,
        /* Set channel type. */
        ua_chan->attr.type = type;
 
-       ret = create_ust_channel(app, ua_sess, ua_chan, consumer);
+       ret = do_create_channel(app, usess, ua_sess, ua_chan);
        if (ret < 0) {
                goto error;
        }
@@ -1772,7 +2407,7 @@ error:
 /*
  * Create UST metadata and open it on the tracer side.
  *
- * Called with UST app session lock held.
+ * Called with UST app session lock held and RCU read side lock.
  */
 static int create_ust_app_metadata(struct ust_app_session *ua_sess,
                struct ust_app *app, struct consumer_output *consumer)
@@ -1780,14 +2415,19 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess,
        int ret = 0;
        struct ust_app_channel *metadata;
        struct consumer_socket *socket;
+       struct ust_registry_session *registry;
 
        assert(ua_sess);
        assert(app);
        assert(consumer);
 
-       if (ua_sess->metadata) {
-               /* Already exist. Return success. */
-               goto end;
+       registry = get_session_registry(ua_sess);
+       assert(registry);
+
+       /* Metadata already exists for this registry. */
+       if (registry->metadata_key) {
+               ret = 0;
+               goto error;
        }
 
        /* Allocate UST metadata */
@@ -1808,20 +2448,33 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess,
        metadata->attr.type = LTTNG_UST_CHAN_METADATA;
 
        /* Get the right consumer socket for the application. */
-       socket = find_consumer_socket_by_bitness(app->bits_per_long, consumer);
+       socket = consumer_find_socket_by_bitness(app->bits_per_long, consumer);
        if (!socket) {
                ret = -EINVAL;
                goto error_consumer;
        }
 
+       /* Need one fd for the channel. */
+       ret = lttng_fd_get(LTTNG_FD_APPS, 1);
+       if (ret < 0) {
+               ERR("Exhausted number of available FD upon create metadata");
+               goto error;
+       }
+
        /*
         * Ask the metadata channel creation to the consumer. The metadata object
         * will be created by the consumer and kept their. However, the stream is
         * never added or monitored until we do a first push metadata to the
         * consumer.
         */
-       ret = ust_consumer_ask_channel(ua_sess, metadata, consumer, socket);
+       ret = ust_consumer_ask_channel(ua_sess, metadata, consumer, socket,
+                       registry);
        if (ret < 0) {
+               /*
+                * Safe because the metadata obj pointer is not set so the delete below
+                * will not put a FD back again.
+                */
+               lttng_fd_put(LTTNG_FD_APPS, 1);
                goto error_consumer;
        }
 
@@ -1831,17 +2484,22 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess,
         * because after this point, if an error occurs, the only way the stream
         * can be deleted is to be monitored in the consumer.
         */
-       ret = ust_consumer_setup_metadata(socket, metadata);
+       ret = consumer_setup_metadata(socket, metadata->key);
        if (ret < 0) {
+               /*
+                * Safe because the metadata obj pointer is not set so the delete below
+                * will not put a FD back again.
+                */
+               lttng_fd_put(LTTNG_FD_APPS, 1);
                goto error_consumer;
        }
 
-       ua_sess->metadata = metadata;
+       /* Keep metadata key so we can identify it on the consumer side. */
+       registry->metadata_key = metadata->key;
 
-       DBG2("UST metadata created for app pid %d", app->pid);
+       DBG2("UST metadata with key %" PRIu64 " created for app pid %d",
+                       metadata->key, app->pid);
 
-end:
-       return 0;
 error_consumer:
        delete_ust_app_channel(-1, metadata, app);
 error:
@@ -2064,6 +2722,8 @@ void ust_app_unregister(int sock)
        /* Remove sessions so they are not visible during deletion.*/
        cds_lfht_for_each_entry(lta->sessions->ht, &iter.iter, ua_sess,
                        node.node) {
+               struct ust_registry_session *registry;
+
                ret = lttng_ht_del(lta->sessions, &iter);
                if (ret) {
                        /* The session was already removed so scheduled for teardown. */
@@ -2087,8 +2747,20 @@ void ust_app_unregister(int sock)
                 * The close metadata below nullifies the metadata pointer in the
                 * session so the delete session will NOT push/close a second time.
                 */
-               (void) push_metadata(lta, ua_sess);
-               (void) close_metadata(lta, ua_sess);
+               registry = get_session_registry(ua_sess);
+               if (registry) {
+                       /* Push metadata for application before freeing the application. */
+                       (void) push_metadata(registry, ua_sess->consumer);
+
+                       /*
+                        * Don't ask to close metadata for global per UID buffers. Close
+                        * metadata only on destroy trace session in this case.
+                        */
+                       if (ua_sess->buffer_type != LTTNG_BUFFER_PER_UID) {
+                               /* And ask to close it for this session registry. */
+                               (void) close_metadata(registry, ua_sess->consumer);
+                       }
+               }
 
                cds_list_add(&ua_sess->teardown_node, &lta->teardown_head);
                pthread_mutex_unlock(&ua_sess->lock);
@@ -2611,7 +3283,7 @@ int ust_app_create_channel_glb(struct ltt_ust_session *usess,
        assert(usess);
        assert(uchan);
 
-       DBG2("UST app adding channel %s to global domain for session id %d",
+       DBG2("UST app adding channel %s to UST domain for session id %d",
                        uchan->name, usess->id);
 
        rcu_read_lock();
@@ -2649,8 +3321,8 @@ int ust_app_create_channel_glb(struct ltt_ust_session *usess,
 
                pthread_mutex_lock(&ua_sess->lock);
                /* Create channel onto application. We don't need the chan ref. */
-               ret = create_ust_app_channel(ua_sess, uchan, app, usess->consumer,
-                               LTTNG_UST_CHAN_PER_CPU, NULL);
+               ret = create_ust_app_channel(ua_sess, uchan, app,
+                               LTTNG_UST_CHAN_PER_CPU, usess, NULL);
                pthread_mutex_unlock(&ua_sess->lock);
                if (ret < 0) {
                        if (ret == -ENOMEM) {
@@ -2836,7 +3508,7 @@ int ust_app_start_trace(struct ltt_ust_session *usess, struct ust_app *app)
        if (usess->consumer->type == CONSUMER_DST_LOCAL &&
                        strlen(usess->consumer->dst.trace_path) > 0) {
                ret = run_as_mkdir_recursive(usess->consumer->dst.trace_path,
-                               S_IRWXU | S_IRWXG, usess->uid, usess->gid);
+                               S_IRWXU | S_IRWXG, ua_sess->euid, ua_sess->egid);
                if (ret < 0) {
                        if (ret != -EEXIST) {
                                ERR("Trace directory creation error");
@@ -2901,6 +3573,7 @@ int ust_app_stop_trace(struct ltt_ust_session *usess, struct ust_app *app)
        struct lttng_ht_iter iter;
        struct ust_app_session *ua_sess;
        struct ust_app_channel *ua_chan;
+       struct ust_registry_session *registry;
 
        DBG("Stopping tracing for ust app pid %d", app->pid);
 
@@ -2975,10 +3648,10 @@ int ust_app_stop_trace(struct ltt_ust_session *usess, struct ust_app *app)
 
        health_code_update();
 
-       ret = push_metadata(app, ua_sess);
-       if (ret < 0) {
-               goto error_rcu_unlock;
-       }
+       registry = get_session_registry(ua_sess);
+       assert(registry);
+       /* Push metadata for application before freeing the application. */
+       (void) push_metadata(registry, ua_sess->consumer);
 
        pthread_mutex_unlock(&ua_sess->lock);
 end_no_session:
@@ -3075,10 +3748,36 @@ int ust_app_stop_trace_all(struct ltt_ust_session *usess)
 
        rcu_read_lock();
 
+       /* Flush all per UID buffers associated to that session. */
+       if (usess->buffer_type == LTTNG_BUFFER_PER_UID) {
+               struct buffer_reg_uid *reg;
+               cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
+                       struct buffer_reg_channel *reg_chan;
+                       struct consumer_socket *socket;
+
+                       /* Get consumer socket to use to push the metadata.*/
+                       socket = consumer_find_socket_by_bitness(reg->bits_per_long,
+                                       usess->consumer);
+                       if (!socket) {
+                               /* Ignore request if no consumer is found for the session. */
+                               continue;
+                       }
+
+                       cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
+                                       reg_chan, node.node) {
+                               /*
+                                * The following call will print error values so the return
+                                * code is of little importance because whatever happens, we
+                                * have to try them all.
+                                */
+                               (void) consumer_flush_channel(socket, reg_chan->consumer_key);
+                       }
+               }
+       }
+
        cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
                ret = ust_app_stop_trace(usess, app);
                if (ret < 0) {
-                       ERR("UST app stop trace failed with ret %d", ret);
                        /* Continue to next apps even on error */
                        continue;
                }
@@ -3166,7 +3865,7 @@ void ust_app_global_update(struct ltt_ust_session *usess, int sock)
         */
        cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, ua_chan,
                        node.node) {
-               ret = create_ust_channel(app, ua_sess, ua_chan, usess->consumer);
+               ret = do_create_channel(app, usess, ua_sess, ua_chan);
                if (ret < 0) {
                        /*
                         * Stop everything. On error, the application failed, no more file
@@ -3534,10 +4233,12 @@ static int reply_ust_register_channel(int sock, int sobjd, int cobjd,
 {
        int ret, ret_code = 0;
        uint32_t chan_id, reg_count;
+       uint64_t chan_reg_key;
        enum ustctl_channel_header type;
        struct ust_app *app;
        struct ust_app_channel *ua_chan;
        struct ust_app_session *ua_sess;
+       struct ust_registry_session *registry;
        struct ust_registry_channel *chan_reg;
 
        rcu_read_lock();
@@ -3557,41 +4258,43 @@ static int reply_ust_register_channel(int sock, int sobjd, int cobjd,
        assert(ua_chan->session);
        ua_sess = ua_chan->session;
 
-       pthread_mutex_lock(&ua_sess->registry->lock);
+       /* Get right session registry depending on the session buffer type. */
+       registry = get_session_registry(ua_sess);
+       assert(registry);
 
-       chan_reg = ust_registry_channel_find(ua_sess->registry, ua_chan->key);
-       assert(chan_reg);
-
-       if (ust_registry_is_max_id(ua_sess->registry->used_channel_id)) {
-               ret_code = -1;
-               chan_id = -1U;
-               type = -1;
-               goto reply;
-       }
-
-       /* Don't assign ID to metadata. */
-       if (ua_chan->attr.type == LTTNG_UST_CHAN_METADATA) {
-               chan_id = -1U;
+       /* Depending on the buffer type, a different channel key is used. */
+       if (ua_sess->buffer_type == LTTNG_BUFFER_PER_UID) {
+               chan_reg_key = ua_chan->tracing_channel_id;
        } else {
-               chan_id = ust_registry_get_next_chan_id(ua_sess->registry);
+               chan_reg_key = ua_chan->key;
        }
 
-       reg_count = ust_registry_get_event_count(chan_reg);
-       if (reg_count < 31) {
-               type = USTCTL_CHANNEL_HEADER_COMPACT;
+       pthread_mutex_lock(&registry->lock);
+
+       chan_reg = ust_registry_channel_find(registry, chan_reg_key);
+       assert(chan_reg);
+
+       if (!chan_reg->register_done) {
+               reg_count = ust_registry_get_event_count(chan_reg);
+               if (reg_count < 31) {
+                       type = USTCTL_CHANNEL_HEADER_COMPACT;
+               } else {
+                       type = USTCTL_CHANNEL_HEADER_LARGE;
+               }
+
+               chan_reg->nr_ctx_fields = nr_fields;
+               chan_reg->ctx_fields = fields;
+               chan_reg->header_type = type;
        } else {
-               type = USTCTL_CHANNEL_HEADER_LARGE;
+               /* Get current already assigned values. */
+               type = chan_reg->header_type;
        }
-
-       chan_reg->nr_ctx_fields = nr_fields;
-       chan_reg->ctx_fields = fields;
-       chan_reg->chan_id = chan_id;
-       chan_reg->header_type = type;
+       /* Channel id is set during the object creation. */
+       chan_id = chan_reg->chan_id;
 
        /* Append to metadata */
-       if (!ret_code) {
-               ret_code = ust_metadata_channel_statedump(ua_chan->session->registry,
-                               chan_reg);
+       if (!chan_reg->metadata_dumped) {
+               ret_code = ust_metadata_channel_statedump(registry, chan_reg);
                if (ret_code) {
                        ERR("Error appending channel metadata (errno = %d)", ret_code);
                        goto reply;
@@ -3599,8 +4302,9 @@ static int reply_ust_register_channel(int sock, int sobjd, int cobjd,
        }
 
 reply:
-       DBG3("UST app replying to register channel with id %u, type: %d, ret: %d",
-                       chan_id, type, ret_code);
+       DBG3("UST app replying to register channel key %" PRIu64
+                       " with id %u, type: %d, ret: %d", chan_reg_key, chan_id, type,
+                       ret_code);
 
        ret = ustctl_reply_register_channel(sock, chan_id, type, ret_code);
        if (ret < 0) {
@@ -3612,8 +4316,11 @@ reply:
                goto error;
        }
 
+       /* This channel registry registration is completed. */
+       chan_reg->register_done = 1;
+
 error:
-       pthread_mutex_unlock(&ua_sess->registry->lock);
+       pthread_mutex_unlock(&registry->lock);
 error_rcu_unlock:
        rcu_read_unlock();
        return ret;
@@ -3634,9 +4341,11 @@ static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name,
 {
        int ret, ret_code;
        uint32_t event_id = 0;
+       uint64_t chan_reg_key;
        struct ust_app *app;
        struct ust_app_channel *ua_chan;
        struct ust_app_session *ua_sess;
+       struct ust_registry_session *registry;
 
        rcu_read_lock();
 
@@ -3655,11 +4364,20 @@ static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name,
        assert(ua_chan->session);
        ua_sess = ua_chan->session;
 
-       pthread_mutex_lock(&ua_sess->registry->lock);
+       registry = get_session_registry(ua_sess);
+       assert(registry);
+
+       if (ua_sess->buffer_type == LTTNG_BUFFER_PER_UID) {
+               chan_reg_key = ua_chan->tracing_channel_id;
+       } else {
+               chan_reg_key = ua_chan->key;
+       }
+
+       pthread_mutex_lock(&registry->lock);
 
-       ret_code = ust_registry_create_event(ua_sess->registry, ua_chan->key,
+       ret_code = ust_registry_create_event(registry, chan_reg_key,
                        sobjd, cobjd, name, sig, nr_fields, fields, loglevel,
-                       model_emf_uri, &event_id);
+                       model_emf_uri, ua_sess->buffer_type, &event_id);
 
        /*
         * The return value is returned to ustctl so in case of an error, the
@@ -3680,10 +4398,11 @@ static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name,
                goto error;
        }
 
-       DBG3("UST registry event %s has been added successfully", name);
+       DBG3("UST registry event %s with id %" PRId32 " added successfully",
+                       name, event_id);
 
 error:
-       pthread_mutex_unlock(&ua_sess->registry->lock);
+       pthread_mutex_unlock(&registry->lock);
 error_rcu_unlock:
        rcu_read_unlock();
        return ret;
index 649c0a96de83f24498e0a5e420cebe6c1ab78b89..67088a7c9eaeb17643bbddce6e5787680ee8ae9a 100644 (file)
@@ -131,6 +131,8 @@ struct ust_app_channel {
        int is_sent;
        /* Unique key used to identify the channel on the consumer side. */
        uint64_t key;
+       /* Id of the tracing channel set on creation. */
+       uint64_t tracing_channel_id;
        /* Number of stream that this channel is expected to receive. */
        unsigned int expected_stream_count;
        char name[LTTNG_UST_SYM_NAME_LEN];
@@ -164,21 +166,31 @@ struct ust_app_session {
        /* started: has the session been in started state at any time ? */
        int started;  /* allows detection of start vs restart. */
        int handle;   /* used has unique identifier for app session */
-       int id;       /* session unique identifier */
-       struct ust_app_channel *metadata;
-       struct ust_registry_session *registry;
+
+       /*
+        * Tracing session ID. Multiple ust app session can have the same tracing
+        * session id making this value NOT unique to the object.
+        */
+       int tracing_id;
+       uint64_t id;    /* Unique session identifier */
        struct lttng_ht *channels; /* Registered channels */
        struct lttng_ht_node_ulong node;
        char path[PATH_MAX];
-       /* UID/GID of the user owning the session */
+       /* UID/GID of the application owning the session */
        uid_t uid;
        gid_t gid;
+       /* Effective UID and GID. Same as the tracing session. */
+       uid_t euid;
+       gid_t egid;
        struct cds_list_head teardown_node;
        /*
         * Once at least *one* session is created onto the application, the
         * corresponding consumer is set so we can use it on unregistration.
         */
        struct consumer_output *consumer;
+       enum lttng_buffer_type buffer_type;
+       /* ABI of the session. Same value as the application. */
+       uint32_t bits_per_long;
 };
 
 /*
@@ -210,6 +222,8 @@ struct ust_app {
        uint32_t v_minor;    /* Version minor number */
        /* Extra for the NULL byte. */
        char name[UST_APP_PROCNAME_LEN + 1];
+       /* Type of buffer this application uses. */
+       enum lttng_buffer_type buffer_type;
        struct lttng_ht *sessions;
        struct lttng_ht_node_ulong pid_n;
        struct lttng_ht_node_ulong sock_n;
index b0264e4bab3f81eccfe31971178e933a73de92b8..ba74112fa72a35758cde4006320dbbfbfd15ce37 100644 (file)
@@ -28,6 +28,7 @@
 #include <common/defaults.h>
 
 #include "consumer.h"
+#include "health.h"
 #include "ust-consumer.h"
 
 /*
@@ -66,8 +67,8 @@ static char *setup_trace_path(struct consumer_output *consumer,
                }
 
                /* Create directory. Ignore if exist. */
-               ret = run_as_mkdir_recursive(pathname, S_IRWXU | S_IRWXG, ua_sess->uid,
-                               ua_sess->gid);
+               ret = run_as_mkdir_recursive(pathname, S_IRWXU | S_IRWXG,
+                               ua_sess->euid, ua_sess->egid);
                if (ret < 0) {
                        if (ret != -EEXIST) {
                                ERR("Trace directory creation error");
@@ -93,21 +94,24 @@ error:
 /*
  * Send a single channel to the consumer using command ADD_CHANNEL.
  *
- * Consumer socket MUST be acquired before calling this.
+ * Consumer socket lock MUST be acquired before calling this.
  */
 static int ask_channel_creation(struct ust_app_session *ua_sess,
                struct ust_app_channel *ua_chan, struct consumer_output *consumer,
-               struct consumer_socket *socket)
+               struct consumer_socket *socket, struct ust_registry_session *registry)
 {
        int ret;
-       uint64_t key;
+       uint32_t chan_id;
+       uint64_t key, chan_reg_key;
        char *pathname = NULL;
        struct lttcomm_consumer_msg msg;
+       struct ust_registry_channel *chan_reg;
 
        assert(ua_sess);
        assert(ua_chan);
        assert(socket);
        assert(consumer);
+       assert(registry);
 
        DBG2("Asking UST consumer for channel");
 
@@ -118,6 +122,21 @@ static int ask_channel_creation(struct ust_app_session *ua_sess,
                goto error;
        }
 
+       /* Depending on the buffer type, a different channel key is used. */
+       if (ua_sess->buffer_type == LTTNG_BUFFER_PER_UID) {
+               chan_reg_key = ua_chan->tracing_channel_id;
+       } else {
+               chan_reg_key = ua_chan->key;
+       }
+
+       if (ua_chan->attr.type == LTTNG_UST_CHAN_METADATA) {
+               chan_id = -1U;
+       } else {
+               chan_reg = ust_registry_channel_find(registry, chan_reg_key);
+               assert(chan_reg);
+               chan_id = chan_reg->chan_id;
+       }
+
        consumer_init_ask_channel_comm_msg(&msg,
                        ua_chan->attr.subbuf_size,
                        ua_chan->attr.num_subbuf,
@@ -126,14 +145,15 @@ static int ask_channel_creation(struct ust_app_session *ua_sess,
                        ua_chan->attr.read_timer_interval,
                        (int) ua_chan->attr.output,
                        (int) ua_chan->attr.type,
-                       ua_sess->id,
+                       ua_sess->tracing_id,
                        pathname,
                        ua_chan->name,
-                       ua_sess->uid,
-                       ua_sess->gid,
+                       ua_sess->euid,
+                       ua_sess->egid,
                        consumer->net_seq_index,
                        ua_chan->key,
-                       ua_sess->registry->uuid);
+                       registry->uuid,
+                       chan_id);
 
        health_code_update();
 
@@ -168,7 +188,7 @@ error:
  */
 int ust_consumer_ask_channel(struct ust_app_session *ua_sess,
                struct ust_app_channel *ua_chan, struct consumer_output *consumer,
-               struct consumer_socket *socket)
+               struct consumer_socket *socket, struct ust_registry_session *registry)
 {
        int ret;
 
@@ -177,10 +197,11 @@ int ust_consumer_ask_channel(struct ust_app_session *ua_sess,
        assert(consumer);
        assert(socket);
        assert(socket->fd >= 0);
+       assert(registry);
 
        pthread_mutex_lock(socket->lock);
 
-       ret = ask_channel_creation(ua_sess, ua_chan, consumer, socket);
+       ret = ask_channel_creation(ua_sess, ua_chan, consumer, socket, registry);
        if (ret < 0) {
                goto error;
        }
@@ -366,8 +387,8 @@ int ust_consumer_send_channel_to_ust(struct ust_app *app,
        assert(channel);
        assert(channel->obj);
 
-       DBG2("UST app send channel to app sock %d pid %d (name: %s, key: %lu)",
-                       app->sock, app->pid, channel->name, channel->key);
+       DBG2("UST app send channel to sock %d pid %d (name: %s, key: %" PRIu64 ")",
+                       app->sock, app->pid, channel->name, channel->tracing_channel_id);
 
        /* Send stream to application. */
        ret = ustctl_send_channel_to_ust(app->sock, ua_sess->handle, channel->obj);
@@ -384,131 +405,3 @@ int ust_consumer_send_channel_to_ust(struct ust_app *app,
 error:
        return ret;
 }
-
-/*
- * Send metadata string to consumer.
- *
- * Return 0 on success else a negative value.
- */
-int ust_consumer_push_metadata(struct consumer_socket *socket,
-               struct ust_app_session *ua_sess, char *metadata_str,
-               size_t len, size_t target_offset)
-{
-       int ret;
-       struct lttcomm_consumer_msg msg;
-
-       assert(socket);
-       assert(socket->fd >= 0);
-       assert(ua_sess);
-       assert(ua_sess->metadata);
-
-       DBG2("UST consumer push metadata to consumer socket %d", socket->fd);
-
-       msg.cmd_type = LTTNG_CONSUMER_PUSH_METADATA;
-       msg.u.push_metadata.key = ua_sess->metadata->key;
-       msg.u.push_metadata.target_offset = target_offset;
-       msg.u.push_metadata.len = len;
-
-       /*
-        * TODO: reenable these locks when the consumerd gets the ability to
-        * reorder the metadata it receives. This fits with locking in
-        * src/bin/lttng-sessiond/ust-app.c:push_metadata()
-        *
-        * pthread_mutex_lock(socket->lock);
-        */
-
-       health_code_update();
-       ret = consumer_send_msg(socket, &msg);
-       if (ret < 0) {
-               goto error;
-       }
-
-       DBG3("UST consumer push metadata on sock %d of len %lu", socket->fd, len);
-
-       ret = lttcomm_send_unix_sock(socket->fd, metadata_str, len);
-       if (ret < 0) {
-               fprintf(stderr, "send error: %d\n", ret);
-               goto error;
-       }
-
-       health_code_update();
-       ret = consumer_recv_status_reply(socket);
-       if (ret < 0) {
-               goto error;
-       }
-
-error:
-       health_code_update();
-       /*
-        * pthread_mutex_unlock(socket->lock);
-        */
-       return ret;
-}
-
-/*
- * Send a close metdata command to consumer using the given channel key.
- *
- * Return 0 on success else a negative value.
- */
-int ust_consumer_close_metadata(struct consumer_socket *socket,
-               struct ust_app_channel *ua_chan)
-{
-       int ret;
-       struct lttcomm_consumer_msg msg;
-
-       assert(ua_chan);
-       assert(socket);
-       assert(socket->fd >= 0);
-
-       DBG2("UST consumer close metadata channel key %lu", ua_chan->key);
-
-       msg.cmd_type = LTTNG_CONSUMER_CLOSE_METADATA;
-       msg.u.close_metadata.key = ua_chan->key;
-
-       pthread_mutex_lock(socket->lock);
-       health_code_update();
-
-       ret = consumer_send_msg(socket, &msg);
-       if (ret < 0) {
-               goto error;
-       }
-
-error:
-       health_code_update();
-       pthread_mutex_unlock(socket->lock);
-       return ret;
-}
-
-/*
- * Send a setup metdata command to consumer using the given channel key.
- *
- * Return 0 on success else a negative value.
- */
-int ust_consumer_setup_metadata(struct consumer_socket *socket,
-               struct ust_app_channel *ua_chan)
-{
-       int ret;
-       struct lttcomm_consumer_msg msg;
-
-       assert(ua_chan);
-       assert(socket);
-       assert(socket->fd >= 0);
-
-       DBG2("UST consumer setup metadata channel key %lu", ua_chan->key);
-
-       msg.cmd_type = LTTNG_CONSUMER_SETUP_METADATA;
-       msg.u.setup_metadata.key = ua_chan->key;
-
-       pthread_mutex_lock(socket->lock);
-       health_code_update();
-
-       ret = consumer_send_msg(socket, &msg);
-       if (ret < 0) {
-               goto error;
-       }
-
-error:
-       health_code_update();
-       pthread_mutex_unlock(socket->lock);
-       return ret;
-}
index 8739af5520c2c8d96838930c62e6332e2dbffbc4..f5f63d90c23c7598cbd56322f0d7ad0962204593 100644 (file)
@@ -23,7 +23,7 @@
 
 int ust_consumer_ask_channel(struct ust_app_session *ua_sess,
                struct ust_app_channel *ua_chan, struct consumer_output *consumer,
-               struct consumer_socket *socket);
+               struct consumer_socket *socket, struct ust_registry_session *registry);
 
 int ust_consumer_get_channel(struct consumer_socket *socket,
                struct ust_app_channel *ua_chan);
@@ -37,14 +37,4 @@ int ust_consumer_send_stream_to_ust(struct ust_app *app,
 int ust_consumer_send_channel_to_ust(struct ust_app *app,
                struct ust_app_session *ua_sess, struct ust_app_channel *channel);
 
-int ust_consumer_push_metadata(struct consumer_socket *socket,
-               struct ust_app_session *ua_sess, char *metadata_str,
-               size_t len, size_t target_offset);
-
-int ust_consumer_close_metadata(struct consumer_socket *socket,
-               struct ust_app_channel *ua_chan);
-
-int ust_consumer_setup_metadata(struct consumer_socket *socket,
-               struct ust_app_channel *ua_chan);
-
 #endif /* _UST_CONSUMER_H */
index f3494d6c376021bb17b2723acfc40c225ab9ff52..c2ab24ac9978dbac9c5876da885170e6bf64543a 100644 (file)
@@ -3,24 +3,24 @@
  *
  * Meta header used to include all relevant file from the lttng ust ABI.
  *
- * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2 only,
- * as published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2 only, as
+ * published by the Free Software Foundation.
  *
- * 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.
+ * 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 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., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef _LTT_UST_CTL_H
-#define _LTT_UST_CTL_H
+#ifndef LTTNG_UST_CTL_H
+#define LTTNG_UST_CTL_H
 
 #include <config.h>
 
  * UST ABI.
  */
 #ifdef HAVE_LIBLTTNG_UST_CTL
+
 #include <lttng/ust-ctl.h>
 #include <lttng/ust-abi.h>
 #include <lttng/ust-error.h>
-#else
+
+static inline
+int ust_ctl_release_object(int sock, struct lttng_ust_object_data *data)
+{
+       return ustctl_release_object(sock, data);
+}
+
+#else /* HAVE_LIBLTTNG_UST_CTL */
+
 #include "lttng-ust-ctl.h"
 #include "lttng-ust-abi.h"
 #include "lttng-ust-error.h"
-#endif
+
+static inline
+int ust_ctl_release_object(int sock, struct lttng_ust_object_data *data)
+{
+       return 0;
+}
+
+#endif /* HAVE_LIBLTTNG_UST_CTL */
 
 #endif /* _LTT_UST_CTL_H */
index 45512ac7ba0df66ec1b2b19368b175c18198d3ae..2735169747e9bfc8108cb5e009cd8a922eefffa8 100644 (file)
@@ -372,6 +372,7 @@ int ust_metadata_event_statedump(struct ust_registry_session *session,
                "};\n\n");
        if (ret)
                goto end;
+       event->metadata_dumped = 1;
 
 end:
        return ret;
@@ -424,6 +425,8 @@ int ust_metadata_channel_statedump(struct ust_registry_session *session,
 
        ret = lttng_metadata_printf(session,
                "};\n\n");
+       /* Flag success of metadata dump. */
+       chan->metadata_dumped = 1;
 
 end:
        return ret;
@@ -525,6 +528,9 @@ int ust_metadata_session_statedump(struct ust_registry_session *session,
        int ret = 0;
        char hostname[HOST_NAME_MAX];
 
+       assert(session);
+       assert(app);
+
        uuid_c = session->uuid;
 
        snprintf(uuid_s, sizeof(uuid_s),
index b92345fec8debf336eed80331d95eb2b5a159dab..19cff09fcd9d26aedb4a79194d10f7875e5fc810 100644 (file)
  */
 #define _GNU_SOURCE
 #include <assert.h>
+#include <inttypes.h>
 
 #include <common/common.h>
+#include <common/hashtable/utils.h>
+#include <lttng/lttng.h>
+
 #include "ust-registry.h"
 
 /*
@@ -53,6 +57,19 @@ no_match:
        return 0;
 }
 
+static unsigned long ht_hash_event(void *_key, unsigned long seed)
+{
+       uint64_t xored_key;
+       struct ust_registry_event *key = _key;
+
+       assert(key);
+
+       xored_key = (uint64_t) (hash_key_str(key->name, seed) ^
+                       hash_key_str(key->signature, seed));
+
+       return hash_key_u64(&xored_key, seed);
+}
+
 /*
  * Allocate event and initialize it. This does NOT set a valid event id from a
  * registry.
@@ -82,7 +99,7 @@ static struct ust_registry_event *alloc_event(int session_objd,
                strncpy(event->name, name, sizeof(event->name));
                event->name[sizeof(event->name) - 1] = '\0';
        }
-       lttng_ht_node_init_str(&event->node, event->name);
+       cds_lfht_node_init(&event->node.node);
 
 error:
        return event;
@@ -110,8 +127,8 @@ static void destroy_event(struct ust_registry_event *event)
  */
 static void destroy_event_rcu(struct rcu_head *head)
 {
-       struct lttng_ht_node_str *node =
-               caa_container_of(head, struct lttng_ht_node_str, head);
+       struct lttng_ht_node_u64 *node =
+               caa_container_of(head, struct lttng_ht_node_u64, head);
        struct ust_registry_event *event =
                caa_container_of(node, struct ust_registry_event, node);
 
@@ -128,7 +145,7 @@ static void destroy_event_rcu(struct rcu_head *head)
 struct ust_registry_event *ust_registry_find_event(
                struct ust_registry_channel *chan, char *name, char *sig)
 {
-       struct lttng_ht_node_str *node;
+       struct lttng_ht_node_u64 *node;
        struct lttng_ht_iter iter;
        struct ust_registry_event *event = NULL;
        struct ust_registry_event key;
@@ -142,9 +159,9 @@ struct ust_registry_event *ust_registry_find_event(
        key.name[sizeof(key.name) - 1] = '\0';
        key.signature = sig;
 
-       cds_lfht_lookup(chan->ht->ht, chan->ht->hash_fct(name, lttng_ht_seed),
+       cds_lfht_lookup(chan->ht->ht, chan->ht->hash_fct(&key, lttng_ht_seed),
                        chan->ht->match_fct, &key, &iter.iter);
-       node = lttng_ht_iter_get_node_str(&iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
        if (!node) {
                goto end;
        }
@@ -167,9 +184,10 @@ end:
 int ust_registry_create_event(struct ust_registry_session *session,
                uint64_t chan_key, int session_objd, int channel_objd, char *name,
                char *sig, size_t nr_fields, struct ustctl_field *fields, int loglevel,
-               char *model_emf_uri, uint32_t *event_id)
+               char *model_emf_uri, int buffer_type, uint32_t *event_id_p)
 {
        int ret;
+       uint32_t event_id;
        struct cds_lfht_node *nptr;
        struct ust_registry_event *event = NULL;
        struct ust_registry_channel *chan;
@@ -177,6 +195,7 @@ int ust_registry_create_event(struct ust_registry_session *session,
        assert(session);
        assert(name);
        assert(sig);
+       assert(event_id_p);
 
        /*
         * This should not happen but since it comes from the UST tracer, an
@@ -208,38 +227,52 @@ int ust_registry_create_event(struct ust_registry_session *session,
                goto error_unlock;
        }
 
-       event->id = ust_registry_get_next_event_id(chan);
-
        DBG3("UST registry creating event with event: %s, sig: %s, id: %u, "
-                       "chan_objd: %u, sess_objd: %u", event->name, event->signature,
-                       event->id, event->channel_objd, event->session_objd);
+                       "chan_objd: %u, sess_objd: %u, chan_id: %u", event->name,
+                       event->signature, event->id, event->channel_objd,
+                       event->session_objd, chan->chan_id);
 
        /*
         * This is an add unique with a custom match function for event. The node
         * are matched using the event name and signature.
         */
-       nptr = cds_lfht_add_unique(chan->ht->ht, chan->ht->hash_fct(event->node.key,
+       nptr = cds_lfht_add_unique(chan->ht->ht, chan->ht->hash_fct(event,
                                lttng_ht_seed), chan->ht->match_fct, event, &event->node.node);
        if (nptr != &event->node.node) {
-               ERR("UST registry create event add unique failed for event: %s, "
-                               "sig: %s, id: %u, chan_objd: %u, sess_objd: %u", event->name,
-                               event->signature, event->id, event->channel_objd,
-                               event->session_objd);
-               ret = -EINVAL;
-               goto error_unlock;
+               if (buffer_type == LTTNG_BUFFER_PER_UID) {
+                       /*
+                        * This is normal, we just have to send the event id of the
+                        * returned node and make sure we destroy the previously allocated
+                        * event object.
+                        */
+                       destroy_event(event);
+                       event = caa_container_of(nptr, struct ust_registry_event,
+                                       node.node);
+                       assert(event);
+                       event_id = event->id;
+               } else {
+                       ERR("UST registry create event add unique failed for event: %s, "
+                                       "sig: %s, id: %u, chan_objd: %u, sess_objd: %u",
+                                       event->name, event->signature, event->id,
+                                       event->channel_objd, event->session_objd);
+                       ret = -EINVAL;
+                       goto error_unlock;
+               }
+       } else {
+               /* Request next event id if the node was successfully added. */
+               event_id = event->id = ust_registry_get_next_event_id(chan);
        }
 
-       /* Set event id if user wants it. */
-       if (event_id) {
-               *event_id = event->id;
-       }
+       *event_id_p = event_id;
 
-       /* Append to metadata */
-       ret = ust_metadata_event_statedump(session, chan, event);
-       if (ret) {
-               ERR("Error appending event metadata (errno = %d)", ret);
-               rcu_read_unlock();
-               return ret;
+       if (!event->metadata_dumped) {
+               /* Append to metadata */
+               ret = ust_metadata_event_statedump(session, chan, event);
+               if (ret) {
+                       ERR("Error appending event metadata (errno = %d)", ret);
+                       rcu_read_unlock();
+                       return ret;
+               }
        }
 
        rcu_read_unlock();
@@ -325,6 +358,18 @@ int ust_registry_channel_add(struct ust_registry_session *session,
 
        /* Set custom match function. */
        chan->ht->match_fct = ht_match_event;
+       chan->ht->hash_fct = ht_hash_event;
+
+       /*
+        * Assign a channel ID right now since the event notification comes
+        * *before* the channel notify so the ID needs to be set at this point so
+        * the metadata can be dumped for that event.
+        */
+       if (ust_registry_is_max_id(session->used_channel_id)) {
+               ret = -1;
+               goto error;
+       }
+       chan->chan_id = ust_registry_get_next_chan_id(session);
 
        rcu_read_lock();
        lttng_ht_node_init_u64(&chan->node, key);
@@ -352,6 +397,8 @@ struct ust_registry_channel *ust_registry_channel_find(
        assert(session);
        assert(session->channels);
 
+       DBG3("UST registry channel finding key %" PRIu64, key);
+
        lttng_ht_lookup(session->channels, &key, &iter);
        node = lttng_ht_iter_get_node_u64(&iter);
        if (!node) {
index 04bbaa0e9f3c94b385ffa4248d5882bc021761e2..1500f74aa54b885c6cd9401f8797e06e9c0e3316 100644 (file)
 
 #include <pthread.h>
 #include <stdint.h>
-#include <lttng/ust-ctl.h>
 
 #include <common/hashtable/hashtable.h>
 #include <common/compat/uuid.h>
 
+#include "ust-ctl.h"
+
 #define CTF_SPEC_MAJOR 1
 #define CTF_SPEC_MINOR 8
 
@@ -32,8 +33,7 @@ struct ust_app;
 
 struct ust_registry_session {
        /*
-        * With multiple writers and readers, use this lock to access
-        * the registry. Use defined macros above to lock it.
+        * With multiple writers and readers, use this lock to access the registry.
         * Can nest within the ust app session lock.
         */
        pthread_mutex_t lock;
@@ -67,6 +67,14 @@ struct ust_registry_session {
         * with a RCU read side lock acquired.
         */
        struct lttng_ht *channels;
+       /* Unique key to identify the metadata on the consumer side. */
+       uint64_t metadata_key;
+       /*
+        * Indicates if the metadata is closed on the consumer side. This is to
+        * avoid double close of metadata when an application unregisters AND
+        * deletes its sessions.
+        */
+       unsigned int metadata_closed;
 };
 
 struct ust_registry_channel {
@@ -75,6 +83,14 @@ struct ust_registry_channel {
        uint32_t chan_id;
        enum ustctl_channel_header header_type;
 
+       /*
+        * Flag for this channel if the metadata was dumped once during
+        * registration. 0 means no, 1 yes.
+        */
+       unsigned int metadata_dumped;
+       /* Indicates if this channel registry has already been registered. */
+       unsigned int register_done;
+
        /*
         * Hash table containing events sent by the UST tracer. MUST be accessed
         * with a RCU read side lock acquired.
@@ -90,7 +106,6 @@ struct ust_registry_channel {
         */
        size_t nr_ctx_fields;
        struct ustctl_field *ctx_fields;
-       /* Hash table node for the session ht indexed by key. */
        struct lttng_ht_node_u64 node;
 };
 
@@ -110,11 +125,17 @@ struct ust_registry_event {
        size_t nr_fields;
        struct ustctl_field *fields;
        char *model_emf_uri;
+       struct lttng_ust_object_data *obj;
+       /*
+        * Flag for this channel if the metadata was dumped once during
+        * registration. 0 means no, 1 yes.
+        */
+       unsigned int metadata_dumped;
        /*
         * Node in the ust-registry hash table. The event name is used to
         * initialize the node and the event_name/signature for the match function.
         */
-       struct lttng_ht_node_str node;
+       struct lttng_ht_node_u64 node;
 };
 
 /*
@@ -176,6 +197,8 @@ static inline uint32_t ust_registry_get_event_count(
        return (uint32_t) uatomic_read(&r->used_event_id);
 }
 
+#ifdef HAVE_LIBLTTNG_UST_CTL
+
 void ust_registry_channel_destroy(struct ust_registry_session *session,
                struct ust_registry_channel *chan);
 struct ust_registry_channel *ust_registry_channel_find(
@@ -199,7 +222,7 @@ void ust_registry_session_destroy(struct ust_registry_session *session);
 int ust_registry_create_event(struct ust_registry_session *session,
                uint64_t chan_key, int session_objd, int channel_objd, char *name,
                char *sig, size_t nr_fields, struct ustctl_field *fields, int loglevel,
-               char *model_emf_uri, uint32_t *event_id);
+               char *model_emf_uri, int buffer_type, uint32_t *event_id_p);
 struct ust_registry_event *ust_registry_find_event(
                struct ust_registry_channel *chan, char *name, char *sig);
 void ust_registry_destroy_event(struct ust_registry_channel *chan,
@@ -214,4 +237,84 @@ int ust_metadata_event_statedump(struct ust_registry_session *session,
                struct ust_registry_channel *chan,
                struct ust_registry_event *event);
 
+#else /* HAVE_LIBLTTNG_UST_CTL */
+
+static inline
+void ust_registry_channel_destroy(struct ust_registry_session *session,
+               struct ust_registry_channel *chan)
+{}
+static inline
+struct ust_registry_channel *ust_registry_channel_find(
+               struct ust_registry_session *session, uint64_t key)
+{
+       return NULL;
+}
+static inline
+int ust_registry_channel_add(struct ust_registry_session *session,
+               uint64_t key)
+{
+       return 0;
+}
+static inline
+void ust_registry_channel_del_free(struct ust_registry_session *session,
+               uint64_t key)
+{}
+static inline
+int ust_registry_session_init(struct ust_registry_session **sessionp,
+               struct ust_app *app,
+               uint32_t bits_per_long,
+               uint32_t uint8_t_alignment,
+               uint32_t uint16_t_alignment,
+               uint32_t uint32_t_alignment,
+               uint32_t uint64_t_alignment,
+               uint32_t long_alignment,
+               int byte_order)
+{
+       return 0;
+}
+static inline
+void ust_registry_session_destroy(struct ust_registry_session *session)
+{}
+static inline
+int ust_registry_create_event(struct ust_registry_session *session,
+               uint64_t chan_key, int session_objd, int channel_objd, char *name,
+               char *sig, size_t nr_fields, struct ustctl_field *fields, int loglevel,
+               char *model_emf_uri, int buffer_type, uint32_t *event_id_p)
+{
+       return 0;
+}
+static inline
+struct ust_registry_event *ust_registry_find_event(
+               struct ust_registry_channel *chan, char *name, char *sig)
+{
+       return NULL;
+}
+static inline
+void ust_registry_destroy_event(struct ust_registry_channel *chan,
+               struct ust_registry_event *event)
+{}
+
+/* The app object can be NULL for registry shared across applications. */
+static inline
+int ust_metadata_session_statedump(struct ust_registry_session *session,
+               struct ust_app *app)
+{
+       return 0;
+}
+static inline
+int ust_metadata_channel_statedump(struct ust_registry_session *session,
+               struct ust_registry_channel *chan)
+{
+       return 0;
+}
+static inline
+int ust_metadata_event_statedump(struct ust_registry_session *session,
+               struct ust_registry_channel *chan,
+               struct ust_registry_event *event)
+{
+       return 0;
+}
+
+#endif /* HAVE_LIBLTTNG_UST_CTL */
+
 #endif /* LTTNG_UST_REGISTRY_H */
index d9a3b022d58f5c9dcea878c230ff60680dd235fc..02a31800a8766cd04a57ed55765cb5636dae857e 100644 (file)
@@ -35,11 +35,9 @@ static char *opt_session_name;
 static int opt_userspace;
 static struct lttng_channel chan;
 static char *opt_output;
-#if 0
-/* Not implemented yet */
-static char *opt_cmd_name;
-static pid_t opt_pid;
-#endif
+static int opt_buffer_uid;
+static int opt_buffer_pid;
+static int opt_buffer_global;
 
 enum {
        OPT_HELP = 1,
@@ -63,13 +61,7 @@ static struct poptOption long_options[] = {
        {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
        {"session",        's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
        {"kernel",         'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
-#if 0
-       /* Not implemented yet */
-       {"userspace",      'u', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_cmd_name, OPT_USERSPACE, 0, 0},
-       {"pid",            'p', POPT_ARG_INT, &opt_pid, 0, 0, 0},
-#else
        {"userspace",      'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
-#endif
        {"discard",        0,   POPT_ARG_NONE, 0, OPT_DISCARD, 0, 0},
        {"overwrite",      0,   POPT_ARG_NONE, 0, OPT_OVERWRITE, 0, 0},
        {"subbuf-size",    0,   POPT_ARG_DOUBLE, 0, OPT_SUBBUF_SIZE, 0, 0},
@@ -78,6 +70,9 @@ static struct poptOption long_options[] = {
        {"read-timer",     0,   POPT_ARG_INT, 0, OPT_READ_TIMER, 0, 0},
        {"list-options",   0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
        {"output",         0,   POPT_ARG_STRING, &opt_output, 0, 0, 0},
+       {"buffers-uid",    0,   POPT_ARG_VAL, &opt_buffer_uid, 1, 0, 0},
+       {"buffers-pid",    0,   POPT_ARG_VAL, &opt_buffer_pid, 1, 0, 0},
+       {"buffers-global", 0,   POPT_ARG_VAL, &opt_buffer_global, 1, 0, 0},
        {0, 0, 0, 0, 0, 0, 0}
 };
 
@@ -117,6 +112,9 @@ static void usage(FILE *ofp)
                DEFAULT_CHANNEL_READ_TIMER);
        fprintf(ofp, "      --output TYPE        Channel output type (Values: %s, %s)\n",
                        output_mmap, output_splice);
+       fprintf(ofp, "      --buffers-uid        Use per UID buffer (-u only)\n");
+       fprintf(ofp, "      --buffers-pid        Use per PID buffer (-u only)\n");
+       fprintf(ofp, "      --buffers-global     Use shared buffer for the whole system (-k only)\n");
        fprintf(ofp, "\n");
 }
 
@@ -165,8 +163,14 @@ static int enable_channel(char *session_name)
        /* Create lttng domain */
        if (opt_kernel) {
                dom.type = LTTNG_DOMAIN_KERNEL;
+               dom.buf_type = LTTNG_BUFFER_GLOBAL;
        } else if (opt_userspace) {
                dom.type = LTTNG_DOMAIN_UST;
+               if (opt_buffer_uid) {
+                       dom.buf_type = LTTNG_BUFFER_PER_UID;
+               } else {
+                       dom.buf_type = LTTNG_BUFFER_PER_PID;
+               }
        } else {
                ERR("Please specify a tracer (-k/--kernel or -u/--userspace)");
                ret = CMD_ERROR;
index 73c9e05209316cb99045a9cc0d744ddd349f83ae..231dac3fbd50c4cdf295c89c20ca1038182cedd5 100644 (file)
@@ -319,8 +319,11 @@ static int enable_events(char *session_name)
        /* Create lttng domain */
        if (opt_kernel) {
                dom.type = LTTNG_DOMAIN_KERNEL;
+               dom.buf_type = LTTNG_BUFFER_GLOBAL;
        } else if (opt_userspace) {
                dom.type = LTTNG_DOMAIN_UST;
+               /* Default. */
+               dom.buf_type = LTTNG_BUFFER_PER_PID;
        } else {
                ERR("Please specify a tracer (-k/--kernel or -u/--userspace)");
                ret = CMD_ERROR;
index 8730e39fbbda7db3fda89758cbd8b5f01385f9f7..29bd0c00c56d95c91a71f031697faa404a6ec7ad 100644 (file)
@@ -876,8 +876,7 @@ int consumer_add_channel(struct lttng_consumer_channel *channel,
        pthread_mutex_lock(&consumer_data.lock);
        rcu_read_lock();
 
-       lttng_ht_lookup(consumer_data.channel_ht,
-                       &channel->key, &iter);
+       lttng_ht_lookup(consumer_data.channel_ht, &channel->key, &iter);
        node = lttng_ht_iter_get_node_u64(&iter);
        if (node != NULL) {
                /* Channel already exist. Ignore the insertion */
@@ -936,7 +935,12 @@ static int update_poll_array(struct lttng_consumer_local_data *ctx,
                                stream->endpoint_status == CONSUMER_ENDPOINT_INACTIVE) {
                        continue;
                }
-               DBG("Active FD %d", stream->wait_fd);
+               /*
+                * This clobbers way too much the debug output. Uncomment that if you
+                * need it for debugging purposes.
+                *
+                * DBG("Active FD %d", stream->wait_fd);
+                */
                (*pollfd)[i].fd = stream->wait_fd;
                (*pollfd)[i].events = POLLIN | POLLPRI;
                local_stream[i] = stream;
index 29836e5b09cf6e25220e20baac2d3fd48b5cfa08..82b9bc65f37f99a45f2db11b625f98597e7a5c6b 100644 (file)
@@ -52,6 +52,7 @@ enum lttng_consumer_command {
        LTTNG_CONSUMER_PUSH_METADATA,
        LTTNG_CONSUMER_CLOSE_METADATA,
        LTTNG_CONSUMER_SETUP_METADATA,
+       LTTNG_CONSUMER_FLUSH_CHANNEL,
 };
 
 /* State of each fd in consumer */
index fca645870f2500649395f7ed0706bc129043d24e..658e7d37d7a5118979ea503e50e4666ca8e47eee 100644 (file)
 #define DEFAULT_KERNEL_TRACE_DIR                "/kernel"
 #define DEFAULT_UST_TRACE_DIR                   "/ust"
 
+/* Subpath for per PID or UID sessions. */
+#define DEFAULT_UST_TRACE_PID_PATH               "/pid"
+#define DEFAULT_UST_TRACE_UID_PATH               "/uid/%d/%u-bit"
+
 /*
  * Default session name for the lttng command line. This default value will
  * get the date and time appended (%Y%m%d-%H%M%S) to it.
@@ -84,7 +88,6 @@
 #define DEFAULT_GLOBAL_HEALTH_UNIX_SOCK         DEFAULT_LTTNG_RUNDIR "/health.sock"
 #define DEFAULT_HOME_HEALTH_UNIX_SOCK           DEFAULT_LTTNG_HOME_RUNDIR "/health.sock"
 
-#ifdef HAVE_LIBLTTNG_UST_CTL
 #define DEFAULT_GLOBAL_APPS_UNIX_SOCK \
        DEFAULT_LTTNG_RUNDIR "/" LTTNG_UST_SOCK_FILENAME
 #define DEFAULT_HOME_APPS_UNIX_SOCK \
 #define DEFAULT_HOME_APPS_WAIT_SHM_PATH \
        DEFAULT_GLOBAL_APPS_WAIT_SHM_PATH "-%d"
 
-#else
-#define DEFAULT_GLOBAL_APPS_UNIX_SOCK
-#define DEFAULT_HOME_APPS_UNIX_SOCK
-#endif /* HAVE_LIBLTTNG_UST_CTL */
-
 /*
  * Value taken from the hard limit allowed by the kernel when using setrlimit
  * with RLIMIT_NOFILE on an Intel i7 CPU and Linux 3.0.3.
index 134e5a28529c943dce0707546d9192613d86aa0c..4fb022cc2948579da84bed73e6bab396536bb704 100644 (file)
@@ -105,6 +105,8 @@ static const char *error_string_array[] = {
        [ ERROR_INDEX(LTTNG_ERR_UST_EVENT_ENABLED) ] = "UST event already enabled",
        [ ERROR_INDEX(LTTNG_ERR_SET_URL) ] = "Error setting URL",
        [ ERROR_INDEX(LTTNG_ERR_URL_EXIST) ] = "URL already exists",
+       [ ERROR_INDEX(LTTNG_ERR_BUFFER_NOT_SUPPORTED)] = "Buffer type not supported",
+       [ ERROR_INDEX(LTTNG_ERR_BUFFER_TYPE_MISMATCH)] = "Buffer type mismatch for session",
 
        /* Last element */
        [ ERROR_INDEX(LTTNG_ERR_NR) ] = "Unknown error code"
index 263df46839d37af58e2efe66770f5e1833c90f0f..30bed07df6b6331cb2dbb18c169a2755a2e0f27b 100644 (file)
@@ -184,7 +184,7 @@ void lttng_ht_node_free_ulong(struct lttng_ht_node_ulong *node)
 /*
  * Free lttng ht node uint64_t.
  */
-void lttng_ht_node_free_u64(struct lttng_ht_node_ulong *node)
+void lttng_ht_node_free_u64(struct lttng_ht_node_u64 *node)
 {
        assert(node);
        free(node);
index b4c1909b79796fe1a84b4714664939697a5488b2..846c5ec47277596fdb231e766feb6f177c9e2f62 100644 (file)
@@ -75,7 +75,7 @@ extern void lttng_ht_node_init_u64(struct lttng_ht_node_u64 *node,
                uint64_t key);
 extern void lttng_ht_node_free_str(struct lttng_ht_node_str *node);
 extern void lttng_ht_node_free_ulong(struct lttng_ht_node_ulong *node);
-extern void lttng_ht_node_free_u64(struct lttng_ht_node_ulong *node);
+extern void lttng_ht_node_free_u64(struct lttng_ht_node_u64 *node);
 
 extern void lttng_ht_lookup(struct lttng_ht *ht, void *key,
                struct lttng_ht_iter *iter);
index 60a3eade6171faf18f886078723ed48b2c1cc2f5..6350fd1e32280424c17b97fa4d7bcc3457d3e346 100644 (file)
@@ -309,6 +309,7 @@ struct lttcomm_consumer_msg {
                        uint64_t relayd_id;                     /* Relayd id if apply. */
                        uint64_t key;                           /* Unique channel key. */
                        unsigned char uuid[UUID_STR_LEN];       /* uuid for ust tracer. */
+                       uint32_t chan_id;                       /* Channel ID on the tracer side. */
                } LTTNG_PACKED ask_channel;
                struct {
                        uint64_t key;
@@ -327,6 +328,9 @@ struct lttcomm_consumer_msg {
                struct {
                        uint64_t key;   /* Metadata channel key. */
                } LTTNG_PACKED setup_metadata;
+               struct {
+                       uint64_t key;   /* Channel key. */
+               } LTTNG_PACKED flush_channel;
        } u;
 } LTTNG_PACKED;
 
index 5a09ff51fb751069a3ad2fdbed17e698a0630dd0..06b59c58442e4a833b3b0947aa3d34244b28a305 100644 (file)
@@ -557,6 +557,43 @@ error:
        return ret;
 }
 
+/*
+ * Flush channel's streams using the given key to retrieve the channel.
+ *
+ * Return 0 on success else an LTTng error code.
+ */
+static int flush_channel(uint64_t chan_key)
+{
+       int ret = 0;
+       struct lttng_consumer_channel *channel;
+       struct lttng_consumer_stream *stream;
+       struct lttng_ht *ht;
+       struct lttng_ht_iter iter;
+
+       DBG("UST consumer flush channel key %lu", chan_key);
+
+       channel = consumer_find_channel(chan_key);
+       if (!channel) {
+               ERR("UST consumer flush channel %lu not found", chan_key);
+               ret = LTTNG_ERR_UST_CHAN_NOT_FOUND;
+               goto error;
+       }
+
+       ht = consumer_data.stream_per_chan_id_ht;
+
+       /* For each stream of the channel id, flush it. */
+       rcu_read_lock();
+       cds_lfht_for_each_entry_duplicate(ht->ht,
+                       ht->hash_fct(&channel->key, lttng_ht_seed), ht->match_fct,
+                       &channel->key, &iter.iter, stream, node_channel_id.node) {
+                       ustctl_flush_buffer(stream->ustream, 1);
+       }
+       rcu_read_unlock();
+
+error:
+       return ret;
+}
+
 /*
  * Close metadata stream wakeup_fd using the given key to retrieve the channel.
  *
@@ -767,6 +804,7 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
                attr.overwrite = msg.u.ask_channel.overwrite;
                attr.switch_timer_interval = msg.u.ask_channel.switch_timer_interval;
                attr.read_timer_interval = msg.u.ask_channel.read_timer_interval;
+               attr.chan_id = msg.u.ask_channel.chan_id;
                memcpy(attr.uuid, msg.u.ask_channel.uuid, sizeof(attr.uuid));
 
                /* Translate the event output type to UST. */
@@ -904,6 +942,17 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
 
                goto end_msg_sessiond;
        }
+       case LTTNG_CONSUMER_FLUSH_CHANNEL:
+       {
+               int ret;
+
+               ret = flush_channel(msg.u.flush_channel.key);
+               if (ret != 0) {
+                       ret_code = ret;
+               }
+
+               goto end_msg_sessiond;
+       }
        case LTTNG_CONSUMER_PUSH_METADATA:
        {
                int ret;
@@ -919,6 +968,7 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
                if (!channel) {
                        ERR("UST consumer push metadata %lu not found", key);
                        ret_code = LTTNG_ERR_UST_CHAN_NOT_FOUND;
+                       goto end_msg_sessiond;
                }
 
                metadata_str = zmalloc(len * sizeof(char));
index 42df7b0d50c00fbe8f0effc4a0d4b1cff737ad7f..db529c53b75b8004a41284bc8621894683e72aa0 100755 (executable)
@@ -24,7 +24,7 @@ SESSION_NAME=""
 
 TRACE_PATH=$(mktemp -d)
 
-NUM_TESTS=11
+NUM_TESTS=10
 
 source $TESTDIR/utils/utils.sh
 
@@ -87,8 +87,8 @@ fi
 
 skip $isroot "Root access is needed. Skipping all kernel streaming tests." $NUM_TESTS ||
 {
-       start_lttng_sessiond
        start_lttng_relayd "-o $TRACE_PATH"
+       start_lttng_sessiond
 
        tests=( test_kernel_before_start )
 
index 95c833dfff1bfe9aa1ccde81ddd60656eb00e602..2d49cde31cfe5bc450064eb06a4f865f974aa876 100755 (executable)
@@ -25,7 +25,7 @@ PID_RELAYD=0
 
 TRACE_PATH=$(mktemp -d)
 
-NUM_TESTS=20
+NUM_TESTS=18
 
 source $TESTDIR/utils/utils.sh
 
@@ -44,7 +44,6 @@ function lttng_create_session_uri
 
 function wait_apps
 {
-
        while [ -n "$(pidof $BIN_NAME)" ]; do
                sleep 0.5
        done
@@ -88,8 +87,8 @@ function test_ust_after_start ()
 
 plan_tests $NUM_TESTS
 
-start_lttng_sessiond
 start_lttng_relayd "-o $TRACE_PATH"
+start_lttng_sessiond
 
 tests=( test_ust_before_start test_ust_after_start )
 
diff --git a/tests/regression/ust/buffers-uid/Makefile.am b/tests/regression/ust/buffers-uid/Makefile.am
new file mode 100644 (file)
index 0000000..31fb019
--- /dev/null
@@ -0,0 +1,16 @@
+AM_CFLAGS = -I$(srcdir) -O2
+AM_LDFLAGS = -llttng-ust
+
+if LTTNG_TOOLS_BUILD_WITH_LIBDL
+AM_LDFLAGS += -ldl
+endif
+if LTTNG_TOOLS_BUILD_WITH_LIBC_DL
+AM_LDFLAGS += -lc
+endif
+
+noinst_PROGRAMS = gen-nevents
+gen_nevents_SOURCES = gen-nevents.c tp.c ust_gen_nevents.h
+gen_nevents_LDADD = -llttng-ust
+
+noinst_SCRIPTS = test_buffers_uid
+EXTRA_DIST = test_buffers_uid
diff --git a/tests/regression/ust/buffers-uid/gen-nevents.c b/tests/regression/ust/buffers-uid/gen-nevents.c
new file mode 100644 (file)
index 0000000..b2c1992
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) - 2009 Pierre-Marc Fournier
+ * Copyright (C) - 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) - 2012 David Goulet <dgoulet@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; version 2.1 of the License.
+ *
+ * This library 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define TRACEPOINT_DEFINE
+#include "ust_gen_nevents.h"
+
+int main(int argc, char **argv)
+{
+       int i, netint;
+       long values[] = { 1, 2, 3 };
+       char text[10] = "test";
+       double dbl = 2.0;
+       float flt = 2222.0;
+       unsigned int nr_iter = 100;
+
+       if (argc == 2) {
+               nr_iter = atoi(argv[1]);
+       }
+
+       for (i = 0; i < nr_iter; i++) {
+               netint = htonl(i);
+               tracepoint(ust_gen_nevents, tptest, i, netint, values, text,
+                               strlen(text), dbl, flt);
+               usleep(100000);
+       }
+
+       return 0;
+}
diff --git a/tests/regression/ust/buffers-uid/test_buffers_uid b/tests/regression/ust/buffers-uid/test_buffers_uid
new file mode 100755 (executable)
index 0000000..a97a90a
--- /dev/null
@@ -0,0 +1,242 @@
+#!/bin/bash
+#
+# Copyright (C) - 2012 David Goulet <dgoulet@efficios.com>
+#
+# This library is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; version 2.1 of the License.
+#
+# This library 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+TEST_DESC="UST tracer - Tracing with per UID buffers"
+
+CURDIR=$(dirname $0)/
+TESTDIR=$CURDIR/../../..
+NR_ITER=100
+SESSION_NAME="buffers-uid"
+EVENT_NAME="ust_gen_nevents:tptest"
+BIN_NAME="gen-nevents"
+NUM_TESTS=58
+
+source $TESTDIR/utils/utils.sh
+
+print_test_banner "$TEST_DESC"
+
+if [ ! -x "$CURDIR/gen-nevents" ]; then
+       BAIL_OUT "No UST nevents binary detected."
+fi
+
+# MUST set TESTDIR before calling those functions
+
+function enable_channel_per_uid()
+{
+       sess_name=$1
+       channel_name=$2
+
+       $TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-channel --buffers-uid -u $channel_name -s $sess_name >/dev/null 2>&1
+       ok $? "Enable channel $channel_name per UID for session $sess_name"
+}
+
+function wait_apps
+{
+       diag "Waiting for applications to end..."
+       while [ -n "$(pidof $BIN_NAME)" ]; do
+               sleep 1
+       done
+}
+
+test_after_multiple_apps() {
+       local out
+       local i
+
+       diag "Start multiple applications AFTER tracing is started"
+
+       # BEFORE application is spawned
+       create_lttng_session $SESSION_NAME $TRACE_PATH
+       enable_channel_per_uid $SESSION_NAME "channel0"
+       enable_ust_lttng_event $SESSION_NAME $EVENT_NAME
+       start_lttng_tracing $SESSION_NAME
+
+       for i in `seq 1 5`; do
+               ./$CURDIR/$BIN_NAME $NR_ITER & >/dev/null 2>&1
+               ok $? "Start application $i for tracing"
+       done
+       wait_apps
+
+       stop_lttng_tracing $SESSION_NAME
+       destroy_lttng_session $SESSION_NAME
+
+       trace_matches $EVENT_NAME $[NR_ITER * 5] $TRACE_PATH
+
+       return $?
+}
+
+test_before_multiple_apps() {
+       local out
+       local i
+
+       diag "Start multiple applications BEFORE tracing is started"
+
+       for i in `seq 1 5`; do
+               ./$CURDIR/$BIN_NAME $NR_ITER & >/dev/null 2>&1
+               ok $? "Start application $i for tracing"
+       done
+
+       # BEFORE application is spawned
+       create_lttng_session $SESSION_NAME $TRACE_PATH
+       enable_channel_per_uid $SESSION_NAME "channel0"
+       enable_ust_lttng_event $SESSION_NAME $EVENT_NAME
+       start_lttng_tracing $SESSION_NAME
+
+       # At least hit one event
+       sleep 2
+
+       stop_lttng_tracing $SESSION_NAME
+       destroy_lttng_session $SESSION_NAME
+
+       out=$(babeltrace $TRACE_PATH | grep $EVENT_NAME | wc -l)
+       if [ $out -eq 0 ]; then
+               fail "Trace validation"
+               diag "No event(s) found. We are supposed to have at least one."
+               out=1
+       else
+               pass "Trace validation"
+               diag "Found $out event(s). Coherent."
+               out=0
+       fi
+
+       wait_apps
+
+       return $out
+}
+
+test_after_app() {
+       local out
+
+       diag "Start application AFTER tracing is started"
+
+       # BEFORE application is spawned
+       create_lttng_session $SESSION_NAME $TRACE_PATH
+       enable_channel_per_uid $SESSION_NAME "channel0"
+       enable_ust_lttng_event $SESSION_NAME $EVENT_NAME
+       start_lttng_tracing $SESSION_NAME
+
+       ./$CURDIR/$BIN_NAME $NR_ITER
+       ok $? "Start application to trace"
+
+       stop_lttng_tracing $SESSION_NAME
+       destroy_lttng_session $SESSION_NAME
+
+       trace_matches $EVENT_NAME $NR_ITER $TRACE_PATH
+
+       return $?
+}
+
+test_before_app() {
+       local out
+
+       diag "Start application BEFORE tracing is started"
+
+       ./$CURDIR/$BIN_NAME $NR_ITER &
+       ok $? "Start application to trace"
+
+       # BEFORE application is spawned
+       create_lttng_session $SESSION_NAME $TRACE_PATH
+       enable_channel_per_uid $SESSION_NAME "channel0"
+       enable_ust_lttng_event $SESSION_NAME $EVENT_NAME
+       start_lttng_tracing $SESSION_NAME
+
+       # At least hit one event
+       sleep 2
+
+       stop_lttng_tracing $SESSION_NAME
+       destroy_lttng_session $SESSION_NAME
+
+       out=$(babeltrace $TRACE_PATH | grep $EVENT_NAME | wc -l)
+       if [ $out -eq 0 ]; then
+               fail "Trace validation"
+               diag "No event(s) found. We are supposed to have at least one."
+               out=1
+       else
+               pass "Trace validation"
+               diag "Found $out event(s). Coherent."
+               out=0
+       fi
+
+       wait_apps
+
+       return $out
+}
+
+test_multiple_channels() {
+       local out
+
+       diag "Start with multiple channels"
+
+       # BEFORE application is spawned
+       create_lttng_session $SESSION_NAME $TRACE_PATH
+       enable_channel_per_uid $SESSION_NAME "channel0"
+       enable_channel_per_uid $SESSION_NAME "channel1"
+       enable_channel_per_uid $SESSION_NAME "channel2"
+       enable_channel_per_uid $SESSION_NAME "channel3"
+       enable_channel_per_uid $SESSION_NAME "channel4"
+       # Enable event in all channels.
+       $TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-event $EVENT_NAME -c channel0 -s $SESSION_NAME -u >/dev/null 2>&1
+       ok $? "Enable event $EVENT_NAME for session $SESSION_NAME in channel0"
+       $TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-event $EVENT_NAME -c channel1 -s $SESSION_NAME -u >/dev/null 2>&1
+       ok $? "Enable event $EVENT_NAME for session $SESSION_NAME in channel1"
+       $TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-event $EVENT_NAME -c channel2 -s $SESSION_NAME -u >/dev/null 2>&1
+       ok $? "Enable event $EVENT_NAME for session $SESSION_NAME in channel2"
+       $TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-event $EVENT_NAME -c channel3 -s $SESSION_NAME -u >/dev/null 2>&1
+       ok $? "Enable event $EVENT_NAME for session $SESSION_NAME in channel3"
+       $TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-event $EVENT_NAME -c channel4 -s $SESSION_NAME -u >/dev/null 2>&1
+       ok $? "Enable event $EVENT_NAME for session $SESSION_NAME in channel4"
+       start_lttng_tracing $SESSION_NAME
+
+       ./$CURDIR/$BIN_NAME $NR_ITER
+       ok $? "Start application to trace"
+
+       stop_lttng_tracing $SESSION_NAME
+       trace_matches $EVENT_NAME $NR_ITER $TRACE_PATH
+       out=$?
+
+       destroy_lttng_session $SESSION_NAME
+
+       return $out
+}
+
+# MUST set TESTDIR before calling those functions
+plan_tests $NUM_TESTS
+
+TESTS=(
+       "test_before_app"
+       "test_after_app"
+       "test_after_multiple_apps"
+       "test_before_multiple_apps"
+       "test_multiple_channels"
+)
+
+TEST_COUNT=${#TESTS[@]}
+i=0
+
+start_lttng_sessiond
+
+while [ $i -lt $TEST_COUNT ]; do
+       TRACE_PATH=$(mktemp -d)
+       ${TESTS[$i]}
+       if [ $? -ne 0 ]; then
+               stop_lttng_sessiond
+               exit 1
+       fi
+
+       rm -rf $TRACE_PATH
+       let "i++"
+done
+
+stop_lttng_sessiond
diff --git a/tests/regression/ust/buffers-uid/tp.c b/tests/regression/ust/buffers-uid/tp.c
new file mode 100644 (file)
index 0000000..e291924
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) - 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (c) - 2012 David Goulet <dgoulet@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR
+ * IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any purpose,
+ * provided the above notices are retained on all copies.  Permission to modify
+ * the code and to distribute modified code is granted, provided the above
+ * notices are retained, and a notice that the code was modified is included
+ * with the above copyright notice.
+ */
+
+#define TRACEPOINT_CREATE_PROBES
+#include "ust_gen_nevents.h"
diff --git a/tests/regression/ust/buffers-uid/ust_gen_nevents.h b/tests/regression/ust/buffers-uid/ust_gen_nevents.h
new file mode 100644 (file)
index 0000000..bc09c44
--- /dev/null
@@ -0,0 +1,56 @@
+#undef TRACEPOINT_PROVIDER
+#define TRACEPOINT_PROVIDER ust_gen_nevents
+
+#if !defined(_TRACEPOINT_UST_GEN_NEVENTS_H) || defined(TRACEPOINT_HEADER_MULTI_READ)
+#define _TRACEPOINT_UST_GEN_NEVENTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Copyright (C) 2011  Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#include <lttng/tracepoint.h>
+
+TRACEPOINT_EVENT(ust_gen_nevents, tptest,
+       TP_ARGS(int, anint, int, netint, long *, values,
+               char *, text, size_t, textlen,
+               double, doublearg, float, floatarg),
+       TP_FIELDS(
+               ctf_integer(int, intfield, anint)
+               ctf_integer_hex(int, intfield2, anint)
+               ctf_integer(long, longfield, anint)
+               ctf_integer_network(int, netintfield, netint)
+               ctf_integer_network_hex(int, netintfieldhex, netint)
+               ctf_array(long, arrfield1, values, 3)
+               ctf_array_text(char, arrfield2, text, 10)
+               ctf_sequence(char, seqfield1, text, size_t, textlen)
+               ctf_sequence_text(char, seqfield2, text, size_t, textlen)
+               ctf_string(stringfield, text)
+               ctf_float(float, floatfield, floatarg)
+               ctf_float(double, doublefield, doublearg)
+       )
+)
+
+#endif /* _TRACEPOINT_UST_GEN_NEVENTS_H */
+
+#undef TRACEPOINT_INCLUDE_FILE
+#define TRACEPOINT_INCLUDE_FILE ./ust_gen_nevents.h
+
+/* This part must be outside ifdef protection */
+#include <lttng/tracepoint-event.h>
+
+#ifdef __cplusplus
+}
+#endif
index e89d02e585481d534a100d5713753baf3eaa504a..ac8e99a159d39beee0670506a73c6c64a02e82f6 100755 (executable)
@@ -14,7 +14,7 @@
 # You should have received a copy of the GNU Lesser General Public License
 # along with this library; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
-NR_ITER=100
+NR_ITER=30
 TEST_DESC="UST tracer - Generate $NR_ITER process"
 
 CURDIR=$(dirname $0)/
@@ -46,16 +46,13 @@ do
        ./$CURDIR/$TEST_BIN_NAME 1000 >/dev/null 2>&1 &
 done
 
-sleep 3
+reg_app_count=0
+while [ $reg_app_count -ne $NR_ITER ]; do
+       listing=$($TESTDIR/../src/bin/lttng/$LTTNG_BIN list -u)
+       reg_app_count=$(echo -n $listing | sed "s/$TEST_BIN_NAME/$TEST_BIN_NAME\n/g" | grep "$TEST_BIN_NAME" | wc -l)
+done
 
-listing=$($TESTDIR/../src/bin/lttng/$LTTNG_BIN list -u)
-reg_app_count=$(echo -n $listing | sed "s/$TEST_BIN_NAME/$TEST_BIN_NAME\n/g" | grep "$TEST_BIN_NAME" | wc -l)
-if [ "$reg_app_count" -ne "$NR_ITER" ]; then
-       fail "Trace validation"
-       diag "$reg_app_count apps listed. Expected $NR_ITER "
-else
-       pass "Trace validation"
-fi
+pass "Trace validation"
 
 TRACE_PATH=$(mktemp -d)
 
@@ -74,8 +71,11 @@ destroy_lttng_session $SESSION_NAME
 
 rm -rf $TRACE_PATH
 
-# Send SIGPIPE to 'silence' bash process status such as "Process as terminated"
-killall -s PIPE -q $TEST_BIN_NAME >/dev/null 2>&1
+while [ -n "$(pidof $TEST_BIN_NAME)" ]; do
+       killall -s PIPE -q $TEST_BIN_NAME >/dev/null 2>&1
+       sleep 0.5
+done
+
 
 pass "Kill all spawned applications"
 
index 631db84cbd9383b3e51d507cd0cc37f3358ce267..4e0d90cc83b457a881ba9e3ff5f17234f597a81b 100755 (executable)
@@ -30,7 +30,7 @@ NUM_DEMO1_2_EVENT=1
 NUM_DEMO2_EVENT=5
 NUM_DEMO3_EVENT=1
 
-NUM_TESTS=260
+NUM_TESTS=259
 
 source $TESTDIR/utils/utils.sh
 
@@ -301,13 +301,12 @@ test_enable_same_wildcard_filter_2()
 
        enable_ust_lttng_event_filter $SESSION_NAME "$event_wild1" "1==1"
 
-       # Enabling the same events with same filters should fail
+       # Enabling the same events with same filters should fail. This one is expected to fail.
        $TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-event "$event_wild2" -s $SESSION_NAME -u --filter "1==1" >/dev/null 2>&1
-
-       if [ $? -eq 1 ]; then
+       if [ $? -ne 0 ]; then
            pass "Enable event $event_name with filtering for session $sess_name twice failure detected"
        else
-           fail "Enable event $event_name with filtering for session $sess_name twice failure detected"
+           fail "Enable event $event_name with filtering for session $sess_name twice failure NOT detected"
        fi
 
        start_lttng_tracing $SESSION_NAME >/dev/null 2>&1
@@ -373,8 +372,6 @@ test_enable_same_event_filter()
        enable_ust_lttng_event_filter $SESSION_NAME "$event_wild1" "1==1&&1==1"
        enable_ust_lttng_event_filter $SESSION_NAME "$event_wild2" "1==1"
 
-       disable_ust_lttng_event $SESSION_NAME "ust*"
-
        start_lttng_tracing $SESSION_NAME >/dev/null 2>&1
 
        run_demo_app
index 79b745c884e609b7b247362356301e39a339afd0..6f1cb11b78ef9ae16410f8bfecb5e440d3733768 100755 (executable)
@@ -30,7 +30,8 @@ tests=( $DIR/test_event_basic
        $DIR/low-throughput/test_low_throughput
        $DIR/multi-session/test_multi_session
        $DIR/nprocesses/test_nprocesses
-       $DIR/overlap/test_overlap )
+       $DIR/overlap/test_overlap
+       $DIR/buffers-uid/test_buffers_uid )
 
 #### END TESTS HERE ####
 
index 51d755784ed6847696557f24766abceaf4d91dc5..1e4cce33a90c055e39ce24d1def0005a9cd1dcc4 100644 (file)
@@ -27,31 +27,43 @@ test_uri_SOURCES = test_uri.c
 test_uri_LDADD = $(LIBTAP) $(LIBCOMMON)
 
 # Session unit test
-SESSIONS=$(top_srcdir)/src/bin/lttng-sessiond/session.c        \
-        $(top_srcdir)/src/bin/lttng-sessiond/consumer.c        \
-        $(top_srcdir)/src/common/uri.c                         \
-        $(top_srcdir)/src/common/utils.c                       \
+SESSIONS=$(top_srcdir)/src/bin/lttng-sessiond/session.c        \
+        $(top_srcdir)/src/bin/lttng-sessiond/consumer.c \
+        $(top_srcdir)/src/bin/lttng-sessiond/health.c \
+        $(top_srcdir)/src/common/uri.c \
+        $(top_srcdir)/src/common/utils.c \
         $(top_srcdir)/src/common/error.c
 
 test_session_SOURCES = test_session.c $(SESSIONS)
-test_session_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBSESSIOND_COMM) $(LIBHASHTABLE)
+test_session_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBSESSIOND_COMM) $(LIBHASHTABLE) \
+                                        -lrt
 
 # UST data structures unit test
 if HAVE_LIBLTTNG_UST_CTL
 UST_DATA_TRACE=$(top_srcdir)/src/bin/lttng-sessiond/trace-ust.c \
-              $(top_srcdir)/src/bin/lttng-sessiond/consumer.c  \
-              $(top_srcdir)/src/common/uri.c                   \
+              $(top_srcdir)/src/bin/lttng-sessiond/consumer.c \
+                  $(top_srcdir)/src/bin/lttng-sessiond/buffer-registry.c \
+                  $(top_srcdir)/src/bin/lttng-sessiond/ust-registry.c \
+                  $(top_srcdir)/src/bin/lttng-sessiond/ust-metadata.c \
+                  $(top_srcdir)/src/bin/lttng-sessiond/ust-app.c \
+                  $(top_srcdir)/src/bin/lttng-sessiond/ust-consumer.c \
+                  $(top_srcdir)/src/bin/lttng-sessiond/fd-limit.c \
+                  $(top_srcdir)/src/bin/lttng-sessiond/health.c \
+              $(top_srcdir)/src/common/uri.c \
               $(top_srcdir)/src/common/utils.c
 
 test_ust_data_SOURCES = test_ust_data.c $(UST_DATA_TRACE)
-test_ust_data_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBSESSIOND_COMM) $(LIBHASHTABLE)
+test_ust_data_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBSESSIOND_COMM) $(LIBHASHTABLE) \
+                                         -lrt -llttng-ust-ctl
 endif
 
 # Kernel data structures unit test
-KERN_DATA_TRACE=$(top_srcdir)/src/bin/lttng-sessiond/trace-kernel.c    \
-               $(top_srcdir)/src/bin/lttng-sessiond/consumer.c         \
-               $(top_srcdir)/src/common/uri.c                          \
+KERN_DATA_TRACE=$(top_srcdir)/src/bin/lttng-sessiond/trace-kernel.c    \
+               $(top_srcdir)/src/bin/lttng-sessiond/consumer.c \
+               $(top_srcdir)/src/bin/lttng-sessiond/health.c \
+               $(top_srcdir)/src/common/uri.c \
                $(top_srcdir)/src/common/utils.c
 
 test_kernel_data_SOURCES = test_kernel_data.c $(KERN_DATA_TRACE)
-test_kernel_data_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBSESSIOND_COMM) $(LIBHASHTABLE)
+test_kernel_data_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBSESSIOND_COMM) $(LIBHASHTABLE) \
+                                                -lrt
index 13f48f9b5c1e5f1fb1f2418c043f36ce78816773..c9dc194d0ca4b449a6837065dfbf9c8150dec91c 100644 (file)
@@ -42,6 +42,9 @@
 int lttng_opt_quiet = 1;
 int lttng_opt_verbose;
 
+int ust_consumerd32_fd;
+int ust_consumerd64_fd;
+
 static const char alphanum[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
index 41c907c1876a180b451b00c12be1f55a2cb9545d..196124bd3c33e5b50beebcb1b49215c89450d879 100644 (file)
@@ -29,6 +29,7 @@
 #include <tap/tap.h>
 
 #include <bin/lttng-sessiond/session.h>
+#include <bin/lttng-sessiond/ust-app.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 #include <common/common.h>
 
@@ -49,6 +50,9 @@ static struct ltt_session_list *session_list;
 int lttng_opt_quiet = 1;
 int lttng_opt_verbose = 0;
 
+int ust_consumerd32_fd;
+int ust_consumerd64_fd;
+
 static const char alphanum[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
index 0f1c99b95d90a650c826a8d7aec527644baa336a..50d43bbd3800dc2cd0828ff4eaa7dff3d797aaac 100644 (file)
@@ -29,6 +29,7 @@
 #include <bin/lttng-sessiond/lttng-ust-abi.h>
 #include <common/defaults.h>
 #include <bin/lttng-sessiond/trace-ust.h>
+#include <bin/lttng-sessiond/ust-app.h>
 
 #include <tap/tap.h>
 
@@ -46,6 +47,9 @@
 int lttng_opt_quiet = 1;
 int lttng_opt_verbose;
 
+int ust_consumerd32_fd;
+int ust_consumerd64_fd;
+
 static const char alphanum[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -82,8 +86,6 @@ static void test_create_one_ust_session(void)
        ok(usess->id == 42 &&
           usess->start_trace == 0 &&
           usess->domain_global.channels != NULL &&
-          usess->domain_pid != NULL &&
-          usess->domain_exec != NULL &&
           usess->uid == 0 &&
           usess->gid == 0,
           "Validate UST session");
@@ -131,7 +133,6 @@ static void test_create_ust_channel(void)
        ok(uchan != NULL, "Create UST channel");
 
        ok(uchan->enabled == 0 &&
-          strcmp(PATH1, uchan->pathname) == 0 &&
           strncmp(uchan->name, "channel0", 8) == 0 &&
           uchan->name[LTTNG_UST_SYM_NAME_LEN - 1] == '\0' &&
           uchan->ctx != NULL &&
This page took 0.154067 seconds and 5 git commands to generate.