AM_CONDITIONAL([LTTNG_TOOLS_HAVE_UST], [ test "x$have_ust_test" = "x1" ])
+AC_CHECK_FUNCS([sched_getcpu sysconf])
+
# Epoll check. If not present, the build will fallback on poll() API
AX_HAVE_EPOLL(
[AX_CONFIG_FEATURE_ENABLE(epoll)],
#include <stdint.h>
#include <string.h>
-#include <urcu/config.h>
#include <urcu.h>
#include <urcu-call-rcu.h>
#include <urcu/arch.h>
#include <urcu/uatomic.h>
#include <urcu/compiler.h>
-#include "rculfhash.h"
#include <stdio.h>
#include <pthread.h>
+#include "rculfhash.h"
+
#ifdef DEBUG
#define dbg_printf(fmt, args...) printf("[debug rculfhash] " fmt, ## args)
#else
#else /* #if defined(HAVE_SCHED_GETCPU) && defined(HAVE_SYSCONF) */
-static const long nr_cpus_mask = -1;
+static const long nr_cpus_mask = -2;
static
struct ht_items_count *alloc_per_cpu_items_count(void)
* We spawn just the number of threads we need to satisfy the minimum
* partition size, up to the number of CPUs in the system.
*/
- nr_threads = min(nr_cpus_mask + 1,
- len >> MIN_PARTITION_PER_THREAD_ORDER);
+ if (nr_cpus_mask > 0) {
+ nr_threads = min(nr_cpus_mask + 1,
+ len >> MIN_PARTITION_PER_THREAD_ORDER);
+ } else {
+ nr_threads = 1;
+ }
partition_len = len >> get_count_order_ulong(nr_threads);
work = calloc(nr_threads, sizeof(*work));
thread_id = calloc(nr_threads, sizeof(*thread_id));
iter->next = next;
}
-void cds_lfht_next(struct cds_lfht *ht, struct cds_lfht_iter *iter)
+void cds_lfht_next_duplicate(struct cds_lfht *ht, struct cds_lfht_iter *iter)
{
struct cds_lfht_node *node, *next;
unsigned long reverse_hash;
iter->next = next;
}
+void cds_lfht_next(struct cds_lfht *ht, struct cds_lfht_iter *iter)
+{
+ struct cds_lfht_node *node, *next;
+
+ node = clear_flag(iter->next);
+ for (;;) {
+ if (unlikely(is_end(node))) {
+ node = next = NULL;
+ break;
+ }
+ next = rcu_dereference(node->p.next);
+ if (likely(!is_removed(next))
+ && !is_dummy(next)) {
+ break;
+ }
+ node = clear_flag(next);
+ }
+ assert(!node || !is_dummy(rcu_dereference(node->p.next)));
+ iter->node = node;
+ iter->next = next;
+}
+
+void cds_lfht_first(struct cds_lfht *ht, struct cds_lfht_iter *iter)
+{
+ struct _cds_lfht_node *lookup;
+
+ /*
+ * Get next after first dummy node. The first dummy node is the
+ * first node of the linked list.
+ */
+ lookup = &ht->t.tbl[0]->nodes[0];
+ iter->next = lookup->next;
+ cds_lfht_next(ht, iter);
+}
+
void cds_lfht_add(struct cds_lfht *ht, struct cds_lfht_node *node)
{
unsigned long hash, size;
unsigned long reverse_hash;
} __attribute__((aligned(4)));
+/*
+ * struct cds_lfht_node can be embedded into a structure (as a field).
+ * caa_container_of() can be used to get the structure from the struct
+ * cds_lfht_node after a lookup.
+ */
struct cds_lfht_node {
/* cache-hot for iteration */
struct _cds_lfht_node p; /* needs to be first field */
struct cds_lfht_iter *iter);
/*
- * cds_lfht_next - get the next item with same key (after a lookup).
+ * cds_lfht_next_duplicate - get the next item with same key (after a lookup).
*
* Uses an iterator initialized by a lookup.
* Sets *iter-node to the following node with same key.
* node returned by a previous cds_lfht_next.
* Call with rcu_read_lock held.
*/
+void cds_lfht_next_duplicate(struct cds_lfht *ht, struct cds_lfht_iter *iter);
+
+/*
+ * cds_lfht_first - get the first node in the table.
+ *
+ * Output in "*iter". *iter->node set to NULL if table is empty.
+ * Call with rcu_read_lock held.
+ */
+void cds_lfht_first(struct cds_lfht *ht, struct cds_lfht_iter *iter);
+
+/*
+ * cds_lfht_next - get the next node in the table.
+ *
+ * Input/Output in "*iter". *iter->node set to NULL if *iter was
+ * pointing to the last table node.
+ * Call with rcu_read_lock held.
+ */
void cds_lfht_next(struct cds_lfht *ht, struct cds_lfht_iter *iter);
/*
LTTCOMM_KERN_NO_SESSION, /* No kernel session found */
LTTCOMM_KERN_LIST_FAIL, /* Kernel listing events failed */
LTTCOMM_UST_SESS_FAIL, /* UST create session failed */
+ LTTCOMM_UST_CHAN_EXIST, /* UST channel already exist */
LTTCOMM_UST_CHAN_FAIL, /* UST create channel failed */
LTTCOMM_UST_CHAN_NOT_FOUND, /* UST channel not found */
LTTCOMM_UST_CHAN_DISABLE_FAIL, /* UST disable channel failed */
#include <lttng/lttng.h>
+/* Default size of a hash table */
+#define DEFAULT_HT_SIZE 32
+
/* Default channel attributes */
#define DEFAULT_CHANNEL_NAME "channel0"
#define DEFAULT_CHANNEL_OVERWRITE 0 /* usec */
[ LTTCOMM_ERR_INDEX(LTTCOMM_KERN_LIST_FAIL) ] = "Listing kernel events failed",
[ LTTCOMM_ERR_INDEX(LTTCOMM_UST_SESS_FAIL) ] = "UST create session failed",
[ LTTCOMM_ERR_INDEX(LTTCOMM_UST_CHAN_FAIL) ] = "UST create channel failed",
+ [ LTTCOMM_ERR_INDEX(LTTCOMM_UST_CHAN_EXIST) ] = "UST channel already exist",
[ LTTCOMM_ERR_INDEX(LTTCOMM_UST_CHAN_NOT_FOUND) ] = "UST channel not found",
[ LTTCOMM_ERR_INDEX(LTTCOMM_UST_CHAN_DISABLE_FAIL) ] = "Disable UST channel failed",
[ LTTCOMM_ERR_INDEX(LTTCOMM_UST_CHAN_ENABLE_FAIL) ] = "Enable UST channel failed",
endif
ltt_sessiond_SOURCES = utils.c utils.h \
+ hashtable.c hashtable.h \
compat/poll.h $(COMPAT) \
trace-kernel.c trace-kernel.h \
kernel-ctl.c kernel-ctl.h \
session.c session.h \
ltt-sessiond.h main.c \
../hashtable/rculfhash.c \
- ../hashtable/rculfhash.h
+ ../hashtable/rculfhash.h \
+ ../hashtable/hash.c ../hashtable/hash.h
if LTTNG_TOOLS_HAVE_UST
ltt_sessiond_SOURCES += \
endif
# link on liblttngctl for check if sessiond is already alive.
-ltt_sessiond_LDADD = -lrt \
+ltt_sessiond_LDADD = -lrt -lurcu-cds -lurcu \
$(top_builddir)/liblttng-sessiond-comm/liblttng-sessiond-comm.la \
$(top_builddir)/libkernelctl/libkernelctl.la \
$(top_builddir)/liblttngctl/liblttngctl.la
#endif
#include "channel.h"
+#include "hashtable.h"
#include "kernel-ctl.h"
#include "ust-ctl.h"
#include "utils.h"
int channel_ust_copy(struct ltt_ust_channel *dst,
struct ltt_ust_channel *src)
{
- struct ltt_ust_event *uevent, *new_uevent;
+ //struct ltt_ust_event *uevent, *new_uevent;
memcpy(dst, src, sizeof(struct ltt_ust_channel));
- CDS_INIT_LIST_HEAD(&dst->events.head);
+ dst->events = hashtable_new_str(0);
+ /*
cds_list_for_each_entry(uevent, &src->events.head, list) {
new_uevent = malloc(sizeof(struct ltt_ust_event));
if (new_uevent == NULL) {
cds_list_add(&new_uevent->list, &dst->events.head);
dst->events.count++;
}
+ */
return 0;
-error:
- return -1;
+//error:
+// return -1;
}
/*
suchan = trace_ust_create_channel(attr, usession->path);
if (suchan == NULL) {
- ret = LTTCOMM_FATAL;
+ ret = LTTCOMM_UST_CHAN_FAIL;
goto error;
}
+
uattr.overwrite = attr->attr.overwrite;
uattr.subbuf_size = attr->attr.subbuf_size;
uattr.num_subbuf = attr->attr.num_subbuf;
ret = LTTCOMM_UST_CHAN_FAIL;
goto error;
}
+
suchan->attr.overwrite = uattr.overwrite;
suchan->attr.subbuf_size = uattr.subbuf_size;
suchan->attr.num_subbuf = uattr.num_subbuf;
#define _LTT_SESSIOND_H
#define _LGPL_SOURCE
+#include <urcu.h>
#include <urcu/wfqueue.h>
#include "ust-app.h"
#include "context.h"
#include "event.h"
#include "futex.h"
+#include "hashtable.h"
#include "kernel-ctl.h"
#include "ltt-sessiond.h"
#include "shm.h"
}
}
+/*
+ * Complete teardown of all UST sessions. This will free everything on his path
+ * and destroy the core essence of all ust sessions :)
+ */
+static void teardown_ust_session(struct ltt_session *session)
+{
+ DBG("Tearing down UST session(s)");
+
+ trace_ust_destroy_session(session->ust_session);
+}
+
/*
* Stop all threads by closing the thread quit pipe.
*/
cds_list_for_each_entry_safe(sess, stmp,
&session_list_ptr->head, list) {
teardown_kernel_session(sess);
- // TODO complete session cleanup (including UST)
+ teardown_ust_session(sess);
+ free(sess);
}
}
DBG("[thread] Manage application started");
+ rcu_register_thread();
+ rcu_thread_online();
+
ret = create_thread_poll_set(&events, 2);
if (ret < 0) {
goto error;
lttng_poll_clean(&events);
+ rcu_thread_offline();
+ rcu_unregister_thread();
return NULL;
}
switch (domain->type) {
case LTTNG_DOMAIN_UST_PID:
- app = ust_app_get_by_pid(domain->attr.pid);
+ app = ust_app_find_by_pid(domain->attr.pid);
if (app == NULL) {
ret = LTTCOMM_APP_NOT_FOUND;
goto error;
}
}
- /* Create session on the UST tracer */
- ret = ustctl_create_session(app->sock);
- if (ret < 0) {
- ret = LTTCOMM_UST_SESS_FAIL;
- goto error;
+ /* The domain type dictate different actions on session creation */
+ switch (domain->type) {
+ case LTTNG_DOMAIN_UST_PID:
+ app = ust_app_find_by_pid(domain->attr.pid);
+ if (app == NULL) {
+ ret = LTTCOMM_APP_NOT_FOUND;
+ goto error;
+ }
+ /* Create session on the UST tracer */
+ ret = ustctl_create_session(app->key.sock, lus);
+ if (ret < 0) {
+ ret = LTTCOMM_UST_SESS_FAIL;
+ goto error;
+ }
+
+ lus->handle = ret;
+ break;
+ case LTTNG_DOMAIN_UST:
+ /* Create session on the UST tracer */
+ ret = ustctl_create_session(app->key.sock, lus);
+ if (ret < 0) {
+ ret = LTTCOMM_UST_SESS_FAIL;
+ goto error;
+ }
+ break;
+ case LTTNG_DOMAIN_UST_EXEC_NAME:
+ break;
+ default:
+ goto error;
}
lus->handle = ret;
lus->sock = app->sock;
- cds_list_add(&lus->list, &session->ust_session_list.head);
- session->ust_session_list.count++;
+ session->ust_session = lus;
+ printf("%p\n", session->ust_session);
return LTTCOMM_OK;
/*
* Copy channel from attributes and set it in the application channel list.
*/
+/*
static int copy_ust_channel_to_app(struct ltt_ust_session *usess,
struct lttng_channel *attr, struct ust_app *app)
{
int ret;
struct ltt_ust_channel *uchan, *new_chan;
- uchan = trace_ust_get_channel_by_name(attr->name, usess);
+ uchan = trace_ust_get_channel_by_key(usess->channels, attr->name);
if (uchan == NULL) {
ret = LTTCOMM_FATAL;
goto error;
goto error;
}
- /* Add channel to the ust app channel list */
- cds_list_add(&new_chan->list, &app->channels.head);
- app->channels.count++;
-
error:
return ret;
}
+*/
/*
* Command LTTNG_ENABLE_CHANNEL processed by the client thread.
struct lttng_domain *domain, struct lttng_channel *attr)
{
int ret;
+ struct ltt_ust_session *usess = session->ust_session;
+
+ DBG("Enabling channel %s for session %s", session->name, attr->name);
switch (domain->type) {
case LTTNG_DOMAIN_KERNEL:
kernel_wait_quiescent(kernel_tracer_fd);
break;
}
+ case LTTNG_DOMAIN_UST:
+ {
+ struct ltt_ust_channel *uchan;
+
+ DBG2("Enabling channel for LTTNG_DOMAIN_UST domain");
+
+ uchan = trace_ust_find_channel_by_name(usess->domain_global.channels,
+ attr->name);
+ if (uchan == NULL) {
+ uchan = trace_ust_create_channel(attr, usess->path);
+ if (uchan == NULL) {
+ ret = LTTCOMM_UST_CHAN_FAIL;
+ goto error;
+ }
+ rcu_read_lock();
+ hashtable_add_unique(usess->domain_global.channels, &uchan->node);
+ rcu_read_unlock();
+ } else {
+ ret = LTTCOMM_UST_CHAN_EXIST;
+ goto error;
+ }
+
+ /* TODO: Iterate over trace apps to enable that channel */
+
+ break;
+ }
case LTTNG_DOMAIN_UST_PID:
{
+ /*
int sock;
struct ltt_ust_channel *uchan;
struct ltt_ust_session *usess;
DBG("UST channel %s created for app sock %d with pid %d",
attr->name, app->sock, domain->attr.pid);
- break;
+ */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
}
default:
ret = LTTCOMM_UNKNOWN_DOMAIN;
nb_dom++;
}
- nb_dom += session->ust_session_list.count;
+ /* TODO: User-space tracer domain support */
*domains = malloc(nb_dom * sizeof(struct lttng_domain));
if (*domains == NULL) {
(*domains)[0].type = LTTNG_DOMAIN_KERNEL;
- /* TODO: User-space tracer domain support */
-
return nb_dom;
error:
case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
{
struct ltt_ust_session *usess;
-
if (need_tracing_session) {
- usess = trace_ust_get_session_by_pid(
- &cmd_ctx->session->ust_session_list,
- cmd_ctx->lsm->domain.attr.pid);
- if (usess == NULL) {
+ if (cmd_ctx->session->ust_session == NULL) {
ret = create_ust_session(cmd_ctx->session,
&cmd_ctx->lsm->domain);
if (ret != LTTCOMM_OK) {
pthread_mutex_unlock(&ustconsumer_data.pid_mutex);
}
break;
- }
default:
break;
}
DBG("[thread] Manage client started");
+ rcu_register_thread();
+
ret = lttcomm_listen_unix_sock(client_sock);
if (ret < 0) {
goto error;
// TODO: Validate cmd_ctx including sanity check for
// security purpose.
+ rcu_thread_online();
/*
* This function dispatch the work to the kernel or userspace tracer
* libs and fill the lttcomm_lttng_msg data structure of all the needed
* everything this function may needs.
*/
ret = process_client_msg(cmd_ctx);
+ rcu_thread_offline();
if (ret < 0) {
/*
* TODO: Inform client somehow of the fatal error. At
lttng_poll_clean(&events);
clean_command_ctx(&cmd_ctx);
+
+ rcu_unregister_thread();
return NULL;
}
void *status;
const char *home_path;
+ rcu_register_thread();
+
/* Create thread quit pipe */
if ((ret = init_thread_quit_pipe()) < 0) {
goto error;
/* Init UST command queue. */
cds_wfq_init(&ust_cmd_queue.queue);
+ /* Init UST app hash table */
+ ust_app_ht_alloc();
+
/*
* Get session list pointer. This pointer MUST NOT be free(). This list is
* statically declared in session.c
/*
* cleanup() is called when no other thread is running.
*/
+ rcu_thread_online();
cleanup();
+ rcu_thread_offline();
+ rcu_unregister_thread();
if (!ret)
exit(EXIT_SUCCESS);
error:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <urcu.h>
#include <lttng-sessiond-comm.h>
#include <lttngerr.h>
+#include "hashtable.h"
#include "session.h"
+#include "../hashtable/hash.h"
+
/*
* NOTES:
*
/* Init kernel session */
new_session->kernel_session = NULL;
-
- /* Init UST session list */
- CDS_INIT_LIST_HEAD(&new_session->ust_session_list.head);
+ new_session->ust_session = NULL;
/* Init lock */
pthread_mutex_init(&new_session->lock, NULL);
char name[NAME_MAX];
char path[PATH_MAX];
struct ltt_kernel_session *kernel_session;
- struct ltt_ust_session_list ust_session_list;
+ struct ltt_ust_session *ust_session;
/*
* Protect any read/write on this session data structure. This lock must be
* acquired *before* using any public functions declared below. Use
struct ltt_session *session_find_by_name(char *name);
struct ltt_session_list *session_get_list(void);
+unsigned long session_ust_count(struct ltt_session *session);
#endif /* _LTT_SESSION_H */
#include <lttngerr.h>
#include <lttng-share.h>
+#include "hashtable.h"
#include "trace-ust.h"
/*
- * Using a ust session list, it will return the session corresponding to the
- * pid. Must be a session of domain LTTNG_DOMAIN_UST_PID.
+ * Find the channel in the hashtable.
*/
-struct ltt_ust_session *trace_ust_get_session_by_pid(
- struct ltt_ust_session_list *session_list, pid_t pid)
+struct ltt_ust_channel *trace_ust_find_channel_by_name(struct cds_lfht *ht,
+ char *name)
{
- struct ltt_ust_session *sess;
+ struct cds_lfht_node *node;
+ struct cds_lfht_iter iter;
- if (session_list == NULL) {
- ERR("Session list is NULL");
+ rcu_read_lock();
+ node = hashtable_lookup(ht, (void *) name, strlen(name), &iter);
+ if (node == NULL) {
+ rcu_read_unlock();
goto error;
}
+ rcu_read_unlock();
- cds_list_for_each_entry(sess, &session_list->head, list) {
- if (sess->domain.type == LTTNG_DOMAIN_UST_PID &&
- sess->domain.attr.pid == pid) {
- DBG2("Trace UST session found by pid %d", pid);
- return sess;
- }
- }
-
-error:
- return NULL;
-}
+ DBG2("Trace UST channel %s found by name", name);
-/*
- * Find the channel name for the given ust session.
- */
-struct ltt_ust_channel *trace_ust_get_channel_by_name(
- char *name, struct ltt_ust_session *session)
-{
- struct ltt_ust_channel *chan;
-
- if (session == NULL) {
- ERR("Undefine session");
- goto error;
- }
-
- cds_list_for_each_entry(chan, &session->channels.head, list) {
- if (strcmp(name, chan->name) == 0) {
- DBG2("Found UST channel by name %s", name);
- return chan;
- }
- }
+ return caa_container_of(node, struct ltt_ust_channel, node);
error:
+ DBG2("Trace UST channel %s not found by name", name);
return NULL;
}
/*
- * Find the event name for the given channel.
+ * Find the event in the hashtable.
*/
-struct ltt_ust_event *trace_ust_get_event_by_name(
- char *name, struct ltt_ust_channel *channel)
+struct ltt_ust_event *trace_ust_find_event_by_name(struct cds_lfht *ht,
+ char *name)
{
- struct ltt_ust_event *ev;
+ struct cds_lfht_node *node;
+ struct cds_lfht_iter iter;
- if (channel == NULL) {
- ERR("Undefine channel");
+ rcu_read_lock();
+ node = hashtable_lookup(ht, (void *) name, strlen(name), &iter);
+ if (node == NULL) {
+ rcu_read_unlock();
goto error;
}
+ rcu_read_unlock();
- cds_list_for_each_entry(ev, &channel->events.head, list) {
- if (strcmp(name, ev->attr.name) == 0) {
- DBG("Found UST event by name %s for channel %s", name,
- channel->name);
- return ev;
- }
- }
+ DBG2("Found UST event by name %s", name);
+
+ return caa_container_of(node, struct ltt_ust_event, node);
error:
return NULL;
lus->enabled = 1;
lus->consumer_fds_sent = 0;
lus->metadata = NULL;
- lus->channels.count = 0;
- CDS_INIT_LIST_HEAD(&lus->channels.head);
- /* Copy lttng_domain */
- memcpy(&lus->domain, domain, sizeof(struct lttng_domain));
+ /* Alloc UST domain hash tables */
+ lus->domain_pid = hashtable_new(0);
+ lus->domain_exec = hashtable_new_str(0);
+
+ /* Alloc UST global domain channels' HT */
+ lus->domain_global.channels = hashtable_new_str(0);
/* Set session path */
ret = snprintf(lus->path, PATH_MAX, "%s/ust_%d", path, pid);
luc->handle = -1;
luc->enabled = 1;
- luc->events.count = 0;
- CDS_INIT_LIST_HEAD(&luc->events.head);
-
- memset(&luc->ctx, 0, sizeof(struct lttng_ust_context));
/* Copy channel name */
strncpy(luc->name, chan->name, sizeof(&luc->name));
luc->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+ /* Init node */
+ hashtable_node_init(&luc->node, (void *) luc->name, strlen(luc->name));
+ /* Alloc hash tables */
+ luc->events = hashtable_new_str(0);
+ luc->ctx = hashtable_new_str(0);
+
/* Set trace output path */
ret = snprintf(luc->trace_path, PATH_MAX, "%s", path);
if (ret < 0) {
}
CDS_INIT_LIST_HEAD(&luc->stream_list.head);
+ DBG2("Trace UST channel %s created", luc->name);
+
return luc;
error:
/* Setting up a ust event */
lue->handle = -1;
lue->enabled = 1;
- memset(&lue->ctx, 0, sizeof(struct lttng_ust_context));
+
+ /* Init node */
+ hashtable_node_init(&lue->node, (void *) lue->attr.name,
+ strlen(lue->attr.name));
+ /* Alloc context hash tables */
+ lue->ctx = hashtable_new_str(5);
return lue;
lum->handle = -1;
/* Set metadata trace path */
- ret = asprintf(&lum->pathname, "%s/metadata", path);
+ ret = snprintf(lum->pathname, PATH_MAX, "%s/metadata", path);
if (ret < 0) {
perror("asprintf ust metadata");
goto error;
return NULL;
}
+/*
+ * RCU safe free context structure.
+ */
+static void destroy_context_rcu(struct rcu_head *head)
+{
+ struct cds_lfht_node *node =
+ caa_container_of(head, struct cds_lfht_node, head);
+ struct ltt_ust_context *ctx =
+ caa_container_of(node, struct ltt_ust_context, node);
+
+ free(ctx);
+}
+
+/*
+ * Cleanup UST context hash table.
+ */
+static void destroy_context(struct cds_lfht *ht)
+{
+ int ret;
+ struct cds_lfht_node *node;
+ struct cds_lfht_iter iter;
+
+ hashtable_get_first(ht, &iter);
+ while ((node = hashtable_iter_get_node(&iter)) != NULL) {
+ ret = hashtable_del(ht, &iter);
+ if (!ret) {
+ call_rcu(&node->head, destroy_context_rcu);
+ }
+ hashtable_get_next(ht, &iter);
+ }
+}
+
/*
* Cleanup ust event structure.
*/
void trace_ust_destroy_event(struct ltt_ust_event *event)
{
- DBG("[trace] Destroy ust event %s", event->attr.name);
-
- /* Remove from event list */
- cds_list_del(&event->list);
+ DBG2("Trace destroy UST event %s", event->attr.name);
+ destroy_context(event->ctx);
free(event);
}
+/*
+ * URCU intermediate call to complete destroy event.
+ */
+static void destroy_event_rcu(struct rcu_head *head)
+{
+ struct cds_lfht_node *node =
+ caa_container_of(head, struct cds_lfht_node, head);
+ struct ltt_ust_event *event =
+ caa_container_of(node, struct ltt_ust_event, node);
+
+ trace_ust_destroy_event(event);
+}
+
/*
* Cleanup ust channel structure.
*/
void trace_ust_destroy_channel(struct ltt_ust_channel *channel)
{
- struct ltt_ust_event *event, *etmp;
+ int ret;
+ struct cds_lfht_node *node;
+ struct cds_lfht_iter iter;
- DBG("[trace] Destroy ust channel %d", channel->handle);
+ DBG2("Trace destroy UST channel %s", channel->name);
- /* For each event in the channel list */
- cds_list_for_each_entry_safe(event, etmp, &channel->events.head, list) {
- trace_ust_destroy_event(event);
+ rcu_read_lock();
+
+ hashtable_get_first(channel->events, &iter);
+ while ((node = hashtable_iter_get_node(&iter)) != NULL) {
+ ret = hashtable_del(channel->events, &iter);
+ if (!ret) {
+ call_rcu(&node->head, destroy_event_rcu);
+ }
+ hashtable_get_next(channel->events, &iter);
}
- /* Remove from channel list */
- cds_list_del(&channel->list);
+ free(channel->events);
+ destroy_context(channel->ctx);
free(channel);
+
+ rcu_read_unlock();
+}
+
+/*
+ * URCU intermediate call to complete destroy channel.
+ */
+static void destroy_channel_rcu(struct rcu_head *head)
+{
+ struct cds_lfht_node *node =
+ caa_container_of(head, struct cds_lfht_node, head);
+ struct ltt_ust_channel *channel =
+ caa_container_of(node, struct ltt_ust_channel, node);
+
+ trace_ust_destroy_channel(channel);
}
/*
*/
void trace_ust_destroy_metadata(struct ltt_ust_metadata *metadata)
{
- DBG("[trace] Destroy ust metadata %d", metadata->handle);
+ DBG2("Trace UST destroy metadata %d", metadata->handle);
- /* Free attributes */
- free(metadata->pathname);
free(metadata);
}
/*
- * Cleanup ust session structure
+ * Iterate over a hash table containing channels and cleanup safely.
*/
-void trace_ust_destroy_session(struct ltt_ust_session *session)
+static void destroy_channels(struct cds_lfht *channels)
+{
+ int ret;
+ struct cds_lfht_node *node;
+ struct cds_lfht_iter iter;
+
+ hashtable_get_first(channels, &iter);
+ while ((node = hashtable_iter_get_node(&iter)) != NULL) {
+ ret = hashtable_del(channels, &iter);
+ if (!ret) {
+ call_rcu(&node->head, destroy_channel_rcu);
+ }
+ hashtable_get_next(channels, &iter);
+ }
+}
+
+/*
+ * Cleanup UST pid domain.
+ */
+static void destroy_domain_pid(struct cds_lfht *ht)
+{
+ int ret;
+ struct cds_lfht_node *node;
+ struct cds_lfht_iter iter;
+ struct ltt_ust_domain_pid *d;
+
+ hashtable_get_first(ht, &iter);
+ while ((node = hashtable_iter_get_node(&iter)) != NULL) {
+ ret = hashtable_del(ht , &iter);
+ if (!ret) {
+ d = caa_container_of(node, struct ltt_ust_domain_pid, node);
+ destroy_channels(d->channels);
+ }
+ hashtable_get_next(ht, &iter);
+ }
+}
+
+/*
+ * Cleanup UST exec name domain.
+ */
+static void destroy_domain_exec(struct cds_lfht *ht)
{
- struct ltt_ust_channel *channel, *ctmp;
+ int ret;
+ struct cds_lfht_node *node;
+ struct cds_lfht_iter iter;
+ struct ltt_ust_domain_exec *d;
+
+ hashtable_get_first(ht, &iter);
+ while ((node = hashtable_iter_get_node(&iter)) != NULL) {
+ ret = hashtable_del(ht , &iter);
+ if (!ret) {
+ d = caa_container_of(node, struct ltt_ust_domain_exec, node);
+ destroy_channels(d->channels);
+ }
+ hashtable_get_next(ht, &iter);
+ }
+}
- DBG("[trace] Destroy ust session %d", session->handle);
+/*
+ * Cleanup UST global domain.
+ */
+static void destroy_domain_global(struct ltt_ust_domain_global *dom)
+{
+ destroy_channels(dom->channels);
+}
+/*
+ * Cleanup ust session structure
+ */
+void trace_ust_destroy_session(struct ltt_ust_session *session)
+{
/* Extra safety */
if (session == NULL) {
return;
}
+ rcu_read_lock();
+
+ DBG2("Trace UST destroy session %d", session->handle);
+
if (session->metadata != NULL) {
trace_ust_destroy_metadata(session->metadata);
}
- cds_list_for_each_entry_safe(channel, ctmp, &session->channels.head, list) {
- trace_ust_destroy_channel(channel);
- }
-
- if (session->path) {
- free(session->path);
- }
+ /* Cleaning up UST domain */
+ destroy_domain_global(&session->domain_global);
+ destroy_domain_pid(session->domain_pid);
+ destroy_domain_exec(session->domain_exec);
free(session);
+
+ rcu_read_unlock();
}
#include <config.h>
#include <limits.h>
+#include <urcu.h>
#include <urcu/list.h>
#include <lttng/lttng.h>
#include "lttng-ust-abi.h"
#endif
-/*
- * UST session list.
- */
-struct ltt_ust_session_list {
- unsigned int count;
- struct cds_list_head head;
-};
+#include "../hashtable/rculfhash.h"
-/* UST event list */
-struct ltt_ust_event_list {
- unsigned int count;
- struct cds_list_head head;
-};
/* UST Stream list */
struct ltt_ust_stream_list {
struct cds_list_head head;
};
-/* UST Channel list */
-struct ltt_ust_channel_list {
- unsigned int count;
- struct cds_list_head head;
+/* Context hash table nodes */
+struct ltt_ust_context {
+ struct lttng_ust_context ctx;
+ struct cds_lfht_node node;
};
/* UST event */
struct ltt_ust_event {
int handle;
int enabled;
- /*
- * TODO: need internal representation to support more than a
- * single context.
- */
- struct lttng_ust_context ctx;
- struct lttng_ust_event attr;
- struct cds_list_head list;
struct object_data *obj;
+ struct lttng_ust_event attr;
+ struct cds_lfht *ctx;
+ struct cds_lfht_node node;
};
/* UST stream */
struct ltt_ust_stream {
+ /* TODO hashtable */
struct object_data *obj;
struct cds_list_head list;
char *pathname;
int enabled;
char name[LTTNG_UST_SYM_NAME_LEN];
char trace_path[PATH_MAX]; /* Trace file path name */
- /*
- * TODO: need internal representation to support more than a
- * single context.
- */
- struct lttng_ust_context ctx;
- struct lttng_ust_channel attr;
- struct ltt_ust_event_list events;
- struct cds_list_head list;
struct object_data *obj;
+
unsigned int stream_count;
struct ltt_ust_stream_list stream_list;
+ struct lttng_ust_channel attr;
+ struct cds_lfht *ctx;
+ struct cds_lfht *events;
+ struct cds_lfht_node node;
};
/* UST Metadata */
struct ltt_ust_metadata {
int handle;
struct object_data *obj;
- char *pathname; /* Trace file path name */
+ char pathname[PATH_MAX]; /* Trace file path name */
struct lttng_ust_channel attr;
struct object_data *stream_obj;
};
+/* UST domain global (LTTNG_DOMAIN_UST) */
+struct ltt_ust_domain_global {
+ struct cds_lfht *channels;
+};
+
+/* UST domain pid (LTTNG_DOMAIN_UST_PID) */
+struct ltt_ust_domain_pid {
+ pid_t pid;
+ struct cds_lfht *channels;
+ struct cds_lfht_node node;
+};
+
+/* UST domain exec name (LTTNG_DOMAIN_UST_EXEC_NAME) */
+struct ltt_ust_domain_exec {
+ char exec_name[LTTNG_UST_SYM_NAME_LEN];
+ struct cds_lfht *channels;
+ struct cds_lfht_node node;
+};
+
/* UST session */
struct ltt_ust_session {
int sock; /* socket to send cmds to app */
int consumer_fds_sent;
int consumer_fd;
char path[PATH_MAX];
- struct lttng_domain domain;
struct ltt_ust_metadata *metadata;
- struct ltt_ust_channel_list channels;
- struct cds_list_head list;
struct object_data *obj;
+ struct ltt_ust_domain_global domain_global;
+ /*
+ * Those two hash tables contains data for a specific UST domain and a HT
+ * of channels for each. See ltt_ust_domain_exec and ltt_ust_domain_pid
+ * data structures.
+ */
+ struct cds_lfht *domain_pid;
+ struct cds_lfht *domain_exec;
};
#ifdef CONFIG_LTTNG_TOOLS_HAVE_UST
/*
* Lookup functions. NULL is returned if not found.
*/
-struct ltt_ust_event *trace_ust_get_event_by_name(
- char *name, struct ltt_ust_channel *channel);
-struct ltt_ust_channel *trace_ust_get_channel_by_name(
- char *name, struct ltt_ust_session *session);
-struct ltt_ust_session *trace_ust_get_session_by_pid(
- struct ltt_ust_session_list *session_list, pid_t pid);
+struct ltt_ust_event *trace_ust_find_event_by_name(struct cds_lfht *ht,
+ char *name);
+struct ltt_ust_channel *trace_ust_find_channel_by_name(struct cds_lfht *ht,
+ char *name);
/*
* Create functions malloc() the data structure.
#else
static inline
-struct ltt_ust_event *trace_ust_get_event_by_name(
- char *name, struct ltt_ust_channel *channel)
+struct ltt_ust_event *trace_ust_find_event_by_name(struct cds_lfht *ht,
+ char *name)
{
return NULL;
}
+
static inline
-struct ltt_ust_channel *trace_ust_get_channel_by_name(
- char *name, struct ltt_ust_session *session)
+struct ltt_ust_channel *trace_ust_find_channel_by_name(struct cds_lfht *ht,
+ char *name)
{
return NULL;
}
+
static inline
struct ltt_ust_session *trace_ust_get_session_by_pid(
struct ltt_ust_session_list *session_list, pid_t pid)
#include <lttngerr.h>
+#include "hashtable.h"
#include "ust-app.h"
-
-/* Init ust traceable application's list */
-static struct ust_app_list ust_app_list = {
- .head = CDS_LIST_HEAD_INIT(ust_app_list.head),
- .lock = PTHREAD_MUTEX_INITIALIZER,
- .count = 0,
-};
-
-/*
- * Add a traceable application structure to the global list.
- */
-static void add_app_to_list(struct ust_app *lta)
-{
- cds_list_add(<a->list, &ust_app_list.head);
- ust_app_list.count++;
-}
+#include "../hashtable/hash.h"
/*
* Delete a traceable application structure from the global list.
*/
-static void del_app_from_list(struct ust_app *lta)
+static void delete_ust_app(struct ust_app *lta)
{
- struct ltt_ust_channel *chan;
+ int ret;
+ struct cds_lfht_node *node;
+ struct cds_lfht_iter iter;
- cds_list_del(<a->list);
- /* Sanity check */
- if (ust_app_list.count > 0) {
- ust_app_list.count--;
- }
+ rcu_read_lock();
- cds_list_for_each_entry(chan, <a->channels.head, list) {
- trace_ust_destroy_channel(chan);
+ hashtable_get_first(lta->channels, &iter);
+ while ((node = hashtable_iter_get_node(&iter)) != NULL) {
+ ret = hashtable_del(lta->channels, &iter);
+ if (!ret) {
+ trace_ust_destroy_channel(
+ caa_container_of(node, struct ltt_ust_channel, node));
+ }
+ hashtable_get_next(lta->channels, &iter);
}
-}
-/*
- * Iterate over the traceable apps list and return a pointer or NULL if not
- * found.
- */
-static struct ust_app *find_app_by_sock(int sock)
-{
- struct ust_app *iter;
+ free(lta->channels);
+ close(lta->key.sock);
- cds_list_for_each_entry(iter, &ust_app_list.head, list) {
- if (iter->sock == sock) {
- /* Found */
- return iter;
+ /* Remove from apps hash table */
+ node = hashtable_lookup(ust_app_ht,
+ (void *) ((unsigned long) lta->key.pid), sizeof(void *), &iter);
+ if (node == NULL) {
+ ERR("UST app pid %d not found in hash table", lta->key.pid);
+ } else {
+ ret = hashtable_del(ust_app_ht, &iter);
+ if (ret) {
+ ERR("UST app unable to delete app %d from hash table",
+ lta->key.pid);
+ } else {
+ DBG2("UST app pid %d deleted", lta->key.pid);
}
}
- return NULL;
+ /* Remove from key hash table */
+ node = hashtable_lookup(ust_app_sock_key_map,
+ (void *) ((unsigned long) lta->key.sock), sizeof(void *), &iter);
+ if (node == NULL) {
+ ERR("UST app key %d not found in key hash table", lta->key.sock);
+ } else {
+ ret = hashtable_del(ust_app_sock_key_map, &iter);
+ if (ret) {
+ ERR("UST app unable to delete app sock %d from key hash table",
+ lta->key.sock);
+ } else {
+ DBG2("UST app pair sock %d key %d deleted",
+ lta->key.sock, lta->key.pid);
+ }
+ }
+
+ free(lta);
+
+ rcu_read_unlock();
}
/*
- * Return pointer to traceable apps list.
+ * URCU intermediate call to delete an UST app.
*/
-struct ust_app_list *ust_app_get_list(void)
+static void delete_ust_app_rcu(struct rcu_head *head)
{
- return &ust_app_list;
+ struct cds_lfht_node *node =
+ caa_container_of(head, struct cds_lfht_node, head);
+ struct ust_app *app =
+ caa_container_of(node, struct ust_app, node);
+
+ delete_ust_app(app);
}
/*
- * Acquire traceable apps list lock.
+ * Find an ust_app using the sock and return it.
*/
-void ust_app_lock_list(void)
+static struct ust_app *find_app_by_sock(int sock)
{
- pthread_mutex_lock(&ust_app_list.lock);
+ struct cds_lfht_node *node;
+ struct ust_app_key *key;
+ struct cds_lfht_iter iter;
+ //struct ust_app *app;
+
+ rcu_read_lock();
+
+ node = hashtable_lookup(ust_app_sock_key_map,
+ (void *)((unsigned long) sock), sizeof(void *), &iter);
+ if (node == NULL) {
+ DBG2("UST app find by sock %d key not found", sock);
+ rcu_read_unlock();
+ goto error;
+ }
+
+ key = caa_container_of(node, struct ust_app_key, node);
+
+ node = hashtable_lookup(ust_app_ht,
+ (void *)((unsigned long) key->pid), sizeof(void *), &iter);
+ if (node == NULL) {
+ DBG2("UST app find by sock %d not found", sock);
+ rcu_read_unlock();
+ goto error;
+ }
+ rcu_read_unlock();
+
+ return caa_container_of(node, struct ust_app, node);
+
+error:
+ return NULL;
}
/*
- * Release traceable apps list lock.
+ * Return pointer to traceable apps list.
*/
-void ust_app_unlock_list(void)
+struct cds_lfht *ust_app_get_ht(void)
{
- pthread_mutex_unlock(&ust_app_list.lock);
+ return ust_app_ht;
}
/*
- * Iterate over the traceable apps list and return a pointer or NULL if not
- * found.
+ * Return ust app pointer or NULL if not found.
*/
-struct ust_app *ust_app_get_by_pid(pid_t pid)
+struct ust_app *ust_app_find_by_pid(pid_t pid)
{
- struct ust_app *iter;
+ struct cds_lfht_node *node;
+ struct cds_lfht_iter iter;
- cds_list_for_each_entry(iter, &ust_app_list.head, list) {
- if (iter->pid == pid) {
- /* Found */
- DBG2("Found traceable app by pid %d", pid);
- return iter;
- }
+ rcu_read_lock();
+ node = hashtable_lookup(ust_app_ht,
+ (void *)((unsigned long) pid), sizeof(void *), &iter);
+ if (node == NULL) {
+ rcu_read_unlock();
+ DBG2("UST app no found with pid %d", pid);
+ goto error;
}
+ rcu_read_unlock();
- DBG2("Traceable app with pid %d not found", pid);
+ DBG2("Found UST app by pid %d", pid);
+ return caa_container_of(node, struct ust_app, node);
+
+error:
return NULL;
}
lta->uid = msg->uid;
lta->gid = msg->gid;
- lta->pid = msg->pid;
+ lta->key.pid = msg->pid;
lta->ppid = msg->ppid;
lta->v_major = msg->major;
lta->v_minor = msg->minor;
- lta->sock = sock;
+ lta->key.sock = sock;
strncpy(lta->name, msg->name, sizeof(lta->name));
lta->name[16] = '\0';
- CDS_INIT_LIST_HEAD(<a->channels.head);
+ hashtable_node_init(<a->node, (void *)((unsigned long)lta->key.pid),
+ sizeof(void *));
+ lta->channels = hashtable_new_str(0);
+
+ /* Set sock key map */
+ hashtable_node_init(<a->key.node, (void *)((unsigned long)lta->key.sock),
+ sizeof(void *));
- ust_app_lock_list();
- add_app_to_list(lta);
- ust_app_unlock_list();
+ rcu_read_lock();
+ hashtable_add_unique(ust_app_ht, <a->node);
+ hashtable_add_unique(ust_app_sock_key_map, <a->key.node);
+ rcu_read_unlock();
DBG("App registered with pid:%d ppid:%d uid:%d gid:%d sock:%d name:%s"
- " (version %d.%d)", lta->pid, lta->ppid, lta->uid, lta->gid,
- lta->sock, lta->name, lta->v_major, lta->v_minor);
+ " (version %d.%d)", lta->key.pid, lta->ppid, lta->uid, lta->gid,
+ lta->key.sock, lta->name, lta->v_major, lta->v_minor);
return 0;
}
{
struct ust_app *lta;
- ust_app_lock_list();
+ DBG2("UST app unregistering sock %d", sock);
+
lta = find_app_by_sock(sock);
if (lta) {
- DBG("PID %d unregistered with sock %d", lta->pid, sock);
- del_app_from_list(lta);
- close(lta->sock);
- free(lta);
+ DBG("PID %d unregistering with sock %d", lta->key.pid, sock);
+ /* FIXME: Better use a call_rcu here ? */
+ delete_ust_app(lta);
}
- ust_app_unlock_list();
}
/*
* Return traceable_app_count
*/
-unsigned int ust_app_list_count(void)
+unsigned long ust_app_list_count(void)
{
- unsigned int count;
+ unsigned long count;
- ust_app_lock_list();
- count = ust_app_list.count;
- ust_app_unlock_list();
+ rcu_read_lock();
+ count = hashtable_get_count(ust_app_ht);
+ rcu_read_unlock();
return count;
}
*/
void ust_app_clean_list(void)
{
- struct ust_app *iter, *tmp;
-
- /*
- * Don't acquire list lock here. This function should be called from
- * cleanup() functions meaning that the program will exit.
- */
- cds_list_for_each_entry_safe(iter, tmp, &ust_app_list.head, list) {
- del_app_from_list(iter);
- close(iter->sock);
- free(iter);
+ int ret;
+ struct cds_lfht_node *node;
+ struct cds_lfht_iter iter;
+
+ DBG2("UST app clean hash table");
+
+ rcu_read_lock();
+
+ hashtable_get_first(ust_app_ht, &iter);
+ while ((node = hashtable_iter_get_node(&iter)) != NULL) {
+ ret = hashtable_del(ust_app_ht, &iter);
+ if (!ret) {
+ call_rcu(&node->head, delete_ust_app_rcu);
+ }
+ hashtable_get_next(ust_app_ht, &iter);
}
+
+ rcu_read_unlock();
+}
+
+/*
+ * Init UST app hash table.
+ */
+void ust_app_ht_alloc(void)
+{
+ ust_app_ht = hashtable_new(0);
+ ust_app_sock_key_map = hashtable_new(0);
}
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#ifndef _TRACEABLE_APP_H
-#define _TRACEABLE_APP_H
+#ifndef _LTT_UST_APP_H
+#define _LTT_UST_APP_H
#include <stdint.h>
#include <urcu/list.h>
char name[16];
};
-/*
- * Traceable application list.
- */
-struct ust_app_list {
- /*
- * This lock protects any read/write access to the list and count (which is
- * basically the list size). All public functions in traceable-app.c
- * acquire this lock and release it before returning. If none of those
- * functions are used, the lock MUST be acquired in order to iterate or/and
- * do any actions on that list.
- */
- pthread_mutex_t lock;
-
- /*
- * Number of element in the list. The session list lock MUST be acquired if
- * this counter is used when iterating over the session list.
- */
- unsigned int count;
-
- /* Linked list head */
- struct cds_list_head head;
+struct cds_lfht *ust_app_ht;
+
+struct cds_lfht *ust_app_sock_key_map;
+
+struct ust_app_key {
+ pid_t pid;
+ int sock;
+ struct cds_lfht_node node;
};
-/* Registered traceable applications. Libust registers to the session daemon
+/*
+ * Registered traceable applications. Libust registers to the session daemon
* and a linked list is kept of all running traceable app.
*/
struct ust_app {
- int sock; /* Communication socket with the application */
- pid_t pid;
+ //int sock;
+ //pid_t pid;
pid_t ppid;
uid_t uid; /* User ID that owns the apps */
gid_t gid; /* Group ID that owns the apps */
uint32_t v_major; /* Verion major number */
uint32_t v_minor; /* Verion minor number */
char name[17]; /* Process name (short) */
- struct ltt_ust_channel_list channels;
- struct cds_list_head list;
+ struct cds_lfht *channels;
+ struct cds_lfht_node node;
+ struct ust_app_key key;
};
#ifdef CONFIG_LTTNG_TOOLS_HAVE_UST
int ust_app_register(struct ust_register_msg *msg, int sock);
void ust_app_unregister(int sock);
-unsigned int ust_app_list_count(void);
+unsigned long ust_app_list_count(void);
-void ust_app_lock_list(void);
-void ust_app_unlock_list(void);
void ust_app_clean_list(void);
-struct ust_app_list *ust_app_get_list(void);
-struct ust_app *ust_app_get_by_pid(pid_t pid);
+void ust_app_ht_alloc(void);
+struct cds_lfht *ust_app_get_ht(void);
+struct ust_app *ust_app_find_by_pid(pid_t pid);
#else
return NULL;
}
-
-
#endif
-#endif /* _TRACEABLE_APP_H */
+#endif /* _LTT_UST_APP_H */
--- /dev/null
+/*
+ * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; only version 2
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <lttng-sessiond-comm.h>
+#include <lttngerr.h>
+
+#include "ust-comm.h"
+#include "ust-ctl.h"
+#include "../hashtable/hash.h"
+
+/*
+ * Init command for tracer with cmd type and correct handle.
+ */
+static void init_command(int cmd, int handle, struct lttcomm_ust_msg *command)
+{
+ memset(command, 0, sizeof(struct lttcomm_ust_msg));
+
+ command->cmd = cmd;
+ command->handle = handle;
+}
+
+/*
+ * Generic send command to ust tracer. Caller must free reply.
+ */
+static struct lttcomm_ust_reply *send_command(int sock,
+ struct lttcomm_ust_msg *command)
+{
+ struct lttcomm_ust_reply *reply;
+
+ reply = ustcomm_send_command(sock, command);
+ if (reply == NULL) {
+ goto error;
+ }
+
+ if (reply->ret_code != LTTCOMM_OK) {
+ ERR("Return code (%d): %s", reply->ret_code,
+ lttcomm_get_readable_code(reply->ret_code));
+ goto error;
+ }
+
+ return reply;
+
+error:
+ return NULL;
+}
+
+/*
+ * Send registration done packet to the application.
+ */
+int ustctl_register_done(int sock)
+{
+ struct lttcomm_ust_msg command;
+ struct lttcomm_ust_reply *reply;
+
+ DBG("Sending register done command to %d", sock);
+
+ command.cmd = LTTNG_UST_REGISTER_DONE;
+ command.handle = LTTNG_UST_ROOT_HANDLE;
+
+ reply = ustcomm_send_command(sock, &command);
+ if (reply == NULL) {
+ goto error;
+ }
+
+ if (reply->ret_code != LTTCOMM_OK) {
+ DBG("Return code: %s", lttcomm_get_readable_code(reply->ret_code));
+ goto error;
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+
+/*
+ * Create an UST session on the tracer.
+ *
+ * Return handle if success else negative value.
+ */
+int ustctl_create_session(int sock, struct ltt_ust_session *session)
+{
+ int ret;
+ struct lttcomm_ust_msg command;
+ struct lttcomm_ust_reply *reply = NULL;
+
+ command.cmd = LTTNG_UST_SESSION;
+ command.handle = LTTNG_UST_ROOT_HANDLE;
+
+ reply = ustcomm_send_command(sock, &command);
+ if (reply == NULL) {
+ goto error;
+ }
+
+ /* Save session handle */
+ ret = reply->ret_val;
+ free(reply);
+
+ DBG2("ustctl create session command successful with handle %d", ret);
+
+ return ret;
+
+error:
+ free(reply);
+ return -1;
+}
+
+/*
+ * Create UST channel to the tracer.
+ *
+ * Return handle if success else negative value.
+ */
+int ustctl_create_channel(int sock, struct ltt_ust_session *session,
+ struct lttng_ust_channel *channel)
+{
+ int ret;
+ struct lttcomm_ust_msg command;
+ struct lttcomm_ust_reply *reply = NULL;
+
+ init_command(LTTNG_UST_CHANNEL, session->handle, &command);
+ /* Copy channel attributes to command */
+ memcpy(&command.u.channel, channel, sizeof(command.u.channel));
+
+ /* Send command to tracer */
+ reply = send_command(sock, &command);
+ if (reply == NULL) {
+ goto error;
+ }
+
+ ret = reply->ret_val;
+ free(reply);
+
+ return ret;
+
+error:
+ free(reply);
+ return -1;
+}
+
+/*
+ * Enable UST channel.
+ */
+int ustctl_enable_channel(int sock, struct ltt_ust_session *session,
+ struct ltt_ust_channel *chan)
+{
+ struct lttcomm_ust_msg command;
+ struct lttcomm_ust_reply *reply = NULL;
+
+ init_command(LTTNG_UST_ENABLE, chan->handle, &command);
+
+ reply = ustcomm_send_command(sock, &command);
+ if (reply == NULL) {
+ goto error;
+ }
+
+ if (reply->handle != chan->handle) {
+ ERR("Receive wrong handle from UST reply on enable channel");
+ goto error;
+ }
+
+ chan->enabled = 1;
+ free(reply);
+
+ DBG2("ustctl enable channel successful for sock %d", sock);
+ return 0;
+
+error:
+ free(reply);
+ return -1;
+}
+
+/*
+ * Disable UST channel.
+ */
+int ustctl_disable_channel(int sock, struct ltt_ust_session *session,
+ struct ltt_ust_channel *chan)
+{
+ struct lttcomm_ust_msg command;
+ struct lttcomm_ust_reply *reply = NULL;
+
+ memset(&command, 0, sizeof(command));
+
+ command.cmd = LTTNG_UST_DISABLE;
+ command.handle = chan->handle;
+
+ reply = ustcomm_send_command(sock, &command);
+ if (reply == NULL) {
+ goto error;
+ }
+
+ if (reply->handle != chan->handle) {
+ ERR("Receive wrong handle from UST reply on enable channel");
+ goto error;
+ }
+
+ chan->enabled = 1;
+ free(reply);
+
+ DBG2("ustctl disable channel successful for sock %d", sock);
+ return 0;
+
+error:
+ free(reply);
+ return -1;
+}
#ifdef CONFIG_LTTNG_TOOLS_HAVE_UST
-
#else
-
#endif
#endif /* _LTT_UST_CTL_H */
dom.type = LTTNG_DOMAIN_UST_PID;
dom.attr.pid = opt_pid;
DBG("PID %d set to lttng handle", opt_pid);
+ } else if (opt_userspace && opt_cmd_name == NULL) {
+ dom.type = LTTNG_DOMAIN_UST;
+ } else if (opt_userspace && opt_cmd_name != NULL) {
+ dom.type = LTTNG_DOMAIN_UST_EXEC_NAME;
+ strncpy(dom.attr.exec_name, opt_cmd_name, NAME_MAX);
} else {
ERR("Please specify a tracer (--kernel or --userspace)");
ret = CMD_NOT_IMPLEMENTED;
AM_CFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/libkernelctl \
- -I$(top_srcdir)/liblttngctl -g -Wall
+ -I$(top_srcdir)/liblttngctl -g -Wall -lurcu -lurcu-cds
EXTRA_DIST = runall.sh lttng/runall.sh lttng/run-kernel-tests.sh
kernel_event_basic
UTILS=utils.h
-SESSIONS=$(top_srcdir)/ltt-sessiond/session.c
+SESSIONS=$(top_srcdir)/ltt-sessiond/session.c $(top_srcdir)/ltt-sessiond/hashtable.c \
+ $(top_srcdir)/hashtable/rculfhash.c $(top_srcdir)/hashtable/hash.c
KERN_DATA_TRACE=$(top_srcdir)/ltt-sessiond/trace-kernel.c
LIBLTTNG=$(top_srcdir)/liblttngctl/lttngctl.c \
$(top_srcdir)/liblttng-sessiond-comm/lttng-sessiond-comm.c
#include <time.h>
#include <lttng-sessiond-comm.h>
-#include "ltt-sessiond/session.h"
+
+#include <ltt-sessiond/session.h>
#include "utils.h"
#define SESSION1 "test1"
}
/* Basic init session values */
assert(tmp->kernel_session == NULL);
- assert(tmp->ust_session_list.count == 0);
assert(strlen(tmp->path));
assert(strlen(tmp->name));
session_lock(tmp);