+ assert(ua_sess);
+
+ pthread_mutex_lock(&ua_sess->lock);
+ if (ua_sess->deleted) {
+ pthread_mutex_unlock(&ua_sess->lock);
+ goto end;
+ }
+
+ rcu_read_lock();
+
+ cds_lfht_for_each_entry(usess->domain_global.channels->ht, &uchan_iter,
+ uchan, node.node) {
+ struct ust_app_channel *ua_chan;
+ struct cds_lfht_iter uevent_iter;
+ struct ltt_ust_event *uevent;
+
+ /*
+ * Search for a matching ust_app_channel. If none is found,
+ * create it. Creating the channel will cause the ua_chan
+ * structure to be allocated, the channel buffers to be
+ * allocated (if necessary) and sent to the application, and
+ * all enabled contexts will be added to the channel.
+ */
+ ret = find_or_create_ust_app_channel(usess, ua_sess,
+ app, uchan, &ua_chan);
+ if (ret) {
+ /* Tracer is probably gone or ENOMEM. */
+ goto error_unlock;
+ }
+
+ if (!ua_chan) {
+ /* ua_chan will be NULL for the metadata channel */
+ continue;
+ }
+
+ cds_lfht_for_each_entry(uchan->events->ht, &uevent_iter, uevent,
+ node.node) {
+ ret = ust_app_channel_synchronize_event(ua_chan,
+ uevent, ua_sess, app);
+ if (ret) {
+ goto error_unlock;
+ }
+ }
+
+ if (ua_chan->enabled != uchan->enabled) {
+ ret = uchan->enabled ?
+ enable_ust_app_channel(ua_sess, uchan, app) :
+ disable_ust_app_channel(ua_sess, ua_chan, app);
+ if (ret) {
+ goto error_unlock;
+ }
+ }
+ }
+
+ /*
+ * Create the metadata for the application. This returns gracefully if a
+ * metadata was already set for the session.
+ *
+ * The metadata channel must be created after the data channels as the
+ * consumer daemon assumes this ordering. When interacting with a relay
+ * daemon, the consumer will use this assumption to send the
+ * "STREAMS_SENT" message to the relay daemon.
+ */
+ ret = create_ust_app_metadata(ua_sess, app, usess->consumer);
+ if (ret < 0) {
+ goto error_unlock;
+ }
+
+ rcu_read_unlock();
+
+end:
+ pthread_mutex_unlock(&ua_sess->lock);
+ /* Everything went well at this point. */
+ return;
+
+error_unlock:
+ rcu_read_unlock();
+ pthread_mutex_unlock(&ua_sess->lock);
+error:
+ if (ua_sess) {
+ destroy_app_session(app, ua_sess);
+ }
+ return;
+}
+
+static
+void ust_app_global_destroy(struct ltt_ust_session *usess, struct ust_app *app)
+{
+ struct ust_app_session *ua_sess;
+
+ ua_sess = lookup_session_by_app(usess, app);
+ if (ua_sess == NULL) {
+ return;
+ }
+ destroy_app_session(app, ua_sess);
+}
+
+/*
+ * Add channels/events from UST global domain to registered apps at sock.
+ *
+ * Called with session lock held.
+ * Called with RCU read-side lock held.
+ */
+void ust_app_global_update(struct ltt_ust_session *usess, struct ust_app *app)
+{
+ assert(usess);
+ assert(usess->active);
+
+ DBG2("UST app global update for app sock %d for session id %" PRIu64,
+ app->sock, usess->id);
+
+ if (!app->compatible) {
+ return;
+ }
+ if (trace_ust_id_tracker_lookup(LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID,
+ usess, app->pid) &&
+ trace_ust_id_tracker_lookup(
+ LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID,
+ usess, app->uid) &&
+ trace_ust_id_tracker_lookup(
+ LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID,
+ usess, app->gid)) {
+ /*
+ * Synchronize the application's internal tracing configuration
+ * and start tracing.
+ */
+ ust_app_synchronize(usess, app);
+ ust_app_start_trace(usess, app);
+ } else {
+ ust_app_global_destroy(usess, app);
+ }
+}
+
+/*
+ * Add all event notifiers to an application.
+ *
+ * Called with session lock held.
+ * Called with RCU read-side lock held.
+ */
+void ust_app_global_update_event_notifier_rules(struct ust_app *app)
+{
+ DBG2("UST application global event notifier rules update: app = '%s' (ppid: %d)",
+ app->name, app->ppid);
+
+ if (!app->compatible) {
+ return;
+ }
+
+ if (app->event_notifier_group.object == NULL) {
+ WARN("UST app global update of event notifiers for app skipped since communication handle is null: app = '%s' (ppid: %d)",
+ app->name, app->ppid);
+ return;
+ }
+
+ ust_app_synchronize_event_notifier_rules(app);
+}