#include "ust-consumer.h"
#include "ust-ctl.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;
/* Event loglevel. */
if (event->attr.loglevel != key->loglevel) {
- goto no_match;
+ 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. */
goto no_match;
}
- /* Both filters are NULL, success. */
- if (!key->filter && !event->filter) {
- goto match;
- }
-
- /* 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 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:
+ /* 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)
{
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
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_node_str *node;
struct ust_app_event *event = NULL;
struct ust_app_ht_key key;
- void *orig_match_fct;
assert(name);
assert(ht);
key.filter = filter;
key.loglevel = loglevel;
- /* Save match function so we can use the ust app event match. */
- orig_match_fct = (void *) ht->match_fct;
- ht->match_fct = ht_match_ust_app_event;
-
- lttng_ht_lookup(ht, (void *) &key, &iter);
+ /* 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:
- /* Put back original match function. */
- ht->match_fct = orig_match_fct;
return event;
}
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);
/* Copy filter bytecode */
if (uevent->filter) {
- ua_event->filter = zmalloc(sizeof(*ua_event->filter) +
- uevent->filter->len);
- if (!ua_event->filter) {
- return;
- }
- memcpy(ua_event->filter, uevent->filter,
- sizeof(*ua_event->filter) + uevent->filter->len);
+ ua_event->filter = alloc_copy_ust_app_filter(uevent->filter);
+ /* Filter might be NULL here in case of ENONEM. */
}
}
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);
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);
return ret;
}
-/*
- * Set UST filter for the event on the tracer.
- */
-static
-int set_ust_app_event_filter(struct ust_app_session *ua_sess,
- struct ust_app_event *ua_event,
- struct lttng_filter_bytecode *bytecode,
- struct ust_app *app)
-{
- int ret = 0;
-
- DBG2("UST app adding context to event %s", ua_event->name);
-
- /* Copy filter bytecode */
- ua_event->filter = zmalloc(sizeof(*ua_event->filter) + bytecode->len);
- if (!ua_event->filter) {
- return -ENOMEM;
- }
- memcpy(ua_event->filter, bytecode,
- sizeof(*ua_event->filter) + bytecode->len);
- ret = set_ust_event_filter(ua_event, 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);
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;
}
/*
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();
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;
health_code_update(&health_thread_cmd);
if (count >= nbmem) {
/* In case the realloc fails, we free the memory */
- void *tmp_ptr = (void *) tmp;
+ 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_ptr);
+ 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);
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;
health_code_update(&health_thread_cmd);
if (count >= nbmem) {
/* In case the realloc fails, we free the memory */
- void *tmp_ptr = (void *) tmp;
+ 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_ptr);
+ 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;
- tmp[count].nowrite = uiter.nowrite;
+ 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);
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);
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. */
- ret = -1;
- goto error;
+ ret = -ENOMEM;
+ goto error_rcu_unlock;
} else if (ua_sess == (void *) -1UL) {
- /* The application's socket is not valid. Contiuing */
- ret = -1;
+ /*
+ * 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() */
- ret = -1;
- 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();
-
-error:
return 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);
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_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 */
}
}
- /* Indicate that the session has been started once */
- ua_sess->started = 1;
-
ret = create_ust_app_metadata(ua_sess, usess->pathname, app);
if (ret < 0) {
ret = LTTNG_ERR_UST_META_FAIL;
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 */
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);
/*
* 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;
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;
}
/*
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);
return ret;
}
-/*
- * Add context to a specific event in a channel for global UST domain.
- */
-int ust_app_set_filter_event_glb(struct ltt_ust_session *usess,
- struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent,
- struct lttng_filter_bytecode *bytecode)
-{
- int ret = 0;
- struct lttng_ht_node_str *ua_chan_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);
-
- ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
- (struct lttng_ust_filter_bytecode *) bytecode,
- uevent->attr.loglevel);
- if (ua_event == NULL) {
- continue;
- }
-
- ret = set_ust_app_event_filter(ua_sess, ua_event, bytecode, app);
- if (ret < 0) {
- continue;
- }
- }
-
- rcu_read_unlock();
- return ret;
-}
-
/*
* Enable event for a channel from a UST session for a specific PID.
*/
}
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_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);