#include <sys/types.h>
#include <unistd.h>
#include <urcu/compiler.h>
+#include <lttng/ust-error.h>
#include <common/common.h>
+#include <common/sessiond-comm/sessiond-comm.h>
+#include "fd-limit.h"
+#include "health.h"
#include "ust-app.h"
#include "ust-consumer.h"
#include "ust-ctl.h"
-#include "fd-limit.h"
+
+/*
+ * Match function for the hash table lookup.
+ *
+ * It matches an ust app event based on three attributes which are the event
+ * name, the filter bytecode and the loglevel.
+ */
+static int ht_match_ust_app_event(struct cds_lfht_node *node, const void *_key)
+{
+ struct ust_app_event *event;
+ const struct ust_app_ht_key *key;
+
+ assert(node);
+ assert(_key);
+
+ event = caa_container_of(node, struct ust_app_event, node.node);
+ key = _key;
+
+ /* Match the 3 elements of the key: name, filter and loglevel. */
+
+ /* Event name */
+ if (strncmp(event->attr.name, key->name, sizeof(event->attr.name)) != 0) {
+ goto no_match;
+ }
+
+ /* Event loglevel. */
+ if (event->attr.loglevel != key->loglevel) {
+ if (event->attr.loglevel_type == LTTNG_UST_LOGLEVEL_ALL
+ && key->loglevel == 0 && event->attr.loglevel == -1) {
+ /*
+ * Match is accepted. This is because on event creation, the
+ * loglevel is set to -1 if the event loglevel type is ALL so 0 and
+ * -1 are accepted for this loglevel type since 0 is the one set by
+ * the API when receiving an enable event.
+ */
+ } else {
+ goto no_match;
+ }
+ }
+
+ /* One of the filters is NULL, fail. */
+ if ((key->filter && !event->filter) || (!key->filter && event->filter)) {
+ goto no_match;
+ }
+
+ if (key->filter && event->filter) {
+ /* Both filters exists, check length followed by the bytecode. */
+ if (event->filter->len != key->filter->len ||
+ memcmp(event->filter->data, key->filter->data,
+ event->filter->len) != 0) {
+ goto no_match;
+ }
+ }
+
+ /* Match. */
+ return 1;
+
+no_match:
+ return 0;
+}
+
+/*
+ * Unique add of an ust app event in the given ht. This uses the custom
+ * ht_match_ust_app_event match function and the event name as hash.
+ */
+static void add_unique_ust_app_event(struct lttng_ht *ht,
+ struct ust_app_event *event)
+{
+ struct cds_lfht_node *node_ptr;
+ struct ust_app_ht_key key;
+
+ assert(ht);
+ assert(ht->ht);
+ assert(event);
+
+ key.name = event->attr.name;
+ key.filter = event->filter;
+ key.loglevel = event->attr.loglevel;
+
+ node_ptr = cds_lfht_add_unique(ht->ht,
+ ht->hash_fct(event->node.key, lttng_ht_seed),
+ ht_match_ust_app_event, &key, &event->node.node);
+ assert(node_ptr == &event->node.node);
+}
/*
* Delete ust context safely. RCU read lock must be held before calling
static
void delete_ust_app_event(int sock, struct ust_app_event *ua_event)
{
- int ret;
- 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);
- assert(!ret);
- delete_ust_app_ctx(sock, ua_ctx);
- }
- lttng_ht_destroy(ua_event->ctx);
+ free(ua_event->filter);
if (ua_event->obj != NULL) {
ustctl_release_object(sock, ua_event->obj);
void delete_ust_app(struct ust_app *app)
{
int ret, sock;
- struct lttng_ht_iter iter;
- struct ust_app_session *ua_sess;
+ struct ust_app_session *ua_sess, *tmp_ua_sess;
rcu_read_lock();
sock = app->sock;
app->sock = -1;
+ lttng_ht_destroy(app->sessions);
+
/* Wipe sessions */
- cds_lfht_for_each_entry(app->sessions->ht, &iter.iter, ua_sess,
- node.node) {
- ret = lttng_ht_del(app->sessions, &iter);
- assert(!ret);
- delete_ust_app_session(app->sock, ua_sess);
+ cds_list_for_each_entry_safe(ua_sess, tmp_ua_sess, &app->teardown_head,
+ teardown_node) {
+ /* Free every object in the session and the session. */
+ delete_ust_app_session(sock, ua_sess);
}
- lttng_ht_destroy(app->sessions);
/*
* Wait until we have deleted the application from the sock hash table
ua_event->enabled = 1;
strncpy(ua_event->name, name, sizeof(ua_event->name));
ua_event->name[sizeof(ua_event->name) - 1] = '\0';
- ua_event->ctx = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
lttng_ht_node_init_str(&ua_event->node, ua_event->name);
/* Copy attributes */
return ua_ctx;
}
+/*
+ * Allocate a filter and copy the given original filter.
+ *
+ * Return allocated filter or NULL on error.
+ */
+static struct lttng_ust_filter_bytecode *alloc_copy_ust_app_filter(
+ struct lttng_ust_filter_bytecode *orig_f)
+{
+ struct lttng_ust_filter_bytecode *filter = NULL;
+
+ /* Copy filter bytecode */
+ filter = zmalloc(sizeof(*filter) + orig_f->len);
+ if (!filter) {
+ PERROR("zmalloc alloc ust app filter");
+ goto error;
+ }
+
+ memcpy(filter, orig_f, sizeof(*filter) + orig_f->len);
+
+error:
+ return filter;
+}
+
/*
* Find an ust_app using the sock and return it. RCU read side lock must be
* held before calling this helper function.
return NULL;
}
+/*
+ * Lookup for an ust app event based on event name, filter bytecode and the
+ * event loglevel.
+ *
+ * Return an ust_app_event object or NULL on error.
+ */
+static struct ust_app_event *find_ust_app_event(struct lttng_ht *ht,
+ char *name, struct lttng_ust_filter_bytecode *filter, int loglevel)
+{
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_str *node;
+ struct ust_app_event *event = NULL;
+ struct ust_app_ht_key key;
+
+ assert(name);
+ assert(ht);
+
+ /* Setup key for event lookup. */
+ key.name = name;
+ key.filter = filter;
+ key.loglevel = loglevel;
+
+ /* Lookup using the event name as hash and a custom match fct. */
+ cds_lfht_lookup(ht->ht, ht->hash_fct((void *) name, lttng_ht_seed),
+ ht_match_ust_app_event, &key, &iter.iter);
+ node = lttng_ht_iter_get_node_str(&iter);
+ if (node == NULL) {
+ goto end;
+ }
+
+ event = caa_container_of(node, struct ust_app_event, node);
+
+end:
+ return event;
+}
+
/*
* Create the channel context on the tracer.
*/
{
int ret;
+ health_code_update(&health_thread_cmd);
+
ret = ustctl_add_context(app->sock, &ua_ctx->ctx,
ua_chan->obj, &ua_ctx->obj);
if (ret < 0) {
DBG2("UST app context created successfully for channel %s", ua_chan->name);
error:
+ health_code_update(&health_thread_cmd);
return ret;
}
/*
- * Create the event context on the tracer.
+ * Set the filter on the tracer.
*/
static
-int create_ust_event_context(struct ust_app_event *ua_event,
- struct ust_app_ctx *ua_ctx, struct ust_app *app)
+int set_ust_event_filter(struct ust_app_event *ua_event,
+ struct ust_app *app)
{
int ret;
- ret = ustctl_add_context(app->sock, &ua_ctx->ctx,
- ua_event->obj, &ua_ctx->obj);
- if (ret < 0) {
+ health_code_update(&health_thread_cmd);
+
+ if (!ua_event->filter) {
+ ret = 0;
goto error;
}
- ua_ctx->handle = ua_ctx->obj->handle;
+ ret = ustctl_set_filter(app->sock, ua_event->filter,
+ ua_event->obj);
+ if (ret < 0) {
+ goto error;
+ }
- DBG2("UST app context created successfully for event %s", ua_event->name);
+ DBG2("UST filter set successfully for event %s", ua_event->name);
error:
+ health_code_update(&health_thread_cmd);
return ret;
}
{
int ret;
+ health_code_update(&health_thread_cmd);
+
ret = ustctl_disable(app->sock, ua_event->obj);
if (ret < 0) {
ERR("UST app event %s disable failed for app (pid: %d) "
ua_event->attr.name, app->pid);
error:
+ health_code_update(&health_thread_cmd);
return ret;
}
{
int ret;
+ health_code_update(&health_thread_cmd);
+
ret = ustctl_disable(app->sock, ua_chan->obj);
if (ret < 0) {
ERR("UST app channel %s disable failed for app (pid: %d) "
ua_chan->name, app->pid);
error:
+ health_code_update(&health_thread_cmd);
return ret;
}
{
int ret;
+ health_code_update(&health_thread_cmd);
+
ret = ustctl_enable(app->sock, ua_chan->obj);
if (ret < 0) {
ERR("UST app channel %s enable failed for app (pid: %d) "
ua_chan->name, app->pid);
error:
+ health_code_update(&health_thread_cmd);
return ret;
}
{
int ret;
+ health_code_update(&health_thread_cmd);
+
ret = ustctl_enable(app->sock, ua_event->obj);
if (ret < 0) {
ERR("UST app event %s enable failed for app (pid: %d) "
ua_event->attr.name, app->pid);
error:
+ health_code_update(&health_thread_cmd);
return ret;
}
int ret;
struct lttng_ust_channel_attr uattr;
+ health_code_update(&health_thread_cmd);
+
uattr.overwrite = ua_sess->metadata->attr.overwrite;
uattr.subbuf_size = ua_sess->metadata->attr.subbuf_size;
uattr.num_subbuf = ua_sess->metadata->attr.num_subbuf;
ua_sess->metadata->handle = ua_sess->metadata->obj->handle;
error:
+ health_code_update(&health_thread_cmd);
return ret;
}
{
int ret;
+ health_code_update(&health_thread_cmd);
+
/* We are going to receive 2 fds, we need to reserve them. */
ret = lttng_fd_get(LTTNG_FD_APPS, 2);
if (ret < 0) {
}
error:
+ health_code_update(&health_thread_cmd);
return ret;
}
{
int ret;
+ health_code_update(&health_thread_cmd);
+
/* TODO: remove cast and use lttng-ust-abi.h */
/* We are going to receive 2 fds, we need to reserve them. */
ERR("Exhausted number of available FD upon create channel");
goto error;
}
+
+ health_code_update(&health_thread_cmd);
+
ret = ustctl_create_channel(app->sock, ua_sess->handle,
(struct lttng_ust_channel_attr *)&ua_chan->attr, &ua_chan->obj);
if (ret < 0) {
DBG2("UST app channel %s created successfully for pid:%d and sock:%d",
ua_chan->name, app->pid, app->sock);
+ health_code_update(&health_thread_cmd);
+
/* If channel is not enabled, disable it on the tracer */
if (!ua_chan->enabled) {
ret = disable_ust_channel(app, ua_sess, ua_chan);
}
error:
+ health_code_update(&health_thread_cmd);
return ret;
}
{
int ret = 0;
+ health_code_update(&health_thread_cmd);
+
/* Create UST event on tracer */
ret = ustctl_create_event(app->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->pid, ret);
goto error;
DBG2("UST app event %s created successfully for pid:%d",
ua_event->attr.name, app->pid);
+ health_code_update(&health_thread_cmd);
+
+ /* Set filter if one is present. */
+ if (ua_event->filter) {
+ ret = set_ust_event_filter(ua_event, app);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
/* If event not enabled, disable it on the tracer */
if (ua_event->enabled == 0) {
ret = disable_ust_event(app, ua_sess, ua_event);
* just created it.
*/
switch (ret) {
- case -EPERM:
+ case -LTTNG_UST_ERR_PERM:
/* Code flow problem */
assert(0);
- case -EEXIST:
+ case -LTTNG_UST_ERR_EXIST:
/* It's OK for our use case. */
ret = 0;
break;
}
error:
+ health_code_update(&health_thread_cmd);
return ret;
}
static void shadow_copy_event(struct ust_app_event *ua_event,
struct ltt_ust_event *uevent)
{
- struct lttng_ht_iter iter;
- struct ltt_ust_context *uctx;
- struct ust_app_ctx *ua_ctx;
-
strncpy(ua_event->name, uevent->attr.name, sizeof(ua_event->name));
ua_event->name[sizeof(ua_event->name) - 1] = '\0';
/* 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) {
- /* 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);
+ /* Copy filter bytecode */
+ if (uevent->filter) {
+ ua_event->filter = alloc_copy_ust_app_filter(uevent->filter);
+ /* Filter might be NULL here in case of ENONEM. */
}
}
struct ltt_ust_channel *uchan)
{
struct lttng_ht_iter iter;
- struct lttng_ht_node_str *ua_event_node;
struct ltt_ust_event *uevent;
struct ltt_ust_context *uctx;
struct ust_app_event *ua_event;
/* Copy all events from ltt ust channel to ust app channel */
cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent, node.node) {
- struct lttng_ht_iter uiter;
-
- lttng_ht_lookup(ua_chan->events, (void *) uevent->attr.name, &uiter);
- ua_event_node = lttng_ht_iter_get_node_str(&uiter);
- if (ua_event_node == NULL) {
+ ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
+ uevent->filter, uevent->attr.loglevel);
+ if (ua_event == NULL) {
DBG2("UST event %s not found on shadow copy channel",
uevent->attr.name);
ua_event = alloc_ust_app_event(uevent->attr.name, &uevent->attr);
continue;
}
shadow_copy_event(ua_event, uevent);
- lttng_ht_add_unique_str(ua_chan->events, &ua_event->node);
+ add_unique_ust_app_event(ua_chan->events, ua_event);
}
}
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->pid, datetime);
+ ret = snprintf(ua_sess->path, PATH_MAX, "%s-%d-%s/", app->name, app->pid,
+ datetime);
if (ret < 0) {
PERROR("asprintf UST shadow copy session");
/* TODO: We cannot return an error from here.. */
static struct ust_app_session *create_ust_app_session(
struct ltt_ust_session *usess, struct ust_app *app)
{
- int ret;
struct ust_app_session *ua_sess;
+ health_code_update(&health_thread_cmd);
+
ua_sess = lookup_session_by_app(usess, app);
if (ua_sess == NULL) {
DBG2("UST app pid: %d session id %d not found, creating it",
shadow_copy_session(ua_sess, usess, app);
}
+ health_code_update(&health_thread_cmd);
+
if (ua_sess->handle == -1) {
+ int ret;
+
ret = ustctl_create_session(app->sock);
if (ret < 0) {
ERR("Creating session for app pid %d", app->pid);
+ delete_ust_app_session(-1, ua_sess);
/* This means that the tracer is gone... */
ua_sess = (void*) -1UL;
- goto error;
+ goto end;
}
ua_sess->handle = ret;
}
end:
+ health_code_update(&health_thread_cmd);
return ua_sess;
-
-error:
- delete_ust_app_session(-1, ua_sess);
- return NULL;
}
/*
return ret;
}
-/*
- * Create an UST context and enable it for the event on the tracer.
- */
-static
-int create_ust_app_event_context(struct ust_app_session *ua_sess,
- struct ust_app_event *ua_event, 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 event %s", ua_event->name);
-
- lttng_ht_lookup(ua_event->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_event->ctx, &ua_ctx->node);
-
- ret = create_ust_event_context(ua_event, 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.
*/
}
/*
- * Create UST app channel and create it on the tracer.
+ * Create UST app channel and create it on the tracer. Set ua_chanp of the
+ * newly created channel if not NULL.
*/
-static struct ust_app_channel *create_ust_app_channel(
- struct ust_app_session *ua_sess, struct ltt_ust_channel *uchan,
- struct ust_app *app)
+static int create_ust_app_channel(struct ust_app_session *ua_sess,
+ struct ltt_ust_channel *uchan, struct ust_app *app,
+ struct ust_app_channel **ua_chanp)
{
int ret = 0;
struct lttng_ht_iter iter;
ua_chan = alloc_ust_app_channel(uchan->name, &uchan->attr);
if (ua_chan == NULL) {
/* Only malloc can fail here */
+ ret = -ENOMEM;
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);
+ assert(ret != -LTTNG_UST_ERR_EXIST);
goto error;
}
+ /* Only add the channel if successful on the tracer side. */
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->pid);
end:
- return ua_chan;
+ if (ua_chanp) {
+ *ua_chanp = ua_chan;
+ }
+
+ /* Everything went well. */
+ return 0;
error:
delete_ust_app_channel(-1, ua_chan);
- return NULL;
+ return ret;
}
/*
struct ust_app *app)
{
int ret = 0;
- struct lttng_ht_iter iter;
- struct lttng_ht_node_str *ua_event_node;
struct ust_app_event *ua_event;
/* Get event node */
- 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) {
+ ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
+ uevent->filter, uevent->attr.loglevel);
+ if (ua_event != NULL) {
ret = -EEXIST;
goto end;
}
ret = create_ust_event(app, ua_sess, ua_chan, ua_event);
if (ret < 0) {
/* Not found previously means that it does not exist on the tracer */
- assert(ret != -EEXIST);
+ assert(ret != -LTTNG_UST_ERR_EXIST);
goto error;
}
- lttng_ht_add_unique_str(ua_chan->events, &ua_event->node);
+ add_unique_ust_app_event(ua_chan->events, ua_event);
DBG2("UST app create event %s for PID %d completed", ua_event->name,
app->pid);
goto error;
}
- ret = run_as_mkdir(ua_sess->path, S_IRWXU | S_IRWXG,
- ua_sess->uid, ua_sess->gid);
- if (ret < 0) {
- PERROR("mkdir UST metadata");
- goto error;
- }
-
ret = snprintf(ua_sess->metadata->pathname, PATH_MAX,
"%s/metadata", ua_sess->path);
if (ret < 0) {
struct ust_app *lta;
int ret;
- if ((msg->bits_per_long == 64 && ust_consumerd64_fd == -EINVAL)
- || (msg->bits_per_long == 32 && ust_consumerd32_fd == -EINVAL)) {
+ if ((msg->bits_per_long == 64 &&
+ (uatomic_read(&ust_consumerd64_fd) == -EINVAL))
+ || (msg->bits_per_long == 32 &&
+ (uatomic_read(&ust_consumerd32_fd) == -EINVAL))) {
ERR("Registration failed: application \"%s\" (pid: %d) has "
"%d-bit long, but no consumerd for this long size is available.\n",
msg->name, msg->pid, msg->bits_per_long);
lta->sock = sock;
lttng_ht_node_init_ulong(<a->sock_n, (unsigned long)lta->sock);
+ CDS_INIT_LIST_HEAD(<a->teardown_head);
+
rcu_read_lock();
/*
struct ust_app *lta;
struct lttng_ht_node_ulong *node;
struct lttng_ht_iter iter;
+ struct ust_app_session *ua_sess;
int ret;
rcu_read_lock();
/* Assign second node for deletion */
iter.iter.node = <a->pid_n.node;
+ /*
+ * Ignore return value since the node might have been removed before by an
+ * add replace during app registration because the PID can be reassigned by
+ * the OS.
+ */
ret = lttng_ht_del(ust_app_ht, &iter);
- assert(!ret);
+ if (ret) {
+ DBG3("Unregister app by PID %d failed. This can happen on pid reuse",
+ lta->pid);
+ }
+
+ /* Remove sessions so they are not visible during deletion.*/
+ cds_lfht_for_each_entry(lta->sessions->ht, &iter.iter, ua_sess,
+ node.node) {
+ ret = lttng_ht_del(lta->sessions, &iter);
+ if (ret) {
+ /* The session was already removed so scheduled for teardown. */
+ continue;
+ }
+
+ /*
+ * Add session to list for teardown. This is safe since at this point we
+ * are the only one using this list.
+ */
+ cds_list_add(&ua_sess->teardown_node, <a->teardown_head);
+ }
/* Free memory */
call_rcu(<a->pid_n.head, delete_ust_app_rcu);
size_t nbmem, count = 0;
struct lttng_ht_iter iter;
struct ust_app *app;
- struct lttng_event *tmp;
+ struct lttng_event *tmp_event;
nbmem = UST_APP_EVENT_LIST_SIZE;
- tmp = zmalloc(nbmem * sizeof(struct lttng_event));
- if (tmp == NULL) {
+ tmp_event = zmalloc(nbmem * sizeof(struct lttng_event));
+ if (tmp_event == NULL) {
PERROR("zmalloc ust app events");
ret = -ENOMEM;
goto error;
cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
struct lttng_ust_tracepoint_iter uiter;
+ health_code_update(&health_thread_cmd);
+
if (!app->compatible) {
/*
* TODO: In time, we should notice the caller of this error by
}
while ((ret = ustctl_tracepoint_list_get(app->sock, handle,
- &uiter)) != -ENOENT) {
+ &uiter)) != -LTTNG_UST_ERR_NOENT) {
+ health_code_update(&health_thread_cmd);
if (count >= nbmem) {
+ /* In case the realloc fails, we free the memory */
+ void *ptr;
+
DBG2("Reallocating event list from %zu to %zu entries", nbmem,
2 * nbmem);
nbmem *= 2;
- tmp = realloc(tmp, nbmem * sizeof(struct lttng_event));
- if (tmp == NULL) {
+ ptr = realloc(tmp_event, nbmem * sizeof(struct lttng_event));
+ if (ptr == NULL) {
PERROR("realloc ust app events");
+ free(tmp_event);
ret = -ENOMEM;
goto rcu_error;
}
+ tmp_event = ptr;
}
- memcpy(tmp[count].name, uiter.name, LTTNG_UST_SYM_NAME_LEN);
- tmp[count].loglevel = uiter.loglevel;
- tmp[count].type = (enum lttng_event_type) LTTNG_UST_TRACEPOINT;
- tmp[count].pid = app->pid;
- tmp[count].enabled = -1;
+ memcpy(tmp_event[count].name, uiter.name, LTTNG_UST_SYM_NAME_LEN);
+ tmp_event[count].loglevel = uiter.loglevel;
+ tmp_event[count].type = (enum lttng_event_type) LTTNG_UST_TRACEPOINT;
+ tmp_event[count].pid = app->pid;
+ tmp_event[count].enabled = -1;
count++;
}
}
ret = count;
- *events = tmp;
+ *events = tmp_event;
DBG2("UST app list events done (%zu events)", count);
rcu_error:
rcu_read_unlock();
error:
+ health_code_update(&health_thread_cmd);
return ret;
}
size_t nbmem, count = 0;
struct lttng_ht_iter iter;
struct ust_app *app;
- struct lttng_event_field *tmp;
+ struct lttng_event_field *tmp_event;
nbmem = UST_APP_EVENT_LIST_SIZE;
- tmp = zmalloc(nbmem * sizeof(struct lttng_event_field));
- if (tmp == NULL) {
+ tmp_event = zmalloc(nbmem * sizeof(struct lttng_event_field));
+ if (tmp_event == NULL) {
PERROR("zmalloc ust app event fields");
ret = -ENOMEM;
goto error;
cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
struct lttng_ust_field_iter uiter;
+ health_code_update(&health_thread_cmd);
+
if (!app->compatible) {
/*
* TODO: In time, we should notice the caller of this error by
}
while ((ret = ustctl_tracepoint_field_list_get(app->sock, handle,
- &uiter)) != -ENOENT) {
+ &uiter)) != -LTTNG_UST_ERR_NOENT) {
+ health_code_update(&health_thread_cmd);
if (count >= nbmem) {
+ /* In case the realloc fails, we free the memory */
+ void *ptr;
+
DBG2("Reallocating event field list from %zu to %zu entries", nbmem,
2 * nbmem);
nbmem *= 2;
- tmp = realloc(tmp, nbmem * sizeof(struct lttng_event_field));
- if (tmp == NULL) {
+ ptr = realloc(tmp_event, nbmem * sizeof(struct lttng_event_field));
+ if (ptr == NULL) {
PERROR("realloc ust app event fields");
+ free(tmp_event);
ret = -ENOMEM;
goto rcu_error;
}
+ tmp_event = ptr;
}
-
- memcpy(tmp[count].field_name, uiter.field_name, LTTNG_UST_SYM_NAME_LEN);
- tmp[count].type = uiter.type;
+ memcpy(tmp_event[count].field_name, uiter.field_name, LTTNG_UST_SYM_NAME_LEN);
+ tmp_event[count].type = uiter.type;
+ tmp_event[count].nowrite = uiter.nowrite;
- memcpy(tmp[count].event.name, uiter.event_name, LTTNG_UST_SYM_NAME_LEN);
- tmp[count].event.loglevel = uiter.loglevel;
- tmp[count].event.type = LTTNG_UST_TRACEPOINT;
- tmp[count].event.pid = app->pid;
- tmp[count].event.enabled = -1;
+ memcpy(tmp_event[count].event.name, uiter.event_name, LTTNG_UST_SYM_NAME_LEN);
+ tmp_event[count].event.loglevel = uiter.loglevel;
+ tmp_event[count].event.type = LTTNG_UST_TRACEPOINT;
+ tmp_event[count].event.pid = app->pid;
+ tmp_event[count].event.enabled = -1;
count++;
}
}
ret = count;
- *fields = tmp;
+ *fields = tmp_event;
DBG2("UST app list event fields done (%zu events)", count);
rcu_error:
rcu_read_unlock();
error:
+ health_code_update(&health_thread_cmd);
return ret;
}
void ust_app_clean_list(void)
{
int ret;
+ struct ust_app *app;
struct lttng_ht_iter iter;
- struct lttng_ht_node_ulong *node;
DBG2("UST app cleaning registered apps hash table");
rcu_read_lock();
- cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, node, node) {
+ cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
ret = lttng_ht_del(ust_app_ht, &iter);
assert(!ret);
- call_rcu(&node->head, delete_ust_app_rcu);
+ call_rcu(&app->pid_n.head, delete_ust_app_rcu);
}
/* Cleanup socket hash table */
- cds_lfht_for_each_entry(ust_app_ht_by_sock->ht, &iter.iter, node, node) {
+ cds_lfht_for_each_entry(ust_app_ht_by_sock->ht, &iter.iter, app,
+ sock_n.node) {
ret = lttng_ht_del(ust_app_ht_by_sock, &iter);
assert(!ret);
}
continue;
}
ua_sess = lookup_session_by_app(usess, app);
- /* If ua_sess is NULL, there is a code flow error */
- assert(ua_sess);
+ if (!ua_sess) {
+ /* The application has problem or is probably dead. */
+ continue;
+ }
/* Lookup channel in the ust app session */
lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &uiter);
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;
/* Very wrong code flow */
assert(usess);
ua_sess = create_ust_app_session(usess, app);
if (ua_sess == NULL) {
/* The malloc() failed. */
- goto error;
+ ret = -ENOMEM;
+ goto error_rcu_unlock;
} else if (ua_sess == (void *) -1UL) {
- /* The application's socket is not valid. Contiuing */
+ /*
+ * The application's socket is not valid. Either a bad socket or a
+ * timeout on it. We can't inform yet the caller that for a
+ * specific app, the session failed so we continue here.
+ */
continue;
}
- /* Create channel onto application */
- ua_chan = create_ust_app_channel(ua_sess, uchan, app);
- if (ua_chan == NULL) {
- /* Major problem here and it's maybe the tracer or malloc() */
- goto error;
+ /* Create channel onto application. We don't need the chan ref. */
+ ret = create_ust_app_channel(ua_sess, uchan, app, NULL);
+ if (ret < 0 && ret == -ENOMEM) {
+ /* No more memory is a fatal error. Stop right now. */
+ goto error_rcu_unlock;
}
}
+error_rcu_unlock:
rcu_read_unlock();
-
- return 0;
-
-error:
- return -1;
+ return ret;
}
/*
{
int ret = 0;
struct lttng_ht_iter iter, uiter;
- struct lttng_ht_node_str *ua_chan_node, *ua_event_node;
+ struct lttng_ht_node_str *ua_chan_node;
struct ust_app *app;
struct ust_app_session *ua_sess;
struct ust_app_channel *ua_chan;
continue;
}
ua_sess = lookup_session_by_app(usess, app);
- /* If ua_sess is NULL, there is a code flow error */
- assert(ua_sess);
+ if (!ua_sess) {
+ /* The application has problem or is probably dead. */
+ continue;
+ }
/* Lookup channel in the ust app session */
lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &uiter);
ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
- lttng_ht_lookup(ua_chan->events, (void*)uevent->attr.name, &uiter);
- ua_event_node = lttng_ht_iter_get_node_str(&uiter);
- if (ua_event_node == NULL) {
+ /* Get event node */
+ ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
+ uevent->filter, uevent->attr.loglevel);
+ if (ua_event == NULL) {
DBG3("UST app enable event %s not found for app PID %d."
"Skipping app", uevent->attr.name, app->pid);
continue;
}
- ua_event = caa_container_of(ua_event_node, struct ust_app_event, node);
ret = enable_ust_app_event(ua_sess, ua_event, app);
if (ret < 0) {
continue;
}
ua_sess = lookup_session_by_app(usess, app);
- /* If ua_sess is NULL, there is a code flow error */
- assert(ua_sess);
+ if (!ua_sess) {
+ /* The application has problem or is probably dead. */
+ continue;
+ }
/* Lookup channel in the ust app session */
lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &uiter);
ret = create_ust_app_event(ua_sess, ua_chan, uevent, app);
if (ret < 0) {
- if (ret != -EEXIST) {
+ if (ret != -LTTNG_UST_ERR_EXIST) {
/* Possible value at this point: -ENOMEM. If so, we stop! */
break;
}
struct ust_app_session *ua_sess;
struct ust_app_channel *ua_chan;
struct ltt_ust_stream *ustream;
- int consumerd_fd;
+ struct consumer_socket *socket;
DBG("Starting tracing for ust app pid %d", app->pid);
ua_sess = lookup_session_by_app(usess, app);
if (ua_sess == NULL) {
- goto error_rcu_unlock;
+ /* The session is in teardown process. Ignore and continue. */
+ goto end;
}
/* Upon restart, we skip the setup, already done */
goto skip_setup;
}
- /* Indicate that the session has been started once */
- ua_sess->started = 1;
+ /* Create directories if consumer is LOCAL and has a path defined. */
+ 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);
+ if (ret < 0) {
+ if (ret != -EEXIST) {
+ ERR("Trace directory creation error");
+ ret = -1;
+ goto error_rcu_unlock;
+ }
+ }
+ }
ret = create_ust_app_metadata(ua_sess, usess->pathname, app);
if (ret < 0) {
+ ret = LTTNG_ERR_UST_META_FAIL;
goto error_rcu_unlock;
}
free(ustream);
goto error_rcu_unlock;
}
+
+ health_code_update(&health_thread_cmd);
+
ret = ustctl_create_stream(app->sock, ua_chan->obj,
&ustream->obj);
if (ret < 0) {
/* Got all streams */
lttng_fd_put(LTTNG_FD_APPS, 2);
free(ustream);
+ ret = LTTNG_ERR_UST_STREAM_FAIL;
break;
}
ustream->handle = ustream->obj->handle;
+ health_code_update(&health_thread_cmd);
+
/* Order is important */
cds_list_add_tail(&ustream->list, &ua_chan->streams.head);
- ret = snprintf(ustream->pathname, PATH_MAX, "%s/%s_%u",
- ua_sess->path, ua_chan->name,
- ua_chan->streams.count++);
+ ret = snprintf(ustream->name, sizeof(ustream->name), "%s_%u",
+ ua_chan->name, ua_chan->streams.count);
+ ua_chan->streams.count++;
if (ret < 0) {
PERROR("asprintf UST create stream");
/*
*/
continue;
}
- DBG2("UST stream %d ready at %s", ua_chan->streams.count,
- ustream->pathname);
+ DBG2("UST stream %d ready (handle: %d)", ua_chan->streams.count,
+ ustream->handle);
}
+
+ health_code_update(&health_thread_cmd);
}
switch (app->bits_per_long) {
case 64:
- consumerd_fd = ust_consumerd64_fd;
+ socket = consumer_find_socket(uatomic_read(&ust_consumerd64_fd),
+ usess->consumer);
+ if (socket == NULL) {
+ goto skip_setup;
+ }
break;
case 32:
- consumerd_fd = ust_consumerd32_fd;
+ socket = consumer_find_socket(uatomic_read(&ust_consumerd32_fd),
+ usess->consumer);
+ if (socket == NULL) {
+ goto skip_setup;
+ }
break;
default:
ret = -EINVAL;
}
/* Setup UST consumer socket and send fds to it */
- ret = ust_consumer_send_session(consumerd_fd, ua_sess);
+ ret = ust_consumer_send_session(ua_sess, usess->consumer, socket);
if (ret < 0) {
goto error_rcu_unlock;
}
+ health_code_update(&health_thread_cmd);
+
skip_setup:
/* This start the UST tracing */
ret = ustctl_start_session(app->sock, ua_sess->handle);
goto error_rcu_unlock;
}
+ /* Indicate that the session has been started once */
+ ua_sess->started = 1;
+
+ health_code_update(&health_thread_cmd);
+
/* Quiescent wait after starting trace */
ustctl_wait_quiescent(app->sock);
end:
rcu_read_unlock();
+ health_code_update(&health_thread_cmd);
return 0;
error_rcu_unlock:
rcu_read_unlock();
+ health_code_update(&health_thread_cmd);
return -1;
}
ua_sess = lookup_session_by_app(usess, app);
if (ua_sess == NULL) {
- /* Only malloc can failed so something is really wrong */
- goto error_rcu_unlock;
+ goto end;
}
/*
* If started = 0, it means that stop trace has been called for a session
- * that was never started. This is a code flow error and should never
- * happen.
+ * that was never started. It's possible since we can have a fail start
+ * from either the application manager thread or the command thread. Simply
+ * indicate that this is a stop error.
*/
- assert(ua_sess->started == 1);
+ if (ua_sess->started == 1) {
+ goto error_rcu_unlock;
+ }
+
+ health_code_update(&health_thread_cmd);
/* This inhibits UST tracing */
ret = ustctl_stop_session(app->sock, ua_sess->handle);
goto error_rcu_unlock;
}
+ health_code_update(&health_thread_cmd);
+
/* Quiescent wait after stopping trace */
ustctl_wait_quiescent(app->sock);
+ health_code_update(&health_thread_cmd);
+
/* Flushing buffers */
cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, ua_chan,
node.node) {
+ health_code_update(&health_thread_cmd);
ret = ustctl_sock_flush_buffer(app->sock, ua_chan->obj);
if (ret < 0) {
ERR("UST app PID %d channel %s flush failed with ret %d",
}
}
+ health_code_update(&health_thread_cmd);
+
/* Flush all buffers before stopping */
ret = ustctl_sock_flush_buffer(app->sock, ua_sess->metadata->obj);
if (ret < 0) {
end:
rcu_read_unlock();
+ health_code_update(&health_thread_cmd);
return 0;
error_rcu_unlock:
rcu_read_unlock();
+ health_code_update(&health_thread_cmd);
return -1;
}
/*
* Destroy a specific UST session in apps.
*/
-int ust_app_destroy_trace(struct ltt_ust_session *usess, struct ust_app *app)
+static int destroy_trace(struct ltt_ust_session *usess, struct ust_app *app)
{
struct ust_app_session *ua_sess;
struct lttng_ust_object_data obj;
__lookup_session_by_app(usess, app, &iter);
node = lttng_ht_iter_get_node_ulong(&iter);
if (node == NULL) {
- /* Only malloc can failed so something is really wrong */
- goto error_rcu_unlock;
+ /* Session is being or is deleted. */
+ goto end;
}
ua_sess = caa_container_of(node, struct ust_app_session, node);
ret = lttng_ht_del(app->sessions, &iter);
- assert(!ret);
+ if (ret) {
+ /* Already scheduled for teardown. */
+ goto end;
+ }
+
obj.handle = ua_sess->handle;
obj.shm_fd = -1;
obj.wait_fd = -1;
obj.memory_map_size = 0;
+ health_code_update(&health_thread_cmd);
ustctl_release_object(app->sock, &obj);
+ health_code_update(&health_thread_cmd);
delete_ust_app_session(app->sock, ua_sess);
/* Quiescent wait after stopping trace */
end:
rcu_read_unlock();
+ health_code_update(&health_thread_cmd);
return 0;
-
-error_rcu_unlock:
- rcu_read_unlock();
- return -1;
}
/*
rcu_read_lock();
cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
- ret = ust_app_destroy_trace(usess, app);
+ ret = destroy_trace(usess, app);
if (ret < 0) {
/* Continue to next apps even on error */
continue;
struct ust_app_event *ua_event;
struct ust_app_ctx *ua_ctx;
- if (usess == NULL) {
- ERR("No UST session on global update. Returning");
- goto error;
- }
+ assert(usess);
DBG2("UST app global update for app sock %d for session id %d", sock,
usess->id);
}
ua_sess = create_ust_app_session(usess, app);
- if (ua_sess == NULL) {
+ if (ua_sess == NULL || ua_sess == (void *) -1UL) {
+ /* Tracer is gone for this session and has been freed */
goto error;
}
continue;
}
- /* Add context on events. */
- cds_lfht_for_each_entry(ua_event->ctx->ht, &iter_ctx.iter,
- ua_ctx, node.node) {
- ret = create_ust_event_context(ua_event, ua_ctx, app);
- if (ret < 0) {
- /* FIXME: Should we quit here or continue... */
- continue;
- }
+ ret = set_ust_event_filter(ua_event, app);
+ if (ret < 0) {
+ /* FIXME: Should we quit here or continue... */
+ continue;
}
}
}
return ret;
}
-/*
- * Add context to a specific event in a channel for global UST domain.
- */
-int ust_app_add_ctx_event_glb(struct ltt_ust_session *usess,
- struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent,
- struct ltt_ust_context *uctx)
-{
- int ret = 0;
- struct lttng_ht_node_str *ua_chan_node, *ua_event_node;
- struct lttng_ht_iter iter, uiter;
- struct ust_app_session *ua_sess;
- struct ust_app_event *ua_event;
- struct ust_app_channel *ua_chan = NULL;
- struct ust_app *app;
-
- rcu_read_lock();
-
- cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
- if (!app->compatible) {
- /*
- * TODO: In time, we should notice the caller of this error by
- * telling him that this is a version error.
- */
- continue;
- }
- ua_sess = lookup_session_by_app(usess, app);
- if (ua_sess == NULL) {
- continue;
- }
-
- /* Lookup channel in the ust app session */
- 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) {
- continue;
- }
- ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel,
- node);
-
- lttng_ht_lookup(ua_chan->events, (void *)uevent->attr.name, &uiter);
- ua_event_node = lttng_ht_iter_get_node_str(&uiter);
- if (ua_event_node == NULL) {
- continue;
- }
- ua_event = caa_container_of(ua_event_node, struct ust_app_event,
- node);
-
- ret = create_ust_app_event_context(ua_sess, ua_event, &uctx->ctx, app);
- if (ret < 0) {
- continue;
- }
- }
-
- rcu_read_unlock();
- return ret;
-}
-
/*
* Enable event for a channel from a UST session for a specific PID.
*/
{
int ret = 0;
struct lttng_ht_iter iter;
- struct lttng_ht_node_str *ua_chan_node, *ua_event_node;
+ struct lttng_ht_node_str *ua_chan_node;
struct ust_app *app;
struct ust_app_session *ua_sess;
struct ust_app_channel *ua_chan;
}
ua_sess = lookup_session_by_app(usess, app);
- /* If ua_sess is NULL, there is a code flow error */
- assert(ua_sess);
+ if (!ua_sess) {
+ /* The application has problem or is probably dead. */
+ goto error;
+ }
/* Lookup channel in the ust app session */
lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &iter);
ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
- 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) {
+ ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
+ uevent->filter, uevent->attr.loglevel);
+ if (ua_event == NULL) {
ret = create_ust_app_event(ua_sess, ua_chan, uevent, app);
if (ret < 0) {
goto error;
}
} else {
- ua_event = caa_container_of(ua_event_node, struct ust_app_event, node);
-
ret = enable_ust_app_event(ua_sess, ua_event, app);
if (ret < 0) {
goto error;
}
ua_sess = lookup_session_by_app(usess, app);
- /* If ua_sess is NULL, there is a code flow error */
- assert(ua_sess);
+ if (!ua_sess) {
+ /* The application has problem or is probably dead. */
+ goto error;
+ }
/* Lookup channel in the ust app session */
lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &iter);
app = find_app_by_sock(sock);
assert(app);
+ health_code_update(&health_thread_cmd);
+
ret = ustctl_tracer_version(sock, &app->version);
if (ret < 0) {
goto error;
}
/* Validate version */
- if (app->version.major > UST_APP_MAJOR_VERSION) {
+ if (app->version.major != UST_APP_MAJOR_VERSION) {
goto error;
}
- DBG2("UST app PID %d is compatible with major version %d "
- "(supporting <= %d)", app->pid, app->version.major,
+ DBG2("UST app PID %d is compatible with internal major version %d "
+ "(supporting == %d)", app->pid, app->version.major,
UST_APP_MAJOR_VERSION);
app->compatible = 1;
rcu_read_unlock();
+ health_code_update(&health_thread_cmd);
return 0;
error:
- DBG2("UST app PID %d is not compatible with major version %d "
- "(supporting <= %d)", app->pid, app->version.major,
+ DBG2("UST app PID %d is not compatible with internal major version %d "
+ "(supporting == %d)", app->pid, app->version.major,
UST_APP_MAJOR_VERSION);
app->compatible = 0;
rcu_read_unlock();
+ health_code_update(&health_thread_cmd);
return -1;
}
continue;
}
+ health_code_update(&health_thread_cmd);
+
ret = ustctl_calibrate(app->sock, calibrate);
if (ret < 0) {
switch (ret) {
rcu_read_unlock();
+ health_code_update(&health_thread_cmd);
+
return ret;
}