+ struct buffer_reg_uid *reg_uid;
+ struct buffer_reg_channel *reg_chan;
+ struct ltt_session *session = NULL;
+ enum lttng_error_code notification_ret;
+ struct ust_registry_channel *chan_reg;
+
+ assert(app);
+ assert(usess);
+ assert(ua_sess);
+ assert(ua_chan);
+
+ DBG("UST app creating channel %s with per UID buffers", ua_chan->name);
+
+ reg_uid = buffer_reg_uid_find(usess->id, app->bits_per_long, app->uid);
+ /*
+ * The session creation handles the creation of this global registry
+ * object. If none can be find, there is a code flow problem or a
+ * teardown race.
+ */
+ assert(reg_uid);
+
+ reg_chan = buffer_reg_channel_find(ua_chan->tracing_channel_id,
+ reg_uid);
+ if (reg_chan) {
+ goto send_channel;
+ }
+
+ /* Create the buffer registry channel object. */
+ ret = create_buffer_reg_channel(reg_uid->registry, ua_chan, ®_chan);
+ if (ret < 0) {
+ ERR("Error creating the UST channel \"%s\" registry instance",
+ ua_chan->name);
+ goto error;
+ }
+
+ session = session_find_by_id(ua_sess->tracing_id);
+ assert(session);
+ assert(pthread_mutex_trylock(&session->lock));
+ assert(session_trylock_list());
+
+ /*
+ * Create the buffers on the consumer side. This call populates the
+ * ust app channel object with all streams and data object.
+ */
+ ret = do_consumer_create_channel(usess, ua_sess, ua_chan,
+ app->bits_per_long, reg_uid->registry->reg.ust,
+ session->most_recent_chunk_id.value);
+ if (ret < 0) {
+ ERR("Error creating UST channel \"%s\" on the consumer daemon",
+ ua_chan->name);
+
+ /*
+ * Let's remove the previously created buffer registry channel so
+ * it's not visible anymore in the session registry.
+ */
+ ust_registry_channel_del_free(reg_uid->registry->reg.ust,
+ ua_chan->tracing_channel_id, false);
+ buffer_reg_channel_remove(reg_uid->registry, reg_chan);
+ buffer_reg_channel_destroy(reg_chan, LTTNG_DOMAIN_UST);
+ goto error;
+ }
+
+ /*
+ * Setup the streams and add it to the session registry.
+ */
+ ret = setup_buffer_reg_channel(reg_uid->registry,
+ ua_chan, reg_chan, app);
+ if (ret < 0) {
+ ERR("Error setting up UST channel \"%s\"", ua_chan->name);
+ goto error;
+ }
+
+ /* Notify the notification subsystem of the channel's creation. */
+ pthread_mutex_lock(®_uid->registry->reg.ust->lock);
+ chan_reg = ust_registry_channel_find(reg_uid->registry->reg.ust,
+ ua_chan->tracing_channel_id);
+ assert(chan_reg);
+ chan_reg->consumer_key = ua_chan->key;
+ chan_reg = NULL;
+ pthread_mutex_unlock(®_uid->registry->reg.ust->lock);
+
+ notification_ret = notification_thread_command_add_channel(
+ notification_thread_handle, session->name,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ ua_chan->name,
+ ua_chan->key, LTTNG_DOMAIN_UST,
+ ua_chan->attr.subbuf_size * ua_chan->attr.num_subbuf);
+ if (notification_ret != LTTNG_OK) {
+ ret = - (int) notification_ret;
+ ERR("Failed to add channel to notification thread");
+ goto error;
+ }
+
+send_channel:
+ /* Send buffers to the application. */
+ ret = send_channel_uid_to_ust(reg_chan, app, ua_sess, ua_chan);
+ if (ret < 0) {
+ if (ret != -ENOTCONN) {
+ ERR("Error sending channel to application");
+ }
+ goto error;
+ }
+
+error:
+ if (session) {
+ session_put(session);
+ }
+ return ret;
+}
+
+/*
+ * Create and send to the application the created buffers with per PID buffers.
+ *
+ * Called with UST app session lock held.
+ * The session list lock and the session's lock must be acquired.
+ *
+ * Return 0 on success else a negative value.
+ */
+static int create_channel_per_pid(struct ust_app *app,
+ struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan)
+{
+ int ret;
+ struct ust_registry_session *registry;
+ enum lttng_error_code cmd_ret;
+ struct ltt_session *session = NULL;
+ uint64_t chan_reg_key;
+ struct ust_registry_channel *chan_reg;
+
+ assert(app);
+ assert(usess);
+ assert(ua_sess);
+ assert(ua_chan);
+
+ DBG("UST app creating channel %s with per PID buffers", ua_chan->name);
+
+ rcu_read_lock();
+
+ registry = get_session_registry(ua_sess);
+ /* The UST app session lock is held, registry shall not be null. */
+ assert(registry);
+
+ /* Create and add a new channel registry to session. */
+ ret = ust_registry_channel_add(registry, ua_chan->key);
+ if (ret < 0) {
+ ERR("Error creating the UST channel \"%s\" registry instance",
+ ua_chan->name);
+ goto error;
+ }
+
+ session = session_find_by_id(ua_sess->tracing_id);
+ assert(session);
+
+ assert(pthread_mutex_trylock(&session->lock));
+ assert(session_trylock_list());
+
+ /* Create and get channel on the consumer side. */
+ ret = do_consumer_create_channel(usess, ua_sess, ua_chan,
+ app->bits_per_long, registry,
+ session->most_recent_chunk_id.value);
+ if (ret < 0) {
+ ERR("Error creating UST channel \"%s\" on the consumer daemon",
+ ua_chan->name);
+ goto error_remove_from_registry;
+ }
+
+ ret = send_channel_pid_to_ust(app, ua_sess, ua_chan);
+ if (ret < 0) {
+ if (ret != -ENOTCONN) {
+ ERR("Error sending channel to application");
+ }
+ goto error_remove_from_registry;
+ }
+
+ chan_reg_key = ua_chan->key;
+ pthread_mutex_lock(®istry->lock);
+ chan_reg = ust_registry_channel_find(registry, chan_reg_key);
+ assert(chan_reg);
+ chan_reg->consumer_key = ua_chan->key;
+ pthread_mutex_unlock(®istry->lock);
+
+ cmd_ret = notification_thread_command_add_channel(
+ notification_thread_handle, session->name,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ ua_chan->name,
+ ua_chan->key, LTTNG_DOMAIN_UST,
+ ua_chan->attr.subbuf_size * ua_chan->attr.num_subbuf);
+ if (cmd_ret != LTTNG_OK) {
+ ret = - (int) cmd_ret;
+ ERR("Failed to add channel to notification thread");
+ goto error_remove_from_registry;
+ }
+
+error_remove_from_registry:
+ if (ret) {
+ ust_registry_channel_del_free(registry, ua_chan->key, false);
+ }
+error:
+ rcu_read_unlock();
+ if (session) {
+ session_put(session);
+ }
+ return ret;
+}
+
+/*
+ * From an already allocated ust app channel, create the channel buffers if
+ * needed and send them to the application. This MUST be called with a RCU read
+ * side lock acquired.
+ *
+ * Called with UST app session lock held.
+ *
+ * Return 0 on success or else a negative value. Returns -ENOTCONN if
+ * the application exited concurrently.
+ */
+static int ust_app_channel_send(struct ust_app *app,
+ struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan)
+{
+ int ret;
+
+ assert(app);
+ assert(usess);
+ assert(usess->active);
+ assert(ua_sess);
+ assert(ua_chan);
+
+ /* Handle buffer type before sending the channel to the application. */
+ switch (usess->buffer_type) {
+ case LTTNG_BUFFER_PER_UID:
+ {
+ ret = create_channel_per_uid(app, usess, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+ break;
+ }
+ case LTTNG_BUFFER_PER_PID:
+ {
+ ret = create_channel_per_pid(app, usess, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+ break;
+ }
+ default:
+ assert(0);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Initialize ust objd object using the received handle and add it. */
+ lttng_ht_node_init_ulong(&ua_chan->ust_objd_node, ua_chan->handle);
+ lttng_ht_add_unique_ulong(app->ust_objd, &ua_chan->ust_objd_node);
+
+ /* If channel is not enabled, disable it on the tracer */
+ if (!ua_chan->enabled) {
+ ret = disable_ust_channel(app, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Create UST app channel and return it through ua_chanp if not NULL.
+ *
+ * Called with UST app session lock and RCU read-side lock held.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int ust_app_channel_allocate(struct ust_app_session *ua_sess,
+ struct ltt_ust_channel *uchan,
+ enum lttng_ust_chan_type type, struct ltt_ust_session *usess,
+ struct ust_app_channel **ua_chanp)
+{
+ int ret = 0;
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_str *ua_chan_node;
+ struct ust_app_channel *ua_chan;
+
+ /* Lookup channel in the ust app session */
+ lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &iter);
+ ua_chan_node = lttng_ht_iter_get_node_str(&iter);
+ if (ua_chan_node != NULL) {
+ ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+ goto end;
+ }
+
+ ua_chan = alloc_ust_app_channel(uchan->name, ua_sess, &uchan->attr);
+ if (ua_chan == NULL) {
+ /* Only malloc can fail here */
+ ret = -ENOMEM;
+ goto error;
+ }
+ shadow_copy_channel(ua_chan, uchan);
+
+ /* Set channel type. */
+ ua_chan->attr.type = type;
+
+ /* Only add the channel if successful on the tracer side. */
+ lttng_ht_add_unique_str(ua_sess->channels, &ua_chan->node);
+end:
+ if (ua_chanp) {
+ *ua_chanp = ua_chan;
+ }
+
+ /* Everything went well. */
+ return 0;
+
+error:
+ return ret;
+}
+
+/*
+ * Create UST app event and create it on the tracer side.
+ *
+ * Must be called with the RCU read side lock held.
+ * Called with ust app session mutex held.
+ */
+static
+int create_ust_app_event(struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan, struct ltt_ust_event *uevent,
+ struct ust_app *app)
+{
+ int ret = 0;
+ struct ust_app_event *ua_event;
+
+ ua_event = alloc_ust_app_event(uevent->attr.name, &uevent->attr);
+ if (ua_event == NULL) {
+ /* Only failure mode of alloc_ust_app_event(). */
+ ret = -ENOMEM;
+ goto end;
+ }
+ shadow_copy_event(ua_event, uevent);
+
+ /* Create it on the tracer side */
+ 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. If the application reports that the event existed,
+ * it means there is a bug in the sessiond or lttng-ust
+ * (or corruption, etc.)
+ */
+ if (ret == -LTTNG_UST_ERR_EXIST) {
+ ERR("Tracer for application reported that an event being created already existed: "
+ "event_name = \"%s\", pid = %d, ppid = %d, uid = %d, gid = %d",
+ uevent->attr.name,
+ app->pid, app->ppid, app->uid,
+ app->gid);
+ }
+ goto error;
+ }
+
+ add_unique_ust_app_event(ua_chan, ua_event);
+
+ DBG2("UST app create event completed: app = '%s' (ppid: %d)",
+ app->name, app->ppid);
+
+end:
+ return ret;
+
+error:
+ /* Valid. Calling here is already in a read side lock */
+ delete_ust_app_event(-1, ua_event, app);
+ return ret;
+}
+
+/*
+ * Create UST app event notifier rule and create it on the tracer side.
+ *
+ * Must be called with the RCU read side lock held.
+ * Called with ust app session mutex held.
+ */
+static
+int create_ust_app_event_notifier_rule(struct lttng_event_rule *rule,
+ struct ust_app *app, uint64_t token)
+{
+ int ret = 0;
+ struct ust_app_event_notifier_rule *ua_event_notifier_rule;
+
+ ua_event_notifier_rule = alloc_ust_app_event_notifier_rule(rule, token);
+ if (ua_event_notifier_rule == NULL) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ /* Create it on the tracer side. */
+ ret = create_ust_event_notifier(app, ua_event_notifier_rule);
+ if (ret < 0) {
+ /*
+ * Not found previously means that it does not exist on the
+ * tracer. If the application reports that the event existed,
+ * it means there is a bug in the sessiond or lttng-ust
+ * (or corruption, etc.)
+ */
+ if (ret == -LTTNG_UST_ERR_EXIST) {
+ ERR("Tracer for application reported that an event notifier being created already exists: "
+ "token = \"%" PRIu64 "\", pid = %d, ppid = %d, uid = %d, gid = %d",
+ token,
+ app->pid, app->ppid, app->uid,
+ app->gid);
+ }
+ goto error;
+ }
+
+ lttng_ht_add_unique_u64(app->token_to_event_notifier_rule_ht,
+ &ua_event_notifier_rule->node);
+
+ DBG2("UST app create token event rule completed: app = '%s' (ppid: %d), token = %" PRIu64,
+ app->name, app->ppid, token);
+
+end:
+ return ret;
+
+error:
+ /* The RCU read side lock is already being held by the caller. */
+ delete_ust_app_event_notifier_rule(-1, ua_event_notifier_rule, app);
+ return ret;
+}
+
+/*
+ * Create UST metadata and open it on the tracer side.
+ *
+ * Called with UST app session lock held and RCU read side lock.
+ */
+static int create_ust_app_metadata(struct ust_app_session *ua_sess,
+ struct ust_app *app, struct consumer_output *consumer)
+{
+ int ret = 0;
+ struct ust_app_channel *metadata;
+ struct consumer_socket *socket;
+ struct ust_registry_session *registry;
+ struct ltt_session *session = NULL;
+
+ assert(ua_sess);
+ assert(app);
+ assert(consumer);
+
+ registry = get_session_registry(ua_sess);
+ /* The UST app session is held registry shall not be null. */
+ assert(registry);
+
+ pthread_mutex_lock(®istry->lock);
+
+ /* Metadata already exists for this registry or it was closed previously */
+ if (registry->metadata_key || registry->metadata_closed) {
+ ret = 0;
+ goto error;
+ }
+
+ /* Allocate UST metadata */
+ metadata = alloc_ust_app_channel(DEFAULT_METADATA_NAME, ua_sess, NULL);
+ if (!metadata) {
+ /* malloc() failed */
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ memcpy(&metadata->attr, &ua_sess->metadata_attr, sizeof(metadata->attr));
+
+ /* Need one fd for the channel. */
+ ret = lttng_fd_get(LTTNG_FD_APPS, 1);
+ if (ret < 0) {
+ ERR("Exhausted number of available FD upon create metadata");
+ goto error;
+ }
+
+ /* Get the right consumer socket for the application. */
+ socket = consumer_find_socket_by_bitness(app->bits_per_long, consumer);
+ if (!socket) {
+ ret = -EINVAL;
+ goto error_consumer;
+ }
+
+ /*
+ * Keep metadata key so we can identify it on the consumer side. Assign it
+ * to the registry *before* we ask the consumer so we avoid the race of the
+ * consumer requesting the metadata and the ask_channel call on our side
+ * did not returned yet.
+ */
+ registry->metadata_key = metadata->key;
+
+ session = session_find_by_id(ua_sess->tracing_id);
+ assert(session);
+
+ assert(pthread_mutex_trylock(&session->lock));
+ assert(session_trylock_list());
+
+ /*
+ * Ask the metadata channel creation to the consumer. The metadata object
+ * will be created by the consumer and kept their. However, the stream is
+ * never added or monitored until we do a first push metadata to the
+ * consumer.
+ */
+ ret = ust_consumer_ask_channel(ua_sess, metadata, consumer, socket,
+ registry, session->current_trace_chunk);
+ if (ret < 0) {
+ /* Nullify the metadata key so we don't try to close it later on. */
+ registry->metadata_key = 0;
+ goto error_consumer;
+ }
+
+ /*
+ * The setup command will make the metadata stream be sent to the relayd,
+ * if applicable, and the thread managing the metadatas. This is important
+ * because after this point, if an error occurs, the only way the stream
+ * can be deleted is to be monitored in the consumer.
+ */
+ ret = consumer_setup_metadata(socket, metadata->key);
+ if (ret < 0) {
+ /* Nullify the metadata key so we don't try to close it later on. */
+ registry->metadata_key = 0;
+ goto error_consumer;
+ }
+
+ DBG2("UST metadata with key %" PRIu64 " created for app pid %d",
+ metadata->key, app->pid);
+
+error_consumer:
+ lttng_fd_put(LTTNG_FD_APPS, 1);
+ delete_ust_app_channel(-1, metadata, app);
+error:
+ pthread_mutex_unlock(®istry->lock);
+ if (session) {
+ session_put(session);
+ }
+ return ret;
+}
+
+/*
+ * Return ust app pointer or NULL if not found. RCU read side lock MUST be
+ * acquired before calling this function.
+ */
+struct ust_app *ust_app_find_by_pid(pid_t pid)
+{
+ struct ust_app *app = NULL;
+ struct lttng_ht_node_ulong *node;
+ struct lttng_ht_iter iter;
+
+ lttng_ht_lookup(ust_app_ht, (void *)((unsigned long) pid), &iter);
+ node = lttng_ht_iter_get_node_ulong(&iter);
+ if (node == NULL) {
+ DBG2("UST app no found with pid %d", pid);
+ goto error;
+ }
+
+ DBG2("Found UST app by pid %d", pid);
+
+ app = caa_container_of(node, struct ust_app, pid_n);
+
+error:
+ return app;
+}
+
+/*
+ * Allocate and init an UST app object using the registration information and
+ * the command socket. This is called when the command socket connects to the
+ * session daemon.
+ *
+ * The object is returned on success or else NULL.
+ */
+struct ust_app *ust_app_create(struct ust_register_msg *msg, int sock)
+{
+ struct ust_app *lta = NULL;
+ struct lttng_pipe *event_notifier_event_source_pipe = NULL;
+
+ assert(msg);
+ assert(sock >= 0);
+
+ DBG3("UST app creating application for socket %d", sock);