/* Wipe context */
cds_lfht_for_each_entry(ua_chan->ctx->ht, &iter.iter, ua_ctx, node.node) {
+ cds_list_del(&ua_ctx->list);
ret = lttng_ht_del(ua_chan->ctx, &iter);
assert(!ret);
delete_ust_app_ctx(sock, ua_ctx);
lttng_ht_node_init_str(&ua_chan->node, ua_chan->name);
CDS_INIT_LIST_HEAD(&ua_chan->streams.head);
+ CDS_INIT_LIST_HEAD(&ua_chan->ctx_list);
/* Copy attributes */
if (attr) {
goto error;
}
+ CDS_INIT_LIST_HEAD(&ua_ctx->list);
+
if (uctx) {
memcpy(&ua_ctx->ctx, uctx, sizeof(ua_ctx->ctx));
}
ua_chan->enabled = uchan->enabled;
ua_chan->tracing_channel_id = uchan->id;
- cds_lfht_for_each_entry(uchan->ctx->ht, &iter.iter, uctx, node.node) {
+ cds_list_for_each_entry(uctx, &uchan->ctx_list, list) {
ua_ctx = alloc_ust_app_ctx(&uctx->ctx);
if (ua_ctx == NULL) {
continue;
lttng_ht_node_init_ulong(&ua_ctx->node,
(unsigned long) ua_ctx->ctx.ctx);
lttng_ht_add_unique_ulong(ua_chan->ctx, &ua_ctx->node);
+ cds_list_add_tail(&ua_ctx->list, &ua_chan->ctx_list);
}
/* Copy all events from ltt ust channel to ust app channel */
lttng_ht_node_init_ulong(&ua_ctx->node, (unsigned long) ua_ctx->ctx.ctx);
lttng_ht_add_unique_ulong(ua_chan->ctx, &ua_ctx->node);
+ cds_list_add_tail(&ua_ctx->list, &ua_chan->ctx_list);
ret = create_ust_channel_context(ua_chan, ua_ctx, app);
if (ret < 0) {
}
assert(reg_chan);
reg_chan->consumer_key = ua_chan->key;
+ reg_chan->subbuf_size = ua_chan->attr.subbuf_size;
/* Create and add a channel registry to session. */
ret = ust_registry_channel_add(reg_sess->reg.ust,
}
}
- /* Flush buffers */
+ /* Flush buffers and push metadata (for UID buffers). */
switch (usess->buffer_type) {
case LTTNG_BUFFER_PER_UID:
{
/* Flush all per UID buffers associated to that session. */
cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
+ struct ust_registry_session *ust_session_reg;
struct buffer_reg_channel *reg_chan;
struct consumer_socket *socket;
*/
(void) consumer_flush_channel(socket, reg_chan->consumer_key);
}
+
+ ust_session_reg = reg->registry->reg.ust;
+ if (!ust_session_reg->metadata_closed) {
+ /* Push metadata. */
+ (void) push_metadata(ust_session_reg, usess->consumer);
+ }
}
+
break;
}
case LTTNG_BUFFER_PER_PID:
void ust_app_global_update(struct ltt_ust_session *usess, int sock)
{
int ret = 0;
- struct lttng_ht_iter iter, uiter, iter_ctx;
+ struct lttng_ht_iter iter, uiter;
struct ust_app *app;
struct ust_app_session *ua_sess = NULL;
struct ust_app_channel *ua_chan;
}
}
- cds_lfht_for_each_entry(ua_chan->ctx->ht, &iter_ctx.iter, ua_ctx,
- node.node) {
+ /*
+ * Add context using the list so they are enabled in the same order the
+ * user added them.
+ */
+ cds_list_for_each_entry(ua_ctx, &ua_chan->ctx_list, list) {
ret = create_ust_channel_context(ua_chan, ua_ctx, app);
if (ret < 0) {
goto error_unlock;
*/
ret_code = ust_registry_create_event(registry, chan_reg_key,
sobjd, cobjd, name, sig, nr_fields, fields, loglevel,
- model_emf_uri, ua_sess->buffer_type, &event_id);
+ model_emf_uri, ua_sess->buffer_type, &event_id,
+ app);
/*
* The return value is returned to ustctl so in case of an error, the
* Return 0 on success or else a negative value.
*/
int ust_app_snapshot_record(struct ltt_ust_session *usess,
- struct snapshot_output *output, int wait)
+ struct snapshot_output *output, int wait, unsigned int nb_streams)
{
int ret = 0;
struct lttng_ht_iter iter;
struct ust_app *app;
char pathname[PATH_MAX];
+ uint64_t max_stream_size = 0;
assert(usess);
assert(output);
rcu_read_lock();
- cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
- struct consumer_socket *socket;
- struct lttng_ht_iter chan_iter;
- struct ust_app_channel *ua_chan;
- struct ust_app_session *ua_sess;
- struct ust_registry_session *registry;
+ /*
+ * Compute the maximum size of a single stream if a max size is asked by
+ * the caller.
+ */
+ if (output->max_size > 0 && nb_streams > 0) {
+ max_stream_size = output->max_size / nb_streams;
+ }
- ua_sess = lookup_session_by_app(usess, app);
- if (!ua_sess) {
- /* Session not associated with this app. */
- continue;
- }
+ switch (usess->buffer_type) {
+ case LTTNG_BUFFER_PER_UID:
+ {
+ struct buffer_reg_uid *reg;
- /* Get the right consumer socket for the application. */
- socket = consumer_find_socket_by_bitness(app->bits_per_long,
- output->consumer);
- if (!socket) {
- ret = -EINVAL;
- goto error;
- }
+ cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
+ struct buffer_reg_channel *reg_chan;
+ struct consumer_socket *socket;
- /* Add the UST default trace dir to path. */
- memset(pathname, 0, sizeof(pathname));
- ret = snprintf(pathname, sizeof(pathname), DEFAULT_UST_TRACE_DIR "/%s",
- ua_sess->path);
- if (ret < 0) {
- PERROR("snprintf snapshot path");
- goto error;
- }
+ /* Get consumer socket to use to push the metadata.*/
+ socket = consumer_find_socket_by_bitness(reg->bits_per_long,
+ usess->consumer);
+ if (!socket) {
+ ret = -EINVAL;
+ goto error;
+ }
- cds_lfht_for_each_entry(ua_sess->channels->ht, &chan_iter.iter,
- ua_chan, node.node) {
- ret = consumer_snapshot_channel(socket, ua_chan->key, output, 0,
- ua_sess->euid, ua_sess->egid, pathname, wait);
+ memset(pathname, 0, sizeof(pathname));
+ ret = snprintf(pathname, sizeof(pathname),
+ DEFAULT_UST_TRACE_DIR "/" DEFAULT_UST_TRACE_UID_PATH,
+ reg->uid, reg->bits_per_long);
if (ret < 0) {
+ PERROR("snprintf snapshot path");
goto error;
}
- }
- registry = get_session_registry(ua_sess);
- assert(registry);
- ret = consumer_snapshot_channel(socket, registry->metadata_key, output,
- 1, ua_sess->euid, ua_sess->egid, pathname, wait);
- if (ret < 0) {
- goto error;
+ /* Add the UST default trace dir to path. */
+ cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
+ reg_chan, node.node) {
+
+ /*
+ * Make sure the maximum stream size is not lower than the
+ * subbuffer size or else it's an error since we won't be able to
+ * snapshot anything.
+ */
+ if (max_stream_size &&
+ reg_chan->subbuf_size > max_stream_size) {
+ ret = -EINVAL;
+ DBG3("UST app snapshot record maximum stream size %" PRIu64
+ " is smaller than subbuffer size of %zu",
+ max_stream_size, reg_chan->subbuf_size);
+ goto error;
+ }
+ ret = consumer_snapshot_channel(socket, reg_chan->consumer_key, output, 0,
+ usess->uid, usess->gid, pathname, wait,
+ max_stream_size);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+ ret = consumer_snapshot_channel(socket, reg->registry->reg.ust->metadata_key, output,
+ 1, usess->uid, usess->gid, pathname, wait,
+ max_stream_size);
+ if (ret < 0) {
+ goto error;
+ }
}
+ break;
+ }
+ case LTTNG_BUFFER_PER_PID:
+ {
+ cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+ struct consumer_socket *socket;
+ struct lttng_ht_iter chan_iter;
+ struct ust_app_channel *ua_chan;
+ struct ust_app_session *ua_sess;
+ struct ust_registry_session *registry;
+
+ ua_sess = lookup_session_by_app(usess, app);
+ if (!ua_sess) {
+ /* Session not associated with this app. */
+ continue;
+ }
+ /* Get the right consumer socket for the application. */
+ socket = consumer_find_socket_by_bitness(app->bits_per_long,
+ output->consumer);
+ if (!socket) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Add the UST default trace dir to path. */
+ memset(pathname, 0, sizeof(pathname));
+ ret = snprintf(pathname, sizeof(pathname), DEFAULT_UST_TRACE_DIR "/%s",
+ ua_sess->path);
+ if (ret < 0) {
+ PERROR("snprintf snapshot path");
+ goto error;
+ }
+
+ cds_lfht_for_each_entry(ua_sess->channels->ht, &chan_iter.iter,
+ ua_chan, node.node) {
+ /*
+ * Make sure the maximum stream size is not lower than the
+ * subbuffer size or else it's an error since we won't be able to
+ * snapshot anything.
+ */
+ if (max_stream_size &&
+ ua_chan->attr.subbuf_size > max_stream_size) {
+ ret = -EINVAL;
+ DBG3("UST app snapshot record maximum stream size %" PRIu64
+ " is smaller than subbuffer size of %" PRIu64,
+ max_stream_size, ua_chan->attr.subbuf_size);
+ goto error;
+ }
+
+ ret = consumer_snapshot_channel(socket, ua_chan->key, output, 0,
+ ua_sess->euid, ua_sess->egid, pathname, wait,
+ max_stream_size);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ registry = get_session_registry(ua_sess);
+ assert(registry);
+ ret = consumer_snapshot_channel(socket, registry->metadata_key, output,
+ 1, ua_sess->euid, ua_sess->egid, pathname, wait,
+ max_stream_size);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+ break;
+ }
+ default:
+ assert(0);
+ break;
}
error:
rcu_read_unlock();
return ret;
}
+
+/*
+ * Return the number of streams for a UST session.
+ */
+unsigned int ust_app_get_nb_stream(struct ltt_ust_session *usess)
+{
+ unsigned int ret = 0;
+ struct ust_app *app;
+ struct lttng_ht_iter iter;
+
+ assert(usess);
+
+ switch (usess->buffer_type) {
+ case LTTNG_BUFFER_PER_UID:
+ {
+ struct buffer_reg_uid *reg;
+
+ cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
+ struct buffer_reg_channel *reg_chan;
+
+ cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
+ reg_chan, node.node) {
+ ret += reg_chan->stream_count;
+ }
+ }
+ break;
+ }
+ case LTTNG_BUFFER_PER_PID:
+ {
+ rcu_read_lock();
+ cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+ struct ust_app_channel *ua_chan;
+ struct ust_app_session *ua_sess;
+ struct lttng_ht_iter chan_iter;
+
+ ua_sess = lookup_session_by_app(usess, app);
+ if (!ua_sess) {
+ /* Session not associated with this app. */
+ continue;
+ }
+
+ cds_lfht_for_each_entry(ua_sess->channels->ht, &chan_iter.iter,
+ ua_chan, node.node) {
+ ret += ua_chan->streams.count;
+ }
+ }
+ rcu_read_unlock();
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+
+ return ret;
+}