static struct lttng_notification *create_notification_from_current_message( struct lttng_notification_channel *channel) { ssize_t ret; struct lttng_notification *notification = NULL; struct lttng_buffer_view view; if (channel->reception_buffer.size <= sizeof(struct lttng_notification_channel_message)) { goto end; } view = lttng_buffer_view_from_dynamic_buffer(&channel->reception_buffer, sizeof(struct lttng_notification_channel_message), -1); ret = lttng_notification_create_from_buffer(&view, ¬ification); if (ret != channel->reception_buffer.size - sizeof(struct lttng_notification_channel_message)) { lttng_notification_destroy(notification); notification = NULL; goto end; } end: return notification; }
static int enqueue_dropped_notification( struct lttng_notification_channel *channel) { int ret = 0; struct pending_notification *pending_notification; struct cds_list_head *last_element = channel->pending_notifications.list.prev; pending_notification = caa_container_of(last_element, struct pending_notification, node); if (!pending_notification->notification) { /* * The last enqueued notification indicates dropped * notifications; there is nothing to do as we group * dropped notifications together. */ goto end; } if (channel->pending_notifications.count >= DEFAULT_CLIENT_MAX_QUEUED_NOTIFICATIONS_COUNT && pending_notification->notification) { /* * Discard the last enqueued notification to indicate * that notifications were dropped at this point. */ lttng_notification_destroy( pending_notification->notification); pending_notification->notification = NULL; goto end; } pending_notification = zmalloc(sizeof(*pending_notification)); if (!pending_notification) { ret = -1; goto end; } CDS_INIT_LIST_HEAD(&pending_notification->node); cds_list_add(&pending_notification->node, &channel->pending_notifications.list); channel->pending_notifications.count++; end: return ret; }
int main(int argc, char **argv) { int ret = 0; enum lttng_condition_status condition_status; enum lttng_notification_channel_status nc_status; struct lttng_notification_channel *notification_channel = NULL; struct lttng_condition *condition = NULL; struct lttng_action *action = NULL; struct lttng_trigger *trigger = NULL; /* * Disable buffering on stdout. * Safety measure to prevent hang on the validation side since * stdout is used for outside synchronization. */ setbuf(stdout, NULL); if (argc < 8) { printf("error: Missing arguments for tests\n"); ret = 1; goto end; } ret = parse_arguments(argv); if (ret) { printf("error: Could not parse arguments\n"); goto end; } /* Setup */ notification_channel = lttng_notification_channel_create( lttng_session_daemon_notification_endpoint); if (!notification_channel) { printf("error: Could not create notification channel\n"); ret = 1; goto end; } switch (buffer_usage_type) { case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW: condition = lttng_condition_buffer_usage_low_create(); break; case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH: condition = lttng_condition_buffer_usage_high_create(); break; default: printf("error: Invalid buffer_usage_type\n"); ret = 1; goto end; } if (!condition) { printf("error: Could not create condition object\n"); ret = 1; goto end; } if (is_threshold_ratio) { condition_status = lttng_condition_buffer_usage_set_threshold_ratio( condition, threshold_ratio); } else { condition_status = lttng_condition_buffer_usage_set_threshold( condition, threshold_bytes); } if (condition_status != LTTNG_CONDITION_STATUS_OK) { printf("error: Could not set threshold\n"); ret = 1; goto end; } condition_status = lttng_condition_buffer_usage_set_session_name( condition, session_name); if (condition_status != LTTNG_CONDITION_STATUS_OK) { printf("error: Could not set session name\n"); ret = 1; goto end; } condition_status = lttng_condition_buffer_usage_set_channel_name( condition, channel_name); if (condition_status != LTTNG_CONDITION_STATUS_OK) { printf("error: Could not set channel name\n"); ret = 1; goto end; } condition_status = lttng_condition_buffer_usage_set_domain_type( condition, domain_type); if (condition_status != LTTNG_CONDITION_STATUS_OK) { printf("error: Could not set domain type\n"); ret = 1; goto end; } action = lttng_action_notify_create(); if (!action) { printf("error: Could not create action notify\n"); ret = 1; goto end; } trigger = lttng_trigger_create(condition, action); if (!trigger) { printf("error: Could not create trigger\n"); ret = 1; goto end; } ret = lttng_register_trigger(trigger); /* * An equivalent trigger might already be registered if an other app * registered an equivalent trigger. */ if (ret < 0 && ret != -LTTNG_ERR_TRIGGER_EXISTS) { printf("error: %s\n", lttng_strerror(ret)); ret = 1; goto end; } nc_status = lttng_notification_channel_subscribe(notification_channel, condition); if (nc_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) { printf("error: Could not subscribe\n"); ret = 1; goto end; } /* Tell outside process that the client is ready */ printf("sync: ready\n"); for (;;) { struct lttng_notification *notification; enum lttng_notification_channel_status status; const struct lttng_evaluation *notification_evaluation; const struct lttng_condition *notification_condition; if (nr_notifications == nr_expected_notifications) { ret = 0; goto end; } /* Receive the next notification. */ status = lttng_notification_channel_get_next_notification( notification_channel, ¬ification); switch (status) { case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK: break; case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED: ret = 1; printf("error: No drop should be observed during this test app\n"); goto end; case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED: /* * The notification channel has been closed by the * session daemon. This is typically caused by a session * daemon shutting down (cleanly or because of a crash). */ printf("error: Notification channel was closed\n"); ret = 1; goto end; default: /* Unhandled conditions / errors. */ printf("error: Unknown notification channel status\n"); ret = 1; goto end; } notification_condition = lttng_notification_get_condition(notification); notification_evaluation = lttng_notification_get_evaluation(notification); ret = handle_condition(notification_condition, notification_evaluation); nr_notifications++; lttng_notification_destroy(notification); if (ret != 0) { goto end; } } end: if (trigger) { lttng_unregister_trigger(trigger); } if (lttng_notification_channel_unsubscribe(notification_channel, condition)) { printf("error: channel unsubscribe error\n"); } lttng_trigger_destroy(trigger); lttng_condition_destroy(condition); lttng_action_destroy(action); lttng_notification_channel_destroy(notification_channel); printf("exit: %d\n", ret); return ret; }
static int test_notification( struct lttng_notification_channel *notification_channel, const struct session *session, const char *expected_notification_type_name, enum lttng_condition_type expected_condition_type) { int ret = 0; bool notification_pending; enum lttng_notification_channel_status notification_channel_status; enum lttng_condition_status condition_status; enum lttng_evaluation_status evaluation_status; enum lttng_trace_archive_location_status location_status; enum lttng_condition_type condition_type; struct lttng_notification *notification = NULL; const struct lttng_condition *condition; const struct lttng_evaluation *evaluation; const char *session_name = NULL; const struct lttng_trace_archive_location *location = NULL; uint64_t rotation_id = UINT64_MAX; const char *chunk_path = NULL; notification_channel_status = lttng_notification_channel_has_pending_notification( notification_channel, ¬ification_pending); ok(notification_channel_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK, "Check for %s notification pending on notification channel", expected_notification_type_name); if (notification_channel_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) { ret = -1; goto end; } ok(notification_pending, "Session %s notification is pending on notification channel", expected_notification_type_name); if (!notification_pending) { ret = -1; goto end; } notification_channel_status = lttng_notification_channel_get_next_notification( notification_channel, ¬ification); ok(notification_channel_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification, "Get %s notification from notification channel", expected_notification_type_name); if (notification_channel_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK || !notification) { ret = -1; goto end; } condition = lttng_notification_get_condition(notification); if (!condition) { diag("Failed to get notification condition"); ret = -1; goto end; } condition_type = lttng_condition_get_type(condition); ok(condition_type == expected_condition_type, "Notification condition obtained from notification channel is of type \"%s\"", expected_notification_type_name); if (condition_type != expected_condition_type) { ret = -1; goto end; } condition_status = lttng_condition_session_rotation_get_session_name( condition, &session_name); ok(condition_status == LTTNG_CONDITION_STATUS_OK && session_name && !strcmp(session_name, session->name), "Condition obtained from notification has the correct session name assigned"); if (condition_status != LTTNG_CONDITION_STATUS_OK || !session_name) { ret = -1; goto end; } evaluation = lttng_notification_get_evaluation(notification); if (!evaluation) { diag("Failed to get notification evaluation"); ret = -1; goto end; } condition_type = lttng_evaluation_get_type(evaluation); ok(condition_type == expected_condition_type, "Condition evaluation obtained from notification channel is of type \"%s\"", expected_notification_type_name); if (condition_type != expected_condition_type) { ret = -1; goto end; } evaluation_status = lttng_evaluation_session_rotation_get_id(evaluation, &rotation_id); ok(evaluation_status == LTTNG_EVALUATION_STATUS_OK, "Get %s id from notification evaluation", expected_notification_type_name); if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) { ret = -1; goto end; } if (expected_condition_type != LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED) { /* * Remaining tests only apply to "session rotation completed" * notifications. */ goto end; } evaluation_status = lttng_evaluation_session_rotation_completed_get_location( evaluation, &location); ok(evaluation_status == LTTNG_EVALUATION_STATUS_OK && location, "Get session %s chunk location from evaluation", expected_notification_type_name); if (evaluation_status != LTTNG_EVALUATION_STATUS_OK || !location) { ret = -1; goto end; } ok(lttng_trace_archive_location_get_type(location) == LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL, "Location returned from the session rotation completed notification is of type 'local'"); location_status = lttng_trace_archive_location_local_get_absolute_path( location, &chunk_path); ok(location_status == LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK && chunk_path, "Retrieved path from location returned by the session rotation completed notification"); diag("Chunk available at %s", chunk_path ? chunk_path : "NULL"); ok(chunk_path && !strncmp(session->output_path, chunk_path, strlen(session->output_path)), "Returned path from location starts with the output path"); end: lttng_notification_destroy(notification); return ret; }