* where the stack grows up (HPPA).
*/
pid = clone(child_run_as, child_stack + (CHILD_STACK_SIZE / 2),
- CLONE_FILES | SIGCHLD | CLONE_VM,
+ CLONE_FILES | SIGCHLD,
&run_as_data, NULL);
if (pid < 0) {
perror("clone");
[CONSUMERD64_LIBDIR=''])
AC_SUBST([CONSUMERD64_LIBDIR])
-AC_DEFINE_UNQUOTED([CONFIG_CONSUMERD32_BIN], $CONSUMERD32_BIN, [Location of the 32-bit consumerd executable.])
-AC_DEFINE_UNQUOTED([CONFIG_CONSUMERD64_BIN], $CONSUMERD64_BIN, [Location of the 64-bit consumerd executable])
-AC_DEFINE_UNQUOTED([CONFIG_CONSUMERD32_LIBDIR], $CONSUMERD32_LIBDIR, [Search for consumerd 32-bit libraries in this location.])
-AC_DEFINE_UNQUOTED([CONFIG_CONSUMERD64_LIBDIR], $CONSUMERD64_LIBDIR, [Search for consumerd 64-bit libraries in this location.])
+AC_DEFINE_UNQUOTED([CONFIG_CONSUMERD32_BIN], "$CONSUMERD32_BIN", [Location of the 32-bit consumerd executable.])
+AC_DEFINE_UNQUOTED([CONFIG_CONSUMERD64_BIN], "$CONSUMERD64_BIN", [Location of the 64-bit consumerd executable])
+AC_DEFINE_UNQUOTED([CONFIG_CONSUMERD32_LIBDIR], "$CONSUMERD32_LIBDIR", [Search for consumerd 32-bit libraries in this location.])
+AC_DEFINE_UNQUOTED([CONFIG_CONSUMERD64_LIBDIR], "$CONSUMERD64_LIBDIR", [Search for consumerd 64-bit libraries in this location.])
# Check for pthread
AC_CHECK_LIB([pthread], [pthread_create], [],
AC_OUTPUT
+#
# Mini-report on what will be built
-AS_ECHO("")
-
+#
+AS_ECHO()
+
+# Target architecture we're building for
+target_arch=$host_cpu
+[
+for f in $CFLAGS; do
+ if test $f = "-m32"; then
+ target_arch="32-bit"
+ elif test $f = "-m64"; then
+ target_arch="64-bit"
+ fi
+done
+]
+AS_ECHO_N("Target architecture: ")
+AS_ECHO($target_arch)
+
+# LTTng-UST enabled/disabled
AS_ECHO_N("Lttng-UST support: ")
-AS_IF([test "x$lttng_ust_support" = "xyes"], [AS_ECHO("Enabled")],
- [AS_ECHO("Disabled")]
-)
+AS_IF([test "x$lttng_ust_support" = "xyes"],[
+ AS_ECHO("Enabled")
+],[
+ AS_ECHO("Disabled")
+])
-AS_IF([test "x$consumerd_only" = "xyes"],
- [AS_ECHO("Only the consumerd daemon will be built.")],
- [AS_ECHO("All binaries will be built.")]
-)
+# Do we build only the consumerd, or everything
+AS_IF([test "x$consumerd_only" = "xyes"],[
+ AS_ECHO("Only the consumerd daemon will be built.")
+],[
+ AS_ECHO("All binaries will be built.")
+])
+
+# Print the bindir and libdir this `make install' will install into.
+AS_ECHO()
+AS_ECHO_N("Binaries will be installed in: ")
+AS_ECHO("`eval eval echo $bindir`")
+AS_ECHO_N("Libraries will be installed in: ")
+AS_ECHO("`eval eval echo $libdir`")
+
+# If we build the sessiond, print the paths it will use
+AS_IF([test "x$consumerd_only" = "xno"],[
+ AS_ECHO()
+ AS_ECHO("The sessiond daemon will look in the following directories: ")
+ AS_ECHO_N("32-bit consumerd executable at: ")
+ AS_IF([test "$CONSUMERD32_BIN" = ""],[
+ AS_ECHO_N("`eval eval echo $bindir`")
+ AS_ECHO("/lttng-consumerd")
+ ],[
+ AS_ECHO("$CONSUMERD32_BIN")
+ ])
+
+ AS_ECHO_N("32-bit consumer libraries in: ")
+ AS_IF([test "$CONSUMERD32_LIBDIR" = ""],[
+ AS_ECHO("`eval eval echo $libdir`")
+ ],[
+ AS_ECHO("$CONSUMERD32_LIBDIR")
+ ])
+
+ AS_ECHO_N("64-bit consumerd executable at: ")
+ AS_IF([test "$CONSUMERD64_BIN" = ""],[
+ AS_ECHO_N("`eval eval echo $bindir`")
+ AS_ECHO("/lttng-consumerd")
+ ],[
+ AS_ECHO("$CONSUMERD64_BIN")
+ ])
+
+ AS_ECHO_N("64-bit consumer libraries in: ")
+ AS_IF([test "$CONSUMERD64_LIBDIR" = ""],[
+ AS_ECHO("`eval eval echo $libdir`")
+ ],[
+ AS_ECHO("$CONSUMERD64_LIBDIR")
+ ])
+])
-AS_ECHO("")
+AS_ECHO()
#include <limits.h>
#include <poll.h>
#include <unistd.h>
-#include <urcu/list.h>
+
#include <lttng/lttng.h>
+#include <lttng-ht.h>
/*
* When the receiving thread dies, we need to have a way to make the polling
LTTNG_CONSUMER_DELETE_STREAM,
};
-struct lttng_consumer_channel_list {
- struct cds_list_head head;
-};
-
-struct lttng_consumer_stream_list {
- struct cds_list_head head;
-};
-
enum lttng_consumer_type {
LTTNG_CONSUMER_UNKNOWN = 0,
LTTNG_CONSUMER_KERNEL,
};
struct lttng_consumer_channel {
- struct cds_list_head list;
+ struct lttng_ht_node_ulong node;
int key;
uint64_t max_sb_size; /* the subbuffer size for this channel */
int refcount; /* Number of streams referencing this channel */
size_t mmap_len;
struct lttng_ust_shm_handle *handle;
int nr_streams;
- int shm_fd_is_copy;
int wait_fd_is_copy;
int cpucount;
};
* uniquely a stream.
*/
struct lttng_consumer_stream {
- struct cds_list_head list;
+ struct lttng_ht_node_ulong node;
struct lttng_consumer_channel *chan; /* associated channel */
/*
* key is the key used by the session daemon to refer to the
* Library-level data. One instance per process.
*/
struct lttng_consumer_global_data {
+
/*
- * consumer_data.lock protects consumer_data.fd_list,
- * consumer_data.stream_count, and consumer_data.need_update. It
- * ensures the count matches the number of items in the fd_list.
- * It ensures the list updates *always* trigger an fd_array
- * update (therefore need to make list update vs
- * consumer_data.need_update flag update atomic, and also flag
- * read, fd array and flag clear atomic).
+ * At this time, this lock is used to ensure coherence between the count
+ * and number of element in the hash table. It's also a protection for
+ * concurrent read/write between threads.
+ *
+ * XXX: We need to see if this lock is still needed with the lockless RCU
+ * hash tables.
*/
pthread_mutex_t lock;
+
/*
- * Number of streams in the list below. Protected by
- * consumer_data.lock.
+ * Number of streams in the hash table. Protected by consumer_data.lock.
*/
int stream_count;
/*
- * Lists of streams and channels. Protected by consumer_data.lock.
+ * Hash tables of streams and channels. Protected by consumer_data.lock.
*/
- struct lttng_consumer_stream_list stream_list;
- struct lttng_consumer_channel_list channel_list;
+ struct lttng_ht *stream_ht;
+ struct lttng_ht *channel_ht;
/*
* Flag specifying if the local array of FDs needs update in the
* poll function. Protected by consumer_data.lock.
enum lttng_consumer_type type;
};
+/*
+ * Init consumer data structures.
+ */
+extern void lttng_consumer_init(void);
+
/*
* Set the error socket for communication with a session daemon.
*/
liblttng_consumer_la_LIBADD = \
$(top_builddir)/liblttng-sessiond-comm/liblttng-sessiond-comm.la \
- $(top_builddir)/liblttng-kconsumer/liblttng-kconsumer.la
-
+ $(top_builddir)/liblttng-kconsumer/liblttng-kconsumer.la \
+ $(top_builddir)/liblttng-ht/liblttng-ht.la
if HAVE_LIBLTTNG_UST_CTL
liblttng_consumer_la_LIBADD += \
#include <lttngerr.h>
struct lttng_consumer_global_data consumer_data = {
- .stream_list.head = CDS_LIST_HEAD_INIT(consumer_data.stream_list.head),
- .channel_list.head = CDS_LIST_HEAD_INIT(consumer_data.channel_list.head),
.stream_count = 0,
.need_update = 1,
.type = LTTNG_CONSUMER_UNKNOWN,
*/
static struct lttng_consumer_stream *consumer_find_stream(int key)
{
- struct lttng_consumer_stream *iter;
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_ulong *node;
+ struct lttng_consumer_stream *stream = NULL;
/* Negative keys are lookup failures */
if (key < 0)
return NULL;
- cds_list_for_each_entry(iter, &consumer_data.stream_list.head, list) {
- if (iter->key == key) {
- DBG("Found stream key %d", key);
- return iter;
- }
+
+ rcu_read_lock();
+
+ lttng_ht_lookup(consumer_data.stream_ht, (void *)((unsigned long) key),
+ &iter);
+ node = lttng_ht_iter_get_node_ulong(&iter);
+ if (node != NULL) {
+ stream = caa_container_of(node, struct lttng_consumer_stream, node);
}
- return NULL;
+
+ rcu_read_unlock();
+
+ return stream;
}
static void consumer_steal_stream_key(int key)
static struct lttng_consumer_channel *consumer_find_channel(int key)
{
- struct lttng_consumer_channel *iter;
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_ulong *node;
+ struct lttng_consumer_channel *channel = NULL;
/* Negative keys are lookup failures */
if (key < 0)
return NULL;
- cds_list_for_each_entry(iter, &consumer_data.channel_list.head, list) {
- if (iter->key == key) {
- DBG("Found channel key %d", key);
- return iter;
- }
+
+ rcu_read_lock();
+
+ lttng_ht_lookup(consumer_data.channel_ht, (void *)((unsigned long) key),
+ &iter);
+ node = lttng_ht_iter_get_node_ulong(&iter);
+ if (node != NULL) {
+ channel = caa_container_of(node, struct lttng_consumer_channel, node);
}
- return NULL;
+
+ rcu_read_unlock();
+
+ return channel;
}
static void consumer_steal_channel_key(int key)
void consumer_del_stream(struct lttng_consumer_stream *stream)
{
int ret;
+ struct lttng_ht_iter iter;
struct lttng_consumer_channel *free_chan = NULL;
pthread_mutex_lock(&consumer_data.lock);
goto end;
}
- cds_list_del(&stream->list);
+ rcu_read_lock();
+
+ /* Get stream node from hash table */
+ lttng_ht_lookup(consumer_data.stream_ht,
+ (void *)((unsigned long) stream->key), &iter);
+ /* Remove stream node from hash table */
+ ret = lttng_ht_del(consumer_data.stream_ht, &iter);
+ assert(!ret);
+
+ rcu_read_unlock();
+
if (consumer_data.stream_count <= 0) {
goto end;
}
if (stream->wait_fd >= 0 && !stream->wait_fd_is_copy) {
close(stream->wait_fd);
}
- if (stream->shm_fd >= 0 && stream->wait_fd != stream->shm_fd
- && !stream->shm_fd_is_copy) {
+ if (stream->shm_fd >= 0 && stream->wait_fd != stream->shm_fd) {
close(stream->shm_fd);
}
if (!--stream->chan->refcount)
consumer_del_channel(free_chan);
}
+static void consumer_del_stream_rcu(struct rcu_head *head)
+{
+ struct lttng_ht_node_ulong *node =
+ caa_container_of(head, struct lttng_ht_node_ulong, head);
+ struct lttng_consumer_stream *stream =
+ caa_container_of(node, struct lttng_consumer_stream, node);
+
+ consumer_del_stream(stream);
+}
+
struct lttng_consumer_stream *consumer_allocate_stream(
int channel_key, int stream_key,
int shm_fd, int wait_fd,
stream->gid = gid;
strncpy(stream->path_name, path_name, PATH_MAX - 1);
stream->path_name[PATH_MAX - 1] = '\0';
+ lttng_ht_node_init_ulong(&stream->node, stream->key);
switch (consumer_data.type) {
case LTTNG_CONSUMER_KERNEL:
pthread_mutex_lock(&consumer_data.lock);
/* Steal stream identifier, for UST */
consumer_steal_stream_key(stream->key);
- cds_list_add(&stream->list, &consumer_data.stream_list.head);
+ rcu_read_lock();
+ lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
+ rcu_read_unlock();
consumer_data.stream_count++;
consumer_data.need_update = 1;
void consumer_del_channel(struct lttng_consumer_channel *channel)
{
int ret;
+ struct lttng_ht_iter iter;
pthread_mutex_lock(&consumer_data.lock);
goto end;
}
- cds_list_del(&channel->list);
+ rcu_read_lock();
+
+ lttng_ht_lookup(consumer_data.channel_ht,
+ (void *)((unsigned long) channel->key), &iter);
+ ret = lttng_ht_del(consumer_data.channel_ht, &iter);
+ assert(!ret);
+
+ rcu_read_unlock();
+
if (channel->mmap_base != NULL) {
ret = munmap(channel->mmap_base, channel->mmap_len);
if (ret != 0) {
if (channel->wait_fd >= 0 && !channel->wait_fd_is_copy) {
close(channel->wait_fd);
}
- if (channel->shm_fd >= 0 && channel->wait_fd != channel->shm_fd
- && !channel->shm_fd_is_copy) {
+ if (channel->shm_fd >= 0 && channel->wait_fd != channel->shm_fd) {
close(channel->shm_fd);
}
free(channel);
pthread_mutex_unlock(&consumer_data.lock);
}
+static void consumer_del_channel_rcu(struct rcu_head *head)
+{
+ struct lttng_ht_node_ulong *node =
+ caa_container_of(head, struct lttng_ht_node_ulong, head);
+ struct lttng_consumer_channel *channel=
+ caa_container_of(node, struct lttng_consumer_channel, node);
+
+ consumer_del_channel(channel);
+}
+
struct lttng_consumer_channel *consumer_allocate_channel(
int channel_key,
int shm_fd, int wait_fd,
channel->max_sb_size = max_sb_size;
channel->refcount = 0;
channel->nr_streams = 0;
+ lttng_ht_node_init_ulong(&channel->node, channel->key);
switch (consumer_data.type) {
case LTTNG_CONSUMER_KERNEL:
pthread_mutex_lock(&consumer_data.lock);
/* Steal channel identifier, for UST */
consumer_steal_channel_key(channel->key);
- cds_list_add(&channel->list, &consumer_data.channel_list.head);
+ rcu_read_lock();
+ lttng_ht_add_unique_ulong(consumer_data.channel_ht, &channel->node);
+ rcu_read_unlock();
pthread_mutex_unlock(&consumer_data.lock);
return 0;
}
struct lttng_consumer_local_data *ctx, struct pollfd **pollfd,
struct lttng_consumer_stream **local_stream)
{
- struct lttng_consumer_stream *iter;
int i = 0;
+ struct lttng_ht_iter iter;
+ struct lttng_consumer_stream *stream;
DBG("Updating poll fd array");
- cds_list_for_each_entry(iter, &consumer_data.stream_list.head, list) {
- if (iter->state != LTTNG_CONSUMER_ACTIVE_STREAM) {
+ cds_lfht_for_each_entry(consumer_data.stream_ht->ht, &iter.iter, stream,
+ node.node) {
+ if (stream->state != LTTNG_CONSUMER_ACTIVE_STREAM) {
continue;
}
- DBG("Active FD %d", iter->wait_fd);
- (*pollfd)[i].fd = iter->wait_fd;
+ DBG("Active FD %d", stream->wait_fd);
+ (*pollfd)[i].fd = stream->wait_fd;
(*pollfd)[i].events = POLLIN | POLLPRI;
- local_stream[i] = iter;
+ local_stream[i] = stream;
i++;
}
*/
void lttng_consumer_cleanup(void)
{
- struct lttng_consumer_stream *iter, *tmp;
- struct lttng_consumer_channel *citer, *ctmp;
+ int ret;
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_ulong *node;
+
+ rcu_read_lock();
/*
- * close all outfd. Called when there are no more threads
- * running (after joining on the threads), no need to protect
- * list iteration with mutex.
+ * close all outfd. Called when there are no more threads running (after
+ * joining on the threads), no need to protect list iteration with mutex.
*/
- cds_list_for_each_entry_safe(iter, tmp,
- &consumer_data.stream_list.head, list) {
- consumer_del_stream(iter);
+ cds_lfht_for_each_entry(consumer_data.stream_ht->ht, &iter.iter, node,
+ node) {
+ ret = lttng_ht_del(consumer_data.stream_ht, &iter);
+ assert(!ret);
+ call_rcu(&node->head, consumer_del_stream_rcu);
}
- cds_list_for_each_entry_safe(citer, ctmp,
- &consumer_data.channel_list.head, list) {
- consumer_del_channel(citer);
+
+ cds_lfht_for_each_entry(consumer_data.channel_ht->ht, &iter.iter, node,
+ node) {
+ ret = lttng_ht_del(consumer_data.channel_ht, &iter);
+ assert(!ret);
+ call_rcu(&node->head, consumer_del_channel_rcu);
}
+
+ rcu_read_unlock();
}
/*
}
/*
- * This thread polls the fds in the ltt_fd_list to consume the data and write
+ * This thread polls the fds in the set to consume the data and write
* it to tracefile if necessary.
*/
void *lttng_consumer_thread_poll_fds(void *data)
int tmp2;
struct lttng_consumer_local_data *ctx = data;
+ rcu_register_thread();
+
local_stream = zmalloc(sizeof(struct lttng_consumer_stream));
while (1) {
num_hup = 0;
/*
- * the ltt_fd_list has been updated, we need to update our
+ * the fds set has been updated, we need to update our
* local array as well
*/
pthread_mutex_lock(&consumer_data.lock);
}
} else if (pollfd[i].revents & POLLERR) {
ERR("Error returned in polling fd %d.", pollfd[i].fd);
- consumer_del_stream(local_stream[i]);
+ rcu_read_lock();
+ consumer_del_stream_rcu(&local_stream[i]->node.head);
+ rcu_read_unlock();
num_hup++;
} else if (pollfd[i].revents & POLLNVAL) {
ERR("Polling fd %d tells fd is not open.", pollfd[i].fd);
- consumer_del_stream(local_stream[i]);
+ rcu_read_lock();
+ consumer_del_stream_rcu(&local_stream[i]->node.head);
+ rcu_read_unlock();
num_hup++;
} else if ((pollfd[i].revents & POLLHUP) &&
!(pollfd[i].revents & POLLIN)) {
} else {
DBG("Polling fd %d tells it has hung up.", pollfd[i].fd);
}
- consumer_del_stream(local_stream[i]);
+ rcu_read_lock();
+ consumer_del_stream_rcu(&local_stream[i]->node.head);
+ rcu_read_unlock();
num_hup++;
}
}
free(local_stream);
local_stream = NULL;
}
+ rcu_unregister_thread();
return NULL;
}
struct pollfd consumer_sockpoll[2];
struct lttng_consumer_local_data *ctx = data;
+ rcu_register_thread();
+
DBG("Creating command socket %s", ctx->consumer_command_sock_path);
unlink(ctx->consumer_command_sock_path);
client_socket = lttcomm_create_unix_sock(ctx->consumer_command_sock_path);
if (ret < 0) {
perror("poll pipe write");
}
+ rcu_unregister_thread();
return NULL;
}
return -ENOSYS;
}
}
+
+/*
+ * Allocate and set consumer data hash tables.
+ */
+void lttng_consumer_init(void)
+{
+ consumer_data.stream_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+ consumer_data.channel_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+}
+
struct lttng_ht *ht;
/* Test size */
- size != 0 ? : (size = DEFAULT_HT_SIZE);
+ if (!size)
+ size = DEFAULT_HT_SIZE;
ht = zmalloc(sizeof(*ht));
if (ht == NULL) {
{
assert(ht);
assert(ht->ht);
- assert(key);
cds_lfht_lookup(ht->ht, ht->hash_fct(key, HASH_SEED),
ht->match_fct, key, &iter->iter);
if (!chan->handle) {
return -ENOMEM;
}
- /*
- * The channel fds are passed to ustctl, we only keep a copy.
- */
- chan->shm_fd_is_copy = 1;
chan->wait_fd_is_copy = 1;
+ chan->shm_fd = -1;
return 0;
}
stream->buf = ustctl_open_stream_read(stream->chan->handle, stream->cpu);
if (!stream->buf)
return -EBUSY;
+ /* ustctl_open_stream_read has closed the shm fd. */
+ stream->wait_fd_is_copy = 1;
+ stream->shm_fd = -1;
+
stream->mmap_base = ustctl_get_mmap_base(stream->chan->handle, stream->buf);
if (!stream->mmap_base) {
return -EINVAL;
}
- /*
- * The stream fds are passed to ustctl, we only keep a copy.
- */
- stream->shm_fd_is_copy = 1;
- stream->wait_fd_is_copy = 1;
return 0;
}
goto error;
}
}
+
+ /* Init */
+ lttng_consumer_init();
+
/* create the consumer instance with and assign the callbacks */
ctx = lttng_consumer_create(opt_type, lttng_consumer_read_subbuffer,
NULL, lttng_consumer_on_recv_stream, NULL);
struct lttng_channel *attr)
{
int ret = LTTCOMM_OK;
- struct lttng_ht *chan_ht;
struct ltt_ust_channel *uchan = NULL;
struct lttng_channel *defattr = NULL;
ret = LTTCOMM_FATAL;
goto error;
}
+ uchan->enabled = 1;
switch (domain) {
case LTTNG_DOMAIN_UST:
DBG2("Channel %s being created in UST global domain", uchan->name);
- chan_ht = usess->domain_global.channels;
/* Enable channel for global domain */
ret = ust_app_create_channel_glb(usess, uchan);
goto error_free_chan;
}
- uchan->enabled = 1;
- lttng_ht_add_unique_str(chan_ht, &uchan->node);
+ /* Adding the channel to the channel hash table. */
+ rcu_read_lock();
+ lttng_ht_add_unique_str(usess->domain_global.channels, &uchan->node);
+ rcu_read_unlock();
+
DBG2("Channel %s created successfully", uchan->name);
free(defattr);
return LTTCOMM_OK;
error_free_chan:
+ /*
+ * No need to remove the channel from the hash table because at this point
+ * it was not added hence the direct call and no call_rcu().
+ */
trace_ust_destroy_channel(uchan);
error:
free(defattr);
int event_ust_enable_tracepoint(struct ltt_ust_session *usess, int domain,
struct ltt_ust_channel *uchan, struct lttng_event *event)
{
- int ret, to_create = 0;
+ int ret = LTTCOMM_OK, to_create = 0;
struct ltt_ust_event *uevent;
uevent = trace_ust_find_event_by_name(uchan->events, event->name);
ret = LTTCOMM_FATAL;
goto error;
}
+ /* Valid to set it after the goto error since uevent is still NULL */
to_create = 1;
}
goto end;
}
+ uevent->enabled = 1;
+
switch (domain) {
case LTTNG_DOMAIN_UST:
{
goto end;
}
- uevent->enabled = 1;
- /* Add ltt ust event to channel */
if (to_create) {
rcu_read_lock();
+ /* Add ltt ust event to channel */
lttng_ht_add_unique_str(uchan->events, &uevent->node);
rcu_read_unlock();
}
DBG("Event UST %s %s in channel %s", uevent->attr.name,
to_create ? "created" : "enabled", uchan->name);
+ ret = LTTCOMM_OK;
+
end:
- return LTTCOMM_OK;
+ return ret;
error:
- trace_ust_destroy_event(uevent);
+ /*
+ * Only destroy event on creation time (not enabling time) because if the
+ * event is found in the channel (to_create == 0), it means that at some
+ * point the enable_event worked and it's thus valid to keep it alive.
+ * Destroying it also implies that we also destroy it's shadow copy to sync
+ * everyone up.
+ */
+ if (to_create) {
+ /* In this code path, the uevent was not added to the hash table */
+ trace_ust_destroy_event(uevent);
+ }
return ret;
}
unsigned int switch_timer_interval; /* usecs */
unsigned int read_timer_interval; /* usecs */
enum lttng_ust_output output; /* output mode */
- /* The following fields are used internally within UST. */
- int shm_fd;
- int wait_fd;
- uint64_t memory_map_size;
-};
-
-/*
- * This structure is only used internally within UST. It is not per-se
- * part of the communication between sessiond and UST.
- */
-struct lttng_ust_stream {
- int shm_fd;
- int wait_fd;
- uint64_t memory_map_size;
};
struct lttng_ust_event {
struct lttng_ust_obj;
+union ust_args {
+ struct {
+ int *shm_fd;
+ int *wait_fd;
+ uint64_t *memory_map_size;
+ } channel;
+ struct {
+ int *shm_fd;
+ int *wait_fd;
+ uint64_t *memory_map_size;
+ } stream;
+};
+
struct lttng_ust_objd_ops {
- long (*cmd)(int objd, unsigned int cmd, unsigned long arg);
+ long (*cmd)(int objd, unsigned int cmd, unsigned long arg,
+ union ust_args *args);
int (*release)(int objd);
};
int ust_consumerd64_fd = -1;
int ust_consumerd32_fd = -1;
-static const char *consumerd32_bin =
- __stringify(CONFIG_CONSUMERD32_BIN);
-static const char *consumerd64_bin =
- __stringify(CONFIG_CONSUMERD64_BIN);
-static const char *consumerd32_libdir =
- __stringify(CONFIG_CONSUMERD32_LIBDIR);
-static const char *consumerd64_libdir =
- __stringify(CONFIG_CONSUMERD64_LIBDIR);
+static const char *consumerd32_bin = CONFIG_CONSUMERD32_BIN;
+static const char *consumerd64_bin = CONFIG_CONSUMERD64_BIN;
+static const char *consumerd32_libdir = CONFIG_CONSUMERD32_LIBDIR;
+static const char *consumerd64_libdir = CONFIG_CONSUMERD64_LIBDIR;
static
void setup_consumerd_path(void)
/*
* Exec consumerd.
*/
- if (opt_verbose > 1 || opt_verbose_consumer) {
+ if (opt_verbose_consumer) {
verbosity = "--verbose";
} else {
verbosity = "--quiet";
* sessiond's installation directory, and
* fallback on the 32-bit one,
*/
+ DBG3("Looking for a kernel consumer at these locations:");
+ DBG3(" 1) %s", consumerd64_bin);
+ DBG3(" 2) %s/%s", INSTALL_BIN_PATH, CONSUMERD_FILE);
+ DBG3(" 3) %s", consumerd32_bin);
if (stat(consumerd64_bin, &st) == 0) {
+ DBG3("Found location #1");
consumer_to_use = consumerd64_bin;
} else if (stat(INSTALL_BIN_PATH "/" CONSUMERD_FILE, &st) == 0) {
+ DBG3("Found location #2");
consumer_to_use = INSTALL_BIN_PATH "/" CONSUMERD_FILE;
} else if (stat(consumerd32_bin, &st) == 0) {
+ DBG3("Found location #3");
consumer_to_use = consumerd32_bin;
} else {
+ DBG("Could not find any valid consumerd executable");
break;
}
DBG("Using kernel consumer at: %s", consumer_to_use);
usess = session->ust_session;
if (!session->enabled) {
- ret = LTTCOMM_UST_START_FAIL;
+ ret = LTTCOMM_UST_STOP_FAIL;
goto error;
}
ret = ust_app_stop_trace_all(usess);
if (ret < 0) {
- ret = LTTCOMM_UST_START_FAIL;
+ ret = LTTCOMM_UST_STOP_FAIL;
goto error;
}
}
/*
* Cleanup UST context hash table.
*/
-static void destroy_context(struct lttng_ht *ht)
+static void destroy_contexts(struct lttng_ht *ht)
{
int ret;
struct lttng_ht_node_ulong *node;
void trace_ust_destroy_event(struct ltt_ust_event *event)
{
DBG2("Trace destroy UST event %s", event->attr.name);
- destroy_context(event->ctx);
+ destroy_contexts(event->ctx);
free(event);
}
/*
* Cleanup UST events hashtable.
*/
-static void destroy_event(struct lttng_ht *events)
+static void destroy_events(struct lttng_ht *events)
{
int ret;
struct lttng_ht_node_str *node;
cds_lfht_for_each_entry(events->ht, &iter.iter, node, node) {
ret = lttng_ht_del(events, &iter);
- if (!ret) {
- call_rcu(&node->head, destroy_event_rcu);
- }
+ assert(!ret);
+ call_rcu(&node->head, destroy_event_rcu);
}
lttng_ht_destroy(events);
*/
void trace_ust_destroy_channel(struct ltt_ust_channel *channel)
{
- int ret;
- struct lttng_ht_node_str *node;
- struct lttng_ht_iter iter;
-
DBG2("Trace destroy UST channel %s", channel->name);
rcu_read_lock();
- cds_lfht_for_each_entry(channel->events->ht, &iter.iter, node, node) {
- ret = lttng_ht_del(channel->events, &iter);
- if (!ret) {
- destroy_event(channel->events);
- }
- }
+ /* Destroying all events of the channel */
+ destroy_events(channel->events);
+ /* Destroying all context of the channel */
+ destroy_contexts(channel->ctx);
- destroy_context(channel->ctx);
free(channel);
rcu_read_unlock();
struct lttng_ht_node_str *node;
struct lttng_ht_iter iter;
+ rcu_read_lock();
+
cds_lfht_for_each_entry(channels->ht, &iter.iter, node, node) {
ret = lttng_ht_del(channels, &iter);
- if (!ret) {
- call_rcu(&node->head, destroy_channel_rcu);
- }
+ assert(!ret);
+ call_rcu(&node->head, destroy_channel_rcu);
}
lttng_ht_destroy(channels);
+
+ rcu_read_unlock();
}
/*
cds_lfht_for_each_entry(ht->ht, &iter.iter, dpid, node.node) {
ret = lttng_ht_del(ht , &iter);
- if (!ret) {
- destroy_channels(dpid->channels);
- }
+ assert(!ret);
+ destroy_channels(dpid->channels);
}
lttng_ht_destroy(ht);
cds_lfht_for_each_entry(ht->ht, &iter.iter, dexec, node.node) {
ret = lttng_ht_del(ht , &iter);
- if (!ret) {
- destroy_channels(dexec->channels);
- }
+ assert(!ret);
+ destroy_channels(dexec->channels);
}
lttng_ht_destroy(ht);
struct lttng_ht_iter iter;
struct ust_app_ctx *ua_ctx;
+ /* Destroy each context of event */
cds_lfht_for_each_entry(ua_event->ctx->ht, &iter.iter, ua_ctx,
node.node) {
ret = lttng_ht_del(ua_event->ctx, &iter);
ret = ustctl_open_metadata(app->key.sock, ua_sess->handle, &uattr,
&ua_sess->metadata->obj);
if (ret < 0) {
- ERR("UST app open metadata failed for app pid:%d",
- app->key.pid);
+ ERR("UST app open metadata failed for app pid:%d with ret %d",
+ app->key.pid, ret);
goto error;
}
ret = ustctl_create_channel(app->key.sock, ua_sess->handle,
(struct lttng_ust_channel_attr *)&ua_chan->attr, &ua_chan->obj);
if (ret < 0) {
- DBG("Error creating channel %s for app (pid: %d, sock: %d) "
+ ERR("Creating channel %s for app (pid: %d, sock: %d) "
"and session handle %d with ret %d",
ua_chan->name, app->key.pid, app->key.sock,
ua_sess->handle, ret);
}
ua_chan->handle = ua_chan->obj->handle;
- ua_chan->attr.shm_fd = ua_chan->obj->shm_fd;
- ua_chan->attr.wait_fd = ua_chan->obj->wait_fd;
- ua_chan->attr.memory_map_size = ua_chan->obj->memory_map_size;
DBG2("UST app channel %s created successfully for pid:%d and sock:%d",
ua_chan->name, app->key.pid, app->key.sock);
ret = ustctl_create_event(app->key.sock, &ua_event->attr, ua_chan->obj,
&ua_event->obj);
if (ret < 0) {
+ if (ret == -EEXIST) {
+ ret = 0;
+ goto error;
+ }
ERR("Error ustctl create event %s for app pid: %d with ret %d",
ua_event->attr.name, app->key.pid, ret);
goto error;
ua_event->attr.name, app->key.pid);
/* If event not enabled, disable it on the tracer */
- if (!ua_event->enabled) {
+ if (ua_event->enabled == 0) {
ret = disable_ust_event(app, ua_sess, ua_event);
if (ret < 0) {
+ /*
+ * If we hit an EPERM, something is wrong with our disable call. If
+ * we get an EEXIST, there is a problem on the tracer side since we
+ * just created it.
+ */
+ switch (ret) {
+ case -EPERM:
+ /* Code flow problem */
+ assert(0);
+ case -EEXIST:
+ /* It's OK for our use case. */
+ ret = 0;
+ break;
+ default:
+ break;
+ }
goto error;
}
}
strncpy(ua_event->name, uevent->attr.name, sizeof(ua_event->name));
ua_event->name[sizeof(ua_event->name) - 1] = '\0';
+ ua_event->enabled = uevent->enabled;
+
/* Copy event attributes */
memcpy(&ua_event->attr, &uevent->attr, sizeof(ua_event->attr));
cds_lfht_for_each_entry(uevent->ctx->ht, &iter.iter, uctx, node.node) {
ua_ctx = alloc_ust_app_ctx(&uctx->ctx);
if (ua_ctx == NULL) {
- continue;
+ /* malloc() failed. We should simply stop */
+ return;
}
+
lttng_ht_node_init_ulong(&ua_ctx->node,
(unsigned long) ua_ctx->ctx.ctx);
lttng_ht_add_unique_ulong(ua_event->ctx, &ua_ctx->node);
struct ust_app_event *ua_event;
struct ust_app_ctx *ua_ctx;
- DBG2("Shadow copy of UST app channel %s", ua_chan->name);
+ DBG2("UST app shadow copy of channel %s started", ua_chan->name);
strncpy(ua_chan->name, uchan->name, sizeof(ua_chan->name));
ua_chan->name[sizeof(ua_chan->name) - 1] = '\0';
/* Copy event attributes */
memcpy(&ua_chan->attr, &uchan->attr, sizeof(ua_chan->attr));
+ ua_chan->enabled = uchan->enabled;
+
cds_lfht_for_each_entry(uchan->ctx->ht, &iter.iter, uctx, node.node) {
ua_ctx = alloc_ust_app_ctx(&uctx->ctx);
if (ua_ctx == NULL) {
}
}
- DBG3("Shadow copy channel done");
+ DBG3("UST app shadow copy of channel %s done", ua_chan->name);
}
/*
ua_sess->uid = usess->uid;
ua_sess->gid = usess->gid;
- ret = snprintf(ua_sess->path, PATH_MAX,
- "%s/%s-%d-%s",
- usess->pathname, app->name, app->key.pid,
- datetime);
+ ret = snprintf(ua_sess->path, PATH_MAX, "%s/%s-%d-%s", usess->pathname,
+ app->name, app->key.pid, datetime);
if (ret < 0) {
PERROR("asprintf UST shadow copy session");
/* TODO: We cannot return an error from here.. */
lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &uiter);
ua_chan_node = lttng_ht_iter_get_node_str(&uiter);
if (ua_chan_node != NULL) {
+ /* Session exist. Contiuing. */
continue;
}
uchan->name);
ua_chan = alloc_ust_app_channel(uchan->name, &uchan->attr);
if (ua_chan == NULL) {
- /* malloc failed... continuing */
+ /* malloc failed FIXME: Might want to do handle ENOMEM .. */
continue;
}
struct ust_app *app, struct lttng_ht_iter *iter)
{
/* Get right UST app session from app */
- lttng_ht_lookup(app->sessions, (void *)((unsigned long) usess->uid), iter);
+ lttng_ht_lookup(app->sessions, (void *)((unsigned long) usess->id), iter);
}
/*
ua_sess = alloc_ust_app_session();
if (ua_sess == NULL) {
/* Only malloc can failed so something is really wrong */
- goto error;
+ goto end;
}
shadow_copy_session(ua_sess, usess, app);
}
if (ua_sess->handle == -1) {
ret = ustctl_create_session(app->key.sock);
if (ret < 0) {
- ERR("Error creating session for app pid %d, sock %d",
- app->key.pid, app->key.sock);
- /* TODO: free() ua_sess */
+ ERR("Creating session for app pid %d", app->key.pid);
goto error;
}
- DBG2("UST app ustctl create session handle %d", 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->uid);
+ lttng_ht_node_init_ulong(&ua_sess->node, (unsigned long) ua_sess->id);
lttng_ht_add_unique_ulong(app->sessions, &ua_sess->node);
DBG2("UST app session created successfully with handle %d", ret);
}
+end:
return ua_sess;
error:
+ delete_ust_app_session(-1, ua_sess);
return NULL;
}
/* Lookup channel in the ust app session */
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);
- ua_chan = alloc_ust_app_channel(uchan->name, &uchan->attr);
- if (ua_chan == NULL) {
- goto error;
- }
- shadow_copy_channel(ua_chan, uchan);
-
- lttng_ht_add_unique_str(ua_sess->channels, &ua_chan->node);
- } else {
+ if (ua_chan_node != NULL) {
ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+ goto end;
}
+ ua_chan = alloc_ust_app_channel(uchan->name, &uchan->attr);
+ if (ua_chan == NULL) {
+ /* Only malloc can fail here */
+ goto error;
+ }
+ shadow_copy_channel(ua_chan, uchan);
+
ret = create_ust_channel(app, ua_sess, ua_chan);
if (ret < 0) {
+ /* Not found previously means that it does not exist on the tracer */
+ assert(ret != -EEXIST);
goto error;
}
+ lttng_ht_add_unique_str(ua_sess->channels, &ua_chan->node);
+
+ DBG2("UST app create channel %s for PID %d completed", ua_chan->name,
+ app->key.pid);
+
+end:
return ua_chan;
error:
+ delete_ust_app_channel(-1, ua_chan);
return NULL;
}
lttng_ht_lookup(ua_chan->events, (void *)uevent->attr.name, &iter);
ua_event_node = lttng_ht_iter_get_node_str(&iter);
if (ua_event_node != NULL) {
- ERR("UST app event %s already exist. Stopping creation.",
- uevent->attr.name);
+ ret = -EEXIST;
goto end;
}
if (ua_event == NULL) {
/* Only malloc can failed so something is really wrong */
ret = -ENOMEM;
- goto error;
+ goto end;
}
shadow_copy_event(ua_event, uevent);
/* Create it on the tracer side */
ret = create_ust_event(app, ua_sess, ua_chan, ua_event);
if (ret < 0) {
- rcu_read_lock();
- delete_ust_app_event(app->key.sock, ua_event);
- rcu_read_unlock();
+ /* Not found previously means that it does not exist on the tracer */
+ assert(ret != -EEXIST);
goto error;
}
- ua_event->enabled = 1;
-
lttng_ht_add_unique_str(ua_chan->events, &ua_event->node);
- DBG2("UST app create event %s for PID %d completed",
- ua_event->name, app->key.pid);
+ DBG2("UST app create event %s for PID %d completed", ua_event->name,
+ app->key.pid);
end:
+ return ret;
+
error:
+ /* Valid. Calling here is already in a read side lock */
+ delete_ust_app_event(-1, ua_event);
return ret;
}
/* Allocate UST metadata */
ua_sess->metadata = trace_ust_create_metadata(pathname);
if (ua_sess->metadata == NULL) {
- ERR("UST app session %d creating metadata failed",
- ua_sess->handle);
+ /* malloc() failed */
goto error;
}
ret = open_ust_metadata(app, ua_sess);
if (ret < 0) {
+ /* Cleanup failed metadata struct */
+ free(ua_sess->metadata);
goto error;
}
DBG("PID %d unregistering with sock %d", lta->key.pid, sock);
+ /* Remove application from socket hash table */
+ lttng_ht_lookup(ust_app_sock_key_map, (void *)((unsigned long) sock), &iter);
+ ret = lttng_ht_del(ust_app_sock_key_map, &iter);
+ assert(!ret);
+
/* Get the node reference for a call_rcu */
lttng_ht_lookup(ust_app_ht, (void *)((unsigned long) lta->key.pid), &iter);
node = lttng_ht_iter_get_node_ulong(&iter);
goto error;
}
+ /* Remove application from PID hash table */
ret = lttng_ht_del(ust_app_ht, &iter);
assert(!ret);
call_rcu(&node->head, delete_ust_app_rcu);
int ust_app_create_channel_glb(struct ltt_ust_session *usess,
struct ltt_ust_channel *uchan)
{
- int ret = 0;
struct lttng_ht_iter iter;
struct ust_app *app;
struct ust_app_session *ua_sess;
struct ust_app_channel *ua_chan;
- if (usess == NULL || uchan == NULL) {
- ERR("Adding UST global channel to NULL values");
- ret = -1;
- goto error;
- }
+ /* Very wrong code flow */
+ assert(usess);
+ assert(uchan);
DBG2("UST app adding channel %s to global domain for session id %d",
uchan->name, usess->id);
*/
ua_sess = create_ust_app_session(usess, app);
if (ua_sess == NULL) {
- continue;
+ /* Major problem here and it's maybe the tracer or malloc() */
+ goto error;
}
/* Create channel onto application */
ua_chan = create_ust_app_channel(ua_sess, uchan, app);
if (ua_chan == NULL) {
- continue;
+ /* Major problem here and it's maybe the tracer or malloc() */
+ goto error;
}
}
rcu_read_unlock();
+ return 0;
+
error:
- return ret;
+ return -1;
}
/*
DBG("UST app creating event %s for all apps for session id %d",
uevent->attr.name, usess->id);
- /*
- * NOTE: At this point, this function is called only if the session and
- * channel passed are already created for all apps. and enabled on the
- * tracer also.
- */
-
rcu_read_lock();
/* For all registered applications */
ret = create_ust_app_event(ua_sess, ua_chan, uevent, app);
if (ret < 0) {
+ if (ret != -EEXIST) {
+ /* Possible value at this point: -ENOMEM. If so, we stop! */
+ break;
+ }
+ DBG2("UST app event %s already exist on app PID %d",
+ uevent->attr.name, app->key.pid);
continue;
}
}
#ifndef _LTT_UTILS_H
#define _LTT_UTILS_H
-#ifndef __stringify
-#define __stringify1(x) #x
-#define __stringify(x) __stringify1(x)
-#endif
-
const char *get_home_dir(void);
int notify_thread_pipe(int wpipe);