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/assert-pre-internal.h>
33 #include <babeltrace/ctf-ir/clock-class-internal.h>
34 #include <babeltrace/ctf-ir/event-class-internal.h>
35 #include <babeltrace/ctf-ir/field-types-internal.h>
36 #include <babeltrace/ctf-ir/fields-internal.h>
37 #include <babeltrace/ctf-ir/stream-class-internal.h>
38 #include <babeltrace/ctf-ir/validation-internal.h>
39 #include <babeltrace/ctf-ir/visitor-internal.h>
40 #include <babeltrace/ctf-ir/utils.h>
41 #include <babeltrace/ctf-ir/utils-internal.h>
42 #include <babeltrace/ref.h>
43 #include <babeltrace/compiler-internal.h>
44 #include <babeltrace/align-internal.h>
45 #include <babeltrace/endian-internal.h>
46 #include <babeltrace/assert-internal.h>
52 int bt_stream_class_common_initialize(struct bt_stream_class_common
*stream_class
,
53 const char *name
, bt_object_release_func release_func
)
55 BT_LOGD("Initializing common stream class object: name=\"%s\"", name
);
57 bt_object_init(stream_class
, release_func
);
58 stream_class
->name
= g_string_new(name
);
59 stream_class
->event_classes
= g_ptr_array_new_with_free_func(
60 (GDestroyNotify
) bt_object_release
);
61 if (!stream_class
->event_classes
) {
62 BT_LOGE_STR("Failed to allocate a GPtrArray.");
66 stream_class
->event_classes_ht
= g_hash_table_new_full(g_int64_hash
,
67 g_int64_equal
, g_free
, NULL
);
68 if (!stream_class
->event_classes_ht
) {
69 BT_LOGE_STR("Failed to allocate a GHashTable.");
73 BT_LOGD("Initialized common stream class object: addr=%p, name=\"%s\"",
82 void bt_stream_class_common_finalize(struct bt_stream_class_common
*stream_class
)
84 BT_LOGD("Finalizing common stream class: addr=%p, name=\"%s\", id=%" PRId64
,
85 stream_class
, bt_stream_class_common_get_name(stream_class
),
86 bt_stream_class_common_get_id(stream_class
));
87 bt_put(stream_class
->clock_class
);
89 if (stream_class
->event_classes_ht
) {
90 g_hash_table_destroy(stream_class
->event_classes_ht
);
92 if (stream_class
->event_classes
) {
93 BT_LOGD_STR("Destroying event classes.");
94 g_ptr_array_free(stream_class
->event_classes
, TRUE
);
97 if (stream_class
->name
) {
98 g_string_free(stream_class
->name
, TRUE
);
101 BT_LOGD_STR("Putting event header field type.");
102 bt_put(stream_class
->event_header_field_type
);
103 BT_LOGD_STR("Putting packet context field type.");
104 bt_put(stream_class
->packet_context_field_type
);
105 BT_LOGD_STR("Putting event context field type.");
106 bt_put(stream_class
->event_context_field_type
);
110 void bt_stream_class_destroy(struct bt_object
*obj
)
112 struct bt_stream_class
*stream_class
;
114 stream_class
= (void *) obj
;
115 BT_LOGD("Destroying stream class: addr=%p, name=\"%s\", id=%" PRId64
,
116 stream_class
, bt_stream_class_get_name(stream_class
),
117 bt_stream_class_get_id(stream_class
));
118 bt_stream_class_common_finalize(BT_TO_COMMON(stream_class
));
119 g_free(stream_class
);
122 struct bt_stream_class
*bt_stream_class_create(const char *name
)
124 struct bt_stream_class
*stream_class
= NULL
;
127 BT_LOGD("Creating stream class object: name=\"%s\"", name
);
128 stream_class
= g_new0(struct bt_stream_class
, 1);
130 BT_LOGE_STR("Failed to allocate one stream class.");
134 ret
= bt_stream_class_common_initialize(BT_TO_COMMON(stream_class
),
135 name
, bt_stream_class_destroy
);
137 /* bt_stream_class_common_initialize() logs errors */
141 BT_LOGD("Created stream class object: addr=%p, name=\"%s\"",
146 bt_put(stream_class
);
150 struct bt_trace
*bt_stream_class_borrow_trace(struct bt_stream_class
*stream_class
)
152 return BT_FROM_COMMON(bt_stream_class_common_borrow_trace(
153 BT_TO_COMMON(stream_class
)));
156 const char *bt_stream_class_get_name(struct bt_stream_class
*stream_class
)
158 return bt_stream_class_common_get_name(BT_TO_COMMON(stream_class
));
161 int bt_stream_class_set_name(struct bt_stream_class
*stream_class
,
164 return bt_stream_class_common_set_name(BT_TO_COMMON(stream_class
),
168 int64_t bt_stream_class_get_id(struct bt_stream_class
*stream_class
)
170 return bt_stream_class_common_get_id(BT_TO_COMMON(stream_class
));
173 int bt_stream_class_set_id(struct bt_stream_class
*stream_class
, uint64_t id
)
175 return bt_stream_class_common_set_id(BT_TO_COMMON(stream_class
), id
);
179 void event_class_exists(gpointer element
, gpointer query
)
181 struct bt_event_class_common
*event_class_a
= element
;
182 struct search_query
*search_query
= query
;
183 struct bt_event_class_common
*event_class_b
= search_query
->value
;
186 if (search_query
->value
== element
) {
187 search_query
->found
= 1;
192 * Two event classes cannot share the same ID in a given
195 id_a
= bt_event_class_common_get_id(event_class_a
);
196 id_b
= bt_event_class_common_get_id(event_class_b
);
198 if (id_a
< 0 || id_b
< 0) {
199 /* at least one ID is not set: will be automatically set later */
204 BT_LOGW("Event class with this ID already exists in the stream class: "
205 "id=%" PRId64
", name=\"%s\"",
206 id_a
, bt_event_class_common_get_name(event_class_a
));
207 search_query
->found
= 1;
216 int bt_stream_class_common_add_event_class(
217 struct bt_stream_class_common
*stream_class
,
218 struct bt_event_class_common
*event_class
,
219 bt_validation_flag_copy_field_type_func copy_field_type_func
)
222 int64_t *event_id
= NULL
;
223 struct bt_trace_common
*trace
= NULL
;
224 struct bt_stream_class_common
*old_stream_class
= NULL
;
225 struct bt_validation_output validation_output
= { 0 };
226 struct bt_field_type_common
*packet_header_type
= NULL
;
227 struct bt_field_type_common
*packet_context_type
= NULL
;
228 struct bt_field_type_common
*event_header_type
= NULL
;
229 struct bt_field_type_common
*stream_event_ctx_type
= NULL
;
230 struct bt_field_type_common
*event_context_type
= NULL
;
231 struct bt_field_type_common
*event_payload_type
= NULL
;
232 const enum bt_validation_flag validation_flags
=
233 BT_VALIDATION_FLAG_EVENT
;
234 struct bt_clock_class
*expected_clock_class
= NULL
;
236 BT_ASSERT(copy_field_type_func
);
238 if (!stream_class
|| !event_class
) {
239 BT_LOGW("Invalid parameter: stream class or event class is NULL: "
240 "stream-class-addr=%p, event-class-addr=%p",
241 stream_class
, event_class
);
246 BT_LOGD("Adding event class to stream class: "
247 "stream-class-addr=%p, stream-class-name=\"%s\", "
248 "stream-class-id=%" PRId64
", event-class-addr=%p, "
249 "event-class-name=\"%s\", event-class-id=%" PRId64
,
250 stream_class
, bt_stream_class_common_get_name(stream_class
),
251 bt_stream_class_common_get_id(stream_class
),
253 bt_event_class_common_get_name(event_class
),
254 bt_event_class_common_get_id(event_class
));
255 trace
= bt_stream_class_common_borrow_trace(stream_class
);
257 if (stream_class
->frozen
) {
259 * We only check that the event class to be added has a
260 * single class which matches the stream class's
261 * expected clock class if the stream class is frozen.
262 * If it's not, then this event class is added "as is"
263 * and the validation will be performed when calling
264 * either bt_trace_add_stream_class() or
265 * bt_event_create(). This is because the stream class's
266 * field types (packet context, event header, event
267 * context) could change before the next call to one of
268 * those two functions.
270 expected_clock_class
= bt_get(stream_class
->clock_class
);
273 * At this point, `expected_clock_class` can be NULL,
274 * and bt_event_class_validate_single_clock_class()
277 ret
= bt_event_class_common_validate_single_clock_class(
278 event_class
, &expected_clock_class
);
280 BT_LOGW("Event class contains a field type which is not "
281 "recursively mapped to its stream class's "
282 "expected clock class: "
283 "stream-class-addr=%p, "
284 "stream-class-id=%" PRId64
", "
285 "stream-class-name=\"%s\", "
286 "expected-clock-class-addr=%p, "
287 "expected-clock-class-name=\"%s\"",
289 bt_stream_class_common_get_id(stream_class
),
290 bt_stream_class_common_get_name(stream_class
),
291 expected_clock_class
,
292 expected_clock_class
?
293 bt_clock_class_get_name(expected_clock_class
) :
299 event_id
= g_new(int64_t, 1);
301 BT_LOGE_STR("Failed to allocate one int64_t.");
306 /* Check for duplicate event classes */
307 struct search_query query
= { .value
= event_class
, .found
= 0 };
308 g_ptr_array_foreach(stream_class
->event_classes
, event_class_exists
,
311 BT_LOGW_STR("Another event class part of this stream class has the same ID.");
316 old_stream_class
= bt_event_class_common_borrow_stream_class(event_class
);
317 if (old_stream_class
) {
318 /* Event class is already associated to a stream class. */
319 BT_LOGW("Event class is already part of another stream class: "
320 "event-class-stream-class-addr=%p, "
321 "event-class-stream-class-name=\"%s\", "
322 "event-class-stream-class-id=%" PRId64
,
324 bt_stream_class_common_get_name(old_stream_class
),
325 bt_stream_class_common_get_id(old_stream_class
));
332 * If the stream class is associated with a trace, then
333 * both those objects are frozen. Also, this event class
334 * is about to be frozen.
336 * Therefore the event class must be validated here.
337 * The trace and stream class should be valid at this
340 BT_ASSERT(trace
->valid
);
341 BT_ASSERT(stream_class
->valid
);
343 bt_trace_common_borrow_packet_header_field_type(trace
);
344 packet_context_type
=
345 bt_stream_class_common_borrow_packet_context_field_type(
348 bt_stream_class_common_borrow_event_header_field_type(
350 stream_event_ctx_type
=
351 bt_stream_class_common_borrow_event_context_field_type(
354 bt_event_class_common_borrow_context_field_type(
357 bt_event_class_common_borrow_payload_field_type(
359 ret
= bt_validate_class_types(
360 trace
->environment
, packet_header_type
,
361 packet_context_type
, event_header_type
,
362 stream_event_ctx_type
, event_context_type
,
363 event_payload_type
, trace
->valid
,
364 stream_class
->valid
, event_class
->valid
,
365 &validation_output
, validation_flags
,
366 copy_field_type_func
);
370 * This means something went wrong during the
371 * validation process, not that the objects are
374 BT_LOGE("Failed to validate event class: ret=%d", ret
);
378 if ((validation_output
.valid_flags
& validation_flags
) !=
380 /* Invalid event class */
381 BT_LOGW("Invalid trace, stream class, or event class: "
383 validation_output
.valid_flags
);
389 /* Only set an event ID if none was explicitly set before */
390 *event_id
= bt_event_class_common_get_id(event_class
);
392 BT_LOGV("Event class has no ID: automatically setting it: "
393 "id=%" PRId64
, stream_class
->next_event_id
);
395 if (bt_event_class_common_set_id(event_class
,
396 stream_class
->next_event_id
)) {
397 BT_LOGE("Cannot set event class's ID: id=%" PRId64
,
398 stream_class
->next_event_id
);
402 stream_class
->next_event_id
++;
403 *event_id
= stream_class
->next_event_id
;
406 bt_object_set_parent(event_class
, stream_class
);
410 * At this point we know that the function will be
411 * successful. Therefore we can replace the event
412 * class's field types with what's in the validation
413 * output structure and mark this event class as valid.
415 bt_validation_replace_types(NULL
, NULL
, event_class
,
416 &validation_output
, validation_flags
);
417 event_class
->valid
= 1;
420 * Put what was not moved in
421 * bt_validation_replace_types().
423 bt_validation_output_put_types(&validation_output
);
426 /* Add to the event classes of the stream class */
427 g_ptr_array_add(stream_class
->event_classes
, event_class
);
428 g_hash_table_insert(stream_class
->event_classes_ht
, event_id
,
432 /* Freeze the event class */
433 bt_event_class_common_freeze(event_class
);
436 * It is safe to set the stream class's unique clock class
437 * now if the stream class is frozen.
439 if (stream_class
->frozen
&& expected_clock_class
) {
440 BT_ASSERT(!stream_class
->clock_class
||
441 stream_class
->clock_class
== expected_clock_class
);
442 BT_MOVE(stream_class
->clock_class
, expected_clock_class
);
445 BT_LOGD("Added event class to stream class: "
446 "stream-class-addr=%p, stream-class-name=\"%s\", "
447 "stream-class-id=%" PRId64
", event-class-addr=%p, "
448 "event-class-name=\"%s\", event-class-id=%" PRId64
,
449 stream_class
, bt_stream_class_common_get_name(stream_class
),
450 bt_stream_class_common_get_id(stream_class
),
452 bt_event_class_common_get_name(event_class
),
453 bt_event_class_common_get_id(event_class
));
456 bt_validation_output_put_types(&validation_output
);
457 bt_put(expected_clock_class
);
462 int bt_stream_class_add_event_class(
463 struct bt_stream_class
*stream_class
,
464 struct bt_event_class
*event_class
)
466 struct bt_trace
*trace
;
470 BT_LOGW("Invalid parameter: stream class is NULL: "
471 "stream-class-addr=%p", stream_class
);
476 trace
= BT_FROM_COMMON(bt_stream_class_common_borrow_trace(
477 BT_TO_COMMON(stream_class
)));
478 if (trace
&& trace
->is_static
) {
479 BT_LOGW("Invalid parameter: stream class's trace is static: "
480 "trace-addr=%p, trace-name=\"%s\"",
481 trace
, bt_trace_get_name(trace
));
486 ret
= bt_stream_class_common_add_event_class(
487 BT_TO_COMMON(stream_class
), BT_TO_COMMON(event_class
),
488 (bt_validation_flag_copy_field_type_func
) bt_field_type_copy
);
493 /* Notifiy listeners of the trace's schema modification. */
495 struct bt_visitor_object obj
= { .object
= event_class
,
496 .type
= BT_VISITOR_OBJECT_TYPE_EVENT_CLASS
};
498 (void) bt_trace_object_modification(&obj
, trace
);
505 int64_t bt_stream_class_get_event_class_count(
506 struct bt_stream_class
*stream_class
)
508 return bt_stream_class_common_get_event_class_count(
509 BT_TO_COMMON(stream_class
));
512 struct bt_event_class
*bt_stream_class_borrow_event_class_by_index(
513 struct bt_stream_class
*stream_class
, uint64_t index
)
515 return BT_FROM_COMMON(bt_stream_class_common_borrow_event_class_by_index(
516 BT_TO_COMMON(stream_class
), index
));
519 struct bt_event_class
*bt_stream_class_borrow_event_class_by_id(
520 struct bt_stream_class
*stream_class
, uint64_t id
)
522 return BT_FROM_COMMON(bt_stream_class_common_borrow_event_class_by_id(
523 BT_TO_COMMON(stream_class
), id
));
526 struct bt_field_type
*bt_stream_class_borrow_packet_context_field_type(
527 struct bt_stream_class
*stream_class
)
529 return BT_FROM_COMMON(bt_stream_class_common_borrow_packet_context_field_type(
530 BT_TO_COMMON(stream_class
)));
533 int bt_stream_class_set_packet_context_field_type(
534 struct bt_stream_class
*stream_class
,
535 struct bt_field_type
*packet_context_type
)
537 return bt_stream_class_common_set_packet_context_field_type(
538 BT_TO_COMMON(stream_class
), (void *) packet_context_type
);
541 struct bt_field_type
*bt_stream_class_borrow_event_header_field_type(
542 struct bt_stream_class
*stream_class
)
544 return BT_FROM_COMMON(bt_stream_class_common_borrow_event_header_field_type(
545 BT_TO_COMMON(stream_class
)));
548 int bt_stream_class_set_event_header_field_type(
549 struct bt_stream_class
*stream_class
,
550 struct bt_field_type
*event_header_type
)
552 return bt_stream_class_common_set_event_header_field_type(
553 BT_TO_COMMON(stream_class
), (void *) event_header_type
);
556 struct bt_field_type
*bt_stream_class_borrow_event_context_field_type(
557 struct bt_stream_class
*stream_class
)
559 return BT_FROM_COMMON(bt_stream_class_common_borrow_event_context_field_type(
560 BT_TO_COMMON(stream_class
)));
563 int bt_stream_class_set_event_context_field_type(
564 struct bt_stream_class
*stream_class
,
565 struct bt_field_type
*event_context_type
)
567 return bt_stream_class_common_set_event_context_field_type(
568 BT_TO_COMMON(stream_class
), (void *) event_context_type
);
572 int64_t get_event_class_count(void *element
)
574 return bt_stream_class_get_event_class_count(
575 (struct bt_stream_class
*) element
);
579 void *get_event_class(void *element
, int i
)
581 return bt_stream_class_get_event_class_by_index(
582 (struct bt_stream_class
*) element
, i
);
586 int visit_event_class(void *object
, bt_visitor visitor
,void *data
)
588 struct bt_visitor_object obj
= {
590 .type
= BT_VISITOR_OBJECT_TYPE_EVENT_CLASS
593 return visitor(&obj
, data
);
597 int bt_stream_class_common_visit(struct bt_stream_class_common
*stream_class
,
598 bt_visitor visitor
, void *data
)
601 struct bt_visitor_object obj
= {
602 .object
= stream_class
,
603 .type
= BT_VISITOR_OBJECT_TYPE_STREAM_CLASS
606 if (!stream_class
|| !visitor
) {
607 BT_LOGW("Invalid parameter: stream class or visitor is NULL: "
608 "stream-class-addr=%p, visitor=%p",
609 stream_class
, visitor
);
614 ret
= visitor_helper(&obj
, get_event_class_count
,
616 visit_event_class
, visitor
, data
);
617 BT_LOGV("visitor_helper() returned: ret=%d", ret
);
623 int bt_stream_class_visit(struct bt_stream_class
*stream_class
,
624 bt_visitor visitor
, void *data
)
626 return bt_stream_class_common_visit(BT_FROM_COMMON(stream_class
),
631 void bt_stream_class_common_freeze(struct bt_stream_class_common
*stream_class
)
633 if (!stream_class
|| stream_class
->frozen
) {
637 BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64
,
638 stream_class
, bt_stream_class_common_get_name(stream_class
),
639 bt_stream_class_common_get_id(stream_class
));
640 stream_class
->frozen
= 1;
641 bt_field_type_common_freeze(stream_class
->event_header_field_type
);
642 bt_field_type_common_freeze(stream_class
->packet_context_field_type
);
643 bt_field_type_common_freeze(stream_class
->event_context_field_type
);
644 bt_clock_class_freeze(stream_class
->clock_class
);
647 void bt_stream_class_freeze(struct bt_stream_class
*stream_class
)
649 bt_stream_class_common_freeze(BT_TO_COMMON(stream_class
));
653 int bt_stream_class_common_validate_single_clock_class(
654 struct bt_stream_class_common
*stream_class
,
655 struct bt_clock_class
**expected_clock_class
)
660 BT_ASSERT(stream_class
);
661 BT_ASSERT(expected_clock_class
);
662 ret
= bt_field_type_common_validate_single_clock_class(
663 stream_class
->packet_context_field_type
,
664 expected_clock_class
);
666 BT_LOGW("Stream class's packet context field type "
667 "is not recursively mapped to the "
668 "expected clock class: "
669 "stream-class-addr=%p, "
670 "stream-class-name=\"%s\", "
671 "stream-class-id=%" PRId64
", "
674 bt_stream_class_common_get_name(stream_class
),
676 stream_class
->packet_context_field_type
);
680 ret
= bt_field_type_common_validate_single_clock_class(
681 stream_class
->event_header_field_type
,
682 expected_clock_class
);
684 BT_LOGW("Stream class's event header field type "
685 "is not recursively mapped to the "
686 "expected clock class: "
687 "stream-class-addr=%p, "
688 "stream-class-name=\"%s\", "
689 "stream-class-id=%" PRId64
", "
692 bt_stream_class_common_get_name(stream_class
),
694 stream_class
->event_header_field_type
);
698 ret
= bt_field_type_common_validate_single_clock_class(
699 stream_class
->event_context_field_type
,
700 expected_clock_class
);
702 BT_LOGW("Stream class's event context field type "
703 "is not recursively mapped to the "
704 "expected clock class: "
705 "stream-class-addr=%p, "
706 "stream-class-name=\"%s\", "
707 "stream-class-id=%" PRId64
", "
710 bt_stream_class_common_get_name(stream_class
),
712 stream_class
->event_context_field_type
);
716 for (i
= 0; i
< stream_class
->event_classes
->len
; i
++) {
717 struct bt_event_class_common
*event_class
=
718 g_ptr_array_index(stream_class
->event_classes
, i
);
720 BT_ASSERT(event_class
);
721 ret
= bt_event_class_common_validate_single_clock_class(
722 event_class
, expected_clock_class
);
724 BT_LOGW("Stream class's event class contains a "
725 "field type which is not recursively mapped to "
726 "the expected clock class: "
727 "stream-class-addr=%p, "
728 "stream-class-name=\"%s\", "
729 "stream-class-id=%" PRId64
,
731 bt_stream_class_common_get_name(stream_class
),