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
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:
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
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 */
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 {
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 \
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
--- /dev/null
+/*
+ * 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(®->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, ®->node.node);
+ assert(nodep == ®->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(®->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, ®->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(®->streams);
+ pthread_mutex_init(®->stream_list_lock, NULL);
+
+ lttng_ht_node_init_u64(®->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 = ®p->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, ®p->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 = ®p->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(®p->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 = ®p->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(®p->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);
+}
--- /dev/null
+/*
+ * 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 */
*/
#define _GNU_SOURCE
+#include <inttypes.h>
#include <string.h>
#include <unistd.h>
/*
* 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;
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;
/* 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;
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;
/*
* 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;
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;
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 */
#include "channel.h"
#include "consumer.h"
#include "event.h"
+#include "health.h"
#include "kernel.h"
#include "kernel-consumer.h"
#include "lttng-sessiond.h"
goto error;
}
- ret = channel_ust_disable(usess, domain, uchan);
+ ret = channel_ust_disable(usess, uchan);
if (ret != LTTNG_OK) {
goto 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;
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;
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. */
}
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;
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;
}
goto error;
}
- ret = event_ust_disable_all_tracepoints(usess, domain, uchan);
+ ret = event_ust_disable_all_tracepoints(usess, uchan);
if (ret != 0) {
goto error;
}
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;
/*
* 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)
{
rcu_read_lock();
- switch (domain) {
+ switch (domain->type) {
case LTTNG_DOMAIN_KERNEL:
{
struct ltt_kernel_channel *kchan;
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;
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;
}
/* 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;
}
/*
* 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;
rcu_read_lock();
- switch (domain) {
+ switch (domain->type) {
case LTTNG_DOMAIN_KERNEL:
{
struct ltt_kernel_channel *kchan;
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;
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;
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;
}
/* 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,
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 */
#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
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
gid_t gid,
uint64_t relayd_id,
uint64_t key,
- unsigned char *uuid)
+ unsigned char *uuid,
+ uint32_t chan_id)
{
assert(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));
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;
+}
#include <common/hashtable/hashtable.h>
#include <lttng/lttng.h>
-#include "health.h"
-
enum consumer_dst_type {
CONSUMER_DST_LOCAL,
CONSUMER_DST_NET,
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);
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,
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 */
/*
* 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;
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;
/*
* 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)
{
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) {
/*
* 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;
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,
/*
* 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;
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;
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 */
#include <common/defaults.h>
#include "consumer.h"
+#include "health.h"
#include "kernel-consumer.h"
/*
#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,
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
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 */
} 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 */
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];
};
#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];
/*
* 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 */
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;
struct {
void *data;
enum lttng_ust_chan_type type;
+ int wakeup_fd;
} channel;
struct {
int shm_fd;
};
#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];
#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)
union ust_args {
struct {
void *chan_data;
+ int wakeup_fd;
} channel;
struct {
int shm_fd;
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);
#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;
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;
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.
*/
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.
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 */
#include <limits.h>
#include <unistd.h>
-
-#include "lttng-ust-abi.h"
+#include <lttng/ust-abi.h>
/*
* ustcomm 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 */
#include <common/utils.h>
#include "lttng-sessiond.h"
+#include "buffer-registry.h"
#include "channel.h"
#include "cmd.h"
#include "consumer.h"
DBG("Closing all UST sockets");
ust_app_clean_list();
+ buffer_reg_destroy_registries();
if (is_root && !opt_no_kernel) {
DBG2("Closing kernel fd");
do {
struct ust_app *app = NULL;
+ ust_cmd = NULL;
/* Dequeue command for registration */
node = cds_wfq_dequeue_blocking(&ust_cmd_queue.queue);
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);
}
lttng_fd_put(1, LTTNG_FD_APPS);
free(wait_node);
+ free(ust_cmd);
continue;
}
/*
*/
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
break;
}
}
+ free(ust_cmd);
}
if (app) {
}
lttng_fd_put(1, LTTNG_FD_APPS);
}
- free(ust_cmd);
} while (node != NULL);
/* Futex wait on queue. Blocking call on futex() */
}
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;
{
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;
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;
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);
#include <urcu/list.h>
#include "trace-kernel.h"
-#include "trace-ust.h"
+
+struct ltt_ust_session;
/*
* Tracing session list
#include <common/common.h>
#include <common/defaults.h>
+#include "buffer-registry.h"
#include "trace-ust.h"
/*
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);
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");
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;
struct ltt_ust_channel *trace_ust_create_channel(struct lttng_channel *chan,
char *path)
{
- int ret;
struct ltt_ust_channel *luc;
assert(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;
}
/*
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.
*/
*/
void trace_ust_destroy_session(struct ltt_ust_session *session)
{
+ struct buffer_reg_uid *reg, *sreg;
+
assert(session);
rcu_read_lock();
/* 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(®->lnode);
+ buffer_reg_uid_remove(reg);
+ buffer_reg_uid_destroy(reg, session->consumer);
+ }
consumer_destroy_output(session->consumer);
consumer_destroy_output(session->tmp_consumer);
/* 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];
/* 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 */
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;
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);
#define _GNU_SOURCE
#include <errno.h>
+#include <inttypes.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#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"
/* 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.
}
/*
- * 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);
}
/*
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.
}
/*
- * 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);
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);
}
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);
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. */
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);
*
* 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;
* ability to reorder the metadata it receives.
*/
pthread_mutex_lock(socket->lock);
- pthread_mutex_lock(&ua_sess->registry->lock);
+ pthread_mutex_lock(®istry->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;
}
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(®istry->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(®istry->lock);
+ registry->metadata_len_sent += len;
+ pthread_mutex_unlock(®istry->lock);
pthread_mutex_unlock(socket->lock);
rcu_read_unlock();
return 0;
error_reg_unlock:
- pthread_mutex_unlock(&ua_sess->registry->lock);
+ pthread_mutex_unlock(®istry->lock);
pthread_mutex_unlock(socket->lock);
error_rcu_unlock:
rcu_read_unlock();
free(metadata_str);
-end:
return ret;
}
*
* 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;
}
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,
}
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);
/* 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
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;
}
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. */
}
/*
- * 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);
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;
}
*/
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);
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) {
lttng_ht_add_unique_str(ua_sess->channels, &ua_chan->node);
}
+
+error:
+ return;
}
/*
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, ®_pid);
+ if (ret < 0) {
+ goto error;
+ }
+ buffer_reg_pid_add(reg_pid);
+ } else {
+ goto end;
+ }
+
+ /* Initialize registry. */
+ ret = ust_registry_session_init(®_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, ®_uid);
+ if (ret < 0) {
+ goto error;
+ }
+ buffer_reg_uid_add(reg_uid);
+ } else {
+ goto end;
+ }
+
+ /* Initialize registry. */
+ ret = ust_registry_session_init(®_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(®_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.
*
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",
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(®_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, ®_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(®_chan->stream_list_lock);
+ cds_list_for_each_entry(reg_stream, ®_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(®_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, ®_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:
* 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;
/* 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;
}
/*
* 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)
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 */
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;
}
* 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:
/* 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. */
* 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, <a->teardown_head);
pthread_mutex_unlock(&ua_sess->lock);
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();
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) {
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");
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);
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:
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;
}
*/
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
{
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();
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(®istry->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;
}
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) {
goto error;
}
+ /* This channel registry registration is completed. */
+ chan_reg->register_done = 1;
+
error:
- pthread_mutex_unlock(&ua_sess->registry->lock);
+ pthread_mutex_unlock(®istry->lock);
error_rcu_unlock:
rcu_read_unlock();
return ret;
{
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();
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(®istry->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
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(®istry->lock);
error_rcu_unlock:
rcu_read_unlock();
return ret;
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];
/* 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;
};
/*
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;
#include <common/defaults.h>
#include "consumer.h"
+#include "health.h"
#include "ust-consumer.h"
/*
}
/* 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");
/*
* 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");
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,
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();
*/
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;
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;
}
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);
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;
-}
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);
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 */
*
* 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 */
"};\n\n");
if (ret)
goto end;
+ event->metadata_dumped = 1;
end:
return ret;
ret = lttng_metadata_printf(session,
"};\n\n");
+ /* Flag success of metadata dump. */
+ chan->metadata_dumped = 1;
end:
return ret;
int ret = 0;
char hostname[HOST_NAME_MAX];
+ assert(session);
+ assert(app);
+
uuid_c = session->uuid;
snprintf(uuid_s, sizeof(uuid_s),
*/
#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"
/*
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.
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;
*/
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);
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;
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;
}
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;
assert(session);
assert(name);
assert(sig);
+ assert(event_id_p);
/*
* This should not happen but since it comes from the UST tracer, an
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();
/* 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);
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) {
#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
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;
* 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 {
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.
*/
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;
};
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;
};
/*
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(
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,
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 */
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,
{"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},
{"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}
};
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");
}
/* 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;
/* 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;
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 */
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;
LTTNG_CONSUMER_PUSH_METADATA,
LTTNG_CONSUMER_CLOSE_METADATA,
LTTNG_CONSUMER_SETUP_METADATA,
+ LTTNG_CONSUMER_FLUSH_CHANNEL,
};
/* State of each fd in consumer */
#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.
#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.
[ 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"
/*
* 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);
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);
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;
struct {
uint64_t key; /* Metadata channel key. */
} LTTNG_PACKED setup_metadata;
+ struct {
+ uint64_t key; /* Channel key. */
+ } LTTNG_PACKED flush_channel;
} u;
} LTTNG_PACKED;
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.
*
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. */
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;
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));
TRACE_PATH=$(mktemp -d)
-NUM_TESTS=11
+NUM_TESTS=10
source $TESTDIR/utils/utils.sh
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 )
TRACE_PATH=$(mktemp -d)
-NUM_TESTS=20
+NUM_TESTS=18
source $TESTDIR/utils/utils.sh
function wait_apps
{
-
while [ -n "$(pidof $BIN_NAME)" ]; do
sleep 0.5
done
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 )
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#!/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
--- /dev/null
+/*
+ * 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"
--- /dev/null
+#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
# 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)/
./$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)
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"
NUM_DEMO2_EVENT=5
NUM_DEMO3_EVENT=1
-NUM_TESTS=260
+NUM_TESTS=259
source $TESTDIR/utils/utils.sh
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
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
$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 ####
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
int lttng_opt_quiet = 1;
int lttng_opt_verbose;
+int ust_consumerd32_fd;
+int ust_consumerd64_fd;
+
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#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>
int lttng_opt_quiet = 1;
int lttng_opt_verbose = 0;
+int ust_consumerd32_fd;
+int ust_consumerd64_fd;
+
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#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>
int lttng_opt_quiet = 1;
int lttng_opt_verbose;
+int ust_consumerd32_fd;
+int ust_consumerd64_fd;
+
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
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");
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 &&