#include "ust-app.h"
#include "ust-consumer.h"
#include "ust-ctl.h"
+#include "utils.h"
/* Next available channel key. */
static unsigned long next_channel_key;
/*
* We need to execute ht_destroy outside of RCU read-side critical
- * section, so we postpone its execution using call_rcu. It is simpler
- * than to change the semantic of the many callers of
- * delete_ust_app_channel().
+ * section and outside of call_rcu thread, so we postpone its execution
+ * using ht_cleanup_push. It is simpler than to change the semantic of
+ * the many callers of delete_ust_app_session().
*/
static
void delete_ust_app_channel_rcu(struct rcu_head *head)
struct ust_app_channel *ua_chan =
caa_container_of(head, struct ust_app_channel, rcu_head);
- lttng_ht_destroy(ua_chan->ctx);
- lttng_ht_destroy(ua_chan->events);
+ ht_cleanup_push(ua_chan->ctx);
+ ht_cleanup_push(ua_chan->events);
free(ua_chan);
}
/*
* We need to execute ht_destroy outside of RCU read-side critical
- * section, so we postpone its execution using call_rcu. It is simpler
- * than to change the semantic of the many callers of
- * delete_ust_app_session().
+ * section and outside of call_rcu thread, so we postpone its execution
+ * using ht_cleanup_push. It is simpler than to change the semantic of
+ * the many callers of delete_ust_app_session().
*/
static
void delete_ust_app_session_rcu(struct rcu_head *head)
struct ust_app_session *ua_sess =
caa_container_of(head, struct ust_app_session, rcu_head);
- lttng_ht_destroy(ua_sess->channels);
+ ht_cleanup_push(ua_sess->channels);
free(ua_sess);
}
rcu_read_unlock();
}
- lttng_ht_destroy(app->sessions);
- lttng_ht_destroy(app->ust_objd);
+ ht_cleanup_push(app->sessions);
+ ht_cleanup_push(app->ust_objd);
/*
* Wait until we have deleted the application from the sock hash table
ua_sess->bits_per_long = app->bits_per_long;
/* There is only one consumer object per session possible. */
ua_sess->consumer = usess->consumer;
+ ua_sess->output_traces = usess->output_traces;
switch (ua_sess->buffer_type) {
case LTTNG_BUFFER_PER_PID:
* Now get the channel from the consumer. This call wil populate the stream
* list of that channel and set the ust objects.
*/
- ret = ust_consumer_get_channel(socket, ua_chan);
- if (ret < 0) {
- goto error_destroy;
+ if (usess->consumer->enabled) {
+ ret = ust_consumer_get_channel(socket, ua_chan);
+ if (ret < 0) {
+ goto error_destroy;
+ }
}
rcu_read_unlock();
ret = ust_consumer_ask_channel(ua_sess, metadata, consumer, socket,
registry);
if (ret < 0) {
- /*
- * Safe because the metadata obj pointer is not set so the delete below
- * will not put a FD back again.
- */
+ /* Nullify the metadata key so we don't try to close it later on. */
+ registry->metadata_key = 0;
goto error_consumer;
}
*/
ret = consumer_setup_metadata(socket, metadata->key);
if (ret < 0) {
- /*
- * Safe because the metadata obj pointer is not set so the delete below
- * will not put a FD back again.
- */
+ /* Nullify the metadata key so we don't try to close it later on. */
+ registry->metadata_key = 0;
goto error_consumer;
}
rcu_read_unlock();
/* Destroy is done only when the ht is empty */
- lttng_ht_destroy(ust_app_ht);
- lttng_ht_destroy(ust_app_ht_by_sock);
- lttng_ht_destroy(ust_app_ht_by_notify_sock);
+ ht_cleanup_push(ust_app_ht);
+ ht_cleanup_push(ust_app_ht_by_sock);
+ ht_cleanup_push(ust_app_ht_by_notify_sock);
}
/*
DBG("Application socket %d is being teardown. Abort event notify",
sock);
ret = 0;
+ free(fields);
goto error_rcu_unlock;
}
if (!ua_chan) {
DBG("Application channel is being teardown. Abort event notify");
ret = 0;
+ free(fields);
goto error_rcu_unlock;
}
} else {
/* Get current already assigned values. */
type = chan_reg->header_type;
+ free(fields);
+ /* Set to NULL so the error path does not do a double free. */
+ fields = NULL;
}
/* Channel id is set during the object creation. */
chan_id = chan_reg->chan_id;
pthread_mutex_unlock(®istry->lock);
error_rcu_unlock:
rcu_read_unlock();
+ if (ret) {
+ free(fields);
+ }
return ret;
}
DBG("Application socket %d is being teardown. Abort event notify",
sock);
ret = 0;
+ free(sig);
+ free(fields);
+ free(model_emf_uri);
goto error_rcu_unlock;
}
if (!ua_chan) {
DBG("Application channel is being teardown. Abort event notify");
ret = 0;
+ free(sig);
+ free(fields);
+ free(model_emf_uri);
goto error_rcu_unlock;
}
pthread_mutex_lock(®istry->lock);
+ /*
+ * From this point on, this call acquires the ownership of the sig, fields
+ * and model_emf_uri meaning any free are done inside it if needed. These
+ * three variables MUST NOT be read/write after this.
+ */
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);
goto error;
}
- /* Add event to the UST registry coming from the notify socket. */
+ /*
+ * Add event to the UST registry coming from the notify socket. This
+ * call will free if needed the sig, fields and model_emf_uri. This
+ * code path loses the ownsership of these variables and transfer them
+ * to the this function.
+ */
ret = add_event_ust_registry(sock, sobjd, cobjd, name, sig, nr_fields,
fields, loglevel, model_emf_uri);
if (ret < 0) {
goto error;
}
+ /*
+ * The fields ownership are transfered to this function call meaning
+ * that if needed it will be freed. After this, it's invalid to access
+ * fields or clean it up.
+ */
ret = reply_ust_register_channel(sock, sobjd, cobjd, nr_fields,
fields);
if (ret < 0) {
call_rcu(&obj->head, close_notify_sock_rcu);
}
}
+
+/*
+ * Destroy a ust app data structure and free its memory.
+ */
+void ust_app_destroy(struct ust_app *app)
+{
+ if (!app) {
+ return;
+ }
+
+ call_rcu(&app->pid_n.head, delete_ust_app_rcu);
+}
+
+/*
+ * Take a snapshot for a given UST session. The snapshot is sent to the given
+ * output.
+ *
+ * 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)
+{
+ int ret = 0;
+ struct lttng_ht_iter iter;
+ struct ust_app *app;
+
+ 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;
+
+ 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;
+ }
+
+ 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, ua_sess->path, wait);
+ 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, ua_sess->path, wait);
+ if (ret < 0) {
+ goto error;
+ }
+
+ }
+
+error:
+ rcu_read_unlock();
+ return ret;
+}