+/* This function must be called with the RCU read lock held. */
+static
+int evaluate_condition_for_client(struct lttng_trigger *trigger,
+ struct lttng_condition *condition,
+ struct notification_client *client,
+ struct notification_thread_state *state)
+{
+ int ret;
+ struct cds_lfht_iter iter;
+ struct cds_lfht_node *node;
+ struct channel_info *channel_info = NULL;
+ struct channel_key *channel_key = NULL;
+ struct channel_state_sample *last_sample = NULL;
+ struct lttng_channel_trigger_list *channel_trigger_list = NULL;
+ struct lttng_evaluation *evaluation = NULL;
+ struct notification_client_list client_list = { 0 };
+ struct notification_client_list_element client_list_element = { 0 };
+
+ assert(trigger);
+ assert(condition);
+ assert(client);
+ assert(state);
+
+ /* Find the channel associated with the trigger. */
+ cds_lfht_for_each_entry(state->channel_triggers_ht, &iter,
+ channel_trigger_list , channel_triggers_ht_node) {
+ struct lttng_trigger_list_element *element;
+
+ cds_list_for_each_entry(element, &channel_trigger_list->list, node) {
+ struct lttng_condition *current_condition =
+ lttng_trigger_get_condition(
+ element->trigger);
+
+ assert(current_condition);
+ if (!lttng_condition_is_equal(condition,
+ current_condition)) {
+ continue;
+ }
+
+ /* Found the trigger, save the channel key. */
+ channel_key = &channel_trigger_list->channel_key;
+ break;
+ }
+ if (channel_key) {
+ /* The channel key was found stop iteration. */
+ break;
+ }
+ }
+
+ if (!channel_key){
+ /* No channel found; normal exit. */
+ DBG("[notification-thread] No channel associated with newly subscribed-to condition");
+ ret = 0;
+ goto end;
+ }
+
+ /* Fetch channel info for the matching channel. */
+ cds_lfht_lookup(state->channels_ht,
+ hash_channel_key(channel_key),
+ match_channel_info,
+ channel_key,
+ &iter);
+ node = cds_lfht_iter_get_node(&iter);
+ assert(node);
+ channel_info = caa_container_of(node, struct channel_info,
+ channels_ht_node);
+
+ /* Retrieve the channel's last sample, if it exists. */
+ cds_lfht_lookup(state->channel_state_ht,
+ hash_channel_key(channel_key),
+ match_channel_state_sample,
+ channel_key,
+ &iter);
+ node = cds_lfht_iter_get_node(&iter);
+ if (node) {
+ last_sample = caa_container_of(node,
+ struct channel_state_sample,
+ channel_state_ht_node);
+ } else {
+ /* Nothing to evaluate, no sample was ever taken. Normal exit */
+ DBG("[notification-thread] No channel sample associated with newly subscribed-to condition");
+ ret = 0;
+ goto end;
+ }
+
+ ret = evaluate_condition(condition, &evaluation, state, NULL,
+ last_sample, channel_info->capacity);
+ if (ret) {
+ WARN("[notification-thread] Fatal error occured while evaluating a newly subscribed-to condition");
+ goto end;
+ }
+
+ if (!evaluation) {
+ /* Evaluation yielded nothing. Normal exit. */
+ DBG("[notification-thread] Newly subscribed-to condition evaluated to false, nothing to report to client");
+ ret = 0;
+ goto end;
+ }
+
+ /*
+ * Create a temporary client list with the client currently
+ * subscribing.
+ */
+ cds_lfht_node_init(&client_list.notification_trigger_ht_node);
+ CDS_INIT_LIST_HEAD(&client_list.list);
+ client_list.trigger = trigger;
+
+ CDS_INIT_LIST_HEAD(&client_list_element.node);
+ client_list_element.client = client;
+ cds_list_add(&client_list_element.node, &client_list.list);
+
+ /* Send evaluation result to the newly-subscribed client. */
+ DBG("[notification-thread] Newly subscribed-to condition evaluated to true, notifying client");
+ ret = send_evaluation_to_clients(trigger, evaluation, &client_list,
+ state, channel_info->uid, channel_info->gid);
+
+end:
+ return ret;
+}
+