2 * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 #define BT_LOG_TAG "CTF-WRITER-STREAM"
25 #include <babeltrace/lib-logging-internal.h>
27 #include <babeltrace/ref.h>
28 #include <babeltrace/ctf-ir/event-class-internal.h>
29 #include <babeltrace/ctf-writer/writer-internal.h>
30 #include <babeltrace/ctf-writer/stream.h>
31 #include <babeltrace/ctf-writer/stream-internal.h>
32 #include <babeltrace/ctf-writer/stream-class-internal.h>
33 #include <babeltrace/ctf-writer/field-types.h>
34 #include <babeltrace/ctf-writer/fields-internal.h>
35 #include <babeltrace/ctf-writer/trace-internal.h>
36 #include <babeltrace/ctf-writer/event-internal.h>
37 #include <babeltrace/compiler-internal.h>
38 #include <babeltrace/assert-internal.h>
39 #include <babeltrace/assert-pre-internal.h>
45 void bt_ctf_stream_destroy(struct bt_object
*obj
);
48 int try_set_structure_field_integer(struct bt_ctf_field
*, char *, uint64_t);
51 int set_integer_field_value(struct bt_ctf_field
* field
, uint64_t value
)
54 struct bt_ctf_field_type
*field_type
= NULL
;
57 BT_LOGW_STR("Invalid parameter: field is NULL.");
62 field_type
= bt_ctf_field_get_type(field
);
63 BT_ASSERT(field_type
);
65 if (bt_ctf_field_type_get_type_id(field_type
) !=
66 BT_CTF_FIELD_TYPE_ID_INTEGER
) {
67 /* Not an integer and the value is unset, error. */
68 BT_LOGW("Invalid parameter: field's type is not an integer field type: "
69 "field-addr=%p, ft-addr=%p, ft-id=%s",
71 bt_common_field_type_id_string((int)
72 bt_ctf_field_type_get_type_id(field_type
)));
77 if (bt_ctf_field_type_integer_is_signed(field_type
)) {
78 ret
= bt_ctf_field_integer_signed_set_value(field
, (int64_t) value
);
80 /* Value is out of range, error. */
81 BT_LOGW("Cannot set signed integer field's value: "
82 "addr=%p, value=%" PRId64
,
83 field
, (int64_t) value
);
87 ret
= bt_ctf_field_integer_unsigned_set_value(field
, value
);
89 /* Value is out of range, error. */
90 BT_LOGW("Cannot set unsigned integer field's value: "
91 "addr=%p, value=%" PRIu64
,
102 int set_packet_header_magic(struct bt_ctf_stream
*stream
)
105 struct bt_ctf_field
*magic_field
= bt_ctf_field_structure_get_field_by_name(
106 stream
->packet_header
, "magic");
107 const uint32_t magic_value
= 0xc1fc1fc1;
112 /* No magic field found. Not an error, skip. */
113 BT_LOGV("No field named `magic` in packet header: skipping: "
114 "stream-addr=%p, stream-name=\"%s\"",
115 stream
, bt_ctf_stream_get_name(stream
));
119 ret
= bt_ctf_field_integer_unsigned_set_value(magic_field
,
120 (uint64_t) magic_value
);
123 BT_LOGW("Cannot set packet header field's `magic` integer field's value: "
124 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64
,
125 stream
, bt_ctf_stream_get_name(stream
),
126 magic_field
, (uint64_t) magic_value
);
128 BT_LOGV("Set packet header field's `magic` field's value: "
129 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64
,
130 stream
, bt_ctf_stream_get_name(stream
),
131 magic_field
, (uint64_t) magic_value
);
139 int set_packet_header_uuid(struct bt_ctf_stream
*stream
)
143 struct bt_ctf_trace
*trace
= NULL
;
144 struct bt_ctf_field
*uuid_field
= bt_ctf_field_structure_get_field_by_name(
145 stream
->packet_header
, "uuid");
150 /* No uuid field found. Not an error, skip. */
151 BT_LOGV("No field named `uuid` in packet header: skipping: "
152 "stream-addr=%p, stream-name=\"%s\"",
153 stream
, bt_ctf_stream_get_name(stream
));
157 trace
= (struct bt_ctf_trace
*)
158 bt_object_get_parent(&stream
->common
.base
);
160 for (i
= 0; i
< 16; i
++) {
161 struct bt_ctf_field
*uuid_element
=
162 bt_ctf_field_array_get_field(uuid_field
, i
);
164 ret
= bt_ctf_field_integer_unsigned_set_value(
165 uuid_element
, (uint64_t) trace
->common
.uuid
[i
]);
166 bt_put(uuid_element
);
168 BT_LOGW("Cannot set integer field's value (for `uuid` packet header field): "
169 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
170 "value=%" PRIu64
", index=%" PRId64
,
171 stream
, bt_ctf_stream_get_name(stream
),
172 uuid_element
, (uint64_t) trace
->common
.uuid
[i
], i
);
177 BT_LOGV("Set packet header field's `uuid` field's value: "
178 "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
179 stream
, bt_ctf_stream_get_name(stream
), uuid_field
);
187 int set_packet_header_stream_id(struct bt_ctf_stream
*stream
)
191 struct bt_ctf_field
*stream_id_field
=
192 bt_ctf_field_structure_get_field_by_name(
193 stream
->packet_header
, "stream_id");
195 if (!stream_id_field
) {
196 /* No stream_id field found. Not an error, skip. */
197 BT_LOGV("No field named `stream_id` in packet header: skipping: "
198 "stream-addr=%p, stream-name=\"%s\"",
199 stream
, bt_ctf_stream_get_name(stream
));
203 stream_id
= stream
->common
.stream_class
->id
;
204 ret
= bt_ctf_field_integer_unsigned_set_value(stream_id_field
,
205 (uint64_t) stream_id
);
207 BT_LOGW("Cannot set packet header field's `stream_id` integer field's value: "
208 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64
,
209 stream
, bt_ctf_stream_get_name(stream
),
210 stream_id_field
, (uint64_t) stream_id
);
212 BT_LOGV("Set packet header field's `stream_id` field's value: "
213 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64
,
214 stream
, bt_ctf_stream_get_name(stream
),
215 stream_id_field
, (uint64_t) stream_id
);
219 bt_put(stream_id_field
);
224 int auto_populate_packet_header(struct bt_ctf_stream
*stream
)
228 if (!stream
->packet_header
) {
232 ret
= set_packet_header_magic(stream
);
234 BT_LOGW("Cannot set packet header's magic number field: "
235 "stream-addr=%p, stream-name=\"%s\"",
236 stream
, bt_ctf_stream_get_name(stream
));
240 ret
= set_packet_header_uuid(stream
);
242 BT_LOGW("Cannot set packet header's UUID field: "
243 "stream-addr=%p, stream-name=\"%s\"",
244 stream
, bt_ctf_stream_get_name(stream
));
248 ret
= set_packet_header_stream_id(stream
);
250 BT_LOGW("Cannot set packet header's stream class ID field: "
251 "stream-addr=%p, stream-name=\"%s\"",
252 stream
, bt_ctf_stream_get_name(stream
));
256 BT_LOGV("Automatically populated stream's packet header's known fields: "
257 "stream-addr=%p, stream-name=\"%s\"",
258 stream
, bt_ctf_stream_get_name(stream
));
265 int set_packet_context_packet_size(struct bt_ctf_stream
*stream
)
268 struct bt_ctf_field
*field
= bt_ctf_field_structure_get_field_by_name(
269 stream
->packet_context
, "packet_size");
274 /* No packet size field found. Not an error, skip. */
275 BT_LOGV("No field named `packet_size` in packet context: skipping: "
276 "stream-addr=%p, stream-name=\"%s\"",
277 stream
, bt_ctf_stream_get_name(stream
));
281 ret
= bt_ctf_field_integer_unsigned_set_value(field
,
282 stream
->pos
.packet_size
);
284 BT_LOGW("Cannot set packet context field's `packet_size` integer field's value: "
285 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64
,
286 stream
, bt_ctf_stream_get_name(stream
),
287 field
, stream
->pos
.packet_size
);
289 BT_LOGV("Set packet context field's `packet_size` field's value: "
290 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64
,
291 stream
, bt_ctf_stream_get_name(stream
),
292 field
, stream
->pos
.packet_size
);
301 int set_packet_context_content_size(struct bt_ctf_stream
*stream
)
304 struct bt_ctf_field
*field
= bt_ctf_field_structure_get_field_by_name(
305 stream
->packet_context
, "content_size");
310 /* No content size field found. Not an error, skip. */
311 BT_LOGV("No field named `content_size` in packet context: skipping: "
312 "stream-addr=%p, stream-name=\"%s\"",
313 stream
, bt_ctf_stream_get_name(stream
));
317 ret
= bt_ctf_field_integer_unsigned_set_value(field
,
320 BT_LOGW("Cannot set packet context field's `content_size` integer field's value: "
321 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRId64
,
322 stream
, bt_ctf_stream_get_name(stream
),
323 field
, stream
->pos
.offset
);
325 BT_LOGV("Set packet context field's `content_size` field's value: "
326 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRId64
,
327 stream
, bt_ctf_stream_get_name(stream
),
328 field
, stream
->pos
.offset
);
337 int set_packet_context_events_discarded(struct bt_ctf_stream
*stream
)
340 struct bt_ctf_field
*field
= bt_ctf_field_structure_get_field_by_name(
341 stream
->packet_context
, "events_discarded");
346 /* No discarded events count field found. Not an error, skip. */
347 BT_LOGV("No field named `events_discarded` in packet context: skipping: "
348 "stream-addr=%p, stream-name=\"%s\"",
349 stream
, bt_ctf_stream_get_name(stream
));
354 * If the field is set by the user, make sure that the value is
355 * greater than or equal to the stream's current count of
356 * discarded events. We do not allow wrapping here. If it's
357 * valid, update the stream's current count.
359 if (bt_ctf_field_is_set_recursive(field
)) {
362 ret
= bt_ctf_field_integer_unsigned_get_value(field
,
365 BT_LOGW("Cannot get packet context `events_discarded` field's unsigned value: "
366 "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
367 stream
, bt_ctf_stream_get_name(stream
), field
);
371 if (user_val
< stream
->discarded_events
) {
372 BT_LOGW("Invalid packet context `events_discarded` field's unsigned value: "
373 "value is lesser than the stream's current discarded events count: "
374 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
375 "value=%" PRIu64
", "
376 "stream-discarded-events-count=%" PRIu64
,
377 stream
, bt_ctf_stream_get_name(stream
), field
,
378 user_val
, stream
->discarded_events
);
382 stream
->discarded_events
= user_val
;
384 ret
= bt_ctf_field_integer_unsigned_set_value(field
,
385 stream
->discarded_events
);
387 BT_LOGW("Cannot set packet context field's `events_discarded` integer field's value: "
388 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64
,
389 stream
, bt_ctf_stream_get_name(stream
),
390 field
, stream
->discarded_events
);
392 BT_LOGV("Set packet context field's `events_discarded` field's value: "
393 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64
,
394 stream
, bt_ctf_stream_get_name(stream
),
395 field
, stream
->discarded_events
);
405 void update_clock_value(uint64_t *val
, uint64_t new_val
,
406 unsigned int new_val_size
)
408 const uint64_t pow2
= 1ULL << new_val_size
;
409 const uint64_t mask
= pow2
- 1;
412 #ifdef BT_LOG_ENABLED_VERBOSE
413 uint64_t old_val
= *val
;
416 if (new_val_size
== 64) {
421 val_masked
= *val
& mask
;
423 if (new_val
< val_masked
) {
432 BT_LOGV("Updated clock value: old-val=%" PRIu64
", new-val=%" PRIu64
,
438 int visit_field_update_clock_value(struct bt_ctf_field
*field
, uint64_t *val
)
441 struct bt_field_common
*field_common
= (void *) field
;
447 switch (bt_ctf_field_get_type_id(field
)) {
448 case BT_CTF_FIELD_TYPE_ID_INTEGER
:
450 struct bt_ctf_clock_class
*cc
=
451 bt_ctf_field_type_integer_get_mapped_clock_class(
452 (void *) field_common
->type
);
461 val_size
= bt_ctf_field_type_integer_get_size(
462 (void *) field_common
->type
);
463 BT_ASSERT(val_size
>= 1);
465 if (bt_ctf_field_type_integer_is_signed(
466 (void *) field_common
->type
)) {
469 ret
= bt_ctf_field_integer_signed_get_value(field
, &ival
);
470 uval
= (uint64_t) ival
;
472 ret
= bt_ctf_field_integer_unsigned_get_value(field
, &uval
);
480 update_clock_value(val
, uval
, val_size
);
483 case BT_CTF_FIELD_TYPE_ID_ENUM
:
485 struct bt_ctf_field
*int_field
=
486 bt_ctf_field_enumeration_get_container(field
);
488 BT_ASSERT(int_field
);
489 ret
= visit_field_update_clock_value(int_field
, val
);
493 case BT_CTF_FIELD_TYPE_ID_ARRAY
:
496 int64_t len
= bt_ctf_field_type_array_get_length(
497 (void *) field_common
->type
);
501 for (i
= 0; i
< len
; i
++) {
502 struct bt_ctf_field
*elem_field
=
503 bt_ctf_field_array_get_field(field
, i
);
505 BT_ASSERT(elem_field
);
506 ret
= visit_field_update_clock_value(elem_field
, val
);
514 case BT_CTF_FIELD_TYPE_ID_SEQUENCE
:
517 int64_t len
= bt_field_common_sequence_get_length(
525 for (i
= 0; i
< len
; i
++) {
526 struct bt_ctf_field
*elem_field
=
527 bt_ctf_field_sequence_get_field(field
, i
);
529 BT_ASSERT(elem_field
);
530 ret
= visit_field_update_clock_value(elem_field
, val
);
538 case BT_CTF_FIELD_TYPE_ID_STRUCT
:
541 int64_t len
= bt_ctf_field_type_structure_get_field_count(
542 (void *) field_common
->type
);
546 for (i
= 0; i
< len
; i
++) {
547 struct bt_ctf_field
*member_field
=
548 bt_ctf_field_structure_get_field_by_index(field
, i
);
550 BT_ASSERT(member_field
);
551 ret
= visit_field_update_clock_value(member_field
, val
);
552 bt_put(member_field
);
559 case BT_CTF_FIELD_TYPE_ID_VARIANT
:
561 struct bt_ctf_field
*cur_field
=
562 bt_ctf_field_variant_get_current_field(field
);
569 ret
= visit_field_update_clock_value(cur_field
, val
);
581 int visit_event_update_clock_value(struct bt_ctf_event
*event
, uint64_t *val
)
584 struct bt_ctf_field
*field
;
586 field
= bt_ctf_event_get_header(event
);
587 ret
= visit_field_update_clock_value(field
, val
);
590 BT_LOGW_STR("Cannot automatically update clock value in "
595 field
= bt_ctf_event_get_stream_event_context(event
);
596 ret
= visit_field_update_clock_value(field
, val
);
599 BT_LOGW_STR("Cannot automatically update clock value in "
600 "event's stream event context.");
604 field
= bt_ctf_event_get_context(event
);
605 ret
= visit_field_update_clock_value(field
, val
);
608 BT_LOGW_STR("Cannot automatically update clock value in "
613 field
= bt_ctf_event_get_payload_field(event
);
614 ret
= visit_field_update_clock_value(field
, val
);
617 BT_LOGW_STR("Cannot automatically update clock value in "
627 int set_packet_context_timestamps(struct bt_ctf_stream
*stream
)
631 uint64_t cur_clock_value
;
632 uint64_t init_clock_value
= 0;
633 struct bt_ctf_field
*ts_begin_field
= bt_ctf_field_structure_get_field_by_name(
634 stream
->packet_context
, "timestamp_begin");
635 struct bt_ctf_field
*ts_end_field
= bt_ctf_field_structure_get_field_by_name(
636 stream
->packet_context
, "timestamp_end");
637 struct bt_field_common
*packet_context
=
638 (void *) stream
->packet_context
;
642 if (ts_begin_field
&& bt_ctf_field_is_set_recursive(ts_begin_field
)) {
643 /* Use provided `timestamp_begin` value as starting value */
644 ret
= bt_ctf_field_integer_unsigned_get_value(ts_begin_field
, &val
);
646 init_clock_value
= val
;
647 } else if (stream
->last_ts_end
!= -1ULL) {
648 /* Use last packet's ending timestamp as starting value */
649 init_clock_value
= stream
->last_ts_end
;
652 cur_clock_value
= init_clock_value
;
654 if (stream
->last_ts_end
!= -1ULL &&
655 cur_clock_value
< stream
->last_ts_end
) {
656 BT_LOGW("Packet's initial timestamp is less than previous "
657 "packet's final timestamp: "
658 "stream-addr=%p, stream-name=\"%s\", "
659 "cur-packet-ts-begin=%" PRIu64
", "
660 "prev-packet-ts-end=%" PRIu64
,
661 stream
, bt_ctf_stream_get_name(stream
),
662 cur_clock_value
, stream
->last_ts_end
);
668 * Visit all the packet context fields, followed by all the
669 * fields of all the events, in order, updating our current
670 * clock value as we visit.
672 * While visiting the packet context fields, do not consider
673 * `timestamp_begin` and `timestamp_end` because this function's
674 * purpose is to set them anyway. Also do not consider
675 * `packet_size`, `content_size`, `events_discarded`, and
676 * `packet_seq_num` if they are not set because those are
677 * autopopulating fields.
679 len
= bt_ctf_field_type_structure_get_field_count(
680 (void *) packet_context
->type
);
683 for (i
= 0; i
< len
; i
++) {
684 const char *member_name
;
685 struct bt_ctf_field
*member_field
;
687 ret
= bt_ctf_field_type_structure_get_field_by_index(
688 (void *) packet_context
->type
, &member_name
, NULL
, i
);
691 if (strcmp(member_name
, "timestamp_begin") == 0 ||
692 strcmp(member_name
, "timestamp_end") == 0) {
696 member_field
= bt_ctf_field_structure_get_field_by_index(
697 stream
->packet_context
, i
);
698 BT_ASSERT(member_field
);
700 if (strcmp(member_name
, "packet_size") == 0 &&
701 !bt_ctf_field_is_set_recursive(member_field
)) {
702 bt_put(member_field
);
706 if (strcmp(member_name
, "content_size") == 0 &&
707 !bt_ctf_field_is_set_recursive(member_field
)) {
708 bt_put(member_field
);
712 if (strcmp(member_name
, "events_discarded") == 0 &&
713 !bt_ctf_field_is_set_recursive(member_field
)) {
714 bt_put(member_field
);
718 if (strcmp(member_name
, "packet_seq_num") == 0 &&
719 !bt_ctf_field_is_set_recursive(member_field
)) {
720 bt_put(member_field
);
724 ret
= visit_field_update_clock_value(member_field
,
726 bt_put(member_field
);
728 BT_LOGW("Cannot automatically update clock value "
729 "in stream's packet context: "
730 "stream-addr=%p, stream-name=\"%s\", "
732 stream
, bt_ctf_stream_get_name(stream
),
738 for (i
= 0; i
< stream
->events
->len
; i
++) {
739 struct bt_ctf_event
*event
= g_ptr_array_index(stream
->events
, i
);
742 ret
= visit_event_update_clock_value(event
, &cur_clock_value
);
744 BT_LOGW("Cannot automatically update clock value "
745 "in stream's packet context: "
746 "stream-addr=%p, stream-name=\"%s\", "
747 "index=%" PRIu64
", event-addr=%p, "
748 "event-class-id=%" PRId64
", "
749 "event-class-name=\"%s\"",
750 stream
, bt_ctf_stream_get_name(stream
),
752 bt_event_class_common_get_id(event
->common
.class),
753 bt_event_class_common_get_name(event
->common
.class));
759 * Everything is visited, thus the current clock value
760 * corresponds to the ending timestamp. Validate this value
761 * against the provided value of `timestamp_end`, if any,
764 if (ts_end_field
&& bt_ctf_field_is_set_recursive(ts_end_field
)) {
765 ret
= bt_ctf_field_integer_unsigned_get_value(ts_end_field
, &val
);
768 if (val
< cur_clock_value
) {
769 BT_LOGW("Packet's final timestamp is less than "
770 "computed packet's final timestamp: "
771 "stream-addr=%p, stream-name=\"%s\", "
772 "cur-packet-ts-end=%" PRIu64
", "
773 "computed-packet-ts-end=%" PRIu64
,
774 stream
, bt_ctf_stream_get_name(stream
),
775 val
, cur_clock_value
);
780 stream
->last_ts_end
= val
;
783 if (ts_end_field
&& !bt_ctf_field_is_set_recursive(ts_end_field
)) {
784 ret
= set_integer_field_value(ts_end_field
, cur_clock_value
);
786 stream
->last_ts_end
= cur_clock_value
;
790 stream
->last_ts_end
= cur_clock_value
;
793 /* Set `timestamp_begin` field to initial clock value */
794 if (ts_begin_field
&& !bt_ctf_field_is_set_recursive(ts_begin_field
)) {
795 ret
= set_integer_field_value(ts_begin_field
, init_clock_value
);
800 bt_put(ts_begin_field
);
801 bt_put(ts_end_field
);
806 int auto_populate_packet_context(struct bt_ctf_stream
*stream
, bool set_ts
)
810 if (!stream
->packet_context
) {
814 ret
= set_packet_context_packet_size(stream
);
816 BT_LOGW("Cannot set packet context's packet size field: "
817 "stream-addr=%p, stream-name=\"%s\"",
818 stream
, bt_ctf_stream_get_name(stream
));
822 ret
= set_packet_context_content_size(stream
);
824 BT_LOGW("Cannot set packet context's content size field: "
825 "stream-addr=%p, stream-name=\"%s\"",
826 stream
, bt_ctf_stream_get_name(stream
));
831 ret
= set_packet_context_timestamps(stream
);
833 BT_LOGW("Cannot set packet context's timestamp fields: "
834 "stream-addr=%p, stream-name=\"%s\"",
835 stream
, bt_ctf_stream_get_name(stream
));
840 ret
= set_packet_context_events_discarded(stream
);
842 BT_LOGW("Cannot set packet context's discarded events count field: "
843 "stream-addr=%p, stream-name=\"%s\"",
844 stream
, bt_ctf_stream_get_name(stream
));
848 BT_LOGV("Automatically populated stream's packet context's known fields: "
849 "stream-addr=%p, stream-name=\"%s\"",
850 stream
, bt_ctf_stream_get_name(stream
));
857 void release_event(struct bt_ctf_event
*event
)
859 if (bt_object_get_ref_count(&event
->common
.base
)) {
861 * The event is being orphaned, but it must guarantee the
862 * existence of its event class for the duration of its
865 bt_get(event
->common
.class);
866 BT_PUT(event
->common
.base
.parent
);
868 bt_object_try_spec_release(&event
->common
.base
);
873 int create_stream_file(struct bt_ctf_writer
*writer
,
874 struct bt_ctf_stream
*stream
)
877 GString
*filename
= g_string_new(NULL
);
878 int64_t stream_class_id
;
879 char *file_path
= NULL
;
881 BT_LOGD("Creating stream file: writer-addr=%p, stream-addr=%p, "
882 "stream-name=\"%s\", stream-class-addr=%p, stream-class-name=\"%s\"",
883 writer
, stream
, bt_ctf_stream_get_name(stream
),
884 stream
->common
.stream_class
,
885 stream
->common
.stream_class
->name
->str
);
887 if (stream
->common
.name
&& stream
->common
.name
->len
> 0) {
888 /* Use stream name's base name as prefix */
889 gchar
*basename
= g_path_get_basename(stream
->common
.name
->str
);
893 if (strcmp(basename
, G_DIR_SEPARATOR_S
) == 0) {
894 g_string_assign(filename
, "stream");
896 g_string_assign(filename
, basename
);
903 if (stream
->common
.stream_class
->name
&&
904 stream
->common
.stream_class
->name
->len
> 0) {
905 /* Use stream class name's base name as prefix */
908 stream
->common
.stream_class
->name
->str
);
912 if (strcmp(basename
, G_DIR_SEPARATOR_S
) == 0) {
913 g_string_assign(filename
, "stream");
915 g_string_assign(filename
, basename
);
922 /* Default to using `stream-` as prefix */
923 g_string_assign(filename
, "stream");
926 stream_class_id
= bt_stream_class_common_get_id(stream
->common
.stream_class
);
927 BT_ASSERT(stream_class_id
>= 0);
928 BT_ASSERT(stream
->common
.id
>= 0);
929 g_string_append_printf(filename
, "-%" PRId64
"-%" PRId64
,
930 stream_class_id
, stream
->common
.id
);
932 file_path
= g_build_filename(writer
->path
->str
, filename
->str
, NULL
);
933 if (file_path
== NULL
) {
939 O_RDWR
| O_CREAT
| O_TRUNC
,
940 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IWGRP
);
943 BT_LOGW_ERRNO("Failed to open stream file for writing",
944 ": file_path=\"%s\", filename=\"%s\", ret=%d",
945 file_path
, filename
->str
, fd
);
949 BT_LOGD("Created stream file for writing: "
950 "stream-addr=%p, stream-name=\"%s\", "
951 "filename=\"%s\", fd=%d", stream
, bt_ctf_stream_get_name(stream
),
955 g_string_free(filename
, TRUE
);
960 void set_stream_fd(struct bt_ctf_stream
*stream
, int fd
)
962 (void) bt_ctf_stream_pos_init(&stream
->pos
, fd
, O_RDWR
);
967 struct bt_ctf_stream
*bt_ctf_stream_create_with_id(
968 struct bt_ctf_stream_class
*stream_class
,
969 const char *name
, uint64_t id
)
973 struct bt_ctf_stream
*stream
= NULL
;
974 struct bt_ctf_trace
*trace
= NULL
;
975 struct bt_ctf_writer
*writer
= NULL
;
977 BT_LOGD("Creating CTF writer stream object: stream-class-addr=%p, "
978 "stream-class-name=\"%s\", stream-name=\"%s\", "
979 "stream-id=%" PRIu64
,
980 stream_class
, bt_ctf_stream_class_get_name(stream_class
),
982 stream
= g_new0(struct bt_ctf_stream
, 1);
984 BT_LOGE_STR("Failed to allocate one stream.");
989 id
= stream_class
->next_stream_id
;
992 ret
= bt_stream_common_initialize(BT_TO_COMMON(stream
),
993 BT_TO_COMMON(stream_class
), name
, id
, bt_ctf_stream_destroy
);
995 /* bt_stream_common_initialize() logs errors */
999 trace
= BT_FROM_COMMON(bt_stream_class_common_borrow_trace(
1000 BT_TO_COMMON(stream_class
)));
1002 BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: "
1003 "stream-class-addr=%p, stream-class-name=\"%s\", "
1004 "stream-name=\"%s\"",
1005 stream_class
, bt_ctf_stream_class_get_name(stream_class
),
1010 stream
->pos
.fd
= -1;
1011 writer
= (struct bt_ctf_writer
*)
1012 bt_object_get_parent(&trace
->common
.base
);
1013 stream
->last_ts_end
= -1ULL;
1014 BT_LOGD("CTF writer stream object belongs writer's trace: "
1015 "writer-addr=%p", writer
);
1018 if (stream_class
->common
.packet_context_field_type
) {
1019 BT_LOGD("Creating stream's packet context field: "
1021 stream_class
->common
.packet_context_field_type
);
1022 stream
->packet_context
= bt_ctf_field_create(
1023 (void *) stream_class
->common
.packet_context_field_type
);
1024 if (!stream
->packet_context
) {
1025 BT_LOGW_STR("Cannot create stream's packet context field.");
1029 /* Initialize events_discarded */
1030 ret
= try_set_structure_field_integer(
1031 stream
->packet_context
, "events_discarded", 0);
1033 BT_LOGW("Cannot set `events_discarded` field in packet context: "
1034 "ret=%d, packet-context-field-addr=%p",
1035 ret
, stream
->packet_context
);
1040 stream
->events
= g_ptr_array_new_with_free_func(
1041 (GDestroyNotify
) release_event
);
1042 if (!stream
->events
) {
1043 BT_LOGE_STR("Failed to allocate a GPtrArray.");
1047 if (trace
->common
.packet_header_field_type
) {
1048 BT_LOGD("Creating stream's packet header field: "
1049 "ft-addr=%p", trace
->common
.packet_header_field_type
);
1050 stream
->packet_header
=
1051 bt_ctf_field_create(
1052 (void *) trace
->common
.packet_header_field_type
);
1053 if (!stream
->packet_header
) {
1054 BT_LOGW_STR("Cannot create stream's packet header field.");
1060 * Attempt to populate the default trace packet header fields
1061 * (magic, uuid and stream_id). This will _not_ fail shall the
1062 * fields not be found or be of an incompatible type; they will
1063 * simply not be populated automatically. The user will have to
1064 * make sure to set the trace packet header fields himself
1067 ret
= auto_populate_packet_header(stream
);
1069 BT_LOGW_STR("Cannot automatically populate the stream's packet header.");
1073 /* Create file associated with this stream */
1074 fd
= create_stream_file(writer
, stream
);
1076 BT_LOGW_STR("Cannot create stream file.");
1080 set_stream_fd(stream
, fd
);
1082 /* Freeze the writer */
1083 BT_LOGD_STR("Freezing stream's CTF writer.");
1084 bt_ctf_writer_freeze(writer
);
1086 /* Add this stream to the trace's streams */
1087 g_ptr_array_add(trace
->common
.streams
, stream
);
1088 stream_class
->next_stream_id
++;
1089 BT_LOGD("Created stream object: addr=%p", stream
);
1100 struct bt_ctf_stream
*bt_ctf_stream_create(
1101 struct bt_ctf_stream_class
*stream_class
,
1102 const char *name
, uint64_t id_param
)
1104 return bt_ctf_stream_create_with_id(stream_class
,
1108 int bt_ctf_stream_get_discarded_events_count(
1109 struct bt_ctf_stream
*stream
, uint64_t *count
)
1114 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1120 BT_LOGW_STR("Invalid parameter: count is NULL.");
1125 if (stream
->pos
.fd
< 0) {
1126 BT_LOGW("Invalid parameter: stream is not a CTF writer stream: "
1127 "stream-addr=%p, stream-name=\"%s\"",
1128 stream
, bt_ctf_stream_get_name(stream
));
1133 *count
= (uint64_t) stream
->discarded_events
;
1140 int set_packet_context_events_discarded_field(struct bt_ctf_stream
*stream
,
1144 struct bt_ctf_field
*events_discarded_field
= NULL
;
1146 if (!stream
->packet_context
) {
1150 events_discarded_field
= bt_ctf_field_structure_get_field_by_name(
1151 stream
->packet_context
, "events_discarded");
1152 if (!events_discarded_field
) {
1156 ret
= bt_ctf_field_integer_unsigned_set_value(
1157 events_discarded_field
, count
);
1159 BT_LOGW("Cannot set packet context's `events_discarded` field: "
1160 "field-addr=%p, value=%" PRIu64
,
1161 events_discarded_field
, count
);
1166 bt_put(events_discarded_field
);
1170 void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream
*stream
,
1171 uint64_t event_count
)
1175 struct bt_ctf_field
*events_discarded_field
= NULL
;
1178 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1182 BT_LOGV("Appending discarded events to stream: "
1183 "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64
,
1184 stream
, bt_ctf_stream_get_name(stream
), event_count
);
1186 if (!stream
->packet_context
) {
1187 BT_LOGW_STR("Invalid parameter: stream has no packet context field.");
1191 if (stream
->pos
.fd
< 0) {
1192 BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
1196 events_discarded_field
= bt_ctf_field_structure_get_field_by_name(
1197 stream
->packet_context
, "events_discarded");
1198 if (!events_discarded_field
) {
1199 BT_LOGW_STR("No field named `events_discarded` in stream's packet context.");
1203 new_count
= stream
->discarded_events
+ event_count
;
1204 if (new_count
< stream
->discarded_events
) {
1205 BT_LOGW("New discarded events count is less than the stream's current discarded events count: "
1206 "cur-count=%" PRIu64
", new-count=%" PRIu64
,
1207 stream
->discarded_events
, new_count
);
1211 ret
= set_packet_context_events_discarded_field(stream
, new_count
);
1213 /* set_packet_context_events_discarded_field() logs errors */
1217 stream
->discarded_events
= new_count
;
1218 BT_LOGV("Appended discarded events to stream: "
1219 "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64
,
1220 stream
, bt_ctf_stream_get_name(stream
), event_count
);
1223 bt_put(events_discarded_field
);
1226 static int auto_populate_event_header(struct bt_ctf_stream
*stream
,
1227 struct bt_ctf_event
*event
)
1230 struct bt_ctf_field
*id_field
= NULL
, *timestamp_field
= NULL
;
1231 struct bt_ctf_clock_class
*mapped_clock_class
= NULL
;
1232 struct bt_ctf_stream_class
*stream_class
=
1233 BT_FROM_COMMON(bt_stream_common_borrow_class(
1234 BT_TO_COMMON(stream
)));
1235 int64_t event_class_id
;
1239 if (!event
->common
.header_field
) {
1243 if (event
->common
.frozen
) {
1244 BT_LOGW_STR("Cannot populate event header field: event is frozen.");
1249 BT_LOGV("Automatically populating event's header field: "
1250 "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
1251 stream
, bt_ctf_stream_get_name(stream
), event
);
1253 id_field
= bt_ctf_field_structure_get_field_by_name(
1254 (void *) event
->common
.header_field
->field
, "id");
1255 event_class_id
= bt_event_class_common_get_id(event
->common
.class);
1256 BT_ASSERT(event_class_id
>= 0);
1258 if (id_field
&& bt_ctf_field_get_type_id(id_field
) == BT_CTF_FIELD_TYPE_ID_INTEGER
) {
1259 ret
= set_integer_field_value(id_field
, event_class_id
);
1261 BT_LOGW("Cannot set event header's `id` field's value: "
1262 "addr=%p, value=%" PRIu64
, id_field
,
1269 * The conditions to automatically set the timestamp are:
1271 * 1. The event header field "timestamp" exists and is an
1273 * 2. This stream's class has a registered clock (set with
1274 * bt_ctf_stream_class_set_clock()).
1275 * 3. The "timestamp" field is not set.
1277 timestamp_field
= bt_ctf_field_structure_get_field_by_name(
1278 (void *) event
->common
.header_field
->field
, "timestamp");
1279 if (timestamp_field
&& stream_class
->clock
&&
1280 bt_ctf_field_get_type_id(id_field
) == BT_CTF_FIELD_TYPE_ID_INTEGER
&&
1281 !bt_ctf_field_is_set_recursive(timestamp_field
)) {
1282 mapped_clock_class
=
1283 bt_ctf_field_type_integer_get_mapped_clock_class(
1284 (void *) ((struct bt_field_common
*) timestamp_field
)->type
);
1285 if (mapped_clock_class
) {
1288 BT_ASSERT(mapped_clock_class
==
1289 stream_class
->clock
->clock_class
);
1290 ret
= bt_ctf_clock_get_value(
1291 stream_class
->clock
,
1293 BT_ASSERT(ret
== 0);
1294 ret
= set_integer_field_value(timestamp_field
,
1297 BT_LOGW("Cannot set event header's `timestamp` field's value: "
1298 "addr=%p, value=%" PRIu64
,
1299 timestamp_field
, timestamp
);
1305 BT_LOGV("Automatically populated event's header field: "
1306 "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
1307 stream
, bt_ctf_stream_get_name(stream
), event
);
1311 bt_put(timestamp_field
);
1312 bt_put(mapped_clock_class
);
1316 int bt_ctf_stream_append_event(struct bt_ctf_stream
*stream
,
1317 struct bt_ctf_event
*event
)
1322 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1328 BT_LOGW_STR("Invalid parameter: event is NULL.");
1333 if (stream
->pos
.fd
< 0) {
1334 BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
1339 BT_LOGV("Appending event to stream: "
1340 "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
1341 "event-class-name=\"%s\", event-class-id=%" PRId64
,
1342 stream
, bt_ctf_stream_get_name(stream
), event
,
1343 bt_event_class_common_get_name(
1344 bt_event_common_borrow_class(BT_TO_COMMON(event
))),
1345 bt_event_class_common_get_id(
1346 bt_event_common_borrow_class(BT_TO_COMMON(event
))));
1349 * The event is not supposed to have a parent stream at this
1350 * point. The only other way an event can have a parent stream
1351 * is if it was assigned when setting a packet to the event,
1352 * in which case the packet's stream is not a writer stream,
1353 * and thus the user is trying to append an event which belongs
1354 * to another stream.
1356 if (event
->common
.base
.parent
) {
1361 bt_object_set_parent(&event
->common
.base
, &stream
->common
.base
);
1362 BT_LOGV_STR("Automatically populating the header of the event to append.");
1363 ret
= auto_populate_event_header(stream
, event
);
1365 /* auto_populate_event_header() reports errors */
1369 /* Make sure the various scopes of the event are set */
1370 BT_LOGV_STR("Validating event to append.");
1371 BT_ASSERT_PRE(bt_event_common_validate(BT_TO_COMMON(event
)) == 0,
1372 "Invalid event: %!+we", event
);
1374 /* Save the new event and freeze it */
1375 BT_LOGV_STR("Freezing the event to append.");
1376 bt_event_common_set_is_frozen(BT_TO_COMMON(event
), true);
1377 g_ptr_array_add(stream
->events
, event
);
1380 * Event had to hold a reference to its event class as long as it wasn't
1381 * part of the same trace hierarchy. From now on, the event and its
1382 * class share the same lifetime guarantees and the reference is no
1385 BT_LOGV_STR("Putting the event's class.");
1386 bt_put(event
->common
.class);
1387 BT_LOGV("Appended event to stream: "
1388 "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
1389 "event-class-name=\"%s\", event-class-id=%" PRId64
,
1390 stream
, bt_ctf_stream_get_name(stream
), event
,
1391 bt_event_class_common_get_name(
1392 bt_event_common_borrow_class(BT_TO_COMMON(event
))),
1393 bt_event_class_common_get_id(
1394 bt_event_common_borrow_class(BT_TO_COMMON(event
))));
1401 * Orphan the event; we were not successful in associating it to
1404 bt_object_set_parent(&event
->common
.base
, NULL
);
1408 struct bt_ctf_field
*bt_ctf_stream_get_packet_context(struct bt_ctf_stream
*stream
)
1410 struct bt_ctf_field
*packet_context
= NULL
;
1413 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1417 if (stream
->pos
.fd
< 0) {
1418 BT_LOGW("Invalid parameter: stream is not a CTF writer stream: "
1419 "stream-addr=%p, stream-name=\"%s\"", stream
,
1420 bt_ctf_stream_get_name(stream
));
1424 packet_context
= stream
->packet_context
;
1425 if (packet_context
) {
1426 bt_get(packet_context
);
1429 return packet_context
;
1432 int bt_ctf_stream_set_packet_context(struct bt_ctf_stream
*stream
,
1433 struct bt_ctf_field
*field
)
1436 struct bt_ctf_field_type
*field_type
;
1439 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1444 if (stream
->pos
.fd
< 0) {
1445 BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
1450 field_type
= bt_ctf_field_get_type(field
);
1451 if (bt_field_type_common_compare((void *) field_type
,
1452 stream
->common
.stream_class
->packet_context_field_type
)) {
1453 BT_LOGW("Invalid parameter: packet context's field type is different from the stream's packet context field type: "
1454 "stream-addr=%p, stream-name=\"%s\", "
1455 "packet-context-field-addr=%p, "
1456 "packet-context-ft-addr=%p",
1457 stream
, bt_ctf_stream_get_name(stream
),
1464 bt_put(stream
->packet_context
);
1465 stream
->packet_context
= bt_get(field
);
1466 BT_LOGV("Set stream's packet context field: "
1467 "stream-addr=%p, stream-name=\"%s\", "
1468 "packet-context-field-addr=%p",
1469 stream
, bt_ctf_stream_get_name(stream
), field
);
1474 struct bt_ctf_field
*bt_ctf_stream_get_packet_header(struct bt_ctf_stream
*stream
)
1476 struct bt_ctf_field
*packet_header
= NULL
;
1479 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1483 if (stream
->pos
.fd
< 0) {
1484 BT_LOGW("Invalid parameter: stream is not a CTF writer stream: "
1485 "stream-addr=%p, stream-name=\"%s\"", stream
,
1486 bt_ctf_stream_get_name(stream
));
1490 packet_header
= stream
->packet_header
;
1491 if (packet_header
) {
1492 bt_get(packet_header
);
1495 return packet_header
;
1498 int bt_ctf_stream_set_packet_header(struct bt_ctf_stream
*stream
,
1499 struct bt_ctf_field
*field
)
1502 struct bt_ctf_trace
*trace
= NULL
;
1503 struct bt_ctf_field_type
*field_type
= NULL
;
1506 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1511 if (stream
->pos
.fd
< 0) {
1512 BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
1517 trace
= (struct bt_ctf_trace
*)
1518 bt_object_get_parent(&stream
->common
.base
);
1521 if (trace
->common
.packet_header_field_type
) {
1522 BT_LOGW("Invalid parameter: setting no packet header but packet header field type is not NULL: "
1523 "stream-addr=%p, stream-name=\"%s\", "
1524 "packet-header-field-addr=%p, "
1525 "expected-ft-addr=%p",
1526 stream
, bt_ctf_stream_get_name(stream
),
1527 field
, trace
->common
.packet_header_field_type
);
1532 goto skip_validation
;
1535 field_type
= bt_ctf_field_get_type(field
);
1536 BT_ASSERT(field_type
);
1538 if (bt_field_type_common_compare((void *) field_type
,
1539 trace
->common
.packet_header_field_type
)) {
1540 BT_LOGW("Invalid parameter: packet header's field type is different from the stream's packet header field type: "
1541 "stream-addr=%p, stream-name=\"%s\", "
1542 "packet-header-field-addr=%p, "
1543 "packet-header-ft-addr=%p",
1544 stream
, bt_ctf_stream_get_name(stream
),
1551 bt_put(stream
->packet_header
);
1552 stream
->packet_header
= bt_get(field
);
1553 BT_LOGV("Set stream's packet header field: "
1554 "stream-addr=%p, stream-name=\"%s\", "
1555 "packet-header-field-addr=%p",
1556 stream
, bt_ctf_stream_get_name(stream
), field
);
1564 void reset_structure_field(struct bt_ctf_field
*structure
, const char *name
)
1566 struct bt_ctf_field
*member
;
1568 member
= bt_ctf_field_structure_get_field_by_name(structure
, name
);
1570 bt_field_common_reset_recursive((void *) member
);
1575 int bt_ctf_stream_flush(struct bt_ctf_stream
*stream
)
1579 struct bt_ctf_stream_pos packet_context_pos
;
1580 struct bt_ctf_trace
*trace
;
1581 enum bt_ctf_byte_order native_byte_order
;
1582 bool has_packet_size
= false;
1585 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1590 if (stream
->pos
.fd
< 0) {
1591 BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
1596 if (stream
->packet_context
) {
1597 struct bt_ctf_field
*packet_size_field
;
1599 packet_size_field
= bt_ctf_field_structure_get_field_by_name(
1600 stream
->packet_context
, "packet_size");
1601 has_packet_size
= (packet_size_field
!= NULL
);
1602 bt_put(packet_size_field
);
1605 if (stream
->flushed_packet_count
== 1) {
1606 if (!stream
->packet_context
) {
1607 BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once.");
1612 if (!has_packet_size
) {
1613 BT_LOGW_STR("Cannot flush a stream which has no packet context's `packet_size` field more than once.");
1619 BT_LOGV("Flushing stream's current packet: stream-addr=%p, "
1620 "stream-name=\"%s\", packet-index=%u", stream
,
1621 bt_ctf_stream_get_name(stream
), stream
->flushed_packet_count
);
1622 trace
= BT_FROM_COMMON(bt_stream_class_common_borrow_trace(
1623 stream
->common
.stream_class
));
1625 native_byte_order
= bt_ctf_trace_get_native_byte_order(trace
);
1627 ret
= auto_populate_packet_header(stream
);
1629 BT_LOGW_STR("Cannot automatically populate the stream's packet header field.");
1634 ret
= auto_populate_packet_context(stream
, true);
1636 BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
1641 /* mmap the next packet */
1642 BT_LOGV("Seeking to the next packet: pos-offset=%" PRId64
,
1643 stream
->pos
.offset
);
1644 bt_ctf_stream_pos_packet_seek(&stream
->pos
, 0, SEEK_CUR
);
1645 BT_ASSERT(stream
->pos
.packet_size
% 8 == 0);
1647 if (stream
->packet_header
) {
1648 BT_LOGV_STR("Serializing packet header field.");
1649 ret
= bt_ctf_field_serialize_recursive(stream
->packet_header
,
1650 &stream
->pos
, native_byte_order
);
1652 BT_LOGW("Cannot serialize stream's packet header field: "
1653 "field-addr=%p", stream
->packet_header
);
1658 if (stream
->packet_context
) {
1659 /* Write packet context */
1660 memcpy(&packet_context_pos
, &stream
->pos
,
1661 sizeof(packet_context_pos
));
1662 BT_LOGV_STR("Serializing packet context field.");
1663 ret
= bt_ctf_field_serialize_recursive(stream
->packet_context
,
1664 &stream
->pos
, native_byte_order
);
1666 BT_LOGW("Cannot serialize stream's packet context field: "
1667 "field-addr=%p", stream
->packet_context
);
1672 BT_LOGV("Serializing events: count=%u", stream
->events
->len
);
1674 for (i
= 0; i
< stream
->events
->len
; i
++) {
1675 struct bt_ctf_event
*event
= g_ptr_array_index(
1677 struct bt_ctf_event_class
*event_class
=
1678 BT_FROM_COMMON(bt_event_common_borrow_class(
1679 BT_TO_COMMON(event
)));
1681 BT_LOGV("Serializing event: index=%zu, event-addr=%p, "
1682 "event-class-name=\"%s\", event-class-id=%" PRId64
", "
1683 "pos-offset=%" PRId64
", packet-size=%" PRIu64
,
1684 i
, event
, bt_ctf_event_class_get_name(event_class
),
1685 bt_ctf_event_class_get_id(event_class
),
1686 stream
->pos
.offset
, stream
->pos
.packet_size
);
1688 /* Write event header */
1689 if (event
->common
.header_field
) {
1690 BT_LOGV_STR("Serializing event's header field.");
1691 ret
= bt_ctf_field_serialize_recursive(
1692 (void *) event
->common
.header_field
->field
,
1693 &stream
->pos
, native_byte_order
);
1695 BT_LOGW("Cannot serialize event's header field: "
1697 event
->common
.header_field
->field
);
1702 /* Write stream event context */
1703 if (event
->common
.stream_event_context_field
) {
1704 BT_LOGV_STR("Serializing event's stream event context field.");
1705 ret
= bt_ctf_field_serialize_recursive(
1706 (void *) event
->common
.stream_event_context_field
,
1707 &stream
->pos
, native_byte_order
);
1709 BT_LOGW("Cannot serialize event's stream event context field: "
1711 event
->common
.stream_event_context_field
);
1716 /* Write event content */
1717 ret
= bt_ctf_event_serialize(event
,
1718 &stream
->pos
, native_byte_order
);
1720 /* bt_ctf_event_serialize() logs errors */
1725 if (!has_packet_size
&& stream
->pos
.offset
% 8 != 0) {
1726 BT_LOGW("Stream's packet context field type has no `packet_size` field, "
1727 "but current content size is not a multiple of 8 bits: "
1728 "content-size=%" PRId64
", "
1729 "packet-size=%" PRIu64
,
1731 stream
->pos
.packet_size
);
1736 BT_ASSERT(stream
->pos
.packet_size
% 8 == 0);
1739 * Remove extra padding bytes.
1741 stream
->pos
.packet_size
= (stream
->pos
.offset
+ 7) & ~7;
1743 if (stream
->packet_context
) {
1745 * The whole packet is serialized at this point. Make sure that,
1746 * if `packet_size` is missing, the current content size is
1747 * equal to the current packet size.
1749 struct bt_ctf_field
*field
= bt_ctf_field_structure_get_field_by_name(
1750 stream
->packet_context
, "content_size");
1754 if (stream
->pos
.offset
!= stream
->pos
.packet_size
) {
1755 BT_LOGW("Stream's packet context's `content_size` field is missing, "
1756 "but current packet's content size is not equal to its packet size: "
1757 "content-size=%" PRId64
", "
1758 "packet-size=%" PRIu64
,
1760 stream
->pos
.packet_size
);
1767 * Overwrite the packet context now that the stream
1768 * position's packet and content sizes have the correct
1771 * Copy base_mma as the packet may have been remapped
1772 * (e.g. when a packet is resized).
1774 packet_context_pos
.base_mma
= stream
->pos
.base_mma
;
1775 ret
= auto_populate_packet_context(stream
, false);
1777 BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
1782 BT_LOGV("Rewriting (serializing) packet context field.");
1783 ret
= bt_ctf_field_serialize_recursive(stream
->packet_context
,
1784 &packet_context_pos
, native_byte_order
);
1786 BT_LOGW("Cannot serialize stream's packet context field: "
1787 "field-addr=%p", stream
->packet_context
);
1792 g_ptr_array_set_size(stream
->events
, 0);
1793 stream
->flushed_packet_count
++;
1794 stream
->size
+= stream
->pos
.packet_size
/ CHAR_BIT
;
1797 /* Reset automatically-set fields. */
1798 if (stream
->packet_context
) {
1799 reset_structure_field(stream
->packet_context
, "timestamp_begin");
1800 reset_structure_field(stream
->packet_context
, "timestamp_end");
1801 reset_structure_field(stream
->packet_context
, "packet_size");
1802 reset_structure_field(stream
->packet_context
, "content_size");
1803 reset_structure_field(stream
->packet_context
, "events_discarded");
1808 * We failed to write the packet. Its size is therefore set to 0
1809 * to ensure the next mapping is done in the same place rather
1810 * than advancing by "stream->pos.packet_size", which would
1811 * leave a corrupted packet in the trace.
1813 stream
->pos
.packet_size
= 0;
1815 BT_LOGV("Flushed stream's current packet: content-size=%" PRId64
", "
1816 "packet-size=%" PRIu64
,
1817 stream
->pos
.offset
, stream
->pos
.packet_size
);
1825 void bt_ctf_stream_destroy(struct bt_object
*obj
)
1827 struct bt_ctf_stream
*stream
= (void *) obj
;
1829 BT_LOGD("Destroying CTF writer stream object: addr=%p, name=\"%s\"",
1830 stream
, bt_ctf_stream_get_name(stream
));
1832 bt_stream_common_finalize(BT_TO_COMMON(stream
));
1833 (void) bt_ctf_stream_pos_fini(&stream
->pos
);
1835 if (stream
->pos
.fd
>= 0) {
1839 * Truncate the file's size to the minimum required to fit the
1840 * last packet as we might have grown it too much on the last
1844 ret
= ftruncate(stream
->pos
.fd
, stream
->size
);
1845 } while (ret
== -1 && errno
== EINTR
);
1847 BT_LOGE_ERRNO("Failed to truncate stream file",
1848 ": ret=%d, size=%" PRIu64
,
1849 ret
, (uint64_t) stream
->size
);
1852 if (close(stream
->pos
.fd
)) {
1853 BT_LOGE_ERRNO("Failed to close stream file",
1858 if (stream
->events
) {
1859 BT_LOGD_STR("Putting events.");
1860 g_ptr_array_free(stream
->events
, TRUE
);
1863 BT_LOGD_STR("Putting packet header field.");
1864 bt_put(stream
->packet_header
);
1865 BT_LOGD_STR("Putting packet context field.");
1866 bt_put(stream
->packet_context
);
1871 int _set_structure_field_integer(struct bt_ctf_field
*structure
, char *name
,
1872 uint64_t value
, bt_bool force
)
1875 struct bt_ctf_field_type
*field_type
= NULL
;
1876 struct bt_ctf_field
*integer
;
1878 BT_ASSERT(structure
);
1881 integer
= bt_ctf_field_structure_get_field_by_name(structure
, name
);
1883 /* Field not found, not an error. */
1884 BT_LOGV("Field not found: struct-field-addr=%p, "
1885 "name=\"%s\", force=%d", structure
, name
, force
);
1889 /* Make sure the payload has not already been set. */
1890 if (!force
&& bt_ctf_field_is_set_recursive(integer
)) {
1891 /* Payload already set, not an error */
1892 BT_LOGV("Field's payload is already set: struct-field-addr=%p, "
1893 "name=\"%s\", force=%d", structure
, name
, force
);
1897 field_type
= bt_ctf_field_get_type(integer
);
1898 BT_ASSERT(field_type
);
1899 if (bt_ctf_field_type_get_type_id(field_type
) != BT_CTF_FIELD_TYPE_ID_INTEGER
) {
1901 * The user most likely meant for us to populate this field
1902 * automatically. However, we can only do this if the field
1903 * is an integer. Return an error.
1905 BT_LOGW("Invalid parameter: field's type is not an integer field type: "
1906 "field-addr=%p, ft-addr=%p, ft-id=%s",
1907 integer
, field_type
,
1908 bt_common_field_type_id_string((int)
1909 bt_ctf_field_type_get_type_id(field_type
)));
1914 if (bt_ctf_field_type_integer_is_signed(field_type
)) {
1915 ret
= bt_ctf_field_integer_signed_set_value(integer
,
1918 ret
= bt_ctf_field_integer_unsigned_set_value(integer
, value
);
1920 ret
= !ret
? 1 : ret
;
1928 * Returns the following codes:
1929 * 1 if the field was found and set,
1930 * 0 if nothing was done (field not found, or was already set),
1931 * <0 if an error was encoutered
1934 int try_set_structure_field_integer(struct bt_ctf_field
*structure
, char *name
,
1937 return _set_structure_field_integer(structure
, name
, value
, BT_FALSE
);
1940 struct bt_ctf_stream_class
*bt_ctf_stream_get_class(
1941 struct bt_ctf_stream
*stream
)
1943 return bt_get(bt_stream_common_borrow_class(BT_TO_COMMON(stream
)));
1946 const char *bt_ctf_stream_get_name(struct bt_ctf_stream
*stream
)
1948 return bt_stream_common_get_name(BT_TO_COMMON(stream
));
1951 int64_t bt_ctf_stream_get_id(struct bt_ctf_stream
*stream
)
1953 return bt_stream_common_get_id(BT_TO_COMMON(stream
));