4 * Babeltrace CTF IR - Stream
6 * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
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:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
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
29 #define BT_LOG_TAG "STREAM"
30 #include <babeltrace/lib-logging-internal.h>
32 #include <babeltrace/ctf-ir/clock-class.h>
33 #include <babeltrace/ctf-writer/clock.h>
34 #include <babeltrace/ctf-writer/clock-internal.h>
35 #include <babeltrace/ctf-writer/event.h>
36 #include <babeltrace/ctf-ir/event-internal.h>
37 #include <babeltrace/ctf-ir/field-types-internal.h>
38 #include <babeltrace/ctf-ir/fields-internal.h>
39 #include <babeltrace/ctf-ir/stream.h>
40 #include <babeltrace/ctf-ir/stream-internal.h>
41 #include <babeltrace/ctf-ir/stream-class-internal.h>
42 #include <babeltrace/ctf-ir/trace.h>
43 #include <babeltrace/ctf-ir/trace-internal.h>
44 #include <babeltrace/ctf-writer/writer-internal.h>
45 #include <babeltrace/graph/component-internal.h>
46 #include <babeltrace/ref.h>
47 #include <babeltrace/ctf-writer/functor-internal.h>
48 #include <babeltrace/compiler-internal.h>
49 #include <babeltrace/align-internal.h>
53 void bt_ctf_stream_destroy(struct bt_object
*obj
);
55 int try_set_structure_field_integer(struct bt_ctf_field
*, char *, uint64_t);
57 int set_structure_field_integer(struct bt_ctf_field
*, char *, uint64_t);
60 int set_integer_field_value(struct bt_ctf_field
* field
, uint64_t value
)
63 struct bt_ctf_field_type
*field_type
= NULL
;
66 BT_LOGW_STR("Invalid parameter: field is NULL.");
71 field_type
= bt_ctf_field_get_type(field
);
74 if (bt_ctf_field_type_get_type_id(field_type
) !=
75 BT_CTF_FIELD_TYPE_ID_INTEGER
) {
76 /* Not an integer and the value is unset, error. */
77 BT_LOGW("Invalid parameter: field's type is not an integer field type: "
78 "field-addr=%p, ft-addr=%p, ft-id=%s",
80 bt_ctf_field_type_id_string(field_type
->id
));
85 if (bt_ctf_field_type_integer_get_signed(field_type
)) {
86 ret
= bt_ctf_field_signed_integer_set_value(field
, (int64_t) value
);
88 /* Value is out of range, error. */
89 BT_LOGW("Cannot set signed integer field's value: "
90 "addr=%p, value=%" PRId64
,
91 field
, (int64_t) value
);
95 ret
= bt_ctf_field_unsigned_integer_set_value(field
, value
);
97 /* Value is out of range, error. */
98 BT_LOGW("Cannot set unsigned integer field's value: "
99 "addr=%p, value=%" PRIu64
,
110 int set_packet_header_magic(struct bt_ctf_stream
*stream
)
113 struct bt_ctf_field_type
*magic_field_type
= NULL
;
114 struct bt_ctf_field
*magic_field
= bt_ctf_field_structure_get_field(
115 stream
->packet_header
, "magic");
116 const uint32_t magic_value
= 0xc1fc1fc1;
121 /* No magic field found. Not an error, skip. */
122 BT_LOGV("No field named `magic` in packet header: skipping: "
123 "stream-addr=%p, stream-name=\"%s\"",
124 stream
, bt_ctf_stream_get_name(stream
));
128 if (bt_ctf_field_is_set(magic_field
)) {
129 /* Value already set. Not an error, skip. */
130 BT_LOGV("Packet header's `magic` field is already set: skipping: "
131 "stream-addr=%p, stream-name=\"%s\"", stream
,
132 bt_ctf_stream_get_name(stream
));
136 magic_field_type
= bt_ctf_field_get_type(magic_field
);
137 assert(magic_field_type
);
139 if (bt_ctf_field_type_get_type_id(magic_field_type
) !=
140 BT_CTF_FIELD_TYPE_ID_INTEGER
) {
141 /* Magic field is not an integer. Not an error, skip. */
142 BT_LOGV("Packet header's `magic` field's type is not an integer field type: skipping: "
143 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, ft-addr=%p, ft-id=%s",
144 stream
, bt_ctf_stream_get_name(stream
), magic_field
,
146 bt_ctf_field_type_id_string(magic_field_type
->id
));
150 if (bt_ctf_field_type_integer_get_size(magic_field_type
) != 32) {
152 * Magic field is not of the expected size.
153 * Not an error, skip.
155 BT_LOGV("Packet header's `magic` field's type is not 32-bit: skipping: "
156 "stream-addr=%p, stream-name=\"%s\", ft-addr=%p, size=%d",
157 stream
, bt_ctf_stream_get_name(stream
), magic_field_type
,
158 bt_ctf_field_type_integer_get_size(magic_field_type
));
162 ret
= bt_ctf_field_type_integer_get_signed(magic_field_type
);
165 ret
= bt_ctf_field_signed_integer_set_value(magic_field
,
166 (int64_t) magic_value
);
168 ret
= bt_ctf_field_unsigned_integer_set_value(magic_field
,
169 (uint64_t) magic_value
);
173 BT_LOGW("Cannot set `magic` integer field's value: "
174 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value-unsigned=%" PRIu64
,
175 stream
, bt_ctf_stream_get_name(stream
),
176 magic_field
, (uint64_t) magic_value
);
178 BT_LOGV("Set packet header field's `magic` field's value: "
179 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value-unsigned=%" PRIu64
,
180 stream
, bt_ctf_stream_get_name(stream
),
181 magic_field
, (uint64_t) magic_value
);
185 bt_put(magic_field_type
);
190 int set_packet_header_uuid(struct bt_ctf_stream
*stream
)
194 struct bt_ctf_trace
*trace
= NULL
;
195 struct bt_ctf_field_type
*uuid_field_type
= NULL
;
196 struct bt_ctf_field_type
*element_field_type
= NULL
;
197 struct bt_ctf_field
*uuid_field
= bt_ctf_field_structure_get_field(
198 stream
->packet_header
, "uuid");
203 /* No uuid field found. Not an error, skip. */
204 BT_LOGV("No field named `uuid` in packet header: skipping: "
205 "stream-addr=%p, stream-name=\"%s\"",
206 stream
, bt_ctf_stream_get_name(stream
));
210 if (bt_ctf_field_is_set(uuid_field
)) {
211 /* Value already set. Not an error, skip. */
212 BT_LOGV("Packet header's `uuid` field is already set: skipping: "
213 "stream-addr=%p, stream-name=\"%s\"",
214 stream
, bt_ctf_stream_get_name(stream
));
218 uuid_field_type
= bt_ctf_field_get_type(uuid_field
);
219 assert(uuid_field_type
);
220 if (bt_ctf_field_type_get_type_id(uuid_field_type
) !=
221 BT_CTF_FIELD_TYPE_ID_ARRAY
) {
222 /* UUID field is not an array. Not an error, skip. */
223 BT_LOGV("Packet header's `uuid` field's type is not an array field type: skipping: "
224 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, ft-addr=%p, ft-id=%s",
225 stream
, bt_ctf_stream_get_name(stream
), uuid_field
,
227 bt_ctf_field_type_id_string(uuid_field_type
->id
));
231 if (bt_ctf_field_type_array_get_length(uuid_field_type
) != 16) {
233 * UUID field is not of the expected size.
234 * Not an error, skip.
236 BT_LOGV("Packet header's `uuid` array field's type's length is not 16: skipping: "
237 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, ft-addr=%p, ft-length=%u",
238 stream
, bt_ctf_stream_get_name(stream
), uuid_field
,
240 (unsigned int) bt_ctf_field_type_array_get_length(uuid_field_type
));
244 element_field_type
= bt_ctf_field_type_array_get_element_type(
246 assert(element_field_type
);
247 if (bt_ctf_field_type_get_type_id(element_field_type
) !=
248 BT_CTF_FIELD_TYPE_ID_INTEGER
) {
249 /* UUID array elements are not integers. Not an error, skip */
250 BT_LOGV("Packet header's `uuid` array field's type's element field type is not an integer field type: skipping: "
251 "stream-addr=%p, stream-name=\"%s\", uuid-field-addr=%p, "
252 "element-ft-addr=%p, element-ft-id=%s",
253 stream
, bt_ctf_stream_get_name(stream
), uuid_field
,
255 bt_ctf_field_type_id_string(element_field_type
->id
));
259 trace
= (struct bt_ctf_trace
*) bt_object_get_parent(stream
);
260 for (i
= 0; i
< 16; i
++) {
261 struct bt_ctf_field
*uuid_element
=
262 bt_ctf_field_array_get_field(uuid_field
, i
);
264 ret
= bt_ctf_field_type_integer_get_signed(element_field_type
);
268 ret
= bt_ctf_field_signed_integer_set_value(
269 uuid_element
, (int64_t) trace
->uuid
[i
]);
271 ret
= bt_ctf_field_unsigned_integer_set_value(
272 uuid_element
, (uint64_t) trace
->uuid
[i
]);
274 bt_put(uuid_element
);
276 BT_LOGW("Cannot set integer field's value (for `uuid` packet header field): "
277 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
278 "value-unsigned=%" PRIu64
", index=%" PRId64
,
279 stream
, bt_ctf_stream_get_name(stream
),
280 uuid_element
, (uint64_t) trace
->uuid
[i
], i
);
285 BT_LOGV("Set packet header field's `uuid` field's value: "
286 "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
287 stream
, bt_ctf_stream_get_name(stream
), uuid_field
);
291 bt_put(uuid_field_type
);
292 bt_put(element_field_type
);
297 int set_packet_header_stream_id(struct bt_ctf_stream
*stream
)
301 struct bt_ctf_field_type
*stream_id_field_type
= NULL
;
302 struct bt_ctf_field
*stream_id_field
= bt_ctf_field_structure_get_field(
303 stream
->packet_header
, "stream_id");
305 if (!stream_id_field
) {
306 /* No stream_id field found. Not an error, skip. */
307 BT_LOGV("No field named `stream_id` in packet header: skipping: "
308 "stream-addr=%p, stream-name=\"%s\"",
309 stream
, bt_ctf_stream_get_name(stream
));
313 if (bt_ctf_field_is_set(stream_id_field
)) {
314 /* Value already set. Not an error, skip. */
315 BT_LOGV("Packet header's `stream_id` field is already set: skipping: "
316 "stream-addr=%p, stream-name=\"%s\"",
317 stream
, bt_ctf_stream_get_name(stream
));
321 stream_id_field_type
= bt_ctf_field_get_type(stream_id_field
);
322 assert(stream_id_field_type
);
323 if (bt_ctf_field_type_get_type_id(stream_id_field_type
) !=
324 BT_CTF_FIELD_TYPE_ID_INTEGER
) {
325 /* stream_id field is not an integer. Not an error, skip. */
326 BT_LOGV("Packet header's `stream_id` field's type is not an integer field type: skipping: "
327 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, ft-addr=%p, ft-id=%s",
328 stream
, bt_ctf_stream_get_name(stream
), stream_id_field
,
329 stream_id_field_type
,
330 bt_ctf_field_type_id_string(stream_id_field_type
->id
));
334 stream_id
= stream
->stream_class
->id
;
335 ret
= bt_ctf_field_type_integer_get_signed(stream_id_field_type
);
338 ret
= bt_ctf_field_signed_integer_set_value(stream_id_field
,
339 (int64_t) stream_id
);
341 ret
= bt_ctf_field_unsigned_integer_set_value(stream_id_field
,
342 (uint64_t) stream_id
);
346 BT_LOGW("Cannot set `stream_id` integer field's value: "
347 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value-unsigned=%" PRIu64
,
348 stream
, bt_ctf_stream_get_name(stream
),
349 stream_id_field
, (uint64_t) stream_id
);
351 BT_LOGV("Set packet header field's `stream_id` field's value: "
352 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value-unsigned=%" PRIu64
,
353 stream
, bt_ctf_stream_get_name(stream
),
354 stream_id_field
, (uint64_t) stream_id
);
358 bt_put(stream_id_field
);
359 bt_put(stream_id_field_type
);
364 int set_packet_header(struct bt_ctf_stream
*stream
)
368 ret
= set_packet_header_magic(stream
);
370 BT_LOGW("Cannot set packet header's magic number field: "
371 "stream-addr=%p, stream-name=\"%s\"",
372 stream
, bt_ctf_stream_get_name(stream
));
376 ret
= set_packet_header_uuid(stream
);
378 BT_LOGW("Cannot set packet header's UUID field: "
379 "stream-addr=%p, stream-name=\"%s\"",
380 stream
, bt_ctf_stream_get_name(stream
));
384 ret
= set_packet_header_stream_id(stream
);
386 BT_LOGW("Cannot set packet header's stream class ID field: "
387 "stream-addr=%p, stream-name=\"%s\"",
388 stream
, bt_ctf_stream_get_name(stream
));
392 BT_LOGV("Set packet header's known fields's values: "
393 "stream-addr=%p, stream-name=\"%s\"",
394 stream
, bt_ctf_stream_get_name(stream
));
401 void release_event(struct bt_ctf_event
*event
)
403 if (bt_object_get_ref_count(event
)) {
405 * The event is being orphaned, but it must guarantee the
406 * existence of its event class for the duration of its
409 bt_get(event
->event_class
);
410 BT_PUT(event
->base
.parent
);
412 bt_object_release(event
);
417 int create_stream_file(struct bt_ctf_writer
*writer
,
418 struct bt_ctf_stream
*stream
)
421 GString
*filename
= g_string_new(stream
->stream_class
->name
->str
);
423 BT_LOGD("Creating stream file: writer-addr=%p, stream-addr=%p, "
424 "stream-name=\"%s\", stream-class-addr=%p, stream-class-name=\"%s\"",
425 writer
, stream
, bt_ctf_stream_get_name(stream
),
426 stream
->stream_class
, stream
->stream_class
->name
->str
);
428 if (stream
->stream_class
->name
->len
== 0) {
431 ret
= bt_ctf_stream_class_get_id(stream
->stream_class
);
433 BT_LOGW("Cannot get stream class's ID: "
434 "stream-class-addr=%p, "
435 "stream-class-name=\"%s\"",
436 stream
->stream_class
,
437 stream
->stream_class
->name
->str
);
442 g_string_printf(filename
, "stream_%" PRId64
, ret
);
445 g_string_append_printf(filename
, "_%" PRIu32
, stream
->id
);
446 fd
= openat(writer
->trace_dir_fd
, filename
->str
,
447 O_RDWR
| O_CREAT
| O_TRUNC
,
448 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IWGRP
);
450 BT_LOGW("Failed to open stream file for writing: "
451 "writer-trace-dir-fd=%d, filename=\"%s\"",
452 writer
->trace_dir_fd
, filename
->str
);
456 BT_LOGD("Created stream file for writing: "
457 "stream-addr=%p, stream-name=\"%s\", writer-trace-dir-fd=%d, "
458 "filename=\"%s\", fd=%d", stream
, bt_ctf_stream_get_name(stream
),
459 writer
->trace_dir_fd
, filename
->str
, fd
);
462 g_string_free(filename
, TRUE
);
467 void set_stream_fd(struct bt_ctf_stream
*stream
, int fd
)
469 (void) bt_ctf_stream_pos_init(&stream
->pos
, fd
, O_RDWR
);
474 void component_destroy_listener(struct bt_component
*component
, void *data
)
476 struct bt_ctf_stream
*stream
= data
;
478 BT_LOGD("Component is being destroyed, stream is notified: "
479 "comp-addr=%p, stream-addr=%p", component
, stream
);
480 g_hash_table_remove(stream
->comp_cur_port
, component
);
483 struct bt_ctf_stream
*bt_ctf_stream_create(
484 struct bt_ctf_stream_class
*stream_class
,
488 struct bt_ctf_stream
*stream
= NULL
;
489 struct bt_ctf_trace
*trace
= NULL
;
490 struct bt_ctf_writer
*writer
= NULL
;
493 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
497 BT_LOGD("Creating stream object: stream-class-addr=%p, "
498 "stream-class-name=\"%s\", stream-name=\"%s\"",
499 stream_class
, bt_ctf_stream_class_get_name(stream_class
),
501 trace
= bt_ctf_stream_class_get_trace(stream_class
);
503 BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: "
504 "stream-class-name=\"%s\", stream-class-name=\"%s\"",
505 stream_class
, bt_ctf_stream_class_get_name(stream_class
),
510 if (bt_ctf_trace_is_static(trace
)) {
512 * A static trace has the property that all its stream
513 * classes, clock classes, and streams are definitive:
514 * no more can be added, and each object is also frozen.
516 BT_LOGW("Invalid parameter: cannot create stream from a stream class which is part of a static trace: "
517 "stream-class-name=\"%s\", stream-class-name=\"%s\", "
519 stream_class
, bt_ctf_stream_class_get_name(stream_class
),
524 stream
= g_new0(struct bt_ctf_stream
, 1);
526 BT_LOGE_STR("Failed to allocate one stream.");
530 bt_object_init(stream
, bt_ctf_stream_destroy
);
532 * Acquire reference to parent since stream will become publicly
533 * reachable; it needs its parent to remain valid.
535 bt_object_set_parent(stream
, trace
);
536 stream
->id
= stream_class
->next_stream_id
++;
537 stream
->stream_class
= stream_class
;
540 stream
->destroy_listeners
= g_array_new(FALSE
, TRUE
,
541 sizeof(struct bt_ctf_stream_destroy_listener
));
542 if (!stream
->destroy_listeners
) {
543 BT_LOGE_STR("Failed to allocate a GArray.");
548 stream
->name
= g_string_new(name
);
550 BT_LOGE_STR("Failed to allocate a GString.");
555 BT_LOGD("Set stream's trace parent: trace-addr=%p", trace
);
557 if (trace
->is_created_by_writer
) {
559 writer
= (struct bt_ctf_writer
*)
560 bt_object_get_parent(trace
);
562 BT_LOGD("Stream object belongs to a writer's trace: "
563 "writer-addr=%p", writer
);
566 if (stream_class
->packet_context_type
) {
567 BT_LOGD("Creating stream's packet context field: "
568 "ft-addr=%p", stream_class
->packet_context_type
);
569 stream
->packet_context
= bt_ctf_field_create(
570 stream_class
->packet_context_type
);
571 if (!stream
->packet_context
) {
572 BT_LOGW_STR("Cannot create stream's packet context field.");
576 /* Initialize events_discarded */
577 ret
= try_set_structure_field_integer(
578 stream
->packet_context
, "events_discarded", 0);
580 BT_LOGW("Cannot set `events_discarded` field in packet context: "
581 "ret=%d, packet-context-field-addr=%p",
582 ret
, stream
->packet_context
);
587 stream
->events
= g_ptr_array_new_with_free_func(
588 (GDestroyNotify
) release_event
);
589 if (!stream
->events
) {
590 BT_LOGE_STR("Failed to allocate a GPtrArray.");
594 /* A trace is not allowed to have a NULL packet header */
595 assert(trace
->packet_header_type
);
596 BT_LOGD("Creating stream's packet header field: "
597 "ft-addr=%p", trace
->packet_header_type
);
598 stream
->packet_header
=
599 bt_ctf_field_create(trace
->packet_header_type
);
600 if (!stream
->packet_header
) {
601 BT_LOGW_STR("Cannot create stream's packet header field.");
606 * Attempt to populate the default trace packet header fields
607 * (magic, uuid and stream_id). This will _not_ fail shall the
608 * fields not be found or be of an incompatible type; they will
609 * simply not be populated automatically. The user will have to
610 * make sure to set the trace packet header fields himself
613 ret
= set_packet_header(stream
);
615 BT_LOGW_STR("Cannot populate the stream's packet header.");
619 /* Create file associated with this stream */
620 fd
= create_stream_file(writer
, stream
);
622 BT_LOGW_STR("Cannot create stream file.");
626 set_stream_fd(stream
, fd
);
628 /* Freeze the writer */
629 BT_LOGD_STR("Freezing stream's CTF writer.");
630 bt_ctf_writer_freeze(writer
);
632 /* Non-writer stream indicated by a negative FD */
633 set_stream_fd(stream
, -1);
634 stream
->comp_cur_port
= g_hash_table_new(g_direct_hash
,
636 if (!stream
->comp_cur_port
) {
637 BT_LOGE_STR("Failed to allocate a GHashTable.");
642 /* Add this stream to the trace's streams */
643 g_ptr_array_add(trace
->streams
, stream
);
647 BT_LOGD("Created stream object: addr=%p", stream
);
656 struct bt_ctf_stream_class
*bt_ctf_stream_get_class(
657 struct bt_ctf_stream
*stream
)
659 struct bt_ctf_stream_class
*stream_class
= NULL
;
662 BT_LOGW_STR("Invalid parameter: stream is NULL.");
666 stream_class
= stream
->stream_class
;
667 bt_get(stream_class
);
672 int bt_ctf_stream_get_discarded_events_count(
673 struct bt_ctf_stream
*stream
, uint64_t *count
)
677 struct bt_ctf_field
*events_discarded_field
= NULL
;
678 struct bt_ctf_field_type
*events_discarded_field_type
= NULL
;
681 BT_LOGW_STR("Invalid parameter: stream is NULL.");
687 BT_LOGW_STR("Invalid parameter: count is NULL.");
692 if (!stream
->packet_context
) {
694 BT_LOGV("Stream has no packet context field: "
695 "stream-addr=%p, stream-name=\"%s\"",
696 stream
, bt_ctf_stream_get_name(stream
));
701 if (stream
->pos
.fd
< 0) {
702 BT_LOGW("Invalid parameter: stream is not a CTF writer stream: "
703 "stream-addr=%p, stream-name=\"%s\"",
704 stream
, bt_ctf_stream_get_name(stream
));
709 events_discarded_field
= bt_ctf_field_structure_get_field(
710 stream
->packet_context
, "events_discarded");
711 if (!events_discarded_field
) {
712 BT_LOGW("Cannot get packet context's `events_discarded` field: "
713 "stream-addr=%p, stream-name=\"%s\", "
714 "packet-context-field-addr=%p",
715 stream
, bt_ctf_stream_get_name(stream
),
716 stream
->packet_context
);
721 events_discarded_field_type
= bt_ctf_field_get_type(
722 events_discarded_field
);
723 assert(events_discarded_field_type
);
724 field_signed
= bt_ctf_field_type_integer_get_signed(
725 events_discarded_field_type
);
726 assert(field_signed
>= 0);
729 int64_t signed_count
;
731 ret
= bt_ctf_field_signed_integer_get_value(
732 events_discarded_field
, &signed_count
);
734 BT_LOGW("Cannot get packet context's `events_discarded` field value: "
735 "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
736 stream
, bt_ctf_stream_get_name(stream
),
737 events_discarded_field
);
740 if (signed_count
< 0) {
742 BT_LOGW("Invalid value for packet context's `events_discarded` field: must be zero or positive: "
743 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
744 "value=%" PRId64
, stream
,
745 bt_ctf_stream_get_name(stream
),
746 events_discarded_field
, signed_count
);
750 *count
= (uint64_t) signed_count
;
752 ret
= bt_ctf_field_unsigned_integer_get_value(
753 events_discarded_field
, count
);
755 BT_LOGW("Cannot get packet context's `events_discarded` field value: "
756 "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
757 stream
, bt_ctf_stream_get_name(stream
),
758 events_discarded_field
);
763 bt_put(events_discarded_field
);
764 bt_put(events_discarded_field_type
);
768 void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream
*stream
,
769 uint64_t event_count
)
773 uint64_t previous_count
;
775 struct bt_ctf_field
*events_discarded_field
= NULL
;
776 struct bt_ctf_field_type
*events_discarded_field_type
= NULL
;
779 BT_LOGW_STR("Invalid parameter: stream is NULL.");
783 BT_LOGV("Appending discarded events to stream: "
784 "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64
,
785 stream
, bt_ctf_stream_get_name(stream
), event_count
);
787 if (!stream
->packet_context
) {
788 BT_LOGW_STR("Invalid parameter: stream has no packet context field.");
792 if (stream
->pos
.fd
< 0) {
793 BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
797 ret
= bt_ctf_stream_get_discarded_events_count(stream
,
800 BT_LOGW_STR("Cannot get stream's number of discarded events.");
804 events_discarded_field
= bt_ctf_field_structure_get_field(
805 stream
->packet_context
, "events_discarded");
806 if (!events_discarded_field
) {
807 BT_LOGW_STR("No field named `events_discarded` in packet context.");
811 events_discarded_field_type
= bt_ctf_field_get_type(
812 events_discarded_field
);
813 assert(events_discarded_field_type
);
814 field_signed
= bt_ctf_field_type_integer_get_signed(
815 events_discarded_field_type
);
816 assert(field_signed
>= 0);
817 new_count
= previous_count
+ event_count
;
818 assert(new_count
>= previous_count
);
820 ret
= bt_ctf_field_signed_integer_set_value(
821 events_discarded_field
, (int64_t) new_count
);
823 BT_LOGW("Cannot set packet context's `events_discarded` field: "
824 "field-addr=%p, value=%" PRId64
,
825 events_discarded_field
, (int64_t) new_count
);
829 ret
= bt_ctf_field_unsigned_integer_set_value(
830 events_discarded_field
, new_count
);
832 BT_LOGW("Cannot set packet context's `events_discarded` field: "
833 "field-addr=%p, value=%" PRIu64
,
834 events_discarded_field
, new_count
);
839 BT_LOGV("Appended discarded events to stream: "
840 "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64
,
841 stream
, bt_ctf_stream_get_name(stream
), event_count
);
845 bt_put(events_discarded_field
);
846 bt_put(events_discarded_field_type
);
849 static int auto_populate_event_header(struct bt_ctf_stream
*stream
,
850 struct bt_ctf_event
*event
)
853 struct bt_ctf_field
*id_field
= NULL
, *timestamp_field
= NULL
;
854 struct bt_ctf_clock_class
*mapped_clock_class
= NULL
;
855 uint64_t event_class_id
;
860 BT_LOGW_STR("Cannot populate event header field: event is frozen.");
865 BT_LOGV("Automatically populating event header field: "
866 "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
867 stream
, bt_ctf_stream_get_name(stream
), event
);
870 * The condition to automatically set the ID are:
872 * 1. The event header field "id" exists and is an integer
874 * 2. The event header field "id" is NOT set.
876 id_field
= bt_ctf_field_structure_get_field(event
->event_header
, "id");
877 event_class_id
= (uint64_t) bt_ctf_event_class_get_id(event
->event_class
);
878 assert(event_class_id
>= 0);
879 if (id_field
&& !bt_ctf_field_is_set(id_field
)) {
880 ret
= set_integer_field_value(id_field
, event_class_id
);
882 BT_LOGW("Cannot set event header's `id` field's value: "
883 "addr=%p, value=%" PRIu64
, id_field
,
890 * The conditions to automatically set the timestamp are:
892 * 1. The event header field "timestamp" exists and is an
894 * 2. This stream's class has a registered clock (set with
895 * bt_ctf_stream_class_set_clock()).
896 * 3. The event header field "timestamp" has its type mapped to
897 * a clock class which is also the clock class of this
898 * stream's class's registered clock.
899 * 4. The event header field "timestamp" is NOT set.
901 timestamp_field
= bt_ctf_field_structure_get_field(event
->event_header
,
903 if (timestamp_field
&& !bt_ctf_field_is_set(timestamp_field
) &&
904 stream
->stream_class
->clock
) {
905 struct bt_ctf_clock_class
*stream_class_clock_class
=
906 stream
->stream_class
->clock
->clock_class
;
907 struct bt_ctf_field_type
*timestamp_field_type
=
908 bt_ctf_field_get_type(timestamp_field
);
910 assert(timestamp_field_type
);
912 bt_ctf_field_type_integer_get_mapped_clock_class(
913 timestamp_field_type
);
914 BT_PUT(timestamp_field_type
);
915 if (mapped_clock_class
== stream_class_clock_class
) {
918 ret
= bt_ctf_clock_get_value(
919 stream
->stream_class
->clock
,
922 ret
= set_integer_field_value(timestamp_field
,
925 BT_LOGW("Cannot set event header's `timestamp` field's value: "
926 "addr=%p, value=%" PRIu64
,
927 timestamp_field
, timestamp
);
933 BT_LOGV("Automatically populated event header field: "
934 "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
935 stream
, bt_ctf_stream_get_name(stream
), event
);
939 bt_put(timestamp_field
);
940 bt_put(mapped_clock_class
);
944 int bt_ctf_stream_append_event(struct bt_ctf_stream
*stream
,
945 struct bt_ctf_event
*event
)
950 BT_LOGW_STR("Invalid parameter: stream is NULL.");
956 BT_LOGW_STR("Invalid parameter: event is NULL.");
961 if (stream
->pos
.fd
< 0) {
962 BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
967 BT_LOGV("Appending event to stream: "
968 "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
969 "event-class-name=\"%s\", event-class-id=%" PRId64
,
970 stream
, bt_ctf_stream_get_name(stream
), event
,
971 bt_ctf_event_class_get_name(bt_ctf_event_borrow_event_class(event
)),
972 bt_ctf_event_class_get_id(bt_ctf_event_borrow_event_class(event
)));
975 * The event is not supposed to have a parent stream at this
976 * point. The only other way an event can have a parent stream
977 * is if it was assigned when setting a packet to the event,
978 * in which case the packet's stream is not a writer stream,
979 * and thus the user is trying to append an event which belongs
982 if (event
->base
.parent
) {
987 bt_object_set_parent(event
, stream
);
988 BT_LOGV_STR("Automatically populating the header of the event to append.");
989 ret
= auto_populate_event_header(stream
, event
);
991 /* auto_populate_event_header() reports errors */
995 /* Make sure the various scopes of the event are set */
996 BT_LOGV_STR("Validating event to append.");
997 ret
= bt_ctf_event_validate(event
);
1002 /* Save the new event and freeze it */
1003 BT_LOGV_STR("Freezing the event to append.");
1004 bt_ctf_event_freeze(event
);
1005 g_ptr_array_add(stream
->events
, event
);
1008 * Event had to hold a reference to its event class as long as it wasn't
1009 * part of the same trace hierarchy. From now on, the event and its
1010 * class share the same lifetime guarantees and the reference is no
1013 BT_LOGV_STR("Putting the event's class.");
1014 bt_put(event
->event_class
);
1015 BT_LOGV("Appended event to stream: "
1016 "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
1017 "event-class-name=\"%s\", event-class-id=%" PRId64
,
1018 stream
, bt_ctf_stream_get_name(stream
), event
,
1019 bt_ctf_event_class_get_name(bt_ctf_event_borrow_event_class(event
)),
1020 bt_ctf_event_class_get_id(bt_ctf_event_borrow_event_class(event
)));
1027 * Orphan the event; we were not successful in associating it to
1030 bt_object_set_parent(event
, NULL
);
1035 struct bt_ctf_field
*bt_ctf_stream_get_packet_context(
1036 struct bt_ctf_stream
*stream
)
1038 struct bt_ctf_field
*packet_context
= NULL
;
1041 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1045 if (stream
->pos
.fd
< 0) {
1046 BT_LOGW("Invalid parameter: stream is not a CTF writer stream: "
1047 "stream-addr=%p, stream-name=\"%s\"", stream
,
1048 bt_ctf_stream_get_name(stream
));
1052 packet_context
= stream
->packet_context
;
1053 if (packet_context
) {
1054 bt_get(packet_context
);
1057 return packet_context
;
1060 int bt_ctf_stream_set_packet_context(struct bt_ctf_stream
*stream
,
1061 struct bt_ctf_field
*field
)
1064 struct bt_ctf_field_type
*field_type
;
1067 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1072 if (stream
->pos
.fd
< 0) {
1073 BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
1078 field_type
= bt_ctf_field_get_type(field
);
1079 if (bt_ctf_field_type_compare(field_type
,
1080 stream
->stream_class
->packet_context_type
)) {
1081 BT_LOGW("Invalid parameter: packet context's field type is different from the stream's packet context field type: "
1082 "stream-addr=%p, stream-name=\"%s\", "
1083 "packet-context-field-addr=%p, "
1084 "packet-context-ft-addr=%p",
1085 stream
, bt_ctf_stream_get_name(stream
),
1092 bt_put(stream
->packet_context
);
1093 stream
->packet_context
= bt_get(field
);
1094 BT_LOGV("Set stream's packet context field: "
1095 "stream-addr=%p, stream-name=\"%s\", "
1096 "packet-context-field-addr=%p",
1097 stream
, bt_ctf_stream_get_name(stream
), field
);
1102 struct bt_ctf_field
*bt_ctf_stream_get_packet_header(
1103 struct bt_ctf_stream
*stream
)
1105 struct bt_ctf_field
*packet_header
= NULL
;
1108 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1112 if (stream
->pos
.fd
< 0) {
1113 BT_LOGW("Invalid parameter: stream is not a CTF writer stream: "
1114 "stream-addr=%p, stream-name=\"%s\"", stream
,
1115 bt_ctf_stream_get_name(stream
));
1119 packet_header
= stream
->packet_header
;
1120 if (packet_header
) {
1121 bt_get(packet_header
);
1124 return packet_header
;
1127 int bt_ctf_stream_set_packet_header(struct bt_ctf_stream
*stream
,
1128 struct bt_ctf_field
*field
)
1131 struct bt_ctf_trace
*trace
= NULL
;
1132 struct bt_ctf_field_type
*field_type
= NULL
;
1135 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1140 if (stream
->pos
.fd
< 0) {
1141 BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
1146 trace
= (struct bt_ctf_trace
*) bt_object_get_parent(stream
);
1147 field_type
= bt_ctf_field_get_type(field
);
1148 if (bt_ctf_field_type_compare(field_type
, trace
->packet_header_type
)) {
1149 BT_LOGW("Invalid parameter: packet header's field type is different from the stream's packet header field type: "
1150 "stream-addr=%p, stream-name=\"%s\", "
1151 "packet-header-field-addr=%p, "
1152 "packet-header-ft-addr=%p",
1153 stream
, bt_ctf_stream_get_name(stream
),
1159 bt_put(stream
->packet_header
);
1160 stream
->packet_header
= bt_get(field
);
1161 BT_LOGV("Set stream's packet header field: "
1162 "stream-addr=%p, stream-name=\"%s\", "
1163 "packet-header-field-addr=%p",
1164 stream
, bt_ctf_stream_get_name(stream
), field
);
1172 int get_event_header_timestamp(struct bt_ctf_field
*event_header
, uint64_t *timestamp
)
1175 struct bt_ctf_field
*timestamp_field
= NULL
;
1176 struct bt_ctf_field_type
*timestamp_field_type
= NULL
;
1178 timestamp_field
= bt_ctf_field_structure_get_field(event_header
,
1180 if (!timestamp_field
) {
1181 BT_LOGV("Cannot get event header's `timestamp` field: "
1182 "field-addr=%p", timestamp_field
);
1187 timestamp_field_type
= bt_ctf_field_get_type(timestamp_field
);
1188 assert(timestamp_field_type
);
1189 if (bt_ctf_field_type_get_type_id(timestamp_field_type
) !=
1190 BT_CTF_FIELD_TYPE_ID_INTEGER
) {
1191 BT_LOGW("Invalid event header: `timestamp` field's type is not an integer field type: "
1192 "event-header-field-addr=%p, "
1193 "timestamp-field-addr=%p, timestamp-ft-addr=%p, "
1194 "timestamp-ft-id=%s",
1195 event_header
, timestamp_field
, timestamp_field_type
,
1196 bt_ctf_field_type_id_string(timestamp_field_type
->id
));
1201 if (bt_ctf_field_type_integer_get_signed(timestamp_field_type
)) {
1204 ret
= bt_ctf_field_signed_integer_get_value(timestamp_field
,
1207 BT_LOGW("Cannot get signed integer field's value: "
1208 "event-header-field-addr=%p, "
1209 "timestamp-field-addr=%p",
1210 event_header
, timestamp_field
);
1213 *timestamp
= (uint64_t) val
;
1215 ret
= bt_ctf_field_unsigned_integer_get_value(timestamp_field
,
1218 BT_LOGW("Cannot get unsigned integer field's value: "
1219 "event-header-field-addr=%p, "
1220 "timestamp-field-addr=%p",
1221 event_header
, timestamp_field
);
1226 bt_put(timestamp_field
);
1227 bt_put(timestamp_field_type
);
1232 void reset_structure_field(struct bt_ctf_field
*structure
, const char *name
)
1234 struct bt_ctf_field
*member
;
1236 member
= bt_ctf_field_structure_get_field(structure
, name
);
1238 (void) bt_ctf_field_reset(member
);
1242 int bt_ctf_stream_flush(struct bt_ctf_stream
*stream
)
1246 uint64_t timestamp_begin
, timestamp_end
;
1247 struct bt_ctf_field
*integer
= NULL
;
1248 struct bt_ctf_stream_pos packet_context_pos
;
1249 struct bt_ctf_trace
*trace
;
1250 enum bt_ctf_byte_order native_byte_order
;
1251 bt_bool empty_packet
;
1252 uint64_t packet_size_bits
;
1254 bt_bool timestamp_begin
;
1255 bt_bool timestamp_end
;
1256 bt_bool content_size
;
1257 bt_bool packet_size
;
1258 } auto_set_fields
= { 0 };
1261 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1266 if (stream
->pos
.fd
< 0) {
1267 BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
1272 if (!stream
->packet_context
&& stream
->flushed_packet_count
> 0) {
1274 * A stream without a packet context, and thus without
1275 * content and packet size members, can't have more than
1278 BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once.");
1283 BT_LOGV("Flushing stream's current packet: stream-addr=%p, "
1284 "stream-name=\"%s\", packet-index=%u", stream
,
1285 bt_ctf_stream_get_name(stream
), stream
->flushed_packet_count
);
1286 trace
= bt_ctf_stream_class_borrow_trace(stream
->stream_class
);
1288 native_byte_order
= bt_ctf_trace_get_native_byte_order(trace
);
1289 empty_packet
= (stream
->events
->len
== 0);
1291 /* mmap the next packet */
1292 BT_LOGV("Seeking to the next packet: pos-offset=%" PRId64
,
1293 stream
->pos
.offset
);
1294 bt_ctf_stream_pos_packet_seek(&stream
->pos
, 0, SEEK_CUR
);
1295 BT_LOGV_STR("Serializing packet header field.");
1296 ret
= bt_ctf_field_serialize(stream
->packet_header
, &stream
->pos
,
1299 BT_LOGE("Cannot serialize stream's packet header field: "
1300 "field-addr=%p", stream
->packet_header
);
1304 if (stream
->packet_context
) {
1305 /* Set the default context attributes if present and unset. */
1306 if (!empty_packet
&& !get_event_header_timestamp(
1307 ((struct bt_ctf_event
*) g_ptr_array_index(
1308 stream
->events
, 0))->event_header
, ×tamp_begin
)) {
1309 ret
= try_set_structure_field_integer(
1310 stream
->packet_context
,
1311 "timestamp_begin", timestamp_begin
);
1313 BT_LOGW("Cannot set `timestamp_begin` field in packet context: "
1314 "ret=%d, packet-context-field-addr=%p",
1315 ret
, stream
->packet_context
);
1318 auto_set_fields
.timestamp_begin
= ret
== 1;
1321 if (!empty_packet
&& !get_event_header_timestamp(
1322 ((struct bt_ctf_event
*) g_ptr_array_index(
1323 stream
->events
, stream
->events
->len
- 1))->event_header
,
1326 ret
= try_set_structure_field_integer(
1327 stream
->packet_context
,
1328 "timestamp_end", timestamp_end
);
1330 BT_LOGW("Cannot set `timestamp_end` field in packet context: "
1331 "ret=%d, packet-context-field-addr=%p",
1332 ret
, stream
->packet_context
);
1335 auto_set_fields
.timestamp_end
= ret
== 1;
1337 ret
= try_set_structure_field_integer(stream
->packet_context
,
1338 "content_size", UINT64_MAX
);
1340 BT_LOGW("Cannot set `content_size` field in packet context: "
1341 "ret=%d, packet-context-field-addr=%p",
1342 ret
, stream
->packet_context
);
1345 auto_set_fields
.content_size
= ret
== 1;
1347 ret
= try_set_structure_field_integer(stream
->packet_context
,
1348 "packet_size", UINT64_MAX
);
1350 BT_LOGW("Cannot set `packet_size` field in packet context: "
1351 "ret=%d, packet-context-field-addr=%p",
1352 ret
, stream
->packet_context
);
1355 auto_set_fields
.packet_size
= ret
== 1;
1357 /* Write packet context */
1358 memcpy(&packet_context_pos
, &stream
->pos
,
1359 sizeof(packet_context_pos
));
1360 BT_LOGV_STR("Serializing packet context field.");
1361 ret
= bt_ctf_field_serialize(stream
->packet_context
,
1362 &stream
->pos
, native_byte_order
);
1364 BT_LOGE("Cannot serialize stream's packet context field: "
1365 "field-addr=%p", stream
->packet_context
);
1370 BT_LOGV("Serializing events: count=%u", stream
->events
->len
);
1372 for (i
= 0; i
< stream
->events
->len
; i
++) {
1373 struct bt_ctf_event
*event
= g_ptr_array_index(
1375 struct bt_ctf_event_class
*event_class
=
1376 bt_ctf_event_borrow_event_class(event
);
1378 BT_LOGV("Serializing event: index=%u, event-addr=%p, "
1379 "event-class-name=\"%s\", event-class-id=%" PRId64
", "
1380 "pos-offset=%" PRId64
", packet-size=%" PRIu64
,
1381 i
, event
, bt_ctf_event_class_get_name(event_class
),
1382 bt_ctf_event_class_get_id(event_class
),
1383 stream
->pos
.offset
, stream
->pos
.packet_size
);
1385 /* Write event header */
1386 BT_LOGV_STR("Serializing event's header field.");
1387 ret
= bt_ctf_field_serialize(event
->event_header
,
1388 &stream
->pos
, native_byte_order
);
1390 BT_LOGE("Cannot serialize event's header field: "
1391 "field-addr=%p", event
->event_header
);
1395 /* Write stream event context */
1396 if (event
->stream_event_context
) {
1397 BT_LOGV_STR("Serializing event's stream event context field.");
1398 ret
= bt_ctf_field_serialize(
1399 event
->stream_event_context
, &stream
->pos
,
1402 BT_LOGE("Cannot serialize event's stream event context field: "
1403 "field-addr=%p", event
->stream_event_context
);
1408 /* Write event content */
1409 ret
= bt_ctf_event_serialize(event
, &stream
->pos
,
1412 /* bt_ctf_event_serialize() logs errors */
1417 /* Rounded-up in case content_size is not byte-aligned. */
1418 packet_size_bits
= (stream
->pos
.offset
+ (CHAR_BIT
- 1)) &
1420 stream
->pos
.packet_size
= packet_size_bits
;
1422 if (stream
->packet_context
) {
1424 * Update the packet total size and content size and overwrite
1425 * the packet context.
1426 * Copy base_mma as the packet may have been remapped (e.g. when
1427 * a packet is resized).
1429 packet_context_pos
.base_mma
= stream
->pos
.base_mma
;
1430 if (auto_set_fields
.content_size
) {
1431 ret
= set_structure_field_integer(
1432 stream
->packet_context
,
1433 "content_size", stream
->pos
.offset
);
1435 BT_LOGW("Cannot set `content_size` field in packet context: "
1436 "ret=%d, packet-context-field-addr=%p",
1437 ret
, stream
->packet_context
);
1442 if (auto_set_fields
.packet_size
) {
1443 ret
= set_structure_field_integer(stream
->packet_context
,
1444 "packet_size", packet_size_bits
);
1446 BT_LOGW("Cannot set `packet_size` field in packet context: "
1447 "ret=%d, packet-context-field-addr=%p",
1448 ret
, stream
->packet_context
);
1453 BT_LOGV("Rewriting (serializing) packet context field.");
1454 ret
= bt_ctf_field_serialize(stream
->packet_context
,
1455 &packet_context_pos
, native_byte_order
);
1457 BT_LOGE("Cannot serialize stream's packet context field: "
1458 "field-addr=%p", stream
->packet_context
);
1463 g_ptr_array_set_size(stream
->events
, 0);
1464 stream
->flushed_packet_count
++;
1465 stream
->size
+= packet_size_bits
/ CHAR_BIT
;
1467 /* Reset automatically-set fields. */
1468 if (auto_set_fields
.timestamp_begin
) {
1469 reset_structure_field(stream
->packet_context
,
1472 if (auto_set_fields
.timestamp_end
) {
1473 reset_structure_field(stream
->packet_context
,
1476 if (auto_set_fields
.packet_size
) {
1477 reset_structure_field(stream
->packet_context
,
1480 if (auto_set_fields
.content_size
) {
1481 reset_structure_field(stream
->packet_context
,
1488 * We failed to write the packet. Its size is therefore set to 0
1489 * to ensure the next mapping is done in the same place rather
1490 * than advancing by "stream->pos.packet_size", which would
1491 * leave a corrupted packet in the trace.
1493 stream
->pos
.packet_size
= 0;
1495 BT_LOGV("Flushed stream's current packet: packet-size=%" PRIu64
,
1501 /* Pre-2.0 CTF writer backward compatibility */
1502 void bt_ctf_stream_get(struct bt_ctf_stream
*stream
)
1507 /* Pre-2.0 CTF writer backward compatibility */
1508 void bt_ctf_stream_put(struct bt_ctf_stream
*stream
)
1514 void bt_ctf_stream_destroy(struct bt_object
*obj
)
1516 struct bt_ctf_stream
*stream
;
1519 stream
= container_of(obj
, struct bt_ctf_stream
, base
);
1520 BT_LOGD("Destroying stream object: addr=%p, name=\"%s\"",
1521 stream
, bt_ctf_stream_get_name(stream
));
1523 /* Call destroy listeners in reverse registration order */
1524 for (i
= stream
->destroy_listeners
->len
- 1; i
>= 0; i
--) {
1525 struct bt_ctf_stream_destroy_listener
*listener
=
1526 &g_array_index(stream
->destroy_listeners
,
1527 struct bt_ctf_stream_destroy_listener
, i
);
1529 BT_LOGD("Calling destroy listener: func=%p, data=%p, index=%d",
1530 listener
->func
, listener
->data
, i
);
1531 listener
->func(stream
, listener
->data
);
1534 (void) bt_ctf_stream_pos_fini(&stream
->pos
);
1535 if (stream
->pos
.fd
>= 0) {
1539 * Truncate the file's size to the minimum required to fit the
1540 * last packet as we might have grown it too much on the last
1544 ret
= ftruncate(stream
->pos
.fd
, stream
->size
);
1545 } while (ret
== -1 && errno
== EINTR
);
1547 BT_LOGE("Failed to truncate stream file: %s: "
1548 "ret=%d, errno=%d, size=%" PRIu64
,
1549 strerror(errno
), ret
, errno
,
1550 (uint64_t) stream
->size
);
1553 if (close(stream
->pos
.fd
)) {
1554 BT_LOGE("Failed to close stream file: %s: "
1555 "ret=%d, errno=%d", strerror(errno
),
1560 if (stream
->events
) {
1561 BT_LOGD_STR("Putting events.");
1562 g_ptr_array_free(stream
->events
, TRUE
);
1566 g_string_free(stream
->name
, TRUE
);
1569 if (stream
->comp_cur_port
) {
1570 GHashTableIter ht_iter
;
1571 gpointer comp_gptr
, port_gptr
;
1574 * Since we're destroying the stream, remove the destroy
1575 * listeners that it registered for each component in
1576 * its component-port mapping hash table. Otherwise they
1577 * would be called and the stream would be accessed once
1578 * it's freed or another stream would be accessed.
1580 g_hash_table_iter_init(&ht_iter
, stream
->comp_cur_port
);
1582 while (g_hash_table_iter_next(&ht_iter
, &comp_gptr
, &port_gptr
)) {
1584 bt_component_remove_destroy_listener((void *) comp_gptr
,
1585 component_destroy_listener
, stream
);
1588 g_hash_table_destroy(stream
->comp_cur_port
);
1591 if (stream
->destroy_listeners
) {
1592 g_array_free(stream
->destroy_listeners
, TRUE
);
1595 BT_LOGD_STR("Putting packet header field.");
1596 bt_put(stream
->packet_header
);
1597 BT_LOGD_STR("Putting packet context field.");
1598 bt_put(stream
->packet_context
);
1603 int _set_structure_field_integer(struct bt_ctf_field
*structure
, char *name
,
1604 uint64_t value
, bt_bool force
)
1607 struct bt_ctf_field_type
*field_type
= NULL
;
1608 struct bt_ctf_field
*integer
;
1613 integer
= bt_ctf_field_structure_get_field(structure
, name
);
1615 /* Field not found, not an error. */
1616 BT_LOGV("Field not found: struct-field-addr=%p, "
1617 "name=\"%s\", force=%d", structure
, name
, force
);
1621 /* Make sure the payload has not already been set. */
1622 if (!force
&& bt_ctf_field_is_set(integer
)) {
1623 /* Payload already set, not an error */
1624 BT_LOGV("Field's payload is already set: struct-field-addr=%p, "
1625 "name=\"%s\", force=%d", structure
, name
, force
);
1629 field_type
= bt_ctf_field_get_type(integer
);
1631 if (bt_ctf_field_type_get_type_id(field_type
) != BT_CTF_FIELD_TYPE_ID_INTEGER
) {
1633 * The user most likely meant for us to populate this field
1634 * automatically. However, we can only do this if the field
1635 * is an integer. Return an error.
1637 BT_LOGW("Invalid parameter: field's type is not an integer field type: "
1638 "field-addr=%p, ft-addr=%p, ft-id=%s",
1639 integer
, field_type
,
1640 bt_ctf_field_type_id_string(field_type
->id
));
1645 if (bt_ctf_field_type_integer_get_signed(field_type
)) {
1646 ret
= bt_ctf_field_signed_integer_set_value(integer
,
1649 ret
= bt_ctf_field_unsigned_integer_set_value(integer
, value
);
1651 ret
= !ret
? 1 : ret
;
1659 int set_structure_field_integer(struct bt_ctf_field
*structure
, char *name
,
1662 return _set_structure_field_integer(structure
, name
, value
, BT_TRUE
);
1666 * Returns the following codes:
1667 * 1 if the field was found and set,
1668 * 0 if nothing was done (field not found, or was already set),
1669 * <0 if an error was encoutered
1672 int try_set_structure_field_integer(struct bt_ctf_field
*structure
, char *name
,
1675 return _set_structure_field_integer(structure
, name
, value
, BT_FALSE
);
1678 const char *bt_ctf_stream_get_name(struct bt_ctf_stream
*stream
)
1680 const char *name
= NULL
;
1683 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1687 name
= stream
->name
? stream
->name
->str
: NULL
;
1693 int bt_ctf_stream_is_writer(struct bt_ctf_stream
*stream
)
1698 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1702 ret
= (stream
->pos
.fd
>= 0);
1709 void bt_ctf_stream_map_component_to_port(struct bt_ctf_stream
*stream
,
1710 struct bt_component
*comp
,
1711 struct bt_port
*port
)
1716 assert(stream
->comp_cur_port
);
1719 * Do not take a reference to the component here because we
1720 * don't want the component to exist as long as this stream
1721 * exists. Instead, keep a weak reference, but add a destroy
1722 * listener so that we remove this hash table entry when we know
1723 * the component is destroyed.
1725 bt_component_add_destroy_listener(comp
, component_destroy_listener
,
1727 g_hash_table_insert(stream
->comp_cur_port
, comp
, port
);
1728 BT_LOGV("Mapped component to port for stream: stream-addr=%p, "
1729 "stream-name=\"%s\", comp-addr=%p, comp-name=\"%s\", "
1730 "port-addr=%p, port-name=\"%s\"",
1731 stream
, bt_ctf_stream_get_name(stream
),
1732 comp
, bt_component_get_name(comp
), port
,
1733 bt_port_get_name(port
));
1737 struct bt_port
*bt_ctf_stream_port_for_component(struct bt_ctf_stream
*stream
,
1738 struct bt_component
*comp
)
1742 assert(stream
->comp_cur_port
);
1743 return g_hash_table_lookup(stream
->comp_cur_port
, comp
);
1747 void bt_ctf_stream_add_destroy_listener(struct bt_ctf_stream
*stream
,
1748 bt_ctf_stream_destroy_listener_func func
, void *data
)
1750 struct bt_ctf_stream_destroy_listener listener
;
1754 listener
.func
= func
;
1755 listener
.data
= data
;
1756 g_array_append_val(stream
->destroy_listeners
, listener
);
1757 BT_LOGV("Added stream destroy listener: stream-addr=%p, "
1758 "stream-name=\"%s\", func=%p, data=%p",
1759 stream
, bt_ctf_stream_get_name(stream
), func
, data
);
1763 void bt_ctf_stream_remove_destroy_listener(struct bt_ctf_stream
*stream
,
1764 bt_ctf_stream_destroy_listener_func func
, void *data
)
1771 for (i
= 0; i
< stream
->destroy_listeners
->len
; i
++) {
1772 struct bt_ctf_stream_destroy_listener
*listener
=
1773 &g_array_index(stream
->destroy_listeners
,
1774 struct bt_ctf_stream_destroy_listener
, i
);
1776 if (listener
->func
== func
&& listener
->data
== data
) {
1777 g_array_remove_index(stream
->destroy_listeners
, i
);
1779 BT_LOGV("Removed stream destroy listener: stream-addr=%p, "
1780 "stream-name=\"%s\", func=%p, data=%p",
1781 stream
, bt_ctf_stream_get_name(stream
),