Document libbabeltrace2's C API
[babeltrace.git] / doc / api / libbabeltrace2 / examples / dust.c
CommitLineData
43c59509
PP
1#include <stdlib.h>
2#include <stdio.h>
3#include <stdint.h>
4#include <inttypes.h>
5#include <string.h>
6#include <babeltrace2/babeltrace.h>
7
8/* Source component's private data */
9struct dust_in {
10 /* Input file path parameter value (owned by this) */
11 const bt_value *path_value;
12
13 /* Stream (owned by this) */
14 bt_stream *stream;
15
16 /* Event classes for each type of event (owned by this) */
17 bt_event_class *send_msg_event_class;
18 bt_event_class *recv_msg_event_class;
19};
20
21/*
22 * Creates an event class within `stream_class` named `name`.
23 */
24static
25bt_event_class *create_event_class(bt_stream_class *stream_class,
26 const char *name)
27{
28 /* Borrow trace class from stream class */
29 bt_trace_class *trace_class =
30 bt_stream_class_borrow_trace_class(stream_class);
31
32 /* Create a default event class */
33 bt_event_class *event_class = bt_event_class_create(stream_class);
34
35 /* Name the event class */
36 bt_event_class_set_name(event_class, name);
37
38 /*
39 * Create an empty structure field class to be used as the
40 * event class's payload field class.
41 */
42 bt_field_class *payload_field_class =
43 bt_field_class_structure_create(trace_class);
44
45 /*
46 * Create a string field class to be used as the payload field
47 * class's `msg` member.
48 */
49 bt_field_class *msg_field_class =
50 bt_field_class_string_create(trace_class);
51
52 /*
53 * Append the string field class to the structure field class as the
54 * `msg` member.
55 */
56 bt_field_class_structure_append_member(payload_field_class, "msg",
57 msg_field_class);
58
59 /* Set the event class's payload field class */
60 bt_event_class_set_payload_field_class(event_class, payload_field_class);
61
62 /* Put the references we don't need anymore */
63 bt_field_class_put_ref(payload_field_class);
64 bt_field_class_put_ref(msg_field_class);
65
66 return event_class;
67}
68
69/*
70 * Creates the source component's metadata and stream objects.
71 */
72static
73void create_metadata_and_stream(bt_self_component *self_component,
74 struct dust_in *dust_in)
75{
76 /* Create a default trace class */
77 bt_trace_class *trace_class = bt_trace_class_create(self_component);
78
79 /* Create a stream trace class within `trace_class` */
80 bt_stream_class *stream_class = bt_stream_class_create(trace_class);
81
82 /* Create a default clock class (1 GHz frequency) */
83 bt_clock_class *clock_class = bt_clock_class_create(self_component);
84
85 /*
86 * Set `clock_class` as the default clock class of `stream_class`.
87 *
88 * This means all the streams created from `stream_class` have a
89 * conceptual default clock which is an instance of `clock_class`.
90 * Any event message created for such a stream has a snapshot of the
91 * stream's default clock.
92 */
93 bt_stream_class_set_default_clock_class(stream_class, clock_class);
94
95 /* Create the two event classes we need */
96 dust_in->send_msg_event_class = create_event_class(stream_class,
97 "send-msg");
98 dust_in->recv_msg_event_class = create_event_class(stream_class,
99 "recv-msg");
100
101 /* Create a default trace from (instance of `trace_class`) */
102 bt_trace *trace = bt_trace_create(trace_class);
103
104 /*
105 * Create the source component's stream (instance of `stream_class`
106 * within `trace`).
107 */
108 dust_in->stream = bt_stream_create(stream_class, trace);
109
110 /* Put the references we don't need anymore */
111 bt_trace_put_ref(trace);
112 bt_clock_class_put_ref(clock_class);
113 bt_stream_class_put_ref(stream_class);
114 bt_trace_class_put_ref(trace_class);
115}
116
117/*
118 * Initializes the source component.
119 */
120static
121bt_component_class_initialize_method_status dust_in_initialize(
122 bt_self_component_source *self_component_source,
123 bt_self_component_source_configuration *configuration,
124 const bt_value *params, void *initialize_method_data)
125{
126 /* Allocate a private data structure */
127 struct dust_in *dust_in = malloc(sizeof(*dust_in));
128
129 /*
130 * Keep a reference of the `path` string value parameter so that the
131 * initialization method of a message iterator can read its string
132 * value to open the file.
133 */
134 dust_in->path_value =
135 bt_value_map_borrow_entry_value_const(params, "path");
136 bt_value_get_ref(dust_in->path_value);
137
138 /* Upcast `self_component_source` to the `bt_self_component` type */
139 bt_self_component *self_component =
140 bt_self_component_source_as_self_component(self_component_source);
141
142 /* Create the source component's metadata and stream objects */
143 create_metadata_and_stream(self_component, dust_in);
144
145 /* Set the component's user data to our private data structure */
146 bt_self_component_set_data(self_component, dust_in);
147
148 /*
149 * Add an output port named `out` to the source component.
150 *
151 * This is needed so that this source component can be connected to
152 * a filter or a sink component. Once a downstream component is
153 * connected, it can create our message iterator.
154 */
155 bt_self_component_source_add_output_port(self_component_source,
156 "out", NULL, NULL);
157
158 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
159}
160
161/*
162 * Finalizes the source component.
163 */
164static
165void dust_in_finalize(bt_self_component_source *self_component_source)
166{
167 /* Retrieve our private data from the component's user data */
168 struct dust_in *dust_in = bt_self_component_get_data(
169 bt_self_component_source_as_self_component(self_component_source));
170
171 /* Put all references */
172 bt_value_put_ref(dust_in->path_value);
173 bt_event_class_put_ref(dust_in->send_msg_event_class);
174 bt_event_class_put_ref(dust_in->recv_msg_event_class);
175 bt_stream_put_ref(dust_in->stream);
176
177 /* Free the allocated structure */
178 free(dust_in);
179}
180
181/* State of a message iterator */
182enum dust_in_message_iterator_state {
183 /* Emit a stream beginning message */
184 DUST_IN_MESSAGE_ITERATOR_STATE_STREAM_BEGINNING,
185
186 /* Emit an event message */
187 DUST_IN_MESSAGE_ITERATOR_STATE_EVENT,
188
189 /* Message iterator is ended */
190 DUST_IN_MESSAGE_ITERATOR_STATE_ENDED,
191};
192
193/* Message iterator's private data */
194struct dust_in_message_iterator {
195 /* (Weak) link to the component's private data */
196 struct dust_in *dust_in;
197
198 /* Current message iterator's state */
199 enum dust_in_message_iterator_state state;
200
201 /* Input file */
202 FILE *file;
203
204 /* Buffers to read data from the input file */
205 char name_buffer[32];
206 char msg_buffer[1024];
207};
208
209/*
210 * Initializes the message iterator.
211 */
212static
213bt_message_iterator_class_initialize_method_status
214dust_in_message_iterator_initialize(
215 bt_self_message_iterator *self_message_iterator,
216 bt_self_message_iterator_configuration *configuration,
217 bt_self_component_port_output *self_port)
218{
219 /* Allocate a private data structure */
220 struct dust_in_message_iterator *dust_in_iter =
221 malloc(sizeof(*dust_in_iter));
222
223 /* Retrieve the component's private data from its user data */
224 struct dust_in *dust_in = bt_self_component_get_data(
225 bt_self_message_iterator_borrow_component(self_message_iterator));
226
227 /* Keep a link to the component's private data */
228 dust_in_iter->dust_in = dust_in;
229
230 /* Set the message iterator's initial state */
231 dust_in_iter->state = DUST_IN_MESSAGE_ITERATOR_STATE_STREAM_BEGINNING;
232
233 /* Get the raw value of the input file path string value */
234 const char *path = bt_value_string_get(dust_in->path_value);
235
236 /* Open the input file in text mode */
237 dust_in_iter->file = fopen(path, "r");
238
239 /* Set the message iterator's user data to our private data structure */
240 bt_self_message_iterator_set_data(self_message_iterator, dust_in_iter);
241
242 return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK;
243}
244
245/*
246 * Finalizes the message iterator.
247 */
248static
249void dust_in_message_iterator_finalize(
250 bt_self_message_iterator *self_message_iterator)
251{
252 /* Retrieve our private data from the message iterator's user data */
253 struct dust_in_message_iterator *dust_in_iter =
254 bt_self_message_iterator_get_data(self_message_iterator);
255
256 /* Close the input file */
257 fclose(dust_in_iter->file);
258
259 /* Free the allocated structure */
260 free(dust_in_iter);
261}
262
263/*
264 * Creates a message from the message iterator's input file's current
265 * line.
266 *
267 * If there's a line to process, this function creates an event message.
268 * Otherwise it creates a stream end message and sets the message
269 * iterator's state accordingly.
270 */
271static
272bt_message *create_message_from_line(
273 struct dust_in_message_iterator *dust_in_iter,
274 bt_self_message_iterator *self_message_iterator)
275{
276 uint64_t timestamp;
277 uint64_t extra_us;
278 bt_message *message;
279
280 /* Try to read a line from the input file into individual tokens */
281 int count = fscanf(dust_in_iter->file, "%" PRIu64 " %" PRIu64 " %s %[^\n]",
282 &timestamp, &extra_us, &dust_in_iter->name_buffer[0],
283 &dust_in_iter->msg_buffer[0]);
284
285 /* Reached the end of the file? */
286 if (count == EOF || feof(dust_in_iter->file)) {
287 /*
288 * Reached the end of the file: create a stream end message and
289 * set the message iterator's state to
290 * `DUST_IN_MESSAGE_ITERATOR_STATE_ENDED` so that the next call
291 * to dust_in_message_iterator_next() returns
292 * `BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END` (end of
293 * iteration).
294 */
295 message = bt_message_stream_end_create(self_message_iterator,
296 dust_in_iter->dust_in->stream);
297 dust_in_iter->state = DUST_IN_MESSAGE_ITERATOR_STATE_ENDED;
298 goto end;
299 }
300
301 /* Choose the correct event class, depending on the event name token */
302 bt_event_class *event_class;
303
304 if (strcmp(dust_in_iter->name_buffer, "send-msg") == 0) {
305 event_class = dust_in_iter->dust_in->send_msg_event_class;
306 } else {
307 event_class = dust_in_iter->dust_in->recv_msg_event_class;
308 }
309
310 /*
311 * At this point `timestamp` contains seconds since the Unix epoch.
312 * Multiply it by 1,000,000,000 to get nanoseconds since the Unix
313 * epoch because the stream's clock's frequency is 1 GHz.
314 */
315 timestamp *= UINT64_C(1000000000);
316
317 /* Add the extra microseconds (as nanoseconds) to `timestamp` */
318 timestamp += extra_us * UINT64_C(1000);
319
320 /* Create the event message */
321 message = bt_message_event_create_with_default_clock_snapshot(
322 self_message_iterator, event_class, dust_in_iter->dust_in->stream,
323 timestamp);
324
325 /*
326 * At this point `message` is an event message which contains
327 * an empty event object.
328 *
329 * We need to fill its fields.
330 *
331 * The only field to fill is the payload field's `msg` field
332 * which is the event record's message.
333 *
334 * All the references below are borrowed references, therefore we
335 * don't need to put them.
336 */
337 bt_event *event = bt_message_event_borrow_event(message);
338 bt_field *payload_field = bt_event_borrow_payload_field(event);
339 bt_field *msg_field = bt_field_structure_borrow_member_field_by_index(
340 payload_field, 0);
341
342 bt_field_string_set_value(msg_field, dust_in_iter->msg_buffer);
343
344end:
345 return message;
346}
347
348/*
349 * Returns the next message to the message iterator's user.
350 *
351 * This method can fill the `messages` array with up to `capacity`
352 * messages.
353 *
354 * To keep this example simple, we put a single message into `messages`
355 * and set `*count` to 1 (if the message iterator is not ended).
356 */
357static
358bt_message_iterator_class_next_method_status dust_in_message_iterator_next(
359 bt_self_message_iterator *self_message_iterator,
360 bt_message_array_const messages, uint64_t capacity,
361 uint64_t *count)
362{
363 /* Retrieve our private data from the message iterator's user data */
364 struct dust_in_message_iterator *dust_in_iter =
365 bt_self_message_iterator_get_data(self_message_iterator);
366
367 /*
368 * This is the message to return (by moving it to the `messages`
369 * array).
370 *
371 * We initialize it to `NULL`. If it's not `NULL` after the
372 * processing below, then we move it to the message array.
373 */
374 bt_message *message = NULL;
375
376 /* Initialize the return status to a success */
377 bt_message_iterator_class_next_method_status status =
378 BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
379
380 switch (dust_in_iter->state) {
381 case DUST_IN_MESSAGE_ITERATOR_STATE_STREAM_BEGINNING:
382 /* Create a stream beginning message */
383 message = bt_message_stream_beginning_create(self_message_iterator,
384 dust_in_iter->dust_in->stream);
385
386 /* Next state: an event message */
387 dust_in_iter->state = DUST_IN_MESSAGE_ITERATOR_STATE_EVENT;
388 break;
389 case DUST_IN_MESSAGE_ITERATOR_STATE_EVENT:
390 /*
391 * Create an event or a stream end message from the message
392 * iterator's input file's current line.
393 *
394 * This function also updates the message iterator's state if
395 * needed.
396 */
397 message = create_message_from_line(dust_in_iter,
398 self_message_iterator);
399 break;
400 case DUST_IN_MESSAGE_ITERATOR_STATE_ENDED:
401 /* Message iterator is ended: return the corresponding status */
402 status =
403 BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END;
404 goto end;
405 }
406
407 if (message) {
408 /*
409 * We created a message above: move it to the beginning of the
410 * `messages` array, setting `*count` to 1 to indicate that the
411 * array contains a single message.
412 */
413 messages[0] = message;
414 *count = 1;
415 }
416
417end:
418 return status;
419}
420
421/* Mandatory */
422BT_PLUGIN_MODULE();
423
424/* Define the `dust` plugin */
425BT_PLUGIN(dust);
426
427/* Define the `input` source component class */
428BT_PLUGIN_SOURCE_COMPONENT_CLASS(input, dust_in_message_iterator_next);
429
430/* Set some of the `input` source component class's optional methods */
431BT_PLUGIN_SOURCE_COMPONENT_CLASS_INITIALIZE_METHOD(input, dust_in_initialize);
432BT_PLUGIN_SOURCE_COMPONENT_CLASS_FINALIZE_METHOD(input, dust_in_finalize);
433BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD(input,
434 dust_in_message_iterator_initialize);
435BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_FINALIZE_METHOD(input,
436 dust_in_message_iterator_finalize);
This page took 0.03881 seconds and 4 git commands to generate.