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 #include <babeltrace/ctf-writer/clock.h>
30 #include <babeltrace/ctf-writer/clock-internal.h>
31 #include <babeltrace/ctf-ir/clock-class-internal.h>
32 #include <babeltrace/ctf-writer/event.h>
33 #include <babeltrace/ctf-ir/event-class-internal.h>
34 #include <babeltrace/ctf-ir/event-internal.h>
35 #include <babeltrace/ctf-ir/field-types-internal.h>
36 #include <babeltrace/ctf-ir/fields-internal.h>
37 #include <babeltrace/ctf-writer/stream.h>
38 #include <babeltrace/ctf-ir/stream-class-internal.h>
39 #include <babeltrace/ctf-ir/validation-internal.h>
40 #include <babeltrace/ctf-ir/visitor-internal.h>
41 #include <babeltrace/ctf-writer/functor-internal.h>
42 #include <babeltrace/ctf-ir/utils.h>
43 #include <babeltrace/ref.h>
44 #include <babeltrace/compiler-internal.h>
45 #include <babeltrace/align-internal.h>
46 #include <babeltrace/endian-internal.h>
51 void bt_ctf_stream_class_destroy(struct bt_object
*obj
);
53 int init_event_header(struct bt_ctf_stream_class
*stream_class
);
55 int init_packet_context(struct bt_ctf_stream_class
*stream_class
);
57 struct bt_ctf_stream_class
*bt_ctf_stream_class_create(const char *name
)
59 struct bt_ctf_stream_class
*stream_class
=
60 bt_ctf_stream_class_create_empty(name
);
67 ret
= init_event_header(stream_class
);
72 ret
= init_packet_context(stream_class
);
84 struct bt_ctf_stream_class
*bt_ctf_stream_class_create_empty(const char *name
)
86 struct bt_ctf_stream_class
*stream_class
= NULL
;
88 if (name
&& bt_ctf_validate_identifier(name
)) {
92 stream_class
= g_new0(struct bt_ctf_stream_class
, 1);
97 stream_class
->name
= g_string_new(name
);
98 stream_class
->event_classes
= g_ptr_array_new_with_free_func(
99 (GDestroyNotify
) bt_object_release
);
100 if (!stream_class
->event_classes
) {
104 stream_class
->event_classes_ht
= g_hash_table_new_full(g_int64_hash
,
105 g_int64_equal
, g_free
, NULL
);
107 stream_class
->packet_context_type
= bt_ctf_field_type_structure_create();
108 if (!stream_class
->packet_context_type
) {
112 stream_class
->event_header_type
= bt_ctf_field_type_structure_create();
113 if (!stream_class
->event_header_type
) {
117 stream_class
->event_context_type
= bt_ctf_field_type_structure_create();
118 if (!stream_class
->event_context_type
) {
122 bt_object_init(stream_class
, bt_ctf_stream_class_destroy
);
126 BT_PUT(stream_class
);
130 struct bt_ctf_trace
*bt_ctf_stream_class_get_trace(
131 struct bt_ctf_stream_class
*stream_class
)
133 return stream_class
?
134 bt_get(bt_ctf_stream_class_borrow_trace(stream_class
)) :
138 const char *bt_ctf_stream_class_get_name(
139 struct bt_ctf_stream_class
*stream_class
)
141 const char *name
= NULL
;
147 name
= stream_class
->name
->str
;
152 int bt_ctf_stream_class_set_name(struct bt_ctf_stream_class
*stream_class
,
157 if (!stream_class
|| stream_class
->frozen
) {
162 g_string_assign(stream_class
->name
, name
);
167 struct bt_ctf_clock
*bt_ctf_stream_class_get_clock(
168 struct bt_ctf_stream_class
*stream_class
)
170 struct bt_ctf_clock
*clock
= NULL
;
172 if (!stream_class
|| !stream_class
->clock
) {
176 clock
= bt_get(stream_class
->clock
);
181 int bt_ctf_stream_class_set_clock(struct bt_ctf_stream_class
*stream_class
,
182 struct bt_ctf_clock
*clock
)
185 struct bt_ctf_field_type
*timestamp_field
= NULL
;
187 if (!stream_class
|| !clock
|| stream_class
->frozen
) {
193 * Look for a "timestamp" integer field type in the stream
194 * class's event header field type and map the stream class's
195 * clock's class to that field type if there's no current
198 timestamp_field
= bt_ctf_field_type_structure_get_field_type_by_name(
199 stream_class
->event_header_type
, "timestamp");
200 if (timestamp_field
) {
201 struct bt_ctf_clock_class
*mapped_clock_class
=
202 bt_ctf_field_type_integer_get_mapped_clock_class(
205 if (!mapped_clock_class
) {
206 ret
= bt_ctf_field_type_integer_set_mapped_clock_class(
207 timestamp_field
, clock
->clock_class
);
213 BT_PUT(mapped_clock_class
);
216 /* Replace the current clock of this stream class. */
217 bt_put(stream_class
->clock
);
218 stream_class
->clock
= bt_get(clock
);
221 bt_put(timestamp_field
);
225 int64_t bt_ctf_stream_class_get_id(struct bt_ctf_stream_class
*stream_class
)
229 if (!stream_class
|| !stream_class
->id_set
) {
234 ret
= stream_class
->id
;
240 int _bt_ctf_stream_class_set_id(
241 struct bt_ctf_stream_class
*stream_class
, int64_t id
)
243 stream_class
->id
= id
;
244 stream_class
->id_set
= 1;
248 struct event_class_set_stream_class_id_data
{
249 int64_t stream_class_id
;
254 void event_class_set_stream_id(gpointer event_class
, gpointer data
)
256 struct event_class_set_stream_class_id_data
*typed_data
= data
;
258 typed_data
->ret
|= bt_ctf_event_class_set_stream_id(event_class
,
259 typed_data
->stream_class_id
);
263 int bt_ctf_stream_class_set_id_no_check(
264 struct bt_ctf_stream_class
*stream_class
, int64_t id
)
267 struct event_class_set_stream_class_id_data data
=
268 { .stream_class_id
= id
, .ret
= 0 };
271 * Make sure all event classes have their "stream_id" attribute
274 g_ptr_array_foreach(stream_class
->event_classes
,
275 event_class_set_stream_id
, &data
);
281 ret
= _bt_ctf_stream_class_set_id(stream_class
, id
);
289 int bt_ctf_stream_class_set_id(struct bt_ctf_stream_class
*stream_class
,
293 int64_t id
= (int64_t) id_param
;
295 if (!stream_class
|| stream_class
->frozen
|| id
< 0) {
300 ret
= bt_ctf_stream_class_set_id_no_check(stream_class
, id
);
306 void event_class_exists(gpointer element
, gpointer query
)
308 struct bt_ctf_event_class
*event_class_a
= element
;
309 struct search_query
*search_query
= query
;
310 struct bt_ctf_event_class
*event_class_b
= search_query
->value
;
313 if (search_query
->value
== element
) {
314 search_query
->found
= 1;
319 * Two event classes cannot share the same ID in a given
322 id_a
= bt_ctf_event_class_get_id(event_class_a
);
323 id_b
= bt_ctf_event_class_get_id(event_class_b
);
325 if (id_a
< 0 || id_b
< 0) {
326 /* at least one ID is not set: will be automatically set later */
331 search_query
->found
= 1;
339 int bt_ctf_stream_class_add_event_class(
340 struct bt_ctf_stream_class
*stream_class
,
341 struct bt_ctf_event_class
*event_class
)
344 int64_t *event_id
= NULL
;
345 struct bt_ctf_trace
*trace
= NULL
;
346 struct bt_ctf_stream_class
*old_stream_class
= NULL
;
347 struct bt_ctf_validation_output validation_output
= { 0 };
348 struct bt_ctf_field_type
*packet_header_type
= NULL
;
349 struct bt_ctf_field_type
*packet_context_type
= NULL
;
350 struct bt_ctf_field_type
*event_header_type
= NULL
;
351 struct bt_ctf_field_type
*stream_event_ctx_type
= NULL
;
352 struct bt_ctf_field_type
*event_context_type
= NULL
;
353 struct bt_ctf_field_type
*event_payload_type
= NULL
;
354 const enum bt_ctf_validation_flag validation_flags
=
355 BT_CTF_VALIDATION_FLAG_EVENT
;
357 if (!stream_class
|| !event_class
) {
362 trace
= bt_ctf_stream_class_get_trace(stream_class
);
363 if (trace
&& trace
->is_static
) {
368 event_id
= g_new(int64_t, 1);
374 /* Check for duplicate event classes */
375 struct search_query query
= { .value
= event_class
, .found
= 0 };
376 g_ptr_array_foreach(stream_class
->event_classes
, event_class_exists
,
383 old_stream_class
= bt_ctf_event_class_get_stream_class(event_class
);
384 if (old_stream_class
) {
385 /* Event class is already associated to a stream class. */
392 * If the stream class is associated with a trace, then
393 * both those objects are frozen. Also, this event class
394 * is about to be frozen.
396 * Therefore the event class must be validated here.
397 * The trace and stream class should be valid at this
400 assert(trace
->valid
);
401 assert(stream_class
->valid
);
403 bt_ctf_trace_get_packet_header_type(trace
);
404 packet_context_type
=
405 bt_ctf_stream_class_get_packet_context_type(
408 bt_ctf_stream_class_get_event_header_type(stream_class
);
409 stream_event_ctx_type
=
410 bt_ctf_stream_class_get_event_context_type(
413 bt_ctf_event_class_get_context_type(event_class
);
415 bt_ctf_event_class_get_payload_type(event_class
);
416 ret
= bt_ctf_validate_class_types(
417 trace
->environment
, packet_header_type
,
418 packet_context_type
, event_header_type
,
419 stream_event_ctx_type
, event_context_type
,
420 event_payload_type
, trace
->valid
,
421 stream_class
->valid
, event_class
->valid
,
422 &validation_output
, validation_flags
);
423 BT_PUT(packet_header_type
);
424 BT_PUT(packet_context_type
);
425 BT_PUT(event_header_type
);
426 BT_PUT(stream_event_ctx_type
);
427 BT_PUT(event_context_type
);
428 BT_PUT(event_payload_type
);
432 * This means something went wrong during the
433 * validation process, not that the objects are
439 if ((validation_output
.valid_flags
& validation_flags
) !=
441 /* Invalid event class */
447 /* Only set an event ID if none was explicitly set before */
448 *event_id
= bt_ctf_event_class_get_id(event_class
);
450 if (bt_ctf_event_class_set_id(event_class
,
451 stream_class
->next_event_id
++)) {
455 *event_id
= stream_class
->next_event_id
;
458 ret
= bt_ctf_event_class_set_stream_id(event_class
, stream_class
->id
);
463 bt_object_set_parent(event_class
, stream_class
);
467 * At this point we know that the function will be
468 * successful. Therefore we can replace the event
469 * class's field types with what's in the validation
470 * output structure and mark this event class as valid.
472 bt_ctf_validation_replace_types(NULL
, NULL
, event_class
,
473 &validation_output
, validation_flags
);
474 event_class
->valid
= 1;
477 * Put what was not moved in
478 * bt_ctf_validation_replace_types().
480 bt_ctf_validation_output_put_types(&validation_output
);
483 /* Add to the event classes of the stream class */
484 g_ptr_array_add(stream_class
->event_classes
, event_class
);
485 g_hash_table_insert(stream_class
->event_classes_ht
, event_id
,
489 /* Freeze the event class */
490 bt_ctf_event_class_freeze(event_class
);
492 /* Notifiy listeners of the trace's schema modification. */
494 struct bt_ctf_object obj
= { .object
= event_class
,
495 .type
= BT_CTF_OBJECT_TYPE_EVENT_CLASS
};
497 (void) bt_ctf_trace_object_modification(&obj
, trace
);
501 BT_PUT(old_stream_class
);
502 bt_ctf_validation_output_put_types(&validation_output
);
503 assert(!packet_header_type
);
504 assert(!packet_context_type
);
505 assert(!event_header_type
);
506 assert(!stream_event_ctx_type
);
507 assert(!event_context_type
);
508 assert(!event_payload_type
);
514 int64_t bt_ctf_stream_class_get_event_class_count(
515 struct bt_ctf_stream_class
*stream_class
)
524 ret
= (int64_t) stream_class
->event_classes
->len
;
529 struct bt_ctf_event_class
*bt_ctf_stream_class_get_event_class_by_index(
530 struct bt_ctf_stream_class
*stream_class
, uint64_t index
)
532 struct bt_ctf_event_class
*event_class
= NULL
;
534 if (!stream_class
|| index
>= stream_class
->event_classes
->len
) {
538 event_class
= g_ptr_array_index(stream_class
->event_classes
, index
);
544 struct bt_ctf_event_class
*bt_ctf_stream_class_get_event_class_by_id(
545 struct bt_ctf_stream_class
*stream_class
, uint64_t id
)
547 int64_t id_key
= (int64_t) id
;
548 struct bt_ctf_event_class
*event_class
= NULL
;
550 if (!stream_class
|| id_key
< 0) {
554 event_class
= g_hash_table_lookup(stream_class
->event_classes_ht
,
561 struct bt_ctf_field_type
*bt_ctf_stream_class_get_packet_context_type(
562 struct bt_ctf_stream_class
*stream_class
)
564 struct bt_ctf_field_type
*ret
= NULL
;
570 bt_get(stream_class
->packet_context_type
);
571 ret
= stream_class
->packet_context_type
;
576 int bt_ctf_stream_class_set_packet_context_type(
577 struct bt_ctf_stream_class
*stream_class
,
578 struct bt_ctf_field_type
*packet_context_type
)
582 if (!stream_class
|| stream_class
->frozen
) {
587 if (packet_context_type
&&
588 bt_ctf_field_type_get_type_id(packet_context_type
) !=
589 BT_CTF_FIELD_TYPE_ID_STRUCT
) {
590 /* A packet context must be a structure. */
595 bt_put(stream_class
->packet_context_type
);
596 bt_get(packet_context_type
);
597 stream_class
->packet_context_type
= packet_context_type
;
602 struct bt_ctf_field_type
*bt_ctf_stream_class_get_event_header_type(
603 struct bt_ctf_stream_class
*stream_class
)
605 struct bt_ctf_field_type
*ret
= NULL
;
607 if (!stream_class
|| !stream_class
->event_header_type
) {
611 bt_get(stream_class
->event_header_type
);
612 ret
= stream_class
->event_header_type
;
617 int bt_ctf_stream_class_set_event_header_type(
618 struct bt_ctf_stream_class
*stream_class
,
619 struct bt_ctf_field_type
*event_header_type
)
623 if (!stream_class
|| stream_class
->frozen
) {
628 if (event_header_type
&&
629 bt_ctf_field_type_get_type_id(event_header_type
) !=
630 BT_CTF_FIELD_TYPE_ID_STRUCT
) {
631 /* An event header must be a structure. */
636 bt_put(stream_class
->event_header_type
);
637 stream_class
->event_header_type
= bt_get(event_header_type
);
642 struct bt_ctf_field_type
*bt_ctf_stream_class_get_event_context_type(
643 struct bt_ctf_stream_class
*stream_class
)
645 struct bt_ctf_field_type
*ret
= NULL
;
647 if (!stream_class
|| !stream_class
->event_context_type
) {
651 bt_get(stream_class
->event_context_type
);
652 ret
= stream_class
->event_context_type
;
657 int bt_ctf_stream_class_set_event_context_type(
658 struct bt_ctf_stream_class
*stream_class
,
659 struct bt_ctf_field_type
*event_context_type
)
663 if (!stream_class
|| stream_class
->frozen
) {
668 if (event_context_type
&&
669 bt_ctf_field_type_get_type_id(event_context_type
) !=
670 BT_CTF_FIELD_TYPE_ID_STRUCT
) {
671 /* A packet context must be a structure. */
676 bt_put(stream_class
->event_context_type
);
677 stream_class
->event_context_type
= bt_get(event_context_type
);
682 void bt_ctf_stream_class_get(struct bt_ctf_stream_class
*stream_class
)
684 bt_get(stream_class
);
687 void bt_ctf_stream_class_put(struct bt_ctf_stream_class
*stream_class
)
689 bt_put(stream_class
);
693 int64_t get_event_class_count(void *element
)
695 return bt_ctf_stream_class_get_event_class_count(
696 (struct bt_ctf_stream_class
*) element
);
700 void *get_event_class(void *element
, int i
)
702 return bt_ctf_stream_class_get_event_class_by_index(
703 (struct bt_ctf_stream_class
*) element
, i
);
707 int visit_event_class(void *object
, bt_ctf_visitor visitor
,void *data
)
709 struct bt_ctf_object obj
=
711 .type
= BT_CTF_OBJECT_TYPE_EVENT_CLASS
};
713 return visitor(&obj
, data
);
716 int bt_ctf_stream_class_visit(struct bt_ctf_stream_class
*stream_class
,
717 bt_ctf_visitor visitor
, void *data
)
720 struct bt_ctf_object obj
=
721 { .object
= stream_class
,
722 .type
= BT_CTF_OBJECT_TYPE_STREAM_CLASS
};
724 if (!stream_class
|| !visitor
) {
729 ret
= visitor_helper(&obj
, get_event_class_count
,
731 visit_event_class
, visitor
, data
);
737 void bt_ctf_stream_class_freeze(struct bt_ctf_stream_class
*stream_class
)
743 stream_class
->frozen
= 1;
744 bt_ctf_field_type_freeze(stream_class
->event_header_type
);
745 bt_ctf_field_type_freeze(stream_class
->packet_context_type
);
746 bt_ctf_field_type_freeze(stream_class
->event_context_type
);
748 if (stream_class
->clock
) {
749 bt_ctf_clock_class_freeze(stream_class
->clock
->clock_class
);
754 int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class
*stream_class
,
755 struct metadata_context
*context
)
760 g_string_assign(context
->field_name
, "");
761 context
->current_indentation_level
= 1;
762 if (!stream_class
->id_set
) {
767 g_string_append_printf(context
->string
,
768 "stream {\n\tid = %" PRId64
";\n\tevent.header := ",
770 ret
= bt_ctf_field_type_serialize(stream_class
->event_header_type
,
776 if (stream_class
->packet_context_type
) {
777 g_string_append(context
->string
, ";\n\n\tpacket.context := ");
778 ret
= bt_ctf_field_type_serialize(stream_class
->packet_context_type
,
785 if (stream_class
->event_context_type
) {
786 g_string_append(context
->string
, ";\n\n\tevent.context := ");
787 ret
= bt_ctf_field_type_serialize(
788 stream_class
->event_context_type
, context
);
794 g_string_append(context
->string
, ";\n};\n\n");
795 for (i
= 0; i
< stream_class
->event_classes
->len
; i
++) {
796 struct bt_ctf_event_class
*event_class
=
797 stream_class
->event_classes
->pdata
[i
];
799 ret
= bt_ctf_event_class_serialize(event_class
, context
);
805 context
->current_indentation_level
= 0;
810 void bt_ctf_stream_class_destroy(struct bt_object
*obj
)
812 struct bt_ctf_stream_class
*stream_class
;
814 stream_class
= container_of(obj
, struct bt_ctf_stream_class
, base
);
815 bt_put(stream_class
->clock
);
817 if (stream_class
->event_classes_ht
) {
818 g_hash_table_destroy(stream_class
->event_classes_ht
);
820 if (stream_class
->event_classes
) {
821 g_ptr_array_free(stream_class
->event_classes
, TRUE
);
824 if (stream_class
->name
) {
825 g_string_free(stream_class
->name
, TRUE
);
828 bt_put(stream_class
->event_header_type
);
829 bt_put(stream_class
->packet_context_type
);
830 bt_put(stream_class
->event_context_type
);
831 g_free(stream_class
);
835 int init_event_header(struct bt_ctf_stream_class
*stream_class
)
838 struct bt_ctf_field_type
*event_header_type
=
839 bt_ctf_field_type_structure_create();
840 struct bt_ctf_field_type
*_uint32_t
=
841 get_field_type(FIELD_TYPE_ALIAS_UINT32_T
);
842 struct bt_ctf_field_type
*_uint64_t
=
843 get_field_type(FIELD_TYPE_ALIAS_UINT64_T
);
845 if (!event_header_type
) {
850 ret
= bt_ctf_field_type_structure_add_field(event_header_type
,
856 ret
= bt_ctf_field_type_structure_add_field(event_header_type
,
857 _uint64_t
, "timestamp");
862 BT_MOVE(stream_class
->event_header_type
, event_header_type
);
865 bt_put(event_header_type
);
874 int init_packet_context(struct bt_ctf_stream_class
*stream_class
)
877 struct bt_ctf_field_type
*packet_context_type
=
878 bt_ctf_field_type_structure_create();
879 struct bt_ctf_field_type
*_uint64_t
=
880 get_field_type(FIELD_TYPE_ALIAS_UINT64_T
);
882 if (!packet_context_type
) {
888 * We create a stream packet context as proposed in the CTF
891 ret
= bt_ctf_field_type_structure_add_field(packet_context_type
,
892 _uint64_t
, "timestamp_begin");
897 ret
= bt_ctf_field_type_structure_add_field(packet_context_type
,
898 _uint64_t
, "timestamp_end");
903 ret
= bt_ctf_field_type_structure_add_field(packet_context_type
,
904 _uint64_t
, "content_size");
909 ret
= bt_ctf_field_type_structure_add_field(packet_context_type
,
910 _uint64_t
, "packet_size");
915 ret
= bt_ctf_field_type_structure_add_field(packet_context_type
,
916 _uint64_t
, "events_discarded");
921 BT_MOVE(stream_class
->packet_context_type
, packet_context_type
);
924 bt_put(packet_context_type
);