4 * Babeltrace CTF IR - Trace
6 * Copyright 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 "TRACE"
30 #include <babeltrace/lib-logging-internal.h>
32 #include <babeltrace/assert-pre-internal.h>
33 #include <babeltrace/ctf-ir/trace-internal.h>
34 #include <babeltrace/ctf-ir/clock-class-internal.h>
35 #include <babeltrace/ctf-ir/stream-internal.h>
36 #include <babeltrace/ctf-ir/stream-class-internal.h>
37 #include <babeltrace/ctf-ir/event-internal.h>
38 #include <babeltrace/ctf-ir/event-class.h>
39 #include <babeltrace/ctf-ir/event-class-internal.h>
40 #include <babeltrace/ctf-writer/functor-internal.h>
41 #include <babeltrace/ctf-writer/clock-internal.h>
42 #include <babeltrace/ctf-ir/field-wrapper-internal.h>
43 #include <babeltrace/ctf-ir/field-types-internal.h>
44 #include <babeltrace/ctf-ir/attributes-internal.h>
45 #include <babeltrace/ctf-ir/validation-internal.h>
46 #include <babeltrace/ctf-ir/visitor-internal.h>
47 #include <babeltrace/ctf-ir/utils.h>
48 #include <babeltrace/ctf-ir/utils-internal.h>
49 #include <babeltrace/compiler-internal.h>
50 #include <babeltrace/values.h>
51 #include <babeltrace/values-internal.h>
52 #include <babeltrace/ref.h>
53 #include <babeltrace/types.h>
54 #include <babeltrace/endian-internal.h>
55 #include <babeltrace/assert-internal.h>
61 #define DEFAULT_IDENTIFIER_SIZE 128
62 #define DEFAULT_METADATA_STRING_SIZE 4096
64 struct listener_wrapper
{
65 bt_listener_cb listener
;
69 struct bt_trace_is_static_listener_elem
{
70 bt_trace_is_static_listener func
;
71 bt_trace_listener_removed removed
;
76 void bt_trace_finalize(struct bt_trace
*trace
)
78 BT_LOGD("Finalizing trace object: addr=%p, name=\"%s\"",
79 trace
, bt_trace_get_name(trace
));
81 if (trace
->environment
) {
82 BT_LOGD_STR("Destroying environment attributes.");
83 bt_attributes_destroy(trace
->environment
);
87 g_string_free(trace
->name
, TRUE
);
90 if (trace
->clock_classes
) {
91 BT_LOGD_STR("Putting clock classes.");
92 g_ptr_array_free(trace
->clock_classes
, TRUE
);
96 BT_LOGD_STR("Destroying streams.");
97 g_ptr_array_free(trace
->streams
, TRUE
);
100 if (trace
->stream_classes
) {
101 BT_LOGD_STR("Destroying stream classes.");
102 g_ptr_array_free(trace
->stream_classes
, TRUE
);
105 BT_LOGD_STR("Putting packet header field type.");
106 bt_put(trace
->packet_header_field_type
);
110 void bt_trace_destroy(struct bt_object
*obj
)
112 struct bt_trace
*trace
= (void *) obj
;
114 BT_LOGD("Destroying trace object: addr=%p, name=\"%s\"",
115 trace
, bt_trace_get_name(trace
));
118 * Call remove listeners first so that everything else still
119 * exists in the trace.
121 if (trace
->is_static_listeners
) {
124 for (i
= 0; i
< trace
->is_static_listeners
->len
; i
++) {
125 struct bt_trace_is_static_listener_elem elem
=
126 g_array_index(trace
->is_static_listeners
,
127 struct bt_trace_is_static_listener_elem
, i
);
130 elem
.removed(trace
, elem
.data
);
134 g_array_free(trace
->is_static_listeners
, TRUE
);
137 if (trace
->listeners
) {
138 g_ptr_array_free(trace
->listeners
, TRUE
);
141 bt_object_pool_finalize(&trace
->packet_header_field_pool
);
142 bt_trace_finalize(trace
);
147 int bt_trace_initialize(struct bt_trace
*trace
,
148 bt_object_release_func release_func
)
152 BT_LOGD_STR("Initializing trace object.");
153 trace
->native_byte_order
= BT_BYTE_ORDER_UNSPECIFIED
;
154 bt_object_init_shared_with_parent(&trace
->base
, release_func
);
155 trace
->clock_classes
= g_ptr_array_new_with_free_func(
156 (GDestroyNotify
) bt_put
);
157 if (!trace
->clock_classes
) {
158 BT_LOGE_STR("Failed to allocate one GPtrArray.");
162 trace
->streams
= g_ptr_array_new_with_free_func(
163 (GDestroyNotify
) bt_object_try_spec_release
);
164 if (!trace
->streams
) {
165 BT_LOGE_STR("Failed to allocate one GPtrArray.");
169 trace
->stream_classes
= g_ptr_array_new_with_free_func(
170 (GDestroyNotify
) bt_object_try_spec_release
);
171 if (!trace
->stream_classes
) {
172 BT_LOGE_STR("Failed to allocate one GPtrArray.");
176 /* Create the environment array object */
177 trace
->environment
= bt_attributes_create();
178 if (!trace
->environment
) {
179 BT_LOGE_STR("Cannot create empty attributes object.");
183 BT_LOGD("Initialized trace object: addr=%p", trace
);
194 void free_packet_header_field(struct bt_field_wrapper
*field_wrapper
,
195 struct bt_trace
*trace
)
197 bt_field_wrapper_destroy(field_wrapper
);
200 struct bt_trace
*bt_trace_create(void)
202 struct bt_trace
*trace
= NULL
;
205 BT_LOGD_STR("Creating trace object.");
206 trace
= g_new0(struct bt_trace
, 1);
208 BT_LOGE_STR("Failed to allocate one trace.");
212 ret
= bt_trace_initialize(trace
, bt_trace_destroy
);
214 /* bt_trace_initialize() logs errors */
218 trace
->listeners
= g_ptr_array_new_with_free_func(
219 (GDestroyNotify
) g_free
);
220 if (!trace
->listeners
) {
221 BT_LOGE_STR("Failed to allocate one GPtrArray.");
225 trace
->is_static_listeners
= g_array_new(FALSE
, TRUE
,
226 sizeof(struct bt_trace_is_static_listener_elem
));
227 if (!trace
->is_static_listeners
) {
228 BT_LOGE_STR("Failed to allocate one GArray.");
232 ret
= bt_object_pool_initialize(&trace
->packet_header_field_pool
,
233 (bt_object_pool_new_object_func
) bt_field_wrapper_new
,
234 (bt_object_pool_destroy_object_func
) free_packet_header_field
,
237 BT_LOGE("Failed to initialize packet header field pool: ret=%d",
242 BT_LOGD("Created trace object: addr=%p", trace
);
250 const char *bt_trace_get_name(struct bt_trace
*trace
)
252 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
253 return trace
->name
? trace
->name
->str
: NULL
;
256 int bt_trace_set_name(struct bt_trace
*trace
, const char *name
)
261 BT_LOGW_STR("Invalid parameter: trace is NULL.");
267 BT_LOGW_STR("Invalid parameter: name is NULL.");
273 BT_LOGW("Invalid parameter: trace is frozen: "
274 "addr=%p, name=\"%s\"",
275 trace
, bt_trace_get_name(trace
));
280 trace
->name
= trace
->name
? g_string_assign(trace
->name
, name
) :
283 BT_LOGE_STR("Failed to allocate one GString.");
288 BT_LOGV("Set trace's name: addr=%p, name=\"%s\"", trace
, name
);
294 const unsigned char *bt_trace_get_uuid(struct bt_trace
*trace
)
296 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
297 return trace
->uuid_set
? trace
->uuid
: NULL
;
300 int bt_trace_set_uuid(struct bt_trace
*trace
,
301 const unsigned char *uuid
)
306 BT_LOGW_STR("Invalid parameter: trace is NULL.");
312 BT_LOGW_STR("Invalid parameter: UUID is NULL.");
318 BT_LOGW("Invalid parameter: trace is frozen: "
319 "addr=%p, name=\"%s\"",
320 trace
, bt_trace_get_name(trace
));
325 memcpy(trace
->uuid
, uuid
, BABELTRACE_UUID_LEN
);
326 trace
->uuid_set
= BT_TRUE
;
327 BT_LOGV("Set trace's UUID: addr=%p, name=\"%s\", "
328 "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
329 trace
, bt_trace_get_name(trace
),
330 (unsigned int) uuid
[0],
331 (unsigned int) uuid
[1],
332 (unsigned int) uuid
[2],
333 (unsigned int) uuid
[3],
334 (unsigned int) uuid
[4],
335 (unsigned int) uuid
[5],
336 (unsigned int) uuid
[6],
337 (unsigned int) uuid
[7],
338 (unsigned int) uuid
[8],
339 (unsigned int) uuid
[9],
340 (unsigned int) uuid
[10],
341 (unsigned int) uuid
[11],
342 (unsigned int) uuid
[12],
343 (unsigned int) uuid
[13],
344 (unsigned int) uuid
[14],
345 (unsigned int) uuid
[15]);
351 int bt_trace_set_environment_field(struct bt_trace
*trace
,
352 const char *name
, struct bt_value
*value
)
357 BT_LOGW_STR("Invalid parameter: trace is NULL.");
363 BT_LOGW_STR("Invalid parameter: name is NULL.");
369 BT_LOGW_STR("Invalid parameter: value is NULL.");
374 if (trace
->is_static
) {
375 BT_LOGW("Invalid parameter: trace is static: "
376 "addr=%p, name=\"%s\"",
377 trace
, bt_trace_get_name(trace
));
382 if (!bt_identifier_is_valid(name
)) {
383 BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: "
384 "trace-addr=%p, trace-name=\"%s\", "
386 trace
, bt_trace_get_name(trace
), name
);
391 if (!bt_value_is_integer(value
) && !bt_value_is_string(value
)) {
392 BT_LOGW("Invalid parameter: environment field's value is not an integer or string value: "
393 "trace-addr=%p, trace-name=\"%s\", "
394 "env-name=\"%s\", env-value-type=%s",
395 trace
, bt_trace_get_name(trace
), name
,
396 bt_value_type_string(bt_value_get_type(value
)));
403 * New environment fields may be added to a frozen trace,
404 * but existing fields may not be changed.
406 * The object passed is frozen like all other attributes.
408 struct bt_value
*attribute
=
409 bt_attributes_borrow_field_value_by_name(
410 trace
->environment
, name
);
413 BT_LOGW("Invalid parameter: trace is frozen and environment field already exists with this name: "
414 "trace-addr=%p, trace-name=\"%s\", "
416 trace
, bt_trace_get_name(trace
), name
);
421 bt_value_freeze(value
);
424 ret
= bt_attributes_set_field_value(trace
->environment
, name
,
427 BT_LOGE("Cannot set environment field's value: "
428 "trace-addr=%p, trace-name=\"%s\", "
430 trace
, bt_trace_get_name(trace
), name
);
432 BT_LOGV("Set environment field's value: "
433 "trace-addr=%p, trace-name=\"%s\", "
434 "env-name=\"%s\", value-addr=%p",
435 trace
, bt_trace_get_name(trace
), name
, value
);
442 int bt_trace_set_environment_field_string(struct bt_trace
*trace
,
443 const char *name
, const char *value
)
446 struct bt_value
*env_value_string_obj
= NULL
;
449 BT_LOGW_STR("Invalid parameter: value is NULL.");
454 env_value_string_obj
= bt_value_string_create_init(value
);
455 if (!env_value_string_obj
) {
456 BT_LOGE_STR("Cannot create string value object.");
461 /* bt_trace_set_environment_field() logs errors */
462 ret
= bt_trace_set_environment_field(trace
, name
,
463 env_value_string_obj
);
466 bt_put(env_value_string_obj
);
470 int bt_trace_set_environment_field_integer(
471 struct bt_trace
*trace
, const char *name
, int64_t value
)
474 struct bt_value
*env_value_integer_obj
= NULL
;
476 env_value_integer_obj
= bt_value_integer_create_init(value
);
477 if (!env_value_integer_obj
) {
478 BT_LOGE_STR("Cannot create integer value object.");
483 /* bt_trace_set_environment_field() logs errors */
484 ret
= bt_trace_set_environment_field(trace
, name
,
485 env_value_integer_obj
);
488 bt_put(env_value_integer_obj
);
492 int64_t bt_trace_get_environment_field_count(struct bt_trace
*trace
)
496 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
497 ret
= bt_attributes_get_count(trace
->environment
);
503 bt_trace_get_environment_field_name_by_index(struct bt_trace
*trace
,
506 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
507 return bt_attributes_get_field_name(trace
->environment
, index
);
510 struct bt_value
*bt_trace_borrow_environment_field_value_by_index(
511 struct bt_trace
*trace
, uint64_t index
)
513 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
514 return bt_attributes_borrow_field_value(trace
->environment
, index
);
517 struct bt_value
*bt_trace_borrow_environment_field_value_by_name(
518 struct bt_trace
*trace
, const char *name
)
520 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
521 BT_ASSERT_PRE_NON_NULL(name
, "Name");
522 return bt_attributes_borrow_field_value_by_name(trace
->environment
,
526 int bt_trace_add_clock_class(struct bt_trace
*trace
,
527 struct bt_clock_class
*clock_class
)
532 BT_LOGW_STR("Invalid parameter: trace is NULL.");
537 if (trace
->is_static
) {
538 BT_LOGW("Invalid parameter: trace is static: "
539 "addr=%p, name=\"%s\"",
540 trace
, bt_trace_get_name(trace
));
545 if (!bt_clock_class_is_valid(clock_class
)) {
546 BT_LOGW("Invalid parameter: clock class is invalid: "
547 "trace-addr=%p, trace-name=\"%s\", "
548 "clock-class-addr=%p, clock-class-name=\"%s\"",
549 trace
, bt_trace_get_name(trace
),
550 clock_class
, bt_clock_class_get_name(clock_class
));
555 /* Check for duplicate clock classes */
556 if (bt_trace_has_clock_class(trace
, clock_class
)) {
557 BT_LOGW("Invalid parameter: clock class already exists in trace: "
558 "trace-addr=%p, trace-name=\"%s\", "
559 "clock-class-addr=%p, clock-class-name=\"%s\"",
560 trace
, bt_trace_get_name(trace
),
561 clock_class
, bt_clock_class_get_name(clock_class
));
567 g_ptr_array_add(trace
->clock_classes
, clock_class
);
570 BT_LOGV_STR("Freezing added clock class because trace is frozen.");
571 bt_clock_class_freeze(clock_class
);
574 BT_LOGV("Added clock class to trace: "
575 "trace-addr=%p, trace-name=\"%s\", "
576 "clock-class-addr=%p, clock-class-name=\"%s\"",
577 trace
, bt_trace_get_name(trace
),
578 clock_class
, bt_clock_class_get_name(clock_class
));
584 int64_t bt_trace_get_clock_class_count(struct bt_trace
*trace
)
586 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
587 return trace
->clock_classes
->len
;
590 struct bt_clock_class
*bt_trace_borrow_clock_class_by_index(
591 struct bt_trace
*trace
, uint64_t index
)
593 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
594 BT_ASSERT_PRE(index
< trace
->clock_classes
->len
,
595 "Index is out of bounds: index=%" PRIu64
", "
597 index
, trace
->clock_classes
->len
);
598 return g_ptr_array_index(trace
->clock_classes
, index
);
602 bool packet_header_field_type_is_valid(struct bt_trace
*trace
,
603 struct bt_field_type
*packet_header_type
)
606 bool is_valid
= true;
607 struct bt_field_type
*field_type
= NULL
;
609 if (!packet_header_type
) {
611 * No packet header field type: trace must have only
612 * one stream. At this point the stream class being
613 * added is not part of the trace yet, so we validate
614 * that the trace contains no stream classes yet.
616 if (trace
->stream_classes
->len
>= 1) {
617 BT_LOGW_STR("Invalid packet header field type: "
618 "packet header field type does not exist but there's more than one stream class in the trace.");
622 /* No packet header field type: valid at this point */
626 /* Packet header field type, if it exists, must be a structure */
627 if (packet_header_type
->id
!= BT_FIELD_TYPE_ID_STRUCT
) {
628 BT_LOGW("Invalid packet header field type: must be a structure field type if it exists: "
629 "ft-addr=%p, ft-id=%s",
631 bt_common_field_type_id_string(packet_header_type
->id
));
636 * If there's a `magic` field, it must be a 32-bit unsigned
637 * integer field type. Also it must be the first field of the
638 * packet header field type.
640 field_type
= bt_field_type_structure_borrow_field_type_by_name(
641 packet_header_type
, "magic");
643 const char *field_name
;
645 if (field_type
->id
!= BT_FIELD_TYPE_ID_INTEGER
) {
646 BT_LOGW("Invalid packet header field type: `magic` field must be an integer field type: "
647 "magic-ft-addr=%p, magic-ft-id=%s",
649 bt_common_field_type_id_string(field_type
->id
));
653 if (bt_field_type_integer_is_signed(field_type
)) {
654 BT_LOGW("Invalid packet header field type: `magic` field must be an unsigned integer field type: "
655 "magic-ft-addr=%p", field_type
);
659 if (bt_field_type_integer_get_size(field_type
) != 32) {
660 BT_LOGW("Invalid packet header field type: `magic` field must be a 32-bit unsigned integer field type: "
661 "magic-ft-addr=%p, magic-ft-size=%u",
663 bt_field_type_integer_get_size(field_type
));
667 ret
= bt_field_type_structure_borrow_field_by_index(
668 packet_header_type
, &field_name
, NULL
, 0);
671 if (strcmp(field_name
, "magic") != 0) {
672 BT_LOGW("Invalid packet header field type: `magic` field must be the first field: "
673 "magic-ft-addr=%p, first-field-name=\"%s\"",
674 field_type
, field_name
);
680 * If there's a `uuid` field, it must be an array field type of
681 * length 16 with an 8-bit unsigned integer element field type.
683 field_type
= bt_field_type_structure_borrow_field_type_by_name(
684 packet_header_type
, "uuid");
686 struct bt_field_type
*elem_ft
;
688 if (field_type
->id
!= BT_FIELD_TYPE_ID_ARRAY
) {
689 BT_LOGW("Invalid packet header field type: `uuid` field must be an array field type: "
690 "uuid-ft-addr=%p, uuid-ft-id=%s",
692 bt_common_field_type_id_string(field_type
->id
));
696 if (bt_field_type_array_get_length(field_type
) != 16) {
697 BT_LOGW("Invalid packet header field type: `uuid` array field type's length must be 16: "
698 "uuid-ft-addr=%p, uuid-ft-length=%" PRId64
,
700 bt_field_type_array_get_length(field_type
));
704 elem_ft
= bt_field_type_array_borrow_element_field_type(field_type
);
707 if (elem_ft
->id
!= BT_FIELD_TYPE_ID_INTEGER
) {
708 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: "
709 "elem-ft-addr=%p, elem-ft-id=%s",
711 bt_common_field_type_id_string(elem_ft
->id
));
715 if (bt_field_type_integer_is_signed(elem_ft
)) {
716 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an unsigned integer field type: "
717 "elem-ft-addr=%p", elem_ft
);
721 if (bt_field_type_integer_get_size(elem_ft
) != 8) {
722 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an 8-bit unsigned integer field type: "
723 "elem-ft-addr=%p, elem-ft-size=%u",
725 bt_field_type_integer_get_size(elem_ft
));
731 * The `stream_id` field must exist if there's more than one
732 * stream classes in the trace.
734 field_type
= bt_field_type_structure_borrow_field_type_by_name(
735 packet_header_type
, "stream_id");
737 if (!field_type
&& trace
->stream_classes
->len
>= 1) {
738 BT_LOGW_STR("Invalid packet header field type: "
739 "`stream_id` field does not exist but there's more than one stream class in the trace.");
744 * If there's a `stream_id` field, it must be an unsigned
745 * integer field type.
748 if (field_type
->id
!= BT_FIELD_TYPE_ID_INTEGER
) {
749 BT_LOGW("Invalid packet header field type: `stream_id` field must be an integer field type: "
750 "stream-id-ft-addr=%p, stream-id-ft-id=%s",
752 bt_common_field_type_id_string(field_type
->id
));
756 if (bt_field_type_integer_is_signed(field_type
)) {
757 BT_LOGW("Invalid packet header field type: `stream_id` field must be an unsigned integer field type: "
758 "stream-id-ft-addr=%p", field_type
);
764 * If there's a `packet_seq_num` field, it must be an unsigned
765 * integer field type.
767 field_type
= bt_field_type_structure_borrow_field_type_by_name(
768 packet_header_type
, "packet_seq_num");
770 if (field_type
->id
!= BT_FIELD_TYPE_ID_INTEGER
) {
771 BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an integer field type: "
772 "stream-id-ft-addr=%p, packet-seq-num-ft-id=%s",
774 bt_common_field_type_id_string(field_type
->id
));
778 if (bt_field_type_integer_is_signed(field_type
)) {
779 BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an unsigned integer field type: "
780 "packet-seq-num-ft-addr=%p", field_type
);
795 bool packet_context_field_type_is_valid(struct bt_trace
*trace
,
796 struct bt_stream_class
*stream_class
,
797 struct bt_field_type
*packet_context_type
,
798 bool check_ts_begin_end_mapped
)
800 bool is_valid
= true;
801 struct bt_field_type
*field_type
= NULL
;
803 if (!packet_context_type
) {
804 /* No packet context field type: valid at this point */
808 /* Packet context field type, if it exists, must be a structure */
809 if (packet_context_type
->id
!= BT_FIELD_TYPE_ID_STRUCT
) {
810 BT_LOGW("Invalid packet context field type: must be a structure field type if it exists: "
811 "ft-addr=%p, ft-id=%s",
813 bt_common_field_type_id_string(packet_context_type
->id
));
818 * If there's a `packet_size` field, it must be an unsigned
819 * integer field type.
821 field_type
= bt_field_type_structure_borrow_field_type_by_name(
822 packet_context_type
, "packet_size");
824 if (field_type
->id
!= BT_FIELD_TYPE_ID_INTEGER
) {
825 BT_LOGW("Invalid packet context field type: `packet_size` field must be an integer field type: "
826 "packet-size-ft-addr=%p, packet-size-ft-id=%s",
828 bt_common_field_type_id_string(field_type
->id
));
832 if (bt_field_type_integer_is_signed(field_type
)) {
833 BT_LOGW("Invalid packet context field type: `packet_size` field must be an unsigned integer field type: "
834 "packet-size-ft-addr=%p", field_type
);
840 * If there's a `content_size` field, it must be an unsigned
841 * integer field type.
843 field_type
= bt_field_type_structure_borrow_field_type_by_name(
844 packet_context_type
, "content_size");
846 if (field_type
->id
!= BT_FIELD_TYPE_ID_INTEGER
) {
847 BT_LOGW("Invalid packet context field type: `content_size` field must be an integer field type: "
848 "content-size-ft-addr=%p, content-size-ft-id=%s",
850 bt_common_field_type_id_string(field_type
->id
));
854 if (bt_field_type_integer_is_signed(field_type
)) {
855 BT_LOGW("Invalid packet context field type: `content_size` field must be an unsigned integer field type: "
856 "content-size-ft-addr=%p", field_type
);
862 * If there's a `events_discarded` field, it must be an unsigned
863 * integer field type.
865 field_type
= bt_field_type_structure_borrow_field_type_by_name(
866 packet_context_type
, "events_discarded");
868 if (field_type
->id
!= BT_FIELD_TYPE_ID_INTEGER
) {
869 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an integer field type: "
870 "events-discarded-ft-addr=%p, events-discarded-ft-id=%s",
872 bt_common_field_type_id_string(field_type
->id
));
876 if (bt_field_type_integer_is_signed(field_type
)) {
877 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an unsigned integer field type: "
878 "events-discarded-ft-addr=%p", field_type
);
884 * If there's a `timestamp_begin` field, it must be an unsigned
885 * integer field type. Also, if the trace is not a CTF writer's
886 * trace, then we cannot automatically set the mapped clock
887 * class of this field, so it must have a mapped clock class.
889 field_type
= bt_field_type_structure_borrow_field_type_by_name(
890 packet_context_type
, "timestamp_begin");
892 if (field_type
->id
!= BT_FIELD_TYPE_ID_INTEGER
) {
893 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an integer field type: "
894 "timestamp-begin-ft-addr=%p, timestamp-begin-ft-id=%s",
896 bt_common_field_type_id_string(field_type
->id
));
900 if (bt_field_type_integer_is_signed(field_type
)) {
901 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an unsigned integer field type: "
902 "timestamp-begin-ft-addr=%p", field_type
);
906 if (check_ts_begin_end_mapped
) {
907 struct bt_clock_class
*clock_class
=
908 bt_field_type_integer_borrow_mapped_clock_class(
912 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be mapped to a clock class: "
913 "timestamp-begin-ft-addr=%p", field_type
);
920 * If there's a `timestamp_end` field, it must be an unsigned
921 * integer field type. Also, if the trace is not a CTF writer's
922 * trace, then we cannot automatically set the mapped clock
923 * class of this field, so it must have a mapped clock class.
925 field_type
= bt_field_type_structure_borrow_field_type_by_name(
926 packet_context_type
, "timestamp_end");
928 if (field_type
->id
!= BT_FIELD_TYPE_ID_INTEGER
) {
929 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an integer field type: "
930 "timestamp-end-ft-addr=%p, timestamp-end-ft-id=%s",
932 bt_common_field_type_id_string(field_type
->id
));
936 if (bt_field_type_integer_is_signed(field_type
)) {
937 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an unsigned integer field type: "
938 "timestamp-end-ft-addr=%p", field_type
);
942 if (check_ts_begin_end_mapped
) {
943 struct bt_clock_class
*clock_class
=
944 bt_field_type_integer_borrow_mapped_clock_class(
948 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be mapped to a clock class: "
949 "timestamp-end-ft-addr=%p", field_type
);
965 bool event_header_field_type_is_valid(struct bt_trace
*trace
,
966 struct bt_stream_class
*stream_class
,
967 struct bt_field_type
*event_header_type
)
969 bool is_valid
= true;
970 struct bt_field_type
*field_type
= NULL
;
973 * We do not validate that the `timestamp` field exists here
974 * because CTF does not require this exact name to be mapped to
978 if (!event_header_type
) {
980 * No event header field type: stream class must have
981 * only one event class.
983 if (bt_stream_class_get_event_class_count(stream_class
) > 1) {
984 BT_LOGW_STR("Invalid event header field type: "
985 "event header field type does not exist but there's more than one event class in the stream class.");
989 /* No event header field type: valid at this point */
993 /* Event header field type, if it exists, must be a structure */
994 if (event_header_type
->id
!= BT_FIELD_TYPE_ID_STRUCT
) {
995 BT_LOGW("Invalid event header field type: must be a structure field type if it exists: "
996 "ft-addr=%p, ft-id=%s",
998 bt_common_field_type_id_string(event_header_type
->id
));
1003 * If there's an `id` field, it must be an unsigned integer
1004 * field type or an enumeration field type with an unsigned
1005 * integer container field type.
1007 field_type
= bt_field_type_structure_borrow_field_type_by_name(
1008 event_header_type
, "id");
1010 struct bt_field_type
*int_ft
;
1012 if (field_type
->id
== BT_FIELD_TYPE_ID_INTEGER
) {
1013 int_ft
= field_type
;
1014 } else if (field_type
->id
== BT_FIELD_TYPE_ID_ENUM
) {
1015 int_ft
= bt_field_type_enumeration_borrow_container_field_type(
1018 BT_LOGW("Invalid event header field type: `id` field must be an integer or enumeration field type: "
1019 "id-ft-addr=%p, id-ft-id=%s",
1021 bt_common_field_type_id_string(field_type
->id
));
1026 if (bt_field_type_integer_is_signed(int_ft
)) {
1027 BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: "
1028 "id-ft-addr=%p", int_ft
);
1043 int check_packet_header_type_has_no_clock_class(struct bt_trace
*trace
)
1047 if (trace
->packet_header_field_type
) {
1048 struct bt_clock_class
*clock_class
= NULL
;
1050 ret
= bt_field_type_validate_single_clock_class(
1051 trace
->packet_header_field_type
,
1053 bt_put(clock_class
);
1054 if (ret
|| clock_class
) {
1055 BT_LOGW("Trace's packet header field type cannot "
1056 "contain a field type which is mapped to "
1058 "trace-addr=%p, trace-name=\"%s\", "
1059 "clock-class-name=\"%s\"",
1060 trace
, bt_trace_get_name(trace
),
1062 bt_clock_class_get_name(clock_class
) :
1071 int bt_trace_add_stream_class(struct bt_trace
*trace
,
1072 struct bt_stream_class
*stream_class
)
1077 struct bt_validation_output trace_sc_validation_output
= { 0 };
1078 struct bt_validation_output
*ec_validation_outputs
= NULL
;
1079 const enum bt_validation_flag trace_sc_validation_flags
=
1080 BT_VALIDATION_FLAG_TRACE
|
1081 BT_VALIDATION_FLAG_STREAM
;
1082 const enum bt_validation_flag ec_validation_flags
=
1083 BT_VALIDATION_FLAG_EVENT
;
1084 struct bt_field_type
*packet_header_type
= NULL
;
1085 struct bt_field_type
*packet_context_type
= NULL
;
1086 struct bt_field_type
*event_header_type
= NULL
;
1087 struct bt_field_type
*stream_event_ctx_type
= NULL
;
1088 int64_t event_class_count
;
1089 struct bt_trace
*current_parent_trace
= NULL
;
1090 struct bt_clock_class
*expected_clock_class
= NULL
;
1093 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1098 if (trace
->is_static
) {
1099 BT_LOGW_STR("Invalid parameter: trace is static.");
1104 if (!stream_class
) {
1105 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
1110 BT_LOGD("Adding stream class to trace: "
1111 "trace-addr=%p, trace-name=\"%s\", "
1112 "stream-class-addr=%p, stream-class-name=\"%s\", "
1113 "stream-class-id=%" PRId64
,
1114 trace
, bt_trace_get_name(trace
),
1115 stream_class
, bt_stream_class_get_name(stream_class
),
1116 bt_stream_class_get_id(stream_class
));
1118 current_parent_trace
= bt_stream_class_borrow_trace(stream_class
);
1119 if (current_parent_trace
) {
1120 /* Stream class is already associated to a trace, abort. */
1121 BT_LOGW("Invalid parameter: stream class is already part of a trace: "
1122 "stream-class-trace-addr=%p, "
1123 "stream-class-trace-name=\"%s\"",
1124 current_parent_trace
,
1125 bt_trace_get_name(current_parent_trace
));
1131 bt_stream_class_get_event_class_count(stream_class
);
1132 BT_ASSERT(event_class_count
>= 0);
1134 if (!stream_class
->frozen
) {
1136 * Stream class is not frozen yet. Validate that the
1137 * stream class contains at most a single clock class
1138 * because the previous
1139 * bt_stream_class_add_event_class() calls did
1140 * not make this validation since the stream class's
1141 * direct field types (packet context, event header,
1142 * event context) could change afterwards. This stream
1143 * class is about to be frozen and those field types
1144 * won't be changed if this function succeeds.
1146 * At this point we're also sure that the stream class's
1147 * clock, if any, has the same class as the stream
1148 * class's expected clock class, if any. This is why, if
1149 * bt_stream_class_validate_single_clock_class()
1150 * succeeds below, the call to
1151 * bt_stream_class_map_clock_class() at the end of this
1152 * function is safe because it maps to the same, single
1155 ret
= bt_stream_class_validate_single_clock_class(
1156 stream_class
, &expected_clock_class
);
1158 BT_LOGW("Invalid parameter: stream class or one of its "
1159 "event classes contains a field type which is "
1160 "not recursively mapped to the expected "
1162 "stream-class-addr=%p, "
1163 "stream-class-id=%" PRId64
", "
1164 "stream-class-name=\"%s\", "
1165 "expected-clock-class-addr=%p, "
1166 "expected-clock-class-name=\"%s\"",
1167 stream_class
, bt_stream_class_get_id(stream_class
),
1168 bt_stream_class_get_name(stream_class
),
1169 expected_clock_class
,
1170 expected_clock_class
?
1171 bt_clock_class_get_name(expected_clock_class
) :
1177 ret
= check_packet_header_type_has_no_clock_class(trace
);
1179 /* check_packet_header_type_has_no_clock_class() logs errors */
1184 * We're about to freeze both the trace and the stream class.
1185 * Also, each event class contained in this stream class are
1188 * This trace, this stream class, and all its event classes
1189 * should be valid at this point.
1191 * Validate trace and stream class first, then each event
1192 * class of this stream class can be validated individually.
1194 packet_header_type
=
1195 bt_trace_borrow_packet_header_field_type(trace
);
1196 packet_context_type
=
1197 bt_stream_class_borrow_packet_context_field_type(stream_class
);
1199 bt_stream_class_borrow_event_header_field_type(stream_class
);
1200 stream_event_ctx_type
=
1201 bt_stream_class_borrow_event_context_field_type(stream_class
);
1203 BT_LOGD("Validating trace and stream class field types.");
1204 ret
= bt_validate_class_types(trace
->environment
,
1205 packet_header_type
, packet_context_type
, event_header_type
,
1206 stream_event_ctx_type
, NULL
, NULL
, trace
->valid
,
1207 stream_class
->valid
, 1, &trace_sc_validation_output
,
1208 trace_sc_validation_flags
, bt_field_type_copy
);
1212 * This means something went wrong during the validation
1213 * process, not that the objects are invalid.
1215 BT_LOGE("Failed to validate trace and stream class field types: "
1220 if ((trace_sc_validation_output
.valid_flags
&
1221 trace_sc_validation_flags
) !=
1222 trace_sc_validation_flags
) {
1223 /* Invalid trace/stream class */
1224 BT_LOGW("Invalid trace or stream class field types: "
1226 trace_sc_validation_output
.valid_flags
);
1231 if (event_class_count
> 0) {
1232 ec_validation_outputs
= g_new0(struct bt_validation_output
,
1234 if (!ec_validation_outputs
) {
1235 BT_LOGE_STR("Failed to allocate one validation output structure.");
1241 /* Validate each event class individually */
1242 for (i
= 0; i
< event_class_count
; i
++) {
1243 struct bt_event_class
*event_class
=
1244 bt_stream_class_borrow_event_class_by_index(
1246 struct bt_field_type
*event_context_type
= NULL
;
1247 struct bt_field_type
*event_payload_type
= NULL
;
1249 event_context_type
=
1250 bt_event_class_borrow_context_field_type(
1252 event_payload_type
=
1253 bt_event_class_borrow_payload_field_type(
1257 * It is important to use the field types returned by
1258 * the previous trace and stream class validation here
1259 * because copies could have been made.
1261 BT_LOGD("Validating event class's field types: "
1262 "addr=%p, name=\"%s\", id=%" PRId64
,
1263 event_class
, bt_event_class_get_name(event_class
),
1264 bt_event_class_get_id(event_class
));
1265 ret
= bt_validate_class_types(trace
->environment
,
1266 trace_sc_validation_output
.packet_header_type
,
1267 trace_sc_validation_output
.packet_context_type
,
1268 trace_sc_validation_output
.event_header_type
,
1269 trace_sc_validation_output
.stream_event_ctx_type
,
1270 event_context_type
, event_payload_type
,
1271 1, 1, event_class
->valid
, &ec_validation_outputs
[i
],
1272 ec_validation_flags
, bt_field_type_copy
);
1275 BT_LOGE("Failed to validate event class field types: "
1280 if ((ec_validation_outputs
[i
].valid_flags
&
1281 ec_validation_flags
) != ec_validation_flags
) {
1282 /* Invalid event class */
1283 BT_LOGW("Invalid event class field types: "
1285 ec_validation_outputs
[i
].valid_flags
);
1291 stream_id
= bt_stream_class_get_id(stream_class
);
1292 if (stream_id
< 0) {
1293 stream_id
= trace
->next_stream_id
++;
1294 if (stream_id
< 0) {
1295 BT_LOGE_STR("No more stream class IDs available.");
1300 /* Try to assign a new stream id */
1301 for (i
= 0; i
< trace
->stream_classes
->len
; i
++) {
1302 if (stream_id
== bt_stream_class_get_id(
1303 trace
->stream_classes
->pdata
[i
])) {
1304 /* Duplicate stream id found */
1305 BT_LOGW("Duplicate stream class ID: "
1306 "id=%" PRId64
, (int64_t) stream_id
);
1312 if (bt_stream_class_set_id_no_check(stream_class
,
1314 /* TODO Should retry with a different stream id */
1315 BT_LOGE("Cannot set stream class's ID: "
1316 "id=%" PRId64
, (int64_t) stream_id
);
1323 * At this point all the field types in the validation output
1324 * are valid. Validate the semantics of some scopes according to
1325 * the CTF specification.
1327 if (!packet_header_field_type_is_valid(trace
,
1328 trace_sc_validation_output
.packet_header_type
)) {
1329 BT_LOGW_STR("Invalid trace's packet header field type.");
1334 if (!packet_context_field_type_is_valid(trace
,
1336 trace_sc_validation_output
.packet_context_type
, true)) {
1337 BT_LOGW_STR("Invalid stream class's packet context field type.");
1342 if (!event_header_field_type_is_valid(trace
,
1344 trace_sc_validation_output
.event_header_type
)) {
1345 BT_LOGW_STR("Invalid steam class's event header field type.");
1350 bt_object_set_parent(&stream_class
->base
, &trace
->base
);
1351 g_ptr_array_add(trace
->stream_classes
, stream_class
);
1354 * At this point we know that the function will be successful.
1355 * Therefore we can replace the trace and stream class field
1356 * types with what's in their validation output structure and
1357 * mark them as valid. We can also replace the field types of
1358 * all the event classes of the stream class and mark them as
1361 bt_validation_replace_types(trace
, stream_class
, NULL
,
1362 &trace_sc_validation_output
, trace_sc_validation_flags
);
1364 stream_class
->valid
= 1;
1367 * Put what was not moved in bt_validation_replace_types().
1369 bt_validation_output_put_types(&trace_sc_validation_output
);
1371 for (i
= 0; i
< event_class_count
; i
++) {
1372 struct bt_event_class
*event_class
=
1373 bt_stream_class_borrow_event_class_by_index(
1376 bt_validation_replace_types(NULL
, NULL
, event_class
,
1377 &ec_validation_outputs
[i
], ec_validation_flags
);
1378 event_class
->valid
= 1;
1381 * Put what was not moved in
1382 * bt_validation_replace_types().
1384 bt_validation_output_put_types(&ec_validation_outputs
[i
]);
1388 * Freeze the trace and the stream class.
1390 bt_stream_class_freeze(stream_class
);
1391 bt_trace_freeze(trace
);
1394 * It is safe to set the stream class's unique clock class
1395 * now because the stream class is frozen.
1397 if (expected_clock_class
) {
1398 BT_MOVE(stream_class
->clock_class
, expected_clock_class
);
1401 /* Notify listeners of the trace's schema modification. */
1402 bt_stream_class_visit(stream_class
,
1403 bt_trace_object_modification
, trace
);
1404 BT_LOGD("Added stream class to trace: "
1405 "trace-addr=%p, trace-name=\"%s\", "
1406 "stream-class-addr=%p, stream-class-name=\"%s\", "
1407 "stream-class-id=%" PRId64
,
1408 trace
, bt_trace_get_name(trace
),
1409 stream_class
, bt_stream_class_get_name(stream_class
),
1410 bt_stream_class_get_id(stream_class
));
1414 bt_object_set_parent(&stream_class
->base
, NULL
);
1416 if (ec_validation_outputs
) {
1417 for (i
= 0; i
< event_class_count
; i
++) {
1418 bt_validation_output_put_types(
1419 &ec_validation_outputs
[i
]);
1424 g_free(ec_validation_outputs
);
1425 bt_validation_output_put_types(&trace_sc_validation_output
);
1426 bt_put(expected_clock_class
);
1430 int64_t bt_trace_get_stream_count(struct bt_trace
*trace
)
1432 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
1433 return (int64_t) trace
->streams
->len
;
1436 struct bt_stream
*bt_trace_borrow_stream_by_index(
1437 struct bt_trace
*trace
, uint64_t index
)
1439 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
1440 BT_ASSERT_PRE(index
< trace
->streams
->len
,
1441 "Index is out of bounds: index=%" PRIu64
", "
1443 index
, trace
->streams
->len
);
1444 return g_ptr_array_index(trace
->streams
, index
);
1447 int64_t bt_trace_get_stream_class_count(struct bt_trace
*trace
)
1449 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
1450 return (int64_t) trace
->stream_classes
->len
;
1453 struct bt_stream_class
*bt_trace_borrow_stream_class_by_index(
1454 struct bt_trace
*trace
, uint64_t index
)
1456 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
1457 BT_ASSERT_PRE(index
< trace
->stream_classes
->len
,
1458 "Index is out of bounds: index=%" PRIu64
", "
1460 index
, trace
->stream_classes
->len
);
1461 return g_ptr_array_index(trace
->stream_classes
, index
);
1464 struct bt_stream_class
*bt_trace_borrow_stream_class_by_id(
1465 struct bt_trace
*trace
, uint64_t id_param
)
1468 struct bt_stream_class
*stream_class
= NULL
;
1469 int64_t id
= (int64_t) id_param
;
1471 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
1472 BT_ASSERT_PRE(id
>= 0,
1473 "Invalid stream class ID: %" PRIu64
, id_param
);
1475 for (i
= 0; i
< trace
->stream_classes
->len
; i
++) {
1476 struct bt_stream_class
*stream_class_candidate
;
1478 stream_class_candidate
=
1479 g_ptr_array_index(trace
->stream_classes
, i
);
1481 if (bt_stream_class_get_id(stream_class_candidate
) ==
1483 stream_class
= stream_class_candidate
;
1489 return stream_class
;
1492 struct bt_clock_class
*bt_trace_borrow_clock_class_by_name(
1493 struct bt_trace
*trace
, const char *name
)
1496 struct bt_clock_class
*clock_class
= NULL
;
1498 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
1499 BT_ASSERT_PRE_NON_NULL(name
, "Name");
1501 for (i
= 0; i
< trace
->clock_classes
->len
; i
++) {
1502 struct bt_clock_class
*cur_clk
=
1503 g_ptr_array_index(trace
->clock_classes
, i
);
1504 const char *cur_clk_name
= bt_clock_class_get_name(cur_clk
);
1506 if (!cur_clk_name
) {
1510 if (!strcmp(cur_clk_name
, name
)) {
1511 clock_class
= cur_clk
;
1521 bt_bool
bt_trace_has_clock_class(struct bt_trace
*trace
,
1522 struct bt_clock_class
*clock_class
)
1524 struct search_query query
= { .value
= clock_class
, .found
= 0 };
1527 BT_ASSERT(clock_class
);
1529 g_ptr_array_foreach(trace
->clock_classes
, value_exists
, &query
);
1533 enum bt_byte_order
bt_trace_get_native_byte_order(
1534 struct bt_trace
*trace
)
1536 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
1537 return trace
->native_byte_order
;
1540 int bt_trace_set_native_byte_order(struct bt_trace
*trace
,
1541 enum bt_byte_order byte_order
)
1546 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1551 if (trace
->frozen
) {
1552 BT_LOGW("Invalid parameter: trace is frozen: "
1553 "addr=%p, name=\"%s\"",
1554 trace
, bt_trace_get_name(trace
));
1559 if (byte_order
!= BT_BYTE_ORDER_LITTLE_ENDIAN
&&
1560 byte_order
!= BT_BYTE_ORDER_BIG_ENDIAN
&&
1561 byte_order
!= BT_BYTE_ORDER_NETWORK
) {
1562 BT_LOGW("Invalid parameter: invalid byte order: "
1563 "addr=%p, name=\"%s\", bo=%s",
1564 trace
, bt_trace_get_name(trace
),
1565 bt_common_byte_order_string(byte_order
));
1570 trace
->native_byte_order
= byte_order
;
1571 BT_LOGV("Set trace's native byte order: "
1572 "addr=%p, name=\"%s\", bo=%s",
1573 trace
, bt_trace_get_name(trace
),
1574 bt_common_byte_order_string(byte_order
));
1580 struct bt_field_type
*bt_trace_borrow_packet_header_field_type(
1581 struct bt_trace
*trace
)
1583 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
1584 return trace
->packet_header_field_type
;
1587 int bt_trace_set_packet_header_field_type(struct bt_trace
*trace
,
1588 struct bt_field_type
*packet_header_type
)
1593 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1598 if (trace
->frozen
) {
1599 BT_LOGW("Invalid parameter: trace is frozen: "
1600 "addr=%p, name=\"%s\"",
1601 trace
, bt_trace_get_name(trace
));
1606 /* packet_header_type must be a structure. */
1607 if (packet_header_type
&&
1608 packet_header_type
->id
!= BT_FIELD_TYPE_ID_STRUCT
) {
1609 BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: "
1610 "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s",
1611 trace
, bt_trace_get_name(trace
),
1613 bt_common_field_type_id_string(packet_header_type
->id
));
1618 bt_put(trace
->packet_header_field_type
);
1619 trace
->packet_header_field_type
= bt_get(packet_header_type
);
1620 BT_LOGV("Set trace's packet header field type: "
1621 "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
1622 trace
, bt_trace_get_name(trace
), packet_header_type
);
1628 int64_t get_stream_class_count(void *element
)
1630 return bt_trace_get_stream_class_count(
1631 (struct bt_trace
*) element
);
1635 void *get_stream_class(void *element
, int i
)
1637 return bt_trace_get_stream_class_by_index(
1638 (struct bt_trace
*) element
, i
);
1642 int visit_stream_class(void *object
, bt_visitor visitor
,void *data
)
1644 return bt_stream_class_visit(object
, visitor
, data
);
1647 int bt_trace_visit(struct bt_trace
*trace
,
1648 bt_visitor visitor
, void *data
)
1651 struct bt_visitor_object obj
= {
1653 .type
= BT_VISITOR_OBJECT_TYPE_TRACE
1657 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1663 BT_LOGW_STR("Invalid parameter: visitor is NULL.");
1668 BT_LOGV("Visiting trace: addr=%p, name=\"%s\"",
1669 trace
, bt_trace_get_name(trace
));
1670 ret
= visitor_helper(&obj
, get_stream_class_count
,
1671 get_stream_class
, visit_stream_class
, visitor
, data
);
1677 int invoke_listener(struct bt_visitor_object
*object
, void *data
)
1679 struct listener_wrapper
*listener_wrapper
= data
;
1681 listener_wrapper
->listener(object
, listener_wrapper
->data
);
1685 // TODO: add logging to this function once we use it internally.
1686 int bt_trace_add_listener(struct bt_trace
*trace
,
1687 bt_listener_cb listener
, void *listener_data
)
1690 struct listener_wrapper
*listener_wrapper
=
1691 g_new0(struct listener_wrapper
, 1);
1693 if (!trace
|| !listener
|| !listener_wrapper
) {
1698 listener_wrapper
->listener
= listener
;
1699 listener_wrapper
->data
= listener_data
;
1701 /* Visit the current schema. */
1702 ret
= bt_trace_visit(trace
, invoke_listener
, listener_wrapper
);
1708 * Add listener to the array of callbacks which will be invoked on
1711 g_ptr_array_add(trace
->listeners
, listener_wrapper
);
1714 g_free(listener_wrapper
);
1719 int bt_trace_object_modification(struct bt_visitor_object
*object
,
1723 struct bt_trace
*trace
= trace_ptr
;
1728 if (trace
->listeners
->len
== 0) {
1732 for (i
= 0; i
< trace
->listeners
->len
; i
++) {
1733 struct listener_wrapper
*listener
=
1734 g_ptr_array_index(trace
->listeners
, i
);
1736 listener
->listener(object
, listener
->data
);
1742 bt_bool
bt_trace_is_static(struct bt_trace
*trace
)
1744 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
1745 return trace
->is_static
;
1748 int bt_trace_set_is_static(struct bt_trace
*trace
)
1754 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1759 ret
= check_packet_header_type_has_no_clock_class(trace
);
1761 /* check_packet_header_type_has_no_clock_class() logs errors */
1765 trace
->is_static
= BT_TRUE
;
1766 bt_trace_freeze(trace
);
1767 BT_LOGV("Set trace static: addr=%p, name=\"%s\"",
1768 trace
, bt_trace_get_name(trace
));
1770 /* Call all the "trace is static" listeners */
1771 for (i
= 0; i
< trace
->is_static_listeners
->len
; i
++) {
1772 struct bt_trace_is_static_listener_elem elem
=
1773 g_array_index(trace
->is_static_listeners
,
1774 struct bt_trace_is_static_listener_elem
, i
);
1777 elem
.func(trace
, elem
.data
);
1785 int bt_trace_add_is_static_listener(struct bt_trace
*trace
,
1786 bt_trace_is_static_listener listener
,
1787 bt_trace_listener_removed listener_removed
, void *data
)
1790 struct bt_trace_is_static_listener_elem new_elem
= {
1792 .removed
= listener_removed
,
1797 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1803 BT_LOGW_STR("Invalid parameter: listener is NULL.");
1808 if (trace
->is_static
) {
1809 BT_LOGW("Invalid parameter: trace is already static: "
1810 "addr=%p, name=\"%s\"",
1811 trace
, bt_trace_get_name(trace
));
1816 if (trace
->in_remove_listener
) {
1817 BT_LOGW("Cannot call this function during the execution of a remove listener: "
1818 "addr=%p, name=\"%s\"",
1819 trace
, bt_trace_get_name(trace
));
1824 /* Find the next available spot */
1825 for (i
= 0; i
< trace
->is_static_listeners
->len
; i
++) {
1826 struct bt_trace_is_static_listener_elem elem
=
1827 g_array_index(trace
->is_static_listeners
,
1828 struct bt_trace_is_static_listener_elem
, i
);
1835 if (i
== trace
->is_static_listeners
->len
) {
1836 g_array_append_val(trace
->is_static_listeners
, new_elem
);
1838 g_array_insert_val(trace
->is_static_listeners
, i
, new_elem
);
1841 BT_LOGV("Added \"trace is static\" listener: "
1842 "trace-addr=%p, trace-name=\"%s\", func-addr=%p, "
1843 "data-addr=%p, listener-id=%d",
1844 trace
, bt_trace_get_name(trace
), listener
, data
, i
);
1850 int bt_trace_remove_is_static_listener(
1851 struct bt_trace
*trace
, int listener_id
)
1854 struct bt_trace_is_static_listener_elem
*elem
;
1857 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1862 if (trace
->in_remove_listener
) {
1863 BT_LOGW("Cannot call this function during the execution of a remove listener: "
1864 "addr=%p, name=\"%s\", listener-id=%d",
1865 trace
, bt_trace_get_name(trace
),
1871 if (listener_id
< 0) {
1872 BT_LOGW("Invalid listener ID: must be zero or positive: "
1873 "listener-id=%d", listener_id
);
1878 if (listener_id
>= trace
->is_static_listeners
->len
) {
1879 BT_LOGW("Invalid parameter: no listener with this listener ID: "
1880 "addr=%p, name=\"%s\", listener-id=%d",
1881 trace
, bt_trace_get_name(trace
),
1887 elem
= &g_array_index(trace
->is_static_listeners
,
1888 struct bt_trace_is_static_listener_elem
,
1891 BT_LOGW("Invalid parameter: no listener with this listener ID: "
1892 "addr=%p, name=\"%s\", listener-id=%d",
1893 trace
, bt_trace_get_name(trace
),
1899 if (elem
->removed
) {
1900 /* Call remove listener */
1901 BT_LOGV("Calling remove listener: "
1902 "trace-addr=%p, trace-name=\"%s\", "
1903 "listener-id=%d", trace
, bt_trace_get_name(trace
),
1905 trace
->in_remove_listener
= BT_TRUE
;
1906 elem
->removed(trace
, elem
->data
);
1907 trace
->in_remove_listener
= BT_FALSE
;
1911 elem
->removed
= NULL
;
1913 BT_LOGV("Removed \"trace is static\" listener: "
1914 "trace-addr=%p, trace-name=\"%s\", "
1915 "listener-id=%d", trace
, bt_trace_get_name(trace
),
1922 struct bt_packet_header_field
*bt_trace_create_packet_header_field(
1923 struct bt_trace
*trace
)
1925 struct bt_field_wrapper
*field_wrapper
;
1927 BT_ASSERT_PRE_NON_NULL(trace
, "Trace");
1928 BT_ASSERT_PRE(trace
->packet_header_field_type
,
1929 "Trace has no packet header field type: %!+t",
1931 field_wrapper
= bt_field_wrapper_create(
1932 &trace
->packet_header_field_pool
,
1933 (void *) trace
->packet_header_field_type
);
1934 if (!field_wrapper
) {
1935 BT_LIB_LOGE("Cannot allocate one packet header field from trace: "
1936 "%![trace-]+t", trace
);
1940 BT_ASSERT(field_wrapper
->field
);
1941 bt_trace_freeze(trace
);
1945 if (field_wrapper
) {
1946 bt_field_wrapper_destroy(field_wrapper
);
1947 field_wrapper
= NULL
;
1951 return (void *) field_wrapper
;