X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=blobdiff_plain;f=doc%2Fapi%2Flibbabeltrace2%2Fexamples%2Fdust.c;fp=doc%2Fapi%2Flibbabeltrace2%2Fexamples%2Fdust.c;h=fd1f1db9da841e555656cf28b72ef8d4931c1377;hp=0000000000000000000000000000000000000000;hb=43c59509042845f8d42c3e99ec74d45fa2dc0908;hpb=1cda4ff4025e4b3f7bd2a861baa51d2113c4cbf9 diff --git a/doc/api/libbabeltrace2/examples/dust.c b/doc/api/libbabeltrace2/examples/dust.c new file mode 100644 index 00000000..fd1f1db9 --- /dev/null +++ b/doc/api/libbabeltrace2/examples/dust.c @@ -0,0 +1,436 @@ +#include +#include +#include +#include +#include +#include + +/* Source component's private data */ +struct dust_in { + /* Input file path parameter value (owned by this) */ + const bt_value *path_value; + + /* Stream (owned by this) */ + bt_stream *stream; + + /* Event classes for each type of event (owned by this) */ + bt_event_class *send_msg_event_class; + bt_event_class *recv_msg_event_class; +}; + +/* + * Creates an event class within `stream_class` named `name`. + */ +static +bt_event_class *create_event_class(bt_stream_class *stream_class, + const char *name) +{ + /* Borrow trace class from stream class */ + bt_trace_class *trace_class = + bt_stream_class_borrow_trace_class(stream_class); + + /* Create a default event class */ + bt_event_class *event_class = bt_event_class_create(stream_class); + + /* Name the event class */ + bt_event_class_set_name(event_class, name); + + /* + * Create an empty structure field class to be used as the + * event class's payload field class. + */ + bt_field_class *payload_field_class = + bt_field_class_structure_create(trace_class); + + /* + * Create a string field class to be used as the payload field + * class's `msg` member. + */ + bt_field_class *msg_field_class = + bt_field_class_string_create(trace_class); + + /* + * Append the string field class to the structure field class as the + * `msg` member. + */ + bt_field_class_structure_append_member(payload_field_class, "msg", + msg_field_class); + + /* Set the event class's payload field class */ + bt_event_class_set_payload_field_class(event_class, payload_field_class); + + /* Put the references we don't need anymore */ + bt_field_class_put_ref(payload_field_class); + bt_field_class_put_ref(msg_field_class); + + return event_class; +} + +/* + * Creates the source component's metadata and stream objects. + */ +static +void create_metadata_and_stream(bt_self_component *self_component, + struct dust_in *dust_in) +{ + /* Create a default trace class */ + bt_trace_class *trace_class = bt_trace_class_create(self_component); + + /* Create a stream trace class within `trace_class` */ + bt_stream_class *stream_class = bt_stream_class_create(trace_class); + + /* Create a default clock class (1 GHz frequency) */ + bt_clock_class *clock_class = bt_clock_class_create(self_component); + + /* + * Set `clock_class` as the default clock class of `stream_class`. + * + * This means all the streams created from `stream_class` have a + * conceptual default clock which is an instance of `clock_class`. + * Any event message created for such a stream has a snapshot of the + * stream's default clock. + */ + bt_stream_class_set_default_clock_class(stream_class, clock_class); + + /* Create the two event classes we need */ + dust_in->send_msg_event_class = create_event_class(stream_class, + "send-msg"); + dust_in->recv_msg_event_class = create_event_class(stream_class, + "recv-msg"); + + /* Create a default trace from (instance of `trace_class`) */ + bt_trace *trace = bt_trace_create(trace_class); + + /* + * Create the source component's stream (instance of `stream_class` + * within `trace`). + */ + dust_in->stream = bt_stream_create(stream_class, trace); + + /* Put the references we don't need anymore */ + bt_trace_put_ref(trace); + bt_clock_class_put_ref(clock_class); + bt_stream_class_put_ref(stream_class); + bt_trace_class_put_ref(trace_class); +} + +/* + * Initializes the source component. + */ +static +bt_component_class_initialize_method_status dust_in_initialize( + bt_self_component_source *self_component_source, + bt_self_component_source_configuration *configuration, + const bt_value *params, void *initialize_method_data) +{ + /* Allocate a private data structure */ + struct dust_in *dust_in = malloc(sizeof(*dust_in)); + + /* + * Keep a reference of the `path` string value parameter so that the + * initialization method of a message iterator can read its string + * value to open the file. + */ + dust_in->path_value = + bt_value_map_borrow_entry_value_const(params, "path"); + bt_value_get_ref(dust_in->path_value); + + /* Upcast `self_component_source` to the `bt_self_component` type */ + bt_self_component *self_component = + bt_self_component_source_as_self_component(self_component_source); + + /* Create the source component's metadata and stream objects */ + create_metadata_and_stream(self_component, dust_in); + + /* Set the component's user data to our private data structure */ + bt_self_component_set_data(self_component, dust_in); + + /* + * Add an output port named `out` to the source component. + * + * This is needed so that this source component can be connected to + * a filter or a sink component. Once a downstream component is + * connected, it can create our message iterator. + */ + bt_self_component_source_add_output_port(self_component_source, + "out", NULL, NULL); + + return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK; +} + +/* + * Finalizes the source component. + */ +static +void dust_in_finalize(bt_self_component_source *self_component_source) +{ + /* Retrieve our private data from the component's user data */ + struct dust_in *dust_in = bt_self_component_get_data( + bt_self_component_source_as_self_component(self_component_source)); + + /* Put all references */ + bt_value_put_ref(dust_in->path_value); + bt_event_class_put_ref(dust_in->send_msg_event_class); + bt_event_class_put_ref(dust_in->recv_msg_event_class); + bt_stream_put_ref(dust_in->stream); + + /* Free the allocated structure */ + free(dust_in); +} + +/* State of a message iterator */ +enum dust_in_message_iterator_state { + /* Emit a stream beginning message */ + DUST_IN_MESSAGE_ITERATOR_STATE_STREAM_BEGINNING, + + /* Emit an event message */ + DUST_IN_MESSAGE_ITERATOR_STATE_EVENT, + + /* Message iterator is ended */ + DUST_IN_MESSAGE_ITERATOR_STATE_ENDED, +}; + +/* Message iterator's private data */ +struct dust_in_message_iterator { + /* (Weak) link to the component's private data */ + struct dust_in *dust_in; + + /* Current message iterator's state */ + enum dust_in_message_iterator_state state; + + /* Input file */ + FILE *file; + + /* Buffers to read data from the input file */ + char name_buffer[32]; + char msg_buffer[1024]; +}; + +/* + * Initializes the message iterator. + */ +static +bt_message_iterator_class_initialize_method_status +dust_in_message_iterator_initialize( + bt_self_message_iterator *self_message_iterator, + bt_self_message_iterator_configuration *configuration, + bt_self_component_port_output *self_port) +{ + /* Allocate a private data structure */ + struct dust_in_message_iterator *dust_in_iter = + malloc(sizeof(*dust_in_iter)); + + /* Retrieve the component's private data from its user data */ + struct dust_in *dust_in = bt_self_component_get_data( + bt_self_message_iterator_borrow_component(self_message_iterator)); + + /* Keep a link to the component's private data */ + dust_in_iter->dust_in = dust_in; + + /* Set the message iterator's initial state */ + dust_in_iter->state = DUST_IN_MESSAGE_ITERATOR_STATE_STREAM_BEGINNING; + + /* Get the raw value of the input file path string value */ + const char *path = bt_value_string_get(dust_in->path_value); + + /* Open the input file in text mode */ + dust_in_iter->file = fopen(path, "r"); + + /* Set the message iterator's user data to our private data structure */ + bt_self_message_iterator_set_data(self_message_iterator, dust_in_iter); + + return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK; +} + +/* + * Finalizes the message iterator. + */ +static +void dust_in_message_iterator_finalize( + bt_self_message_iterator *self_message_iterator) +{ + /* Retrieve our private data from the message iterator's user data */ + struct dust_in_message_iterator *dust_in_iter = + bt_self_message_iterator_get_data(self_message_iterator); + + /* Close the input file */ + fclose(dust_in_iter->file); + + /* Free the allocated structure */ + free(dust_in_iter); +} + +/* + * Creates a message from the message iterator's input file's current + * line. + * + * If there's a line to process, this function creates an event message. + * Otherwise it creates a stream end message and sets the message + * iterator's state accordingly. + */ +static +bt_message *create_message_from_line( + struct dust_in_message_iterator *dust_in_iter, + bt_self_message_iterator *self_message_iterator) +{ + uint64_t timestamp; + uint64_t extra_us; + bt_message *message; + + /* Try to read a line from the input file into individual tokens */ + int count = fscanf(dust_in_iter->file, "%" PRIu64 " %" PRIu64 " %s %[^\n]", + ×tamp, &extra_us, &dust_in_iter->name_buffer[0], + &dust_in_iter->msg_buffer[0]); + + /* Reached the end of the file? */ + if (count == EOF || feof(dust_in_iter->file)) { + /* + * Reached the end of the file: create a stream end message and + * set the message iterator's state to + * `DUST_IN_MESSAGE_ITERATOR_STATE_ENDED` so that the next call + * to dust_in_message_iterator_next() returns + * `BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END` (end of + * iteration). + */ + message = bt_message_stream_end_create(self_message_iterator, + dust_in_iter->dust_in->stream); + dust_in_iter->state = DUST_IN_MESSAGE_ITERATOR_STATE_ENDED; + goto end; + } + + /* Choose the correct event class, depending on the event name token */ + bt_event_class *event_class; + + if (strcmp(dust_in_iter->name_buffer, "send-msg") == 0) { + event_class = dust_in_iter->dust_in->send_msg_event_class; + } else { + event_class = dust_in_iter->dust_in->recv_msg_event_class; + } + + /* + * At this point `timestamp` contains seconds since the Unix epoch. + * Multiply it by 1,000,000,000 to get nanoseconds since the Unix + * epoch because the stream's clock's frequency is 1 GHz. + */ + timestamp *= UINT64_C(1000000000); + + /* Add the extra microseconds (as nanoseconds) to `timestamp` */ + timestamp += extra_us * UINT64_C(1000); + + /* Create the event message */ + message = bt_message_event_create_with_default_clock_snapshot( + self_message_iterator, event_class, dust_in_iter->dust_in->stream, + timestamp); + + /* + * At this point `message` is an event message which contains + * an empty event object. + * + * We need to fill its fields. + * + * The only field to fill is the payload field's `msg` field + * which is the event record's message. + * + * All the references below are borrowed references, therefore we + * don't need to put them. + */ + bt_event *event = bt_message_event_borrow_event(message); + bt_field *payload_field = bt_event_borrow_payload_field(event); + bt_field *msg_field = bt_field_structure_borrow_member_field_by_index( + payload_field, 0); + + bt_field_string_set_value(msg_field, dust_in_iter->msg_buffer); + +end: + return message; +} + +/* + * Returns the next message to the message iterator's user. + * + * This method can fill the `messages` array with up to `capacity` + * messages. + * + * To keep this example simple, we put a single message into `messages` + * and set `*count` to 1 (if the message iterator is not ended). + */ +static +bt_message_iterator_class_next_method_status dust_in_message_iterator_next( + bt_self_message_iterator *self_message_iterator, + bt_message_array_const messages, uint64_t capacity, + uint64_t *count) +{ + /* Retrieve our private data from the message iterator's user data */ + struct dust_in_message_iterator *dust_in_iter = + bt_self_message_iterator_get_data(self_message_iterator); + + /* + * This is the message to return (by moving it to the `messages` + * array). + * + * We initialize it to `NULL`. If it's not `NULL` after the + * processing below, then we move it to the message array. + */ + bt_message *message = NULL; + + /* Initialize the return status to a success */ + bt_message_iterator_class_next_method_status status = + BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK; + + switch (dust_in_iter->state) { + case DUST_IN_MESSAGE_ITERATOR_STATE_STREAM_BEGINNING: + /* Create a stream beginning message */ + message = bt_message_stream_beginning_create(self_message_iterator, + dust_in_iter->dust_in->stream); + + /* Next state: an event message */ + dust_in_iter->state = DUST_IN_MESSAGE_ITERATOR_STATE_EVENT; + break; + case DUST_IN_MESSAGE_ITERATOR_STATE_EVENT: + /* + * Create an event or a stream end message from the message + * iterator's input file's current line. + * + * This function also updates the message iterator's state if + * needed. + */ + message = create_message_from_line(dust_in_iter, + self_message_iterator); + break; + case DUST_IN_MESSAGE_ITERATOR_STATE_ENDED: + /* Message iterator is ended: return the corresponding status */ + status = + BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END; + goto end; + } + + if (message) { + /* + * We created a message above: move it to the beginning of the + * `messages` array, setting `*count` to 1 to indicate that the + * array contains a single message. + */ + messages[0] = message; + *count = 1; + } + +end: + return status; +} + +/* Mandatory */ +BT_PLUGIN_MODULE(); + +/* Define the `dust` plugin */ +BT_PLUGIN(dust); + +/* Define the `input` source component class */ +BT_PLUGIN_SOURCE_COMPONENT_CLASS(input, dust_in_message_iterator_next); + +/* Set some of the `input` source component class's optional methods */ +BT_PLUGIN_SOURCE_COMPONENT_CLASS_INITIALIZE_METHOD(input, dust_in_initialize); +BT_PLUGIN_SOURCE_COMPONENT_CLASS_FINALIZE_METHOD(input, dust_in_finalize); +BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD(input, + dust_in_message_iterator_initialize); +BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_FINALIZE_METHOD(input, + dust_in_message_iterator_finalize);