Tests: Add unit tests for stream event context accessors
[babeltrace.git] / formats / ctf / ir / stream.c
CommitLineData
273b65be
JG
1/*
2 * stream.c
3 *
d2dc44b6 4 * Babeltrace CTF IR - Stream
273b65be 5 *
de9dd397 6 * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
273b65be
JG
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
3f043b05 29#include <babeltrace/ctf-ir/clock.h>
adc315b8 30#include <babeltrace/ctf-ir/clock-internal.h>
273b65be 31#include <babeltrace/ctf-writer/event.h>
adc315b8
JG
32#include <babeltrace/ctf-ir/event-internal.h>
33#include <babeltrace/ctf-ir/event-types-internal.h>
34#include <babeltrace/ctf-ir/event-fields-internal.h>
3f043b05
JG
35#include <babeltrace/ctf-ir/stream.h>
36#include <babeltrace/ctf-ir/stream-internal.h>
adc315b8 37#include <babeltrace/ctf-ir/stream-class-internal.h>
273b65be
JG
38#include <babeltrace/ctf-writer/functor-internal.h>
39#include <babeltrace/compiler.h>
40#include <babeltrace/align.h>
41
42static
43void bt_ctf_stream_destroy(struct bt_ctf_ref *ref);
44static
273b65be
JG
45int set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t);
46
273b65be
JG
47BT_HIDDEN
48struct bt_ctf_stream *bt_ctf_stream_create(
49 struct bt_ctf_stream_class *stream_class)
50{
12c8a1a3 51 int ret;
273b65be
JG
52 struct bt_ctf_stream *stream = NULL;
53
54 if (!stream_class) {
55 goto end;
56 }
57
58 stream = g_new0(struct bt_ctf_stream, 1);
59 if (!stream) {
60 goto end;
61 }
62
63 bt_ctf_ref_init(&stream->ref_count);
12c8a1a3
JG
64 stream->packet_context = bt_ctf_field_create(
65 stream_class->packet_context_type);
66 if (!stream->packet_context) {
67 goto error_destroy;
68 }
69
af181248
JG
70 /*
71 * A stream class may not have a stream event context defined
72 * in which case this stream will never have a stream_event_context
73 * member since, after a stream's creation, the parent stream class
74 * is "frozen" (immutable).
75 */
76 if (stream_class->event_context_type) {
77 stream->event_context = bt_ctf_field_create(
78 stream_class->event_context_type);
79 if (!stream->packet_context) {
80 goto error_destroy;
81 }
82 }
83
e19cc57d 84 /* Initialize events_discarded */
12c8a1a3
JG
85 ret = set_structure_field_integer(stream->packet_context,
86 "events_discarded", 0);
87 if (ret) {
88 goto error_destroy;
89 }
90
273b65be
JG
91 stream->pos.fd = -1;
92 stream->id = stream_class->next_stream_id++;
93 stream->stream_class = stream_class;
94 bt_ctf_stream_class_get(stream_class);
95 bt_ctf_stream_class_freeze(stream_class);
96 stream->events = g_ptr_array_new_with_free_func(
8bfa3f9c
JG
97 (GDestroyNotify) bt_ctf_event_put);
98 if (!stream->events) {
99 goto error_destroy;
100 }
101 if (stream_class->event_context_type) {
102 stream->event_contexts = g_ptr_array_new_with_free_func(
103 (GDestroyNotify) bt_ctf_field_put);
104 if (!stream->event_contexts) {
105 goto error_destroy;
106 }
107 }
273b65be
JG
108end:
109 return stream;
12c8a1a3
JG
110error_destroy:
111 bt_ctf_stream_destroy(&stream->ref_count);
112 return NULL;
273b65be
JG
113}
114
115BT_HIDDEN
116int bt_ctf_stream_set_flush_callback(struct bt_ctf_stream *stream,
117 flush_func callback, void *data)
118{
119 int ret = stream ? 0 : -1;
120
121 if (!stream) {
122 goto end;
123 }
124
125 stream->flush.func = callback;
126 stream->flush.data = data;
127end:
128 return ret;
129}
130
131BT_HIDDEN
132int bt_ctf_stream_set_fd(struct bt_ctf_stream *stream, int fd)
133{
134 int ret = 0;
135
136 if (stream->pos.fd != -1) {
137 ret = -1;
138 goto end;
139 }
140
141 ctf_init_pos(&stream->pos, NULL, fd, O_RDWR);
142 stream->pos.fd = fd;
143end:
144 return ret;
145}
146
a78a2e25
JG
147int bt_ctf_stream_get_discarded_events_count(
148 struct bt_ctf_stream *stream, uint64_t *count)
149{
150 int64_t ret = 0;
12c8a1a3
JG
151 int field_signed;
152 struct bt_ctf_field *events_discarded_field = NULL;
153 struct bt_ctf_field_type *events_discarded_field_type = NULL;
a78a2e25 154
12c8a1a3 155 if (!stream || !count || !stream->packet_context) {
a78a2e25
JG
156 ret = -1;
157 goto end;
158 }
159
12c8a1a3
JG
160 events_discarded_field = bt_ctf_field_structure_get_field(
161 stream->packet_context, "events_discarded");
162 if (!events_discarded_field) {
163 ret = -1;
164 goto end;
165 }
166
167 events_discarded_field_type = bt_ctf_field_get_type(
168 events_discarded_field);
169 if (!events_discarded_field_type) {
170 ret = -1;
171 goto end;
172 }
173
174 field_signed = bt_ctf_field_type_integer_get_signed(
175 events_discarded_field_type);
176 if (field_signed < 0) {
177 ret = field_signed;
178 goto end;
179 }
180
181 if (field_signed) {
182 int64_t signed_count;
183
184 ret = bt_ctf_field_signed_integer_get_value(
185 events_discarded_field, &signed_count);
186 if (ret) {
187 goto end;
188 }
189 if (signed_count < 0) {
190 /* Invalid value */
191 ret = -1;
192 goto end;
193 }
194 *count = (uint64_t) signed_count;
195 } else {
196 ret = bt_ctf_field_unsigned_integer_get_value(
197 events_discarded_field, count);
198 if (ret) {
199 goto end;
200 }
201 }
a78a2e25 202end:
12c8a1a3
JG
203 if (events_discarded_field) {
204 bt_ctf_field_put(events_discarded_field);
205 }
206 if (events_discarded_field_type) {
207 bt_ctf_field_type_put(events_discarded_field_type);
208 }
a78a2e25
JG
209 return ret;
210}
211
273b65be
JG
212void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
213 uint64_t event_count)
214{
12c8a1a3
JG
215 int ret;
216 int field_signed;
217 uint64_t previous_count;
218 uint64_t new_count;
219 struct bt_ctf_field *events_discarded_field = NULL;
220 struct bt_ctf_field_type *events_discarded_field_type = NULL;
221
222 if (!stream || !stream->packet_context) {
223 goto end;
224 }
225
226 ret = bt_ctf_stream_get_discarded_events_count(stream,
227 &previous_count);
228 if (ret) {
229 goto end;
230 }
231
232 events_discarded_field = bt_ctf_field_structure_get_field(
233 stream->packet_context, "events_discarded");
234 if (!events_discarded_field) {
235 goto end;
236 }
237
238 events_discarded_field_type = bt_ctf_field_get_type(
239 events_discarded_field);
240 if (!events_discarded_field_type) {
241 goto end;
242 }
243
244 field_signed = bt_ctf_field_type_integer_get_signed(
245 events_discarded_field_type);
246 if (field_signed < 0) {
247 goto end;
273b65be
JG
248 }
249
12c8a1a3
JG
250 new_count = previous_count + event_count;
251 if (field_signed) {
252 ret = bt_ctf_field_signed_integer_set_value(
253 events_discarded_field, (int64_t) new_count);
254 if (ret) {
255 goto end;
256 }
257 } else {
258 ret = bt_ctf_field_unsigned_integer_set_value(
259 events_discarded_field, new_count);
260 if (ret) {
261 goto end;
262 }
263 }
264
265end:
266 if (events_discarded_field) {
267 bt_ctf_field_put(events_discarded_field);
268 }
269 if (events_discarded_field_type) {
270 bt_ctf_field_type_put(events_discarded_field_type);
271 }
273b65be
JG
272}
273
274int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
275 struct bt_ctf_event *event)
276{
277 int ret = 0;
278 uint64_t timestamp;
af181248 279 struct bt_ctf_field *event_context_copy = NULL;
273b65be
JG
280
281 if (!stream || !event) {
282 ret = -1;
283 goto end;
284 }
285
286 ret = bt_ctf_event_validate(event);
287 if (ret) {
288 goto end;
289 }
290
8bfa3f9c
JG
291 /* Sample the current stream event context by copying it */
292 if (stream->event_context) {
293 /* Make sure the event context's payload is set */
294 ret = bt_ctf_field_validate(stream->event_context);
295 if (ret) {
296 goto end;
297 }
298
299 event_context_copy = bt_ctf_field_copy(stream->event_context);
300 if (!event_context_copy) {
301 ret = -1;
302 goto end;
303 }
304 }
305
273b65be
JG
306 timestamp = bt_ctf_clock_get_time(stream->stream_class->clock);
307 ret = bt_ctf_event_set_timestamp(event, timestamp);
308 if (ret) {
309 goto end;
310 }
311
312 bt_ctf_event_get(event);
8bfa3f9c 313 /* Save the new event along with its associated stream event context */
273b65be 314 g_ptr_array_add(stream->events, event);
8bfa3f9c
JG
315 if (event_context_copy) {
316 g_ptr_array_add(stream->event_contexts, event_context_copy);
317 }
273b65be
JG
318end:
319 return ret;
320}
321
12c8a1a3
JG
322struct bt_ctf_field *bt_ctf_stream_get_packet_context(
323 struct bt_ctf_stream *stream)
324{
325 struct bt_ctf_field *packet_context = NULL;
326
327 if (!stream) {
328 goto end;
329 }
330
331 packet_context = stream->packet_context;
332end:
333 if (packet_context) {
334 bt_ctf_field_get(packet_context);
335 }
336 return packet_context;
337}
338
339int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream,
340 struct bt_ctf_field *field)
341{
342 int ret = 0;
343 struct bt_ctf_field_type *field_type;
344
345 if (!stream || !field) {
346 ret = -1;
347 goto end;
348 }
349
350 field_type = bt_ctf_field_get_type(field);
351 if (field_type != stream->stream_class->packet_context_type) {
352 ret = -1;
353 goto end;
354 }
355
356 bt_ctf_field_type_put(field_type);
357 bt_ctf_field_get(field);
358 bt_ctf_field_put(stream->packet_context);
359 stream->packet_context = field;
360end:
361 return ret;
362}
363
8bfa3f9c
JG
364struct bt_ctf_field *bt_ctf_stream_get_event_context(
365 struct bt_ctf_stream *stream)
366{
367 struct bt_ctf_field *event_context = NULL;
368
369 if (!stream) {
370 goto end;
371 }
372
373 event_context = stream->event_context;
374 if (event_context) {
375 bt_ctf_field_get(event_context);
376 }
377end:
378 return event_context;
379}
380
381int bt_ctf_stream_set_event_context(struct bt_ctf_stream *stream,
382 struct bt_ctf_field *field)
383{
384 int ret = 0;
385 struct bt_ctf_field_type *field_type = NULL;
386
387 if (!stream || !field) {
388 ret = -1;
389 goto end;
390 }
391
392 field_type = bt_ctf_field_get_type(field);
393 if (field_type != stream->stream_class->event_context_type) {
394 ret = -1;
395 goto end;
396 }
397
398 bt_ctf_field_get(field);
399 bt_ctf_field_put(stream->event_context);
400 stream->event_context = field;
401end:
402 if (field_type) {
403 bt_ctf_field_type_put(field_type);
404 }
405 return ret;
406}
407
273b65be
JG
408int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
409{
410 int ret = 0;
411 size_t i;
12c8a1a3 412 uint64_t timestamp_begin, timestamp_end, events_discarded;
9f56e450 413 struct bt_ctf_stream_class *stream_class;
273b65be
JG
414 struct bt_ctf_field *integer = NULL;
415 struct ctf_stream_pos packet_context_pos;
416
bc37ae52
JG
417 if (!stream || stream->pos.fd < 0) {
418 /*
419 * Stream does not have an associated fd. It is,
420 * therefore, not a stream being used to write events.
421 */
273b65be
JG
422 ret = -1;
423 goto end;
424 }
425
426 if (!stream->events->len) {
427 goto end;
428 }
429
430 if (stream->flush.func) {
431 stream->flush.func(stream, stream->flush.data);
432 }
433
9f56e450 434 stream_class = stream->stream_class;
273b65be
JG
435 timestamp_begin = ((struct bt_ctf_event *) g_ptr_array_index(
436 stream->events, 0))->timestamp;
437 timestamp_end = ((struct bt_ctf_event *) g_ptr_array_index(
438 stream->events, stream->events->len - 1))->timestamp;
12c8a1a3
JG
439
440 /* Set the default context attributes if present and unset. */
441 ret = set_structure_field_integer(stream->packet_context,
273b65be
JG
442 "timestamp_begin", timestamp_begin);
443 if (ret) {
444 goto end;
445 }
446
12c8a1a3 447 ret = set_structure_field_integer(stream->packet_context,
273b65be
JG
448 "timestamp_end", timestamp_end);
449 if (ret) {
450 goto end;
451 }
452
12c8a1a3 453 ret = set_structure_field_integer(stream->packet_context,
273b65be
JG
454 "content_size", UINT64_MAX);
455 if (ret) {
456 goto end;
457 }
458
12c8a1a3 459 ret = set_structure_field_integer(stream->packet_context,
273b65be
JG
460 "packet_size", UINT64_MAX);
461 if (ret) {
462 goto end;
463 }
464
465 /* Write packet context */
466 memcpy(&packet_context_pos, &stream->pos,
467 sizeof(struct ctf_stream_pos));
12c8a1a3 468 ret = bt_ctf_field_serialize(stream->packet_context,
273b65be
JG
469 &stream->pos);
470 if (ret) {
471 goto end;
472 }
473
12c8a1a3
JG
474 ret = bt_ctf_stream_get_discarded_events_count(stream,
475 &events_discarded);
476 if (ret) {
477 goto end;
478 }
479
480 /* Unset the packet context's fields. */
481 ret = bt_ctf_field_reset(stream->packet_context);
482 if (ret) {
483 goto end;
484 }
485
486 /* Set the previous number of discarded events. */
487 ret = set_structure_field_integer(stream->packet_context,
488 "events_discarded", events_discarded);
489 if (ret) {
490 goto end;
491 }
492
273b65be
JG
493 for (i = 0; i < stream->events->len; i++) {
494 struct bt_ctf_event *event = g_ptr_array_index(
495 stream->events, i);
496 uint32_t event_id = bt_ctf_event_class_get_id(
497 event->event_class);
498 uint64_t timestamp = bt_ctf_event_get_timestamp(event);
499
12c8a1a3
JG
500 ret = bt_ctf_field_reset(stream_class->event_header);
501 if (ret) {
502 goto end;
503 }
504
273b65be
JG
505 ret = set_structure_field_integer(stream_class->event_header,
506 "id", event_id);
507 if (ret) {
508 goto end;
509 }
510 ret = set_structure_field_integer(stream_class->event_header,
511 "timestamp", timestamp);
512 if (ret) {
513 goto end;
514 }
515
516 /* Write event header */
517 ret = bt_ctf_field_serialize(stream_class->event_header,
518 &stream->pos);
519 if (ret) {
520 goto end;
521 }
522
8bfa3f9c
JG
523 /* Write stream event context */
524 if (stream->event_contexts) {
525 ret = bt_ctf_field_serialize(
526 g_ptr_array_index(stream->event_contexts, i),
527 &stream->pos);
528 if (ret) {
529 goto end;
530 }
531 }
532
273b65be
JG
533 /* Write event content */
534 ret = bt_ctf_event_serialize(event, &stream->pos);
535 if (ret) {
536 goto end;
537 }
538 }
539
540 /*
541 * Update the packet total size and content size and overwrite the
542 * packet context.
3a092c05
JG
543 * Copy base_mma as the packet may have been remapped (e.g. when a
544 * packet is resized).
273b65be 545 */
3a092c05 546 packet_context_pos.base_mma = stream->pos.base_mma;
12c8a1a3 547 ret = set_structure_field_integer(stream->packet_context,
273b65be
JG
548 "content_size", stream->pos.offset);
549 if (ret) {
550 goto end;
551 }
552
12c8a1a3 553 ret = set_structure_field_integer(stream->packet_context,
273b65be
JG
554 "packet_size", stream->pos.packet_size);
555 if (ret) {
556 goto end;
557 }
558
12c8a1a3 559 ret = bt_ctf_field_serialize(stream->packet_context,
273b65be
JG
560 &packet_context_pos);
561 if (ret) {
562 goto end;
563 }
564
565 g_ptr_array_set_size(stream->events, 0);
8bfa3f9c
JG
566 if (stream->event_contexts) {
567 g_ptr_array_set_size(stream->event_contexts, 0);
568 }
273b65be
JG
569 stream->flushed_packet_count++;
570end:
571 bt_ctf_field_put(integer);
572 return ret;
573}
574
575void bt_ctf_stream_get(struct bt_ctf_stream *stream)
576{
577 if (!stream) {
578 return;
579 }
580
581 bt_ctf_ref_get(&stream->ref_count);
582}
583
584void bt_ctf_stream_put(struct bt_ctf_stream *stream)
585{
586 if (!stream) {
587 return;
588 }
589
590 bt_ctf_ref_put(&stream->ref_count, bt_ctf_stream_destroy);
591}
592
593static
594void bt_ctf_stream_destroy(struct bt_ctf_ref *ref)
595{
596 struct bt_ctf_stream *stream;
597
598 if (!ref) {
599 return;
600 }
601
602 stream = container_of(ref, struct bt_ctf_stream, ref_count);
603 ctf_fini_pos(&stream->pos);
9f56e450
JG
604 if (close(stream->pos.fd)) {
605 perror("close");
606 }
12c8a1a3
JG
607
608 if (stream->stream_class) {
609 bt_ctf_stream_class_put(stream->stream_class);
610 }
611 if (stream->events) {
612 g_ptr_array_free(stream->events, TRUE);
613 }
8bfa3f9c
JG
614 if (stream->event_contexts) {
615 g_ptr_array_free(stream->event_contexts, TRUE);
616 }
12c8a1a3
JG
617 if (stream->packet_context) {
618 bt_ctf_field_put(stream->packet_context);
619 }
8bfa3f9c
JG
620 if (stream->event_context) {
621 bt_ctf_field_put(stream->event_context);
622 }
273b65be
JG
623 g_free(stream);
624}
625
273b65be
JG
626static
627int set_structure_field_integer(struct bt_ctf_field *structure, char *name,
628 uint64_t value)
629{
630 int ret = 0;
273b65be
JG
631 struct bt_ctf_field *integer =
632 bt_ctf_field_structure_get_field(structure, name);
12c8a1a3
JG
633
634 if (!structure || !name) {
273b65be
JG
635 ret = -1;
636 goto end;
637 }
638
12c8a1a3
JG
639 if (!integer) {
640 /* Field not found, not an error. */
641 goto end;
642 }
643
644 /* Make sure the payload has not already been set. */
645 if (!bt_ctf_field_validate(integer)) {
646 /* Payload already set, not an error */
647 goto end;
648 }
649
273b65be
JG
650 ret = bt_ctf_field_unsigned_integer_set_value(integer, value);
651end:
652 bt_ctf_field_put(integer);
653 return ret;
654}
This page took 0.051174 seconds and 4 git commands to generate.