4 * Babeltrace CTF IR - Stream Class
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-CLASS"
30 #include <babeltrace/lib-logging-internal.h>
32 #include <babeltrace/ctf-writer/clock.h>
33 #include <babeltrace/ctf-writer/clock-internal.h>
34 #include <babeltrace/ctf-ir/clock-class-internal.h>
35 #include <babeltrace/ctf-writer/event.h>
36 #include <babeltrace/ctf-ir/event-class-internal.h>
37 #include <babeltrace/ctf-ir/event-internal.h>
38 #include <babeltrace/ctf-ir/field-types-internal.h>
39 #include <babeltrace/ctf-ir/fields-internal.h>
40 #include <babeltrace/ctf-writer/stream.h>
41 #include <babeltrace/ctf-ir/stream-class-internal.h>
42 #include <babeltrace/ctf-ir/validation-internal.h>
43 #include <babeltrace/ctf-ir/visitor-internal.h>
44 #include <babeltrace/ctf-writer/functor-internal.h>
45 #include <babeltrace/ctf-ir/utils.h>
46 #include <babeltrace/ctf-ir/utils-internal.h>
47 #include <babeltrace/ref.h>
48 #include <babeltrace/compiler-internal.h>
49 #include <babeltrace/align-internal.h>
50 #include <babeltrace/endian-internal.h>
56 void bt_stream_class_destroy(struct bt_object
*obj
);
58 int init_event_header(struct bt_stream_class
*stream_class
);
60 int init_packet_context(struct bt_stream_class
*stream_class
);
62 struct bt_stream_class
*bt_stream_class_create(const char *name
)
64 struct bt_stream_class
*stream_class
;
67 BT_LOGD("Creating default stream class object: name=\"%s\"", name
);
68 stream_class
= bt_stream_class_create_empty(name
);
70 BT_LOGD_STR("Cannot create empty stream class.");
74 ret
= init_event_header(stream_class
);
76 BT_LOGE_STR("Cannot initialize stream class's event header field type.");
80 ret
= init_packet_context(stream_class
);
82 BT_LOGE_STR("Cannot initialize stream class's packet context field type.");
86 BT_LOGD("Created default stream class object: addr=%p, name=\"%s\"",
95 struct bt_stream_class
*bt_stream_class_create_empty(const char *name
)
97 struct bt_stream_class
*stream_class
= NULL
;
99 BT_LOGD("Creating empty stream class object: name=\"%s\"", name
);
101 stream_class
= g_new0(struct bt_stream_class
, 1);
103 BT_LOGE_STR("Failed to allocate one stream class.");
107 stream_class
->name
= g_string_new(name
);
108 stream_class
->event_classes
= g_ptr_array_new_with_free_func(
109 (GDestroyNotify
) bt_object_release
);
110 if (!stream_class
->event_classes
) {
111 BT_LOGE_STR("Failed to allocate a GPtrArray.");
115 stream_class
->event_classes_ht
= g_hash_table_new_full(g_int64_hash
,
116 g_int64_equal
, g_free
, NULL
);
117 if (!stream_class
->event_classes_ht
) {
118 BT_LOGE_STR("Failed to allocate a GHashTable.");
122 bt_object_init(stream_class
, bt_stream_class_destroy
);
123 BT_LOGD("Created empty stream class object: addr=%p, name=\"%s\"",
128 BT_PUT(stream_class
);
132 struct bt_trace
*bt_stream_class_get_trace(
133 struct bt_stream_class
*stream_class
)
135 return stream_class
?
136 bt_get(bt_stream_class_borrow_trace(stream_class
)) :
140 const char *bt_stream_class_get_name(
141 struct bt_stream_class
*stream_class
)
143 const char *name
= NULL
;
146 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
150 name
= stream_class
->name
->len
> 0 ? stream_class
->name
->str
: NULL
;
155 int bt_stream_class_set_name(struct bt_stream_class
*stream_class
,
161 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
166 if (stream_class
->frozen
) {
167 BT_LOGW("Invalid parameter: stream class is frozen: "
168 "addr=%p, name=\"%s\", id=%" PRId64
,
169 stream_class
, bt_stream_class_get_name(stream_class
),
170 bt_stream_class_get_id(stream_class
));
176 g_string_assign(stream_class
->name
, "");
178 if (strlen(name
) == 0) {
179 BT_LOGW("Invalid parameter: name is empty.");
184 g_string_assign(stream_class
->name
, name
);
187 BT_LOGV("Set stream class's name: "
188 "addr=%p, name=\"%s\", id=%" PRId64
,
189 stream_class
, bt_stream_class_get_name(stream_class
),
190 bt_stream_class_get_id(stream_class
));
195 struct bt_ctf_clock
*bt_stream_class_get_clock(
196 struct bt_stream_class
*stream_class
)
198 struct bt_ctf_clock
*clock
= NULL
;
201 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
205 if (!stream_class
->clock
) {
206 BT_LOGV("Stream class has no clock: "
207 "addr=%p, name=\"%s\", id=%" PRId64
,
208 stream_class
, bt_stream_class_get_name(stream_class
),
209 bt_stream_class_get_id(stream_class
));
213 clock
= bt_get(stream_class
->clock
);
218 int bt_stream_class_set_clock(struct bt_stream_class
*stream_class
,
219 struct bt_ctf_clock
*clock
)
222 struct bt_field_type
*timestamp_field
= NULL
;
224 if (!stream_class
|| !clock
) {
225 BT_LOGW("Invalid parameter: stream class or clock is NULL: "
226 "stream-class-addr=%p, clock-addr=%p",
227 stream_class
, clock
);
232 if (stream_class
->frozen
) {
233 BT_LOGW("Invalid parameter: stream class is frozen: "
234 "addr=%p, name=\"%s\", id=%" PRId64
,
235 stream_class
, bt_stream_class_get_name(stream_class
),
236 bt_stream_class_get_id(stream_class
));
241 /* Replace the current clock of this stream class. */
242 bt_put(stream_class
->clock
);
243 stream_class
->clock
= bt_get(clock
);
244 BT_LOGV("Set stream class's clock: "
245 "addr=%p, name=\"%s\", id=%" PRId64
", "
246 "clock-addr=%p, clock-name=\"%s\"",
247 stream_class
, bt_stream_class_get_name(stream_class
),
248 bt_stream_class_get_id(stream_class
),
250 bt_ctf_clock_get_name(stream_class
->clock
));
253 bt_put(timestamp_field
);
257 int64_t bt_stream_class_get_id(struct bt_stream_class
*stream_class
)
262 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
267 if (!stream_class
->id_set
) {
268 BT_LOGV("Stream class's ID is not set: addr=%p, name=\"%s\"",
270 bt_stream_class_get_name(stream_class
));
275 ret
= stream_class
->id
;
281 void _bt_stream_class_set_id(
282 struct bt_stream_class
*stream_class
, int64_t id
)
284 assert(stream_class
);
285 stream_class
->id
= id
;
286 stream_class
->id_set
= 1;
287 BT_LOGV("Set stream class's ID (internal): "
288 "addr=%p, name=\"%s\", id=%" PRId64
,
289 stream_class
, bt_stream_class_get_name(stream_class
),
290 bt_stream_class_get_id(stream_class
));
293 struct event_class_set_stream_class_id_data
{
294 int64_t stream_class_id
;
299 int bt_stream_class_set_id_no_check(
300 struct bt_stream_class
*stream_class
, int64_t id
)
302 _bt_stream_class_set_id(stream_class
, id
);
306 int bt_stream_class_set_id(struct bt_stream_class
*stream_class
,
310 int64_t id
= (int64_t) id_param
;
313 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
318 if (stream_class
->frozen
) {
319 BT_LOGW("Invalid parameter: stream class is frozen: "
320 "addr=%p, name=\"%s\", id=%" PRId64
,
321 stream_class
, bt_stream_class_get_name(stream_class
),
322 bt_stream_class_get_id(stream_class
));
328 BT_LOGW("Invalid parameter: invalid stream class's ID: "
329 "stream-class-addr=%p, stream-class-name=\"%s\", "
330 "stream-class-id=%" PRId64
", id=%" PRIu64
,
331 stream_class
, bt_stream_class_get_name(stream_class
),
332 bt_stream_class_get_id(stream_class
),
338 ret
= bt_stream_class_set_id_no_check(stream_class
, id
);
340 BT_LOGV("Set stream class's ID: "
341 "addr=%p, name=\"%s\", id=%" PRId64
,
342 stream_class
, bt_stream_class_get_name(stream_class
),
343 bt_stream_class_get_id(stream_class
));
350 void event_class_exists(gpointer element
, gpointer query
)
352 struct bt_event_class
*event_class_a
= element
;
353 struct search_query
*search_query
= query
;
354 struct bt_event_class
*event_class_b
= search_query
->value
;
357 if (search_query
->value
== element
) {
358 search_query
->found
= 1;
363 * Two event classes cannot share the same ID in a given
366 id_a
= bt_event_class_get_id(event_class_a
);
367 id_b
= bt_event_class_get_id(event_class_b
);
369 if (id_a
< 0 || id_b
< 0) {
370 /* at least one ID is not set: will be automatically set later */
375 BT_LOGW("Event class with this ID already exists in the stream class: "
376 "id=%" PRId64
", name=\"%s\"",
377 id_a
, bt_event_class_get_name(event_class_a
));
378 search_query
->found
= 1;
386 int bt_stream_class_add_event_class(
387 struct bt_stream_class
*stream_class
,
388 struct bt_event_class
*event_class
)
391 int64_t *event_id
= NULL
;
392 struct bt_trace
*trace
= NULL
;
393 struct bt_stream_class
*old_stream_class
= NULL
;
394 struct bt_validation_output validation_output
= { 0 };
395 struct bt_field_type
*packet_header_type
= NULL
;
396 struct bt_field_type
*packet_context_type
= NULL
;
397 struct bt_field_type
*event_header_type
= NULL
;
398 struct bt_field_type
*stream_event_ctx_type
= NULL
;
399 struct bt_field_type
*event_context_type
= NULL
;
400 struct bt_field_type
*event_payload_type
= NULL
;
401 const enum bt_validation_flag validation_flags
=
402 BT_VALIDATION_FLAG_EVENT
;
403 struct bt_clock_class
*expected_clock_class
= NULL
;
405 if (!stream_class
|| !event_class
) {
406 BT_LOGW("Invalid parameter: stream class or event class is NULL: "
407 "stream-class-addr=%p, event-class-addr=%p",
408 stream_class
, event_class
);
413 BT_LOGD("Adding event class to stream class: "
414 "stream-class-addr=%p, stream-class-name=\"%s\", "
415 "stream-class-id=%" PRId64
", event-class-addr=%p, "
416 "event-class-name=\"%s\", event-class-id=%" PRId64
,
417 stream_class
, bt_stream_class_get_name(stream_class
),
418 bt_stream_class_get_id(stream_class
),
420 bt_event_class_get_name(event_class
),
421 bt_event_class_get_id(event_class
));
423 trace
= bt_stream_class_get_trace(stream_class
);
424 if (trace
&& trace
->is_static
) {
425 BT_LOGW("Invalid parameter: stream class's trace is static: "
426 "trace-addr=%p, trace-name=\"%s\"",
427 trace
, bt_trace_get_name(trace
));
432 if (stream_class
->frozen
) {
434 * We only check that the event class to be added has a
435 * single class which matches the stream class's
436 * expected clock class if the stream class is frozen.
437 * If it's not, then this event class is added "as is"
438 * and the validation will be performed when calling
439 * either bt_trace_add_stream_class() or
440 * bt_event_create(). This is because the stream class's
441 * field types (packet context, event header, event
442 * context) could change before the next call to one of
443 * those two functions.
445 expected_clock_class
= bt_get(stream_class
->clock_class
);
448 * At this point, `expected_clock_class` can be NULL,
449 * and bt_event_class_validate_single_clock_class()
452 ret
= bt_event_class_validate_single_clock_class(
453 event_class
, &expected_clock_class
);
455 BT_LOGW("Event class contains a field type which is not "
456 "recursively mapped to its stream class's "
457 "expected clock class: "
458 "stream-class-addr=%p, "
459 "stream-class-id=%" PRId64
", "
460 "stream-class-name=\"%s\", "
461 "expected-clock-class-addr=%p, "
462 "expected-clock-class-name=\"%s\"",
464 bt_stream_class_get_id(stream_class
),
465 bt_stream_class_get_name(stream_class
),
466 expected_clock_class
,
467 expected_clock_class
?
468 bt_clock_class_get_name(expected_clock_class
) :
474 event_id
= g_new(int64_t, 1);
476 BT_LOGE_STR("Failed to allocate one int64_t.");
481 /* Check for duplicate event classes */
482 struct search_query query
= { .value
= event_class
, .found
= 0 };
483 g_ptr_array_foreach(stream_class
->event_classes
, event_class_exists
,
486 BT_LOGW_STR("Another event class part of this stream class has the same ID.");
491 old_stream_class
= bt_event_class_get_stream_class(event_class
);
492 if (old_stream_class
) {
493 /* Event class is already associated to a stream class. */
494 BT_LOGW("Event class is already part of another stream class: "
495 "event-class-stream-class-addr=%p, "
496 "event-class-stream-class-name=\"%s\", "
497 "event-class-stream-class-id=%" PRId64
,
499 bt_stream_class_get_name(old_stream_class
),
500 bt_stream_class_get_id(old_stream_class
));
507 * If the stream class is associated with a trace, then
508 * both those objects are frozen. Also, this event class
509 * is about to be frozen.
511 * Therefore the event class must be validated here.
512 * The trace and stream class should be valid at this
515 assert(trace
->valid
);
516 assert(stream_class
->valid
);
518 bt_trace_get_packet_header_type(trace
);
519 packet_context_type
=
520 bt_stream_class_get_packet_context_type(
523 bt_stream_class_get_event_header_type(stream_class
);
524 stream_event_ctx_type
=
525 bt_stream_class_get_event_context_type(
528 bt_event_class_get_context_type(event_class
);
530 bt_event_class_get_payload_type(event_class
);
531 ret
= bt_validate_class_types(
532 trace
->environment
, packet_header_type
,
533 packet_context_type
, event_header_type
,
534 stream_event_ctx_type
, event_context_type
,
535 event_payload_type
, trace
->valid
,
536 stream_class
->valid
, event_class
->valid
,
537 &validation_output
, validation_flags
);
538 BT_PUT(packet_header_type
);
539 BT_PUT(packet_context_type
);
540 BT_PUT(event_header_type
);
541 BT_PUT(stream_event_ctx_type
);
542 BT_PUT(event_context_type
);
543 BT_PUT(event_payload_type
);
547 * This means something went wrong during the
548 * validation process, not that the objects are
551 BT_LOGE("Failed to validate event class: ret=%d", ret
);
555 if ((validation_output
.valid_flags
& validation_flags
) !=
557 /* Invalid event class */
558 BT_LOGW("Invalid trace, stream class, or event class: "
560 validation_output
.valid_flags
);
566 /* Only set an event ID if none was explicitly set before */
567 *event_id
= bt_event_class_get_id(event_class
);
569 BT_LOGV("Event class has no ID: automatically setting it: "
570 "id=%" PRId64
, stream_class
->next_event_id
);
572 if (bt_event_class_set_id(event_class
,
573 stream_class
->next_event_id
)) {
574 BT_LOGE("Cannot set event class's ID: id=%" PRId64
,
575 stream_class
->next_event_id
);
579 stream_class
->next_event_id
++;
580 *event_id
= stream_class
->next_event_id
;
583 bt_object_set_parent(event_class
, stream_class
);
587 * At this point we know that the function will be
588 * successful. Therefore we can replace the event
589 * class's field types with what's in the validation
590 * output structure and mark this event class as valid.
592 bt_validation_replace_types(NULL
, NULL
, event_class
,
593 &validation_output
, validation_flags
);
594 event_class
->valid
= 1;
597 * Put what was not moved in
598 * bt_validation_replace_types().
600 bt_validation_output_put_types(&validation_output
);
603 /* Add to the event classes of the stream class */
604 g_ptr_array_add(stream_class
->event_classes
, event_class
);
605 g_hash_table_insert(stream_class
->event_classes_ht
, event_id
,
609 /* Freeze the event class */
610 bt_event_class_freeze(event_class
);
613 * It is safe to set the stream class's unique clock class
614 * now if the stream class is frozen.
616 if (stream_class
->frozen
&& expected_clock_class
) {
617 assert(!stream_class
->clock_class
||
618 stream_class
->clock_class
== expected_clock_class
);
619 BT_MOVE(stream_class
->clock_class
, expected_clock_class
);
622 /* Notifiy listeners of the trace's schema modification. */
624 struct bt_visitor_object obj
= { .object
= event_class
,
625 .type
= BT_VISITOR_OBJECT_TYPE_EVENT_CLASS
};
627 (void) bt_trace_object_modification(&obj
, trace
);
630 BT_LOGD("Added event class to stream class: "
631 "stream-class-addr=%p, stream-class-name=\"%s\", "
632 "stream-class-id=%" PRId64
", event-class-addr=%p, "
633 "event-class-name=\"%s\", event-class-id=%" PRId64
,
634 stream_class
, bt_stream_class_get_name(stream_class
),
635 bt_stream_class_get_id(stream_class
),
637 bt_event_class_get_name(event_class
),
638 bt_event_class_get_id(event_class
));
642 BT_PUT(old_stream_class
);
643 bt_validation_output_put_types(&validation_output
);
644 bt_put(expected_clock_class
);
645 assert(!packet_header_type
);
646 assert(!packet_context_type
);
647 assert(!event_header_type
);
648 assert(!stream_event_ctx_type
);
649 assert(!event_context_type
);
650 assert(!event_payload_type
);
656 int64_t bt_stream_class_get_event_class_count(
657 struct bt_stream_class
*stream_class
)
662 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
667 ret
= (int64_t) stream_class
->event_classes
->len
;
672 struct bt_event_class
*bt_stream_class_get_event_class_by_index(
673 struct bt_stream_class
*stream_class
, uint64_t index
)
675 struct bt_event_class
*event_class
= NULL
;
678 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
682 if (index
>= stream_class
->event_classes
->len
) {
683 BT_LOGW("Invalid parameter: index is out of bounds: "
684 "addr=%p, name=\"%s\", id=%" PRId64
", "
685 "index=%" PRIu64
", count=%u",
686 stream_class
, bt_stream_class_get_name(stream_class
),
687 bt_stream_class_get_id(stream_class
),
688 index
, stream_class
->event_classes
->len
);
692 event_class
= g_ptr_array_index(stream_class
->event_classes
, index
);
698 struct bt_event_class
*bt_stream_class_get_event_class_by_id(
699 struct bt_stream_class
*stream_class
, uint64_t id
)
701 int64_t id_key
= (int64_t) id
;
702 struct bt_event_class
*event_class
= NULL
;
705 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
710 BT_LOGW("Invalid parameter: invalid event class's ID: "
711 "stream-class-addr=%p, stream-class-name=\"%s\", "
712 "stream-class-id=%" PRId64
", event-class-id=%" PRIu64
,
714 bt_stream_class_get_name(stream_class
),
715 bt_stream_class_get_id(stream_class
), id
);
719 event_class
= g_hash_table_lookup(stream_class
->event_classes_ht
,
726 struct bt_field_type
*bt_stream_class_get_packet_context_type(
727 struct bt_stream_class
*stream_class
)
729 struct bt_field_type
*ret
= NULL
;
732 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
736 bt_get(stream_class
->packet_context_type
);
737 ret
= stream_class
->packet_context_type
;
742 int bt_stream_class_set_packet_context_type(
743 struct bt_stream_class
*stream_class
,
744 struct bt_field_type
*packet_context_type
)
749 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
754 if (stream_class
->frozen
) {
755 BT_LOGW("Invalid parameter: stream class is frozen: "
756 "addr=%p, name=\"%s\", id=%" PRId64
,
757 stream_class
, bt_stream_class_get_name(stream_class
),
758 bt_stream_class_get_id(stream_class
));
763 if (packet_context_type
&&
764 bt_field_type_get_type_id(packet_context_type
) !=
765 BT_FIELD_TYPE_ID_STRUCT
) {
766 /* A packet context must be a structure. */
767 BT_LOGW("Invalid parameter: stream class's packet context field type must be a structure: "
768 "addr=%p, name=\"%s\", id=%" PRId64
", "
769 "packet-context-ft-addr=%p, packet-context-ft-id=%s",
770 stream_class
, bt_stream_class_get_name(stream_class
),
771 bt_stream_class_get_id(stream_class
),
773 bt_field_type_id_string(
774 bt_field_type_get_type_id(packet_context_type
)));
779 bt_put(stream_class
->packet_context_type
);
780 bt_get(packet_context_type
);
781 stream_class
->packet_context_type
= packet_context_type
;
782 BT_LOGV("Set stream class's packet context field type: "
783 "addr=%p, name=\"%s\", id=%" PRId64
", "
784 "packet-context-ft-addr=%p",
785 stream_class
, bt_stream_class_get_name(stream_class
),
786 bt_stream_class_get_id(stream_class
),
787 packet_context_type
);
793 struct bt_field_type
*bt_stream_class_get_event_header_type(
794 struct bt_stream_class
*stream_class
)
796 struct bt_field_type
*ret
= NULL
;
799 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
803 if (!stream_class
->event_header_type
) {
804 BT_LOGV("Stream class has no event header field type: "
805 "addr=%p, name=\"%s\", id=%" PRId64
,
806 stream_class
, bt_stream_class_get_name(stream_class
),
807 bt_stream_class_get_id(stream_class
));
811 bt_get(stream_class
->event_header_type
);
812 ret
= stream_class
->event_header_type
;
817 int bt_stream_class_set_event_header_type(
818 struct bt_stream_class
*stream_class
,
819 struct bt_field_type
*event_header_type
)
824 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
829 if (stream_class
->frozen
) {
830 BT_LOGW("Invalid parameter: stream class is frozen: "
831 "addr=%p, name=\"%s\", id=%" PRId64
,
832 stream_class
, bt_stream_class_get_name(stream_class
),
833 bt_stream_class_get_id(stream_class
));
838 if (event_header_type
&&
839 bt_field_type_get_type_id(event_header_type
) !=
840 BT_FIELD_TYPE_ID_STRUCT
) {
841 /* An event header must be a structure. */
842 BT_LOGW("Invalid parameter: stream class's event header field type must be a structure: "
843 "addr=%p, name=\"%s\", id=%" PRId64
", "
844 "event-header-ft-addr=%p, event-header-ft-id=%s",
845 stream_class
, bt_stream_class_get_name(stream_class
),
846 bt_stream_class_get_id(stream_class
),
848 bt_field_type_id_string(
849 bt_field_type_get_type_id(event_header_type
)));
854 bt_put(stream_class
->event_header_type
);
855 stream_class
->event_header_type
= bt_get(event_header_type
);
856 BT_LOGV("Set stream class's event header field type: "
857 "addr=%p, name=\"%s\", id=%" PRId64
", "
858 "event-header-ft-addr=%p",
859 stream_class
, bt_stream_class_get_name(stream_class
),
860 bt_stream_class_get_id(stream_class
),
866 struct bt_field_type
*bt_stream_class_get_event_context_type(
867 struct bt_stream_class
*stream_class
)
869 struct bt_field_type
*ret
= NULL
;
872 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
876 if (!stream_class
->event_context_type
) {
880 bt_get(stream_class
->event_context_type
);
881 ret
= stream_class
->event_context_type
;
886 int bt_stream_class_set_event_context_type(
887 struct bt_stream_class
*stream_class
,
888 struct bt_field_type
*event_context_type
)
893 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
898 if (stream_class
->frozen
) {
899 BT_LOGW("Invalid parameter: stream class is frozen: "
900 "addr=%p, name=\"%s\", id=%" PRId64
,
901 stream_class
, bt_stream_class_get_name(stream_class
),
902 bt_stream_class_get_id(stream_class
));
907 if (event_context_type
&&
908 bt_field_type_get_type_id(event_context_type
) !=
909 BT_FIELD_TYPE_ID_STRUCT
) {
910 /* A packet context must be a structure. */
911 BT_LOGW("Invalid parameter: stream class's event context field type must be a structure: "
912 "addr=%p, name=\"%s\", id=%" PRId64
", "
913 "event-context-ft-addr=%p, event-context-ft-id=%s",
914 stream_class
, bt_stream_class_get_name(stream_class
),
915 bt_stream_class_get_id(stream_class
),
917 bt_field_type_id_string(
918 bt_field_type_get_type_id(event_context_type
)));
923 bt_put(stream_class
->event_context_type
);
924 stream_class
->event_context_type
= bt_get(event_context_type
);
925 BT_LOGV("Set stream class's event context field type: "
926 "addr=%p, name=\"%s\", id=%" PRId64
", "
927 "event-context-ft-addr=%p",
928 stream_class
, bt_stream_class_get_name(stream_class
),
929 bt_stream_class_get_id(stream_class
),
935 /* Pre-2.0 CTF writer backward compatibility */
936 void bt_ctf_stream_class_get(struct bt_stream_class
*stream_class
)
938 bt_get(stream_class
);
941 /* Pre-2.0 CTF writer backward compatibility */
942 void bt_ctf_stream_class_put(struct bt_stream_class
*stream_class
)
944 bt_put(stream_class
);
948 int64_t get_event_class_count(void *element
)
950 return bt_stream_class_get_event_class_count(
951 (struct bt_stream_class
*) element
);
955 void *get_event_class(void *element
, int i
)
957 return bt_stream_class_get_event_class_by_index(
958 (struct bt_stream_class
*) element
, i
);
962 int visit_event_class(void *object
, bt_visitor visitor
,void *data
)
964 struct bt_visitor_object obj
=
966 .type
= BT_VISITOR_OBJECT_TYPE_EVENT_CLASS
};
968 return visitor(&obj
, data
);
971 int bt_stream_class_visit(struct bt_stream_class
*stream_class
,
972 bt_visitor visitor
, void *data
)
975 struct bt_visitor_object obj
=
976 { .object
= stream_class
,
977 .type
= BT_VISITOR_OBJECT_TYPE_STREAM_CLASS
};
979 if (!stream_class
|| !visitor
) {
980 BT_LOGW("Invalid parameter: stream class or visitor is NULL: "
981 "stream-class-addr=%p, visitor=%p",
982 stream_class
, visitor
);
987 ret
= visitor_helper(&obj
, get_event_class_count
,
989 visit_event_class
, visitor
, data
);
990 BT_LOGV("visitor_helper() returned: ret=%d", ret
);
996 void bt_stream_class_freeze(struct bt_stream_class
*stream_class
)
998 if (!stream_class
|| stream_class
->frozen
) {
1002 BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64
,
1003 stream_class
, bt_stream_class_get_name(stream_class
),
1004 bt_stream_class_get_id(stream_class
));
1005 stream_class
->frozen
= 1;
1006 bt_field_type_freeze(stream_class
->event_header_type
);
1007 bt_field_type_freeze(stream_class
->packet_context_type
);
1008 bt_field_type_freeze(stream_class
->event_context_type
);
1010 if (stream_class
->clock
) {
1011 bt_clock_class_freeze(stream_class
->clock
->clock_class
);
1016 int bt_stream_class_serialize(struct bt_stream_class
*stream_class
,
1017 struct metadata_context
*context
)
1021 struct bt_trace
*trace
;
1022 struct bt_field_type
*packet_header_type
= NULL
;
1024 BT_LOGD("Serializing stream class's metadata: "
1025 "stream-class-addr=%p, stream-class-name=\"%s\", "
1026 "stream-class-id=%" PRId64
", metadata-context-addr=%p",
1027 stream_class
, bt_stream_class_get_name(stream_class
),
1028 bt_stream_class_get_id(stream_class
), context
);
1029 g_string_assign(context
->field_name
, "");
1030 context
->current_indentation_level
= 1;
1031 if (!stream_class
->id_set
) {
1032 BT_LOGW_STR("Stream class's ID is not set.");
1037 g_string_append(context
->string
, "stream {\n");
1040 * The reference to the trace is only borrowed since the
1041 * serialization of the stream class might have been triggered
1042 * by the trace's destruction. In such a case, the trace's
1043 * reference count would, unexepectedly, go through the sequence
1044 * 1 -> 0 -> 1 -> 0 -> ..., provoking an endless loop of destruction
1045 * and serialization.
1047 trace
= bt_stream_class_borrow_trace(stream_class
);
1049 packet_header_type
= bt_trace_get_packet_header_type(trace
);
1051 if (packet_header_type
) {
1052 struct bt_field_type
*stream_id_type
;
1055 bt_field_type_structure_get_field_type_by_name(
1056 packet_header_type
, "stream_id");
1057 if (stream_id_type
) {
1059 * Only set the stream's id if the trace's packet header
1060 * contains a stream_id field. This field is only
1061 * needed if the trace contains only one stream
1064 g_string_append_printf(context
->string
,
1065 "\tid = %" PRId64
";\n", stream_class
->id
);
1067 bt_put(stream_id_type
);
1069 if (stream_class
->event_header_type
) {
1070 BT_LOGD_STR("Serializing stream class's event header field type's metadata.");
1071 g_string_append(context
->string
, "\tevent.header := ");
1072 ret
= bt_field_type_serialize(stream_class
->event_header_type
,
1075 BT_LOGW("Cannot serialize stream class's event header field type's metadata: "
1079 g_string_append(context
->string
, ";");
1083 if (stream_class
->packet_context_type
) {
1084 BT_LOGD_STR("Serializing stream class's packet context field type's metadata.");
1085 g_string_append(context
->string
, "\n\n\tpacket.context := ");
1086 ret
= bt_field_type_serialize(stream_class
->packet_context_type
,
1089 BT_LOGW("Cannot serialize stream class's packet context field type's metadata: "
1093 g_string_append(context
->string
, ";");
1096 if (stream_class
->event_context_type
) {
1097 BT_LOGD_STR("Serializing stream class's event context field type's metadata.");
1098 g_string_append(context
->string
, "\n\n\tevent.context := ");
1099 ret
= bt_field_type_serialize(
1100 stream_class
->event_context_type
, context
);
1102 BT_LOGW("Cannot serialize stream class's event context field type's metadata: "
1106 g_string_append(context
->string
, ";");
1109 g_string_append(context
->string
, "\n};\n\n");
1111 for (i
= 0; i
< stream_class
->event_classes
->len
; i
++) {
1112 struct bt_event_class
*event_class
=
1113 stream_class
->event_classes
->pdata
[i
];
1115 ret
= bt_event_class_serialize(event_class
, context
);
1117 BT_LOGW("Cannot serialize event class's metadata: "
1118 "event-class-addr=%p, event-class-name=\"%s\", "
1119 "event-class-id=%" PRId64
,
1121 bt_event_class_get_name(event_class
),
1122 bt_event_class_get_id(event_class
));
1127 bt_put(packet_header_type
);
1128 context
->current_indentation_level
= 0;
1133 void bt_stream_class_destroy(struct bt_object
*obj
)
1135 struct bt_stream_class
*stream_class
;
1137 stream_class
= container_of(obj
, struct bt_stream_class
, base
);
1138 BT_LOGD("Destroying stream class: addr=%p, name=\"%s\", id=%" PRId64
,
1139 stream_class
, bt_stream_class_get_name(stream_class
),
1140 bt_stream_class_get_id(stream_class
));
1141 bt_put(stream_class
->clock
);
1142 bt_put(stream_class
->clock_class
);
1144 if (stream_class
->event_classes_ht
) {
1145 g_hash_table_destroy(stream_class
->event_classes_ht
);
1147 if (stream_class
->event_classes
) {
1148 BT_LOGD_STR("Destroying event classes.");
1149 g_ptr_array_free(stream_class
->event_classes
, TRUE
);
1152 if (stream_class
->name
) {
1153 g_string_free(stream_class
->name
, TRUE
);
1156 BT_LOGD_STR("Putting event header field type.");
1157 bt_put(stream_class
->event_header_type
);
1158 BT_LOGD_STR("Putting packet context field type.");
1159 bt_put(stream_class
->packet_context_type
);
1160 BT_LOGD_STR("Putting event context field type.");
1161 bt_put(stream_class
->event_context_type
);
1162 g_free(stream_class
);
1166 int init_event_header(struct bt_stream_class
*stream_class
)
1169 struct bt_field_type
*event_header_type
=
1170 bt_field_type_structure_create();
1171 struct bt_field_type
*_uint32_t
=
1172 get_field_type(FIELD_TYPE_ALIAS_UINT32_T
);
1173 struct bt_field_type
*_uint64_t
=
1174 get_field_type(FIELD_TYPE_ALIAS_UINT64_T
);
1176 if (!event_header_type
) {
1177 BT_LOGE_STR("Cannot create empty structure field type.");
1182 ret
= bt_field_type_structure_add_field(event_header_type
,
1185 BT_LOGE_STR("Cannot add `id` field to event header field type.");
1189 ret
= bt_field_type_structure_add_field(event_header_type
,
1190 _uint64_t
, "timestamp");
1192 BT_LOGE_STR("Cannot add `timestamp` field to event header field type.");
1196 BT_MOVE(stream_class
->event_header_type
, event_header_type
);
1199 bt_put(event_header_type
);
1208 int init_packet_context(struct bt_stream_class
*stream_class
)
1211 struct bt_field_type
*packet_context_type
=
1212 bt_field_type_structure_create();
1213 struct bt_field_type
*_uint64_t
=
1214 get_field_type(FIELD_TYPE_ALIAS_UINT64_T
);
1215 struct bt_field_type
*ts_begin_end_uint64_t
;
1217 if (!packet_context_type
) {
1218 BT_LOGE_STR("Cannot create empty structure field type.");
1223 ts_begin_end_uint64_t
= bt_field_type_copy(_uint64_t
);
1224 if (!ts_begin_end_uint64_t
) {
1225 BT_LOGE_STR("Cannot copy integer field type for `timestamp_begin` and `timestamp_end` fields.");
1231 * We create a stream packet context as proposed in the CTF
1234 ret
= bt_field_type_structure_add_field(packet_context_type
,
1235 ts_begin_end_uint64_t
, "timestamp_begin");
1237 BT_LOGE_STR("Cannot add `timestamp_begin` field to event header field type.");
1241 ret
= bt_field_type_structure_add_field(packet_context_type
,
1242 ts_begin_end_uint64_t
, "timestamp_end");
1244 BT_LOGE_STR("Cannot add `timestamp_end` field to event header field type.");
1248 ret
= bt_field_type_structure_add_field(packet_context_type
,
1249 _uint64_t
, "content_size");
1251 BT_LOGE_STR("Cannot add `content_size` field to event header field type.");
1255 ret
= bt_field_type_structure_add_field(packet_context_type
,
1256 _uint64_t
, "packet_size");
1258 BT_LOGE_STR("Cannot add `packet_size` field to event header field type.");
1262 ret
= bt_field_type_structure_add_field(packet_context_type
,
1263 _uint64_t
, "events_discarded");
1265 BT_LOGE_STR("Cannot add `events_discarded` field to event header field type.");
1269 BT_MOVE(stream_class
->packet_context_type
, packet_context_type
);
1272 bt_put(packet_context_type
);
1277 bt_put(ts_begin_end_uint64_t
);
1282 int try_map_clock_class(struct bt_stream_class
*stream_class
,
1283 struct bt_field_type
*parent_ft
, const char *field_name
)
1285 struct bt_clock_class
*mapped_clock_class
= NULL
;
1287 struct bt_field_type
*ft
=
1288 bt_field_type_structure_get_field_type_by_name(parent_ft
,
1291 assert(stream_class
->clock
);
1294 /* Field does not exist: not an error */
1298 assert(bt_field_type_is_integer(ft
));
1299 mapped_clock_class
=
1300 bt_field_type_integer_get_mapped_clock_class(ft
);
1301 if (!mapped_clock_class
) {
1302 struct bt_field_type
*ft_copy
;
1304 if (!stream_class
->clock
) {
1305 BT_LOGW("Cannot automatically set field's type mapped clock class: stream class's clock is not set: "
1306 "stream-class-addr=%p, stream-class-name=\"%s\", "
1307 "stream-class-id=%" PRId64
", ft-addr=%p",
1308 stream_class
, bt_stream_class_get_name(stream_class
),
1309 bt_stream_class_get_id(stream_class
), ft
);
1314 ft_copy
= bt_field_type_copy(ft
);
1316 BT_LOGE("Failed to copy integer field type: ft-addr=%p",
1320 ret
= bt_field_type_integer_set_mapped_clock_class_no_check(
1321 ft_copy
, stream_class
->clock
->clock_class
);
1323 ret
= bt_field_type_structure_replace_field(parent_ft
,
1324 field_name
, ft_copy
);
1326 BT_LOGV("Automatically mapped field type to stream class's clock class: "
1327 "stream-class-addr=%p, stream-class-name=\"%s\", "
1328 "stream-class-id=%" PRId64
", ft-addr=%p, "
1330 stream_class
, bt_stream_class_get_name(stream_class
),
1331 bt_stream_class_get_id(stream_class
), ft
, ft_copy
);
1336 bt_put(mapped_clock_class
);
1341 int bt_stream_class_map_clock_class(
1342 struct bt_stream_class
*stream_class
,
1343 struct bt_field_type
*packet_context_type
,
1344 struct bt_field_type
*event_header_type
)
1348 assert(stream_class
);
1350 if (!stream_class
->clock
) {
1351 /* No clock class to map to */
1355 if (packet_context_type
) {
1356 if (try_map_clock_class(stream_class
, packet_context_type
,
1357 "timestamp_begin")) {
1358 BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_begin` field's mapped clock class.");
1363 if (try_map_clock_class(stream_class
, packet_context_type
,
1365 BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_end` field's mapped clock class.");
1371 if (event_header_type
) {
1372 if (try_map_clock_class(stream_class
, event_header_type
,
1374 BT_LOGE_STR("Cannot automatically set stream class's event header field type's `timestamp` field's mapped clock class.");
1385 int bt_stream_class_validate_single_clock_class(
1386 struct bt_stream_class
*stream_class
,
1387 struct bt_clock_class
**expected_clock_class
)
1392 assert(stream_class
);
1393 assert(expected_clock_class
);
1394 ret
= bt_validate_single_clock_class(stream_class
->packet_context_type
,
1395 expected_clock_class
);
1397 BT_LOGW("Stream class's packet context field type "
1398 "is not recursively mapped to the "
1399 "expected clock class: "
1400 "stream-class-addr=%p, "
1401 "stream-class-name=\"%s\", "
1402 "stream-class-id=%" PRId64
", "
1405 bt_stream_class_get_name(stream_class
),
1407 stream_class
->packet_context_type
);
1411 ret
= bt_validate_single_clock_class(stream_class
->event_header_type
,
1412 expected_clock_class
);
1414 BT_LOGW("Stream class's event header field type "
1415 "is not recursively mapped to the "
1416 "expected clock class: "
1417 "stream-class-addr=%p, "
1418 "stream-class-name=\"%s\", "
1419 "stream-class-id=%" PRId64
", "
1422 bt_stream_class_get_name(stream_class
),
1424 stream_class
->event_header_type
);
1428 ret
= bt_validate_single_clock_class(stream_class
->event_context_type
,
1429 expected_clock_class
);
1431 BT_LOGW("Stream class's event context field type "
1432 "is not recursively mapped to the "
1433 "expected clock class: "
1434 "stream-class-addr=%p, "
1435 "stream-class-name=\"%s\", "
1436 "stream-class-id=%" PRId64
", "
1439 bt_stream_class_get_name(stream_class
),
1441 stream_class
->event_context_type
);
1445 for (i
= 0; i
< stream_class
->event_classes
->len
; i
++) {
1446 struct bt_event_class
*event_class
=
1447 g_ptr_array_index(stream_class
->event_classes
, i
);
1449 assert(event_class
);
1450 ret
= bt_event_class_validate_single_clock_class(event_class
,
1451 expected_clock_class
);
1453 BT_LOGW("Stream class's event class contains a "
1454 "field type which is not recursively mapped to "
1455 "the expected clock class: "
1456 "stream-class-addr=%p, "
1457 "stream-class-name=\"%s\", "
1458 "stream-class-id=%" PRId64
,
1460 bt_stream_class_get_name(stream_class
),