X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fnotification-thread-events.c;h=6ba6a2e603d01ad3c5a2fffc116b5f006b654870;hp=5e53b79a1661a458e5d4bada395350b152f6d725;hb=2ae99f0b1ce4b1ae352a7bf179b1f040111afd46;hpb=e4db5ace44cc9a1d2ecc6898cb1764675af381c8 diff --git a/src/bin/lttng-sessiond/notification-thread-events.c b/src/bin/lttng-sessiond/notification-thread-events.c index 5e53b79a1..6ba6a2e60 100644 --- a/src/bin/lttng-sessiond/notification-thread-events.c +++ b/src/bin/lttng-sessiond/notification-thread-events.c @@ -88,7 +88,7 @@ struct notification_client { uid_t uid; gid_t gid; /* - * Indicates if the credentials and versions of the client has been + * Indicates if the credentials and versions of the client have been * checked. */ bool validated; @@ -416,7 +416,7 @@ int evaluate_condition_for_client(struct lttng_trigger *trigger, assert(current_condition); if (!lttng_condition_is_equal(condition, - current_condition)) { + current_condition)) { continue; } @@ -469,7 +469,7 @@ int evaluate_condition_for_client(struct lttng_trigger *trigger, 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"); + WARN("[notification-thread] Fatal error occurred while evaluating a newly subscribed-to condition"); goto end; } @@ -555,12 +555,22 @@ int notification_thread_client_subscribe(struct notification_client *client, &iter); node = cds_lfht_iter_get_node(&iter); if (!node) { + /* + * No notification-emiting trigger registered with this + * condition. We don't evaluate the condition right away + * since this trigger is not registered yet. + */ free(client_list_element); goto end_unlock; } client_list = caa_container_of(node, struct notification_client_list, notification_trigger_ht_node); + /* + * The condition to which the client just subscribed is evaluated + * at this point so that conditions that are already TRUE result + * in a notification being sent out. + */ if (evaluate_condition_for_client(client_list->trigger, condition, client, state)) { WARN("[notification-thread] Evaluation of a condition on client subscription failed, aborting."); @@ -1104,11 +1114,6 @@ int handle_notification_thread_command_register_trigger( cds_lfht_add(state->notification_trigger_clients_ht, lttng_condition_hash(condition), &client_list->notification_trigger_ht_node); - /* - * Client list ownership transferred to the - * notification_trigger_clients_ht. - */ - client_list = NULL; /* * Add the trigger to list of triggers bound to the channels currently @@ -1147,6 +1152,47 @@ int handle_notification_thread_command_register_trigger( break; } + /* + * Since there is nothing preventing clients from subscribing to a + * condition before the corresponding trigger is registered, we have + * to evaluate this new condition right away. + * + * At some point, we were waiting for the next "evaluation" (e.g. on + * reception of a channel sample) to evaluate this new condition, but + * that was broken. + * + * The reason it was broken is that waiting for the next sample + * does not allow us to properly handle transitions for edge-triggered + * conditions. + * + * Consider this example: when we handle a new channel sample, we + * evaluate each conditions twice: once with the previous state, and + * again with the newest state. We then use those two results to + * determine whether a state change happened: a condition was false and + * became true. If a state change happened, we have to notify clients. + * + * Now, if a client subscribes to a given notification and registers + * a trigger *after* that subscription, we have to make sure the + * condition is evaluated at this point while considering only the + * current state. Otherwise, the next evaluation cycle may only see + * that the evaluations remain the same (true for samples n-1 and n) and + * the client will never know that the condition has been met. + */ + cds_list_for_each_entry_safe(client_list_element, tmp, + &client_list->list, node) { + ret = evaluate_condition_for_client(trigger, condition, + client_list_element->client, state); + if (ret) { + goto error_free_client_list; + } + } + + /* + * Client list ownership transferred to the + * notification_trigger_clients_ht. + */ + client_list = NULL; + *cmd_result = LTTNG_OK; error_free_client_list: if (client_list) { @@ -1275,7 +1321,7 @@ int handle_notification_thread_command( struct notification_thread_command *cmd; /* Read event_fd to put it back into a quiescent state. */ - ret = read(handle->cmd_queue.event_fd, &counter, sizeof(counter)); + ret = read(lttng_pipe_get_readfd(handle->cmd_queue.event_pipe), &counter, sizeof(counter)); if (ret == -1) { goto error; }