#include <sys/time.h>
#include <time.h>
-#include <lttng/condition/event-rule.h>
+#include <lttng/condition/event-rule-matches.h>
#include <lttng/lttng.h>
#include "utils.h"
static struct option long_options[] =
{
/* These options set a flag. */
- {"trigger", required_argument, 0, 'i'},
+ {"trigger", required_argument, 0, 't'},
{"sync-after-notif-register", required_argument, 0, 'a'},
+ /* Default alue for count is 1 */
+ {"count", required_argument, 0, 'b'},
+ /*
+ * When end-trigger is present the reception loop is exited only when a
+ * notification matching the end trigger is received.
+ * Otherwise the loop is exited when the count of notification received
+ * for `trigger` math the `count` argument.
+ */
+ {"end-trigger", required_argument, 0, 'c'},
{0, 0, 0, 0}
};
-static bool action_group_contains_notify(
- const struct lttng_action *action_group)
+static bool action_list_contains_notify(
+ const struct lttng_action *action_list)
{
unsigned int i, count;
enum lttng_action_status status =
- lttng_action_group_get_count(action_group, &count);
+ lttng_action_list_get_count(action_list, &count);
if (status != LTTNG_ACTION_STATUS_OK) {
- printf("Failed to get action count from action group\n");
+ printf("Failed to get action count from action list\n");
exit(1);
}
for (i = 0; i < count; i++) {
const struct lttng_action *action =
- lttng_action_group_get_at_index(
- action_group, i);
+ lttng_action_list_get_at_index(
+ action_list, i);
const enum lttng_action_type action_type =
lttng_action_get_type(action);
return false;
}
-static bool is_expected_trigger_name(const char *expected_trigger_name,
+/* Only expects named triggers. */
+static bool is_trigger_name(const char *expected_trigger_name,
struct lttng_notification *notification)
{
- int ret = false;
- const struct lttng_evaluation *evaluation =
- lttng_notification_get_evaluation(notification);
- const enum lttng_condition_type type =
- lttng_evaluation_get_type(evaluation);
-
- switch (type) {
- case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
- case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
- case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
- case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
- case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
- break;
- case LTTNG_CONDITION_TYPE_ON_EVENT:
- {
- const char *trigger_name;
- enum lttng_evaluation_status evaluation_status;
-
- evaluation_status =
- lttng_evaluation_on_event_get_trigger_name(
- evaluation, &trigger_name);
- if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) {
- fprintf(stderr, "Failed to get trigger name of event rule notification\n");
- ret = -1;
- break;
- }
+ const char *trigger_name = NULL;
+ enum lttng_trigger_status trigger_status;
+ const struct lttng_trigger *trigger;
+ bool names_match;
- ret = true;
- break;
+ trigger = lttng_notification_get_trigger(notification);
+ if (!trigger) {
+ fprintf(stderr, "Failed to get trigger from notification\n");
+ names_match = false;
+ goto end;
}
- default:
- fprintf(stderr, "Unknown notification type (%d)\n", type);
+
+ trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+ fprintf(stderr, "Failed to get name from notification's trigger\n");
+ names_match = false;
+ goto end;
}
- return ret;
+ names_match = strcmp(expected_trigger_name, trigger_name) == 0;
+ if (!names_match) {
+ fprintf(stderr, "Got an unexpected trigger name: name = '%s', expected name = '%s'\n",
+ trigger_name, expected_trigger_name);
+ }
+end:
+ return names_match;
}
int main(int argc, char **argv)
int ret;
int option;
int option_index;
- const char *expected_trigger_name = NULL;
+ char *expected_trigger_name = NULL;
+ char *end_trigger_name = NULL;
struct lttng_triggers *triggers = NULL;
unsigned int count, i, subcription_count = 0;
enum lttng_trigger_status trigger_status;
char *after_notif_register_file_path = NULL;
struct lttng_notification_channel *notification_channel = NULL;
+ int expected_notifications = 1, notification_count = 0;
- while ((option = getopt_long(argc, argv, "a:t:",
- long_options, &option_index)) != -1) {
+ while ((option = getopt_long(argc, argv, "a:b:c:t:", long_options,
+ &option_index)) != -1) {
switch (option) {
case 'a':
after_notif_register_file_path = strdup(optarg);
break;
+ case 'b':
+ expected_notifications = atoi(optarg);
+ break;
+ case 'c':
+ end_trigger_name = strdup(optarg);
+ break;
case 't':
expected_trigger_name = strdup(optarg);
break;
ret = lttng_list_triggers(&triggers);
if (ret != LTTNG_OK) {
fprintf(stderr, "Failed to list triggers\n");
+ ret = -1;
goto end;
}
goto end;
}
+ /* Look for the trigger we want to subscribe to. */
for (i = 0; i < count; i++) {
const struct lttng_trigger *trigger =
lttng_triggers_get_at_index(triggers, i);
lttng_trigger_get_name(trigger, &trigger_name);
if (strcmp(trigger_name, expected_trigger_name)) {
- continue;
+ /* Might match the end event trigger */
+ if (end_trigger_name != NULL &&
+ strcmp(trigger_name,
+ end_trigger_name)) {
+ continue;
+ }
}
-
- if (!((action_type == LTTNG_ACTION_TYPE_GROUP &&
- action_group_contains_notify(action)) ||
+ if (!((action_type == LTTNG_ACTION_TYPE_LIST &&
+ action_list_contains_notify(action)) ||
action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
/* "The action of trigger is not notify, skipping. */
continue;
}
if (subcription_count == 0) {
- printf("No matching trigger with a notify action found.\n");
- ret = 0;
+ fprintf(stderr, "No matching trigger with a notify action found.\n");
+ ret = -1;
goto end;
}
+ if (end_trigger_name != NULL && subcription_count != 2) {
+ fprintf(stderr, "No matching end event trigger with a notify action found.\n");
+ ret = -1;
+ goto end;
+ }
/*
* We registered to the notification of our target trigger. We can now
switch (channel_status) {
case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
printf("Dropped notification\n");
- break;
+ ret = -1;
+ goto end;
case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
- ret = 0;
+ ret = -1;
goto end;
case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
break;
goto end;
}
- ret = is_expected_trigger_name(expected_trigger_name,
- notification);
+ /* Early exit check. */
+ if (end_trigger_name != NULL &&
+ is_trigger_name(end_trigger_name,
+ notification)) {
+ /* Exit the loop immediately. */
+ printf("Received end event notification from trigger %s\n",
+ end_trigger_name);
+ lttng_notification_destroy(notification);
+ goto evaluate_success;
+ }
+
+ ret = is_trigger_name(expected_trigger_name, notification);
lttng_notification_destroy(notification);
- if (ret) {
- ret = 0;
+ if (!ret) {
+ ret = -1;
goto end;
}
+
+ printf("Received event notification from trigger %s\n",
+ expected_trigger_name);
+ notification_count++;
+ if (end_trigger_name == NULL &&
+ expected_notifications == notification_count) {
+ /*
+ * Here the loop exit is controlled by the number of
+ * notification and not by the reception of the end
+ * event trigger notification. This represent the
+ * default behavior.
+ *
+ */
+ goto evaluate_success;
+ }
}
+
+evaluate_success:
+ if (expected_notifications == notification_count) {
+ /* Success */
+ ret = 0;
+ } else {
+ fprintf(stderr, "Expected %d notification got %d\n",
+ expected_notifications, notification_count);
+ ret = 1;
+ }
+
end:
lttng_triggers_destroy(triggers);
lttng_notification_channel_destroy(notification_channel);
+ free(after_notif_register_file_path);
+ free(end_trigger_name);
+ free(expected_trigger_name);
return !!ret;
}