Update test_ctf_writer.c header
[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
ac0c6bdd
PP
29#include <babeltrace/ctf-ir/clock-class.h>
30#include <babeltrace/ctf-writer/clock.h>
31#include <babeltrace/ctf-writer/clock-internal.h>
273b65be 32#include <babeltrace/ctf-writer/event.h>
adc315b8 33#include <babeltrace/ctf-ir/event-internal.h>
2e33ac5a
PP
34#include <babeltrace/ctf-ir/field-types-internal.h>
35#include <babeltrace/ctf-ir/fields-internal.h>
3f043b05
JG
36#include <babeltrace/ctf-ir/stream.h>
37#include <babeltrace/ctf-ir/stream-internal.h>
adc315b8 38#include <babeltrace/ctf-ir/stream-class-internal.h>
319fd969
PP
39#include <babeltrace/ctf-ir/trace-internal.h>
40#include <babeltrace/ctf-writer/writer-internal.h>
83509119 41#include <babeltrace/ref.h>
273b65be
JG
42#include <babeltrace/ctf-writer/functor-internal.h>
43#include <babeltrace/compiler.h>
44#include <babeltrace/align.h>
d246b111 45#include <babeltrace/ctf/ctf-index.h>
273b65be
JG
46
47static
83509119 48void bt_ctf_stream_destroy(struct bt_object *obj);
273b65be 49static
273b65be
JG
50int set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t);
51
ac0c6bdd
PP
52static
53int set_integer_field_value(struct bt_ctf_field* field, uint64_t value)
54{
55 int ret = 0;
56 struct bt_ctf_field_type *field_type = NULL;
57
58 if (!field) {
59 ret = -1;
60 goto end;
61 }
62
63 field_type = bt_ctf_field_get_type(field);
64 assert(field_type);
65
66 if (bt_ctf_field_type_get_type_id(field_type) !=
67 BT_CTF_TYPE_ID_INTEGER) {
68 /* Not an integer and the value is unset, error. */
69 ret = -1;
70 goto end;
71 }
72
73 if (bt_ctf_field_type_integer_get_signed(field_type)) {
74 ret = bt_ctf_field_signed_integer_set_value(field, (int64_t) value);
75 if (ret) {
76 /* Value is out of range, error. */
77 goto end;
78 }
79 } else {
80 ret = bt_ctf_field_unsigned_integer_set_value(field, value);
81 if (ret) {
82 /* Value is out of range, error. */
83 goto end;
84 }
85 }
86end:
87 bt_put(field_type);
88 return ret;
89}
90
d246b111
JG
91static
92int set_packet_header_magic(struct bt_ctf_stream *stream)
93{
94 int ret = 0;
95 struct bt_ctf_field_type *magic_field_type = NULL;
96 struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field(
97 stream->packet_header, "magic");
98
99 if (!magic_field) {
100 /* No magic field found. Not an error, skip. */
101 goto end;
102 }
103
fc47320a 104 if (bt_ctf_field_is_set(magic_field)) {
d246b111
JG
105 /* Value already set. Not an error, skip. */
106 goto end;
107 }
108
109 magic_field_type = bt_ctf_field_get_type(magic_field);
110 assert(magic_field_type);
111
112 if (bt_ctf_field_type_get_type_id(magic_field_type) !=
9a19a512 113 BT_CTF_TYPE_ID_INTEGER) {
d246b111
JG
114 /* Magic field is not an integer. Not an error, skip. */
115 goto end;
116 }
117
118 if (bt_ctf_field_type_integer_get_size(magic_field_type) != 32) {
119 /*
120 * Magic field is not of the expected size.
121 * Not an error, skip.
122 */
123 goto end;
124 }
125
126 ret = bt_ctf_field_type_integer_get_signed(magic_field_type);
127 assert(ret >= 0);
128 if (ret) {
129 ret = bt_ctf_field_signed_integer_set_value(magic_field,
130 (int64_t) 0xC1FC1FC1);
131 } else {
132 ret = bt_ctf_field_unsigned_integer_set_value(magic_field,
133 (uint64_t) 0xC1FC1FC1);
134 }
135end:
83509119
JG
136 bt_put(magic_field);
137 bt_put(magic_field_type);
d246b111
JG
138 return ret;
139}
140
141static
142int set_packet_header_uuid(struct bt_ctf_stream *stream)
143{
144 int i, ret = 0;
e6a8e8e4 145 struct bt_ctf_trace *trace = NULL;
d246b111
JG
146 struct bt_ctf_field_type *uuid_field_type = NULL;
147 struct bt_ctf_field_type *element_field_type = NULL;
148 struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field(
149 stream->packet_header, "uuid");
150
151 if (!uuid_field) {
152 /* No uuid field found. Not an error, skip. */
153 goto end;
154 }
155
fc47320a 156 if (bt_ctf_field_is_set(uuid_field)) {
d246b111
JG
157 /* Value already set. Not an error, skip. */
158 goto end;
159 }
160
161 uuid_field_type = bt_ctf_field_get_type(uuid_field);
162 assert(uuid_field_type);
163 if (bt_ctf_field_type_get_type_id(uuid_field_type) !=
9a19a512 164 BT_CTF_TYPE_ID_ARRAY) {
d246b111
JG
165 /* UUID field is not an array. Not an error, skip. */
166 goto end;
167 }
168
169 if (bt_ctf_field_type_array_get_length(uuid_field_type) != 16) {
170 /*
171 * UUID field is not of the expected size.
172 * Not an error, skip.
173 */
174 goto end;
175 }
176
177 element_field_type = bt_ctf_field_type_array_get_element_type(
178 uuid_field_type);
179 assert(element_field_type);
180 if (bt_ctf_field_type_get_type_id(element_field_type) !=
9a19a512 181 BT_CTF_TYPE_ID_INTEGER) {
d246b111
JG
182 /* UUID array elements are not integers. Not an error, skip */
183 goto end;
184 }
185
e6a8e8e4 186 trace = (struct bt_ctf_trace *) bt_object_get_parent(stream);
d246b111
JG
187 for (i = 0; i < 16; i++) {
188 struct bt_ctf_field *uuid_element =
189 bt_ctf_field_array_get_field(uuid_field, i);
190
191 ret = bt_ctf_field_type_integer_get_signed(element_field_type);
192 assert(ret >= 0);
193
194 if (ret) {
195 ret = bt_ctf_field_signed_integer_set_value(
e6a8e8e4 196 uuid_element, (int64_t) trace->uuid[i]);
d246b111
JG
197 } else {
198 ret = bt_ctf_field_unsigned_integer_set_value(
199 uuid_element,
e6a8e8e4 200 (uint64_t) trace->uuid[i]);
d246b111 201 }
83509119 202 bt_put(uuid_element);
d246b111
JG
203 if (ret) {
204 goto end;
205 }
206 }
207
208end:
83509119
JG
209 bt_put(uuid_field);
210 bt_put(uuid_field_type);
211 bt_put(element_field_type);
e6a8e8e4 212 BT_PUT(trace);
d246b111
JG
213 return ret;
214}
215static
216int set_packet_header_stream_id(struct bt_ctf_stream *stream)
217{
218 int ret = 0;
219 uint32_t stream_id;
220 struct bt_ctf_field_type *stream_id_field_type = NULL;
221 struct bt_ctf_field *stream_id_field = bt_ctf_field_structure_get_field(
222 stream->packet_header, "stream_id");
223
224 if (!stream_id_field) {
225 /* No stream_id field found. Not an error, skip. */
226 goto end;
227 }
228
fc47320a 229 if (bt_ctf_field_is_set(stream_id_field)) {
d246b111
JG
230 /* Value already set. Not an error, skip. */
231 goto end;
232 }
233
234 stream_id_field_type = bt_ctf_field_get_type(stream_id_field);
235 assert(stream_id_field_type);
236 if (bt_ctf_field_type_get_type_id(stream_id_field_type) !=
9a19a512 237 BT_CTF_TYPE_ID_INTEGER) {
d246b111
JG
238 /* stream_id field is not an integer. Not an error, skip. */
239 goto end;
240 }
241
242 stream_id = stream->stream_class->id;
243 ret = bt_ctf_field_type_integer_get_signed(stream_id_field_type);
244 assert(ret >= 0);
245 if (ret) {
246 ret = bt_ctf_field_signed_integer_set_value(stream_id_field,
247 (int64_t) stream_id);
248 } else {
249 ret = bt_ctf_field_unsigned_integer_set_value(stream_id_field,
250 (uint64_t) stream_id);
251 }
252end:
83509119
JG
253 bt_put(stream_id_field);
254 bt_put(stream_id_field_type);
d246b111
JG
255 return ret;
256}
257
258static
259int set_packet_header(struct bt_ctf_stream *stream)
260{
261 int ret;
262
263 ret = set_packet_header_magic(stream);
264 if (ret) {
265 goto end;
266 }
267
268 ret = set_packet_header_uuid(stream);
269 if (ret) {
270 goto end;
271 }
272
273 ret = set_packet_header_stream_id(stream);
274 if (ret) {
275 goto end;
276 }
277end:
278 return ret;
279}
280
123fbdec 281static
e6a8e8e4 282void release_event(struct bt_ctf_event *event)
123fbdec 283{
e6a8e8e4
JG
284 if (bt_object_get_ref_count(event)) {
285 /*
286 * The event is being orphaned, but it must guarantee the
287 * existence of its event class for the duration of its
288 * lifetime.
289 */
290 bt_get(event->event_class);
291 BT_PUT(event->base.parent);
292 } else {
293 bt_object_release(event);
294 }
123fbdec
JG
295}
296
319fd969
PP
297static
298int create_stream_file(struct bt_ctf_writer *writer,
299 struct bt_ctf_stream *stream)
300{
301 int fd;
302 GString *filename = g_string_new(stream->stream_class->name->str);
303
304 if (stream->stream_class->name->len == 0) {
305 int64_t ret;
306
307 ret = bt_ctf_stream_class_get_id(stream->stream_class);
308 if (ret < 0) {
309 fd = -1;
310 goto error;
311 }
312
313 g_string_printf(filename, "stream_%" PRId64, ret);
314 }
315
316 g_string_append_printf(filename, "_%" PRIu32, stream->id);
317 fd = openat(writer->trace_dir_fd, filename->str,
318 O_RDWR | O_CREAT | O_TRUNC,
319 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
320error:
321 g_string_free(filename, TRUE);
322 return fd;
323}
324
325static
326int set_stream_fd(struct bt_ctf_stream *stream, int fd)
327{
328 int ret = 0;
329
330 if (stream->pos.fd != -1) {
331 ret = -1;
332 goto end;
333 }
334
335 ctf_init_pos(&stream->pos, NULL, fd, O_RDWR);
336 stream->pos.fd = fd;
337end:
338 return ret;
339}
340
273b65be 341struct bt_ctf_stream *bt_ctf_stream_create(
b71d7298
PP
342 struct bt_ctf_stream_class *stream_class,
343 const char *name)
273b65be 344{
12c8a1a3 345 int ret;
273b65be 346 struct bt_ctf_stream *stream = NULL;
319fd969
PP
347 struct bt_ctf_trace *trace = NULL;
348 struct bt_ctf_writer *writer = NULL;
273b65be 349
319fd969 350 if (!stream_class) {
b71d7298 351 goto error;
319fd969
PP
352 }
353
354 trace = bt_ctf_stream_class_get_trace(stream_class);
355 if (!trace) {
b71d7298 356 goto error;
273b65be
JG
357 }
358
359 stream = g_new0(struct bt_ctf_stream, 1);
360 if (!stream) {
b71d7298 361 goto error;
273b65be
JG
362 }
363
83509119 364 bt_object_init(stream, bt_ctf_stream_destroy);
e6a8e8e4
JG
365 /*
366 * Acquire reference to parent since stream will become publicly
367 * reachable; it needs its parent to remain valid.
368 */
369 bt_object_set_parent(stream, trace);
273b65be
JG
370 stream->id = stream_class->next_stream_id++;
371 stream->stream_class = stream_class;
319fd969 372 stream->pos.fd = -1;
d246b111 373
b71d7298
PP
374 if (name) {
375 stream->name = g_string_new(name);
376 if (!stream->name) {
377 goto error;
378 }
379 }
380
319fd969
PP
381 if (trace->is_created_by_writer) {
382 int fd;
383 writer = (struct bt_ctf_writer *)
384 bt_object_get_parent(trace);
385
386 assert(writer);
387 stream->packet_context = bt_ctf_field_create(
388 stream_class->packet_context_type);
389 if (!stream->packet_context) {
390 goto error;
391 }
392
393 /* Initialize events_discarded */
394 ret = set_structure_field_integer(stream->packet_context,
395 "events_discarded", 0);
396 if (ret) {
397 goto error;
398 }
399
400 stream->events = g_ptr_array_new_with_free_func(
401 (GDestroyNotify) release_event);
402 if (!stream->events) {
403 goto error;
404 }
405
406 /* A trace is not allowed to have a NULL packet header */
407 assert(trace->packet_header_type);
408 stream->packet_header =
409 bt_ctf_field_create(trace->packet_header_type);
410 if (!stream->packet_header) {
411 goto error;
412 }
413
414 /*
415 * Attempt to populate the default trace packet header fields
416 * (magic, uuid and stream_id). This will _not_ fail shall the
417 * fields not be found or be of an incompatible type; they will
418 * simply not be populated automatically. The user will have to
419 * make sure to set the trace packet header fields himself
420 * before flushing.
421 */
422 ret = set_packet_header(stream);
423 if (ret) {
424 goto error;
425 }
426
427 /* Create file associated with this stream */
428 fd = create_stream_file(writer, stream);
429 if (fd < 0) {
430 goto error;
431 }
432
433 ret = set_stream_fd(stream, fd);
434 if (ret) {
435 goto error;
436 }
437
438 /* Freeze the writer */
439 bt_ctf_writer_freeze(writer);
440 } else {
441 /* Non-writer stream indicated by a negative FD */
442 ret = set_stream_fd(stream, -1);
443 if (ret) {
444 goto error;
445 }
d246b111 446 }
319fd969
PP
447
448 /* Add this stream to the trace's streams */
449 g_ptr_array_add(trace->streams, stream);
450
319fd969
PP
451 BT_PUT(trace);
452 BT_PUT(writer);
273b65be 453 return stream;
83509119
JG
454error:
455 BT_PUT(stream);
319fd969
PP
456 BT_PUT(trace);
457 BT_PUT(writer);
83509119 458 return stream;
273b65be
JG
459}
460
3baf0856
JG
461struct bt_ctf_stream_class *bt_ctf_stream_get_class(
462 struct bt_ctf_stream *stream)
463{
464 struct bt_ctf_stream_class *stream_class = NULL;
465
466 if (!stream) {
467 goto end;
468 }
469
470 stream_class = stream->stream_class;
83509119 471 bt_get(stream_class);
3baf0856
JG
472end:
473 return stream_class;
474}
475
a78a2e25
JG
476int bt_ctf_stream_get_discarded_events_count(
477 struct bt_ctf_stream *stream, uint64_t *count)
478{
479 int64_t ret = 0;
12c8a1a3
JG
480 int field_signed;
481 struct bt_ctf_field *events_discarded_field = NULL;
482 struct bt_ctf_field_type *events_discarded_field_type = NULL;
a78a2e25 483
1579cde5
PP
484 if (!stream || !count || !stream->packet_context ||
485 stream->pos.fd < 0) {
a78a2e25
JG
486 ret = -1;
487 goto end;
488 }
489
12c8a1a3
JG
490 events_discarded_field = bt_ctf_field_structure_get_field(
491 stream->packet_context, "events_discarded");
492 if (!events_discarded_field) {
493 ret = -1;
494 goto end;
495 }
496
497 events_discarded_field_type = bt_ctf_field_get_type(
498 events_discarded_field);
499 if (!events_discarded_field_type) {
500 ret = -1;
501 goto end;
502 }
503
504 field_signed = bt_ctf_field_type_integer_get_signed(
505 events_discarded_field_type);
506 if (field_signed < 0) {
507 ret = field_signed;
508 goto end;
509 }
510
511 if (field_signed) {
512 int64_t signed_count;
513
514 ret = bt_ctf_field_signed_integer_get_value(
515 events_discarded_field, &signed_count);
516 if (ret) {
517 goto end;
518 }
519 if (signed_count < 0) {
520 /* Invalid value */
521 ret = -1;
522 goto end;
523 }
524 *count = (uint64_t) signed_count;
525 } else {
526 ret = bt_ctf_field_unsigned_integer_get_value(
527 events_discarded_field, count);
528 if (ret) {
529 goto end;
530 }
531 }
a78a2e25 532end:
83509119
JG
533 bt_put(events_discarded_field);
534 bt_put(events_discarded_field_type);
a78a2e25
JG
535 return ret;
536}
537
273b65be
JG
538void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
539 uint64_t event_count)
540{
12c8a1a3
JG
541 int ret;
542 int field_signed;
543 uint64_t previous_count;
544 uint64_t new_count;
545 struct bt_ctf_field *events_discarded_field = NULL;
546 struct bt_ctf_field_type *events_discarded_field_type = NULL;
547
1579cde5 548 if (!stream || !stream->packet_context || stream->pos.fd < 0) {
12c8a1a3
JG
549 goto end;
550 }
551
552 ret = bt_ctf_stream_get_discarded_events_count(stream,
553 &previous_count);
554 if (ret) {
555 goto end;
556 }
557
558 events_discarded_field = bt_ctf_field_structure_get_field(
559 stream->packet_context, "events_discarded");
560 if (!events_discarded_field) {
561 goto end;
562 }
563
564 events_discarded_field_type = bt_ctf_field_get_type(
565 events_discarded_field);
566 if (!events_discarded_field_type) {
567 goto end;
568 }
569
570 field_signed = bt_ctf_field_type_integer_get_signed(
571 events_discarded_field_type);
572 if (field_signed < 0) {
573 goto end;
273b65be
JG
574 }
575
12c8a1a3
JG
576 new_count = previous_count + event_count;
577 if (field_signed) {
578 ret = bt_ctf_field_signed_integer_set_value(
579 events_discarded_field, (int64_t) new_count);
580 if (ret) {
581 goto end;
582 }
583 } else {
584 ret = bt_ctf_field_unsigned_integer_set_value(
585 events_discarded_field, new_count);
586 if (ret) {
587 goto end;
588 }
589 }
590
591end:
83509119
JG
592 bt_put(events_discarded_field);
593 bt_put(events_discarded_field_type);
273b65be
JG
594}
595
ac0c6bdd
PP
596static int auto_populate_event_header(struct bt_ctf_stream *stream,
597 struct bt_ctf_event *event)
598{
599 int ret = 0;
600 struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL;
601 struct bt_ctf_clock_class *mapped_clock_class = NULL;
602
603 if (!event || event->frozen) {
604 ret = -1;
605 goto end;
606 }
607
608 /*
609 * The condition to automatically set the ID are:
610 *
611 * 1. The event header field "id" exists and is an integer
612 * field.
613 * 2. The event header field "id" is NOT set.
614 */
615 id_field = bt_ctf_field_structure_get_field(event->event_header, "id");
616 if (id_field && !bt_ctf_field_is_set(id_field)) {
617 ret = set_integer_field_value(id_field,
618 (uint64_t) bt_ctf_event_class_get_id(
619 event->event_class));
620 if (ret) {
621 goto end;
622 }
623 }
624
625 /*
626 * The conditions to automatically set the timestamp are:
627 *
628 * 1. The event header field "timestamp" exists and is an
629 * integer field.
630 * 2. This stream's class has a registered clock (set with
631 * bt_ctf_stream_class_set_clock()).
632 * 3. The event header field "timestamp" has its type mapped to
633 * a clock class which is also the clock class of this
634 * stream's class's registered clock.
635 * 4. The event header field "timestamp" is NOT set.
636 */
637 timestamp_field = bt_ctf_field_structure_get_field(event->event_header,
638 "timestamp");
639 if (timestamp_field && !bt_ctf_field_is_set(timestamp_field) &&
640 stream->stream_class->clock) {
641 struct bt_ctf_clock_class *stream_class_clock_class =
642 stream->stream_class->clock->clock_class;
643 struct bt_ctf_field_type *timestamp_field_type =
644 bt_ctf_field_get_type(timestamp_field);
645
646 assert(timestamp_field_type);
647 mapped_clock_class =
648 bt_ctf_field_type_integer_get_mapped_clock_class(
649 timestamp_field_type);
650 BT_PUT(timestamp_field_type);
651 if (mapped_clock_class == stream_class_clock_class) {
652 uint64_t timestamp;
653
654 ret = bt_ctf_clock_get_value(
655 stream->stream_class->clock,
656 &timestamp);
657 if (ret) {
658 goto end;
659 }
660
661 ret = set_integer_field_value(timestamp_field,
662 timestamp);
663 if (ret) {
664 goto end;
665 }
666 }
667 }
668
669end:
670 bt_put(id_field);
671 bt_put(timestamp_field);
672 bt_put(mapped_clock_class);
673 return ret;
674}
675
273b65be
JG
676int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
677 struct bt_ctf_event *event)
678{
679 int ret = 0;
273b65be 680
1579cde5 681 if (!stream || !event || stream->pos.fd < 0) {
273b65be
JG
682 ret = -1;
683 goto end;
684 }
685
fa29ba83
PP
686 /*
687 * The event is not supposed to have a parent stream at this
688 * point. The only other way an event can have a parent stream
689 * is if it was assigned when setting a packet to the event,
690 * in which case the packet's stream is not a writer stream,
691 * and thus the user is trying to append an event which belongs
692 * to another stream.
693 */
694 if (event->base.parent) {
695 ret = -1;
696 goto end;
697 }
698
e6a8e8e4 699 bt_object_set_parent(event, stream);
ac0c6bdd 700 ret = auto_populate_event_header(stream, event);
662e778c 701 if (ret) {
37f30168 702 goto error;
662e778c
JG
703 }
704
5fd2e9fd 705 /* Make sure the various scopes of the event are set */
273b65be
JG
706 ret = bt_ctf_event_validate(event);
707 if (ret) {
37f30168 708 goto error;
273b65be
JG
709 }
710
0d688c15
PP
711 /* Save the new event and freeze it */
712 bt_ctf_event_freeze(event);
273b65be 713 g_ptr_array_add(stream->events, event);
5fd2e9fd 714
e6a8e8e4
JG
715 /*
716 * Event had to hold a reference to its event class as long as it wasn't
717 * part of the same trace hierarchy. From now on, the event and its
718 * class share the same lifetime guarantees and the reference is no
719 * longer needed.
720 */
721 bt_put(event->event_class);
37f30168 722
273b65be 723end:
37f30168
PP
724 return ret;
725
726error:
727 /*
728 * Orphan the event; we were not successful in associating it to
729 * a stream.
730 */
731 bt_object_set_parent(event, NULL);
732
273b65be
JG
733 return ret;
734}
735
12c8a1a3
JG
736struct bt_ctf_field *bt_ctf_stream_get_packet_context(
737 struct bt_ctf_stream *stream)
738{
739 struct bt_ctf_field *packet_context = NULL;
740
1579cde5 741 if (!stream || stream->pos.fd < 0) {
12c8a1a3
JG
742 goto end;
743 }
744
745 packet_context = stream->packet_context;
12c8a1a3 746 if (packet_context) {
83509119 747 bt_get(packet_context);
12c8a1a3 748 }
34629a55 749end:
12c8a1a3
JG
750 return packet_context;
751}
752
753int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream,
754 struct bt_ctf_field *field)
755{
756 int ret = 0;
757 struct bt_ctf_field_type *field_type;
758
835b2d10 759 if (!stream || stream->pos.fd < 0) {
12c8a1a3
JG
760 ret = -1;
761 goto end;
762 }
763
764 field_type = bt_ctf_field_get_type(field);
09840de5
PP
765 if (bt_ctf_field_type_compare(field_type,
766 stream->stream_class->packet_context_type)) {
12c8a1a3
JG
767 ret = -1;
768 goto end;
769 }
770
83509119 771 bt_put(field_type);
83509119 772 bt_put(stream->packet_context);
835b2d10 773 stream->packet_context = bt_get(field);
12c8a1a3
JG
774end:
775 return ret;
776}
777
263a7df5
JG
778struct bt_ctf_field *bt_ctf_stream_get_packet_header(
779 struct bt_ctf_stream *stream)
780{
781 struct bt_ctf_field *packet_header = NULL;
782
1579cde5 783 if (!stream || stream->pos.fd < 0) {
263a7df5
JG
784 goto end;
785 }
786
787 packet_header = stream->packet_header;
788 if (packet_header) {
83509119 789 bt_get(packet_header);
263a7df5
JG
790 }
791end:
792 return packet_header;
793}
794
795int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream,
796 struct bt_ctf_field *field)
797{
798 int ret = 0;
e6a8e8e4 799 struct bt_ctf_trace *trace = NULL;
263a7df5
JG
800 struct bt_ctf_field_type *field_type = NULL;
801
835b2d10 802 if (!stream || stream->pos.fd < 0) {
263a7df5
JG
803 ret = -1;
804 goto end;
805 }
806
e6a8e8e4 807 trace = (struct bt_ctf_trace *) bt_object_get_parent(stream);
263a7df5 808 field_type = bt_ctf_field_get_type(field);
09840de5 809 if (bt_ctf_field_type_compare(field_type, trace->packet_header_type)) {
263a7df5
JG
810 ret = -1;
811 goto end;
812 }
813
83509119 814 bt_put(stream->packet_header);
835b2d10 815 stream->packet_header = bt_get(field);
263a7df5 816end:
e6a8e8e4 817 BT_PUT(trace);
83509119 818 bt_put(field_type);
263a7df5
JG
819 return ret;
820}
821
9a220c32
JG
822static
823int get_event_header_timestamp(struct bt_ctf_field *event_header, uint64_t *timestamp)
824{
825 int ret = 0;
826 struct bt_ctf_field *timestamp_field = NULL;
827 struct bt_ctf_field_type *timestamp_field_type = NULL;
828
829 timestamp_field = bt_ctf_field_structure_get_field(event_header,
830 "timestamp");
831 if (!timestamp_field) {
832 ret = -1;
833 goto end;
834 }
835
836 timestamp_field_type = bt_ctf_field_get_type(timestamp_field);
837 assert(timestamp_field_type);
838 if (bt_ctf_field_type_get_type_id(timestamp_field_type) !=
9a19a512 839 BT_CTF_TYPE_ID_INTEGER) {
9a220c32
JG
840 ret = -1;
841 goto end;
842 }
843
844 if (bt_ctf_field_type_integer_get_signed(timestamp_field_type)) {
845 int64_t val;
846
847 ret = bt_ctf_field_signed_integer_get_value(timestamp_field,
848 &val);
849 if (ret) {
850 goto end;
851 }
852 *timestamp = (uint64_t) val;
853 } else {
854 ret = bt_ctf_field_unsigned_integer_get_value(timestamp_field,
855 timestamp);
856 if (ret) {
857 goto end;
858 }
859 }
860end:
83509119
JG
861 bt_put(timestamp_field);
862 bt_put(timestamp_field_type);
9a220c32
JG
863 return ret;
864}
865
273b65be
JG
866int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
867{
868 int ret = 0;
869 size_t i;
12c8a1a3 870 uint64_t timestamp_begin, timestamp_end, events_discarded;
273b65be
JG
871 struct bt_ctf_field *integer = NULL;
872 struct ctf_stream_pos packet_context_pos;
873
bc37ae52
JG
874 if (!stream || stream->pos.fd < 0) {
875 /*
876 * Stream does not have an associated fd. It is,
877 * therefore, not a stream being used to write events.
878 */
273b65be
JG
879 ret = -1;
880 goto end;
881 }
882
883 if (!stream->events->len) {
884 goto end;
885 }
886
d246b111
JG
887 ret = bt_ctf_field_validate(stream->packet_header);
888 if (ret) {
889 goto end;
890 }
891
28362f2b
JG
892 /* mmap the next packet */
893 ctf_packet_seek(&stream->pos.parent, 0, SEEK_CUR);
d246b111
JG
894
895 ret = bt_ctf_field_serialize(stream->packet_header, &stream->pos);
896 if (ret) {
897 goto end;
273b65be
JG
898 }
899
12c8a1a3 900 /* Set the default context attributes if present and unset. */
9a220c32
JG
901 if (!get_event_header_timestamp(
902 ((struct bt_ctf_event *) g_ptr_array_index(
903 stream->events, 0))->event_header, &timestamp_begin)) {
904 ret = set_structure_field_integer(stream->packet_context,
905 "timestamp_begin", timestamp_begin);
906 if (ret) {
907 goto end;
908 }
273b65be
JG
909 }
910
9a220c32
JG
911 if (!get_event_header_timestamp(
912 ((struct bt_ctf_event *) g_ptr_array_index(
913 stream->events, stream->events->len - 1))->event_header,
914 &timestamp_end)) {
273b65be 915
9a220c32
JG
916 ret = set_structure_field_integer(stream->packet_context,
917 "timestamp_end", timestamp_end);
918 if (ret) {
919 goto end;
920 }
921 }
12c8a1a3 922 ret = set_structure_field_integer(stream->packet_context,
273b65be
JG
923 "content_size", UINT64_MAX);
924 if (ret) {
925 goto end;
926 }
927
12c8a1a3 928 ret = set_structure_field_integer(stream->packet_context,
273b65be
JG
929 "packet_size", UINT64_MAX);
930 if (ret) {
931 goto end;
932 }
933
934 /* Write packet context */
935 memcpy(&packet_context_pos, &stream->pos,
936 sizeof(struct ctf_stream_pos));
12c8a1a3 937 ret = bt_ctf_field_serialize(stream->packet_context,
273b65be
JG
938 &stream->pos);
939 if (ret) {
940 goto end;
941 }
942
12c8a1a3
JG
943 ret = bt_ctf_stream_get_discarded_events_count(stream,
944 &events_discarded);
945 if (ret) {
946 goto end;
947 }
948
949 /* Unset the packet context's fields. */
950 ret = bt_ctf_field_reset(stream->packet_context);
951 if (ret) {
952 goto end;
953 }
954
955 /* Set the previous number of discarded events. */
956 ret = set_structure_field_integer(stream->packet_context,
957 "events_discarded", events_discarded);
958 if (ret) {
959 goto end;
960 }
961
273b65be
JG
962 for (i = 0; i < stream->events->len; i++) {
963 struct bt_ctf_event *event = g_ptr_array_index(
964 stream->events, i);
273b65be 965
662e778c 966 ret = bt_ctf_field_reset(event->event_header);
12c8a1a3
JG
967 if (ret) {
968 goto end;
969 }
970
273b65be 971 /* Write event header */
662e778c 972 ret = bt_ctf_field_serialize(event->event_header,
273b65be
JG
973 &stream->pos);
974 if (ret) {
975 goto end;
976 }
977
8bfa3f9c 978 /* Write stream event context */
5fd2e9fd 979 if (event->stream_event_context) {
8bfa3f9c 980 ret = bt_ctf_field_serialize(
5fd2e9fd 981 event->stream_event_context, &stream->pos);
8bfa3f9c
JG
982 if (ret) {
983 goto end;
984 }
985 }
986
273b65be
JG
987 /* Write event content */
988 ret = bt_ctf_event_serialize(event, &stream->pos);
989 if (ret) {
990 goto end;
991 }
992 }
993
994 /*
995 * Update the packet total size and content size and overwrite the
996 * packet context.
3a092c05
JG
997 * Copy base_mma as the packet may have been remapped (e.g. when a
998 * packet is resized).
273b65be 999 */
3a092c05 1000 packet_context_pos.base_mma = stream->pos.base_mma;
12c8a1a3 1001 ret = set_structure_field_integer(stream->packet_context,
273b65be
JG
1002 "content_size", stream->pos.offset);
1003 if (ret) {
1004 goto end;
1005 }
1006
12c8a1a3 1007 ret = set_structure_field_integer(stream->packet_context,
273b65be
JG
1008 "packet_size", stream->pos.packet_size);
1009 if (ret) {
1010 goto end;
1011 }
1012
12c8a1a3 1013 ret = bt_ctf_field_serialize(stream->packet_context,
273b65be
JG
1014 &packet_context_pos);
1015 if (ret) {
1016 goto end;
1017 }
1018
1019 g_ptr_array_set_size(stream->events, 0);
1020 stream->flushed_packet_count++;
1021end:
83509119 1022 bt_put(integer);
273b65be
JG
1023 return ret;
1024}
1025
1026void bt_ctf_stream_get(struct bt_ctf_stream *stream)
1027{
83509119 1028 bt_get(stream);
273b65be
JG
1029}
1030
1031void bt_ctf_stream_put(struct bt_ctf_stream *stream)
1032{
83509119 1033 bt_put(stream);
273b65be
JG
1034}
1035
1036static
83509119 1037void bt_ctf_stream_destroy(struct bt_object *obj)
273b65be
JG
1038{
1039 struct bt_ctf_stream *stream;
273b65be 1040
83509119 1041 stream = container_of(obj, struct bt_ctf_stream, base);
273b65be 1042 ctf_fini_pos(&stream->pos);
0e45d308 1043 if (stream->pos.fd >= 0 && close(stream->pos.fd)) {
9f56e450
JG
1044 perror("close");
1045 }
12c8a1a3 1046
12c8a1a3
JG
1047 if (stream->events) {
1048 g_ptr_array_free(stream->events, TRUE);
1049 }
b71d7298
PP
1050
1051 if (stream->name) {
1052 g_string_free(stream->name, TRUE);
1053 }
41ac640a 1054
83509119
JG
1055 bt_put(stream->packet_header);
1056 bt_put(stream->packet_context);
273b65be
JG
1057 g_free(stream);
1058}
1059
273b65be
JG
1060static
1061int set_structure_field_integer(struct bt_ctf_field *structure, char *name,
1062 uint64_t value)
1063{
1064 int ret = 0;
d7b1ea66 1065 struct bt_ctf_field_type *field_type = NULL;
273b65be
JG
1066 struct bt_ctf_field *integer =
1067 bt_ctf_field_structure_get_field(structure, name);
12c8a1a3
JG
1068
1069 if (!structure || !name) {
273b65be
JG
1070 ret = -1;
1071 goto end;
1072 }
1073
12c8a1a3
JG
1074 if (!integer) {
1075 /* Field not found, not an error. */
1076 goto end;
1077 }
1078
1079 /* Make sure the payload has not already been set. */
fc47320a 1080 if (bt_ctf_field_is_set(integer)) {
12c8a1a3
JG
1081 /* Payload already set, not an error */
1082 goto end;
1083 }
1084
d7b1ea66
JG
1085 field_type = bt_ctf_field_get_type(integer);
1086 /* Something is serioulsly wrong */
1087 assert(field_type);
9a19a512 1088 if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_TYPE_ID_INTEGER) {
d7b1ea66
JG
1089 /*
1090 * The user most likely meant for us to populate this field
1091 * automatically. However, we can only do this if the field
1092 * is an integer. Return an error.
1093 */
1094 ret = -1;
1095 goto end;
1096 }
1097
1098 if (bt_ctf_field_type_integer_get_signed(field_type)) {
1099 ret = bt_ctf_field_signed_integer_set_value(integer,
1100 (int64_t) value);
1101 } else {
1102 ret = bt_ctf_field_unsigned_integer_set_value(integer, value);
1103 }
273b65be 1104end:
83509119
JG
1105 bt_put(integer);
1106 bt_put(field_type);
273b65be
JG
1107 return ret;
1108}
b71d7298
PP
1109
1110const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream)
1111{
1112 const char *name = NULL;
1113
1114 if (!stream) {
1115 goto end;
1116 }
1117
1118 name = stream->name ? stream->name->str : NULL;
1119
1120end:
1121 return name;
1122}
98a4cbef
PP
1123
1124int bt_ctf_stream_is_writer(struct bt_ctf_stream *stream)
1125{
1126 int ret = -1;
1127
1128 if (!stream) {
1129 goto end;
1130 }
1131
1132 ret = (stream->pos.fd >= 0);
1133
1134end:
1135 return ret;
1136}
This page took 0.085903 seconds and 4 git commands to generate.