Move to kernel style SPDX license identifiers
[babeltrace.git] / src / ctf-writer / stream-class.c
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
6 */
7
8 #define BT_LOG_TAG "CTF-WRITER/STREAM-CLASS"
9 #include "logging.h"
10
11 #include <inttypes.h>
12 #include <stdint.h>
13
14 #include <babeltrace2-ctf-writer/event.h>
15 #include <babeltrace2-ctf-writer/object.h>
16 #include <babeltrace2-ctf-writer/trace.h>
17 #include <babeltrace2-ctf-writer/utils.h>
18
19 #include "common/align.h"
20 #include "common/assert.h"
21 #include "compat/compiler.h"
22 #include "compat/endian.h"
23
24 #include "assert-pre.h"
25 #include "clock-class.h"
26 #include "event-class.h"
27 #include "event.h"
28 #include "fields.h"
29 #include "field-types.h"
30 #include "field-wrapper.h"
31 #include "stream-class.h"
32 #include "utils.h"
33 #include "validation.h"
34 #include "visitor.h"
35 #include "writer.h"
36
37 BT_HIDDEN
38 int bt_ctf_stream_class_common_initialize(struct bt_ctf_stream_class_common *stream_class,
39 const char *name, bt_ctf_object_release_func release_func)
40 {
41 BT_LOGD("Initializing common stream class object: name=\"%s\"", name);
42
43 bt_ctf_object_init_shared_with_parent(&stream_class->base, release_func);
44 stream_class->name = g_string_new(name);
45 stream_class->event_classes = g_ptr_array_new_with_free_func(
46 (GDestroyNotify) bt_ctf_object_try_spec_release);
47 if (!stream_class->event_classes) {
48 BT_LOGE_STR("Failed to allocate a GPtrArray.");
49 goto error;
50 }
51
52 stream_class->event_classes_ht = g_hash_table_new_full(g_int64_hash,
53 g_int64_equal, g_free, NULL);
54 if (!stream_class->event_classes_ht) {
55 BT_LOGE_STR("Failed to allocate a GHashTable.");
56 goto error;
57 }
58
59 BT_LOGD("Initialized common stream class object: addr=%p, name=\"%s\"",
60 stream_class, name);
61 return 0;
62
63 error:
64 return -1;
65 }
66
67 BT_HIDDEN
68 void bt_ctf_stream_class_common_finalize(struct bt_ctf_stream_class_common *stream_class)
69 {
70 BT_LOGD("Finalizing common stream class: addr=%p, name=\"%s\", id=%" PRId64,
71 stream_class, bt_ctf_stream_class_common_get_name(stream_class),
72 bt_ctf_stream_class_common_get_id(stream_class));
73 bt_ctf_object_put_ref(stream_class->clock_class);
74
75 if (stream_class->event_classes_ht) {
76 g_hash_table_destroy(stream_class->event_classes_ht);
77 }
78 if (stream_class->event_classes) {
79 BT_LOGD_STR("Destroying event classes.");
80 g_ptr_array_free(stream_class->event_classes, TRUE);
81 }
82
83 if (stream_class->name) {
84 g_string_free(stream_class->name, TRUE);
85 }
86
87 BT_LOGD_STR("Putting event header field type.");
88 bt_ctf_object_put_ref(stream_class->event_header_field_type);
89 BT_LOGD_STR("Putting packet context field type.");
90 bt_ctf_object_put_ref(stream_class->packet_context_field_type);
91 BT_LOGD_STR("Putting event context field type.");
92 bt_ctf_object_put_ref(stream_class->event_context_field_type);
93 }
94
95 static
96 void event_class_exists(gpointer element, gpointer query)
97 {
98 struct bt_ctf_event_class_common *event_class_a = element;
99 struct bt_ctf_search_query *search_query = query;
100 struct bt_ctf_event_class_common *event_class_b = search_query->value;
101 int64_t id_a, id_b;
102
103 if (search_query->value == element) {
104 search_query->found = 1;
105 goto end;
106 }
107
108 /*
109 * Two event classes cannot share the same ID in a given
110 * stream class.
111 */
112 id_a = bt_ctf_event_class_common_get_id(event_class_a);
113 id_b = bt_ctf_event_class_common_get_id(event_class_b);
114
115 if (id_a < 0 || id_b < 0) {
116 /* at least one ID is not set: will be automatically set later */
117 goto end;
118 }
119
120 if (id_a == id_b) {
121 BT_LOGW("Event class with this ID already exists in the stream class: "
122 "id=%" PRId64 ", name=\"%s\"",
123 id_a, bt_ctf_event_class_common_get_name(event_class_a));
124 search_query->found = 1;
125 goto end;
126 }
127
128 end:
129 return;
130 }
131
132 BT_HIDDEN
133 int bt_ctf_stream_class_common_add_event_class(
134 struct bt_ctf_stream_class_common *stream_class,
135 struct bt_ctf_event_class_common *event_class,
136 bt_ctf_validation_flag_copy_field_type_func copy_field_type_func)
137 {
138 int ret = 0;
139 int64_t *event_id = NULL;
140 struct bt_ctf_trace_common *trace = NULL;
141 struct bt_ctf_stream_class_common *old_stream_class = NULL;
142 struct bt_ctf_validation_output validation_output = { 0 };
143 struct bt_ctf_field_type_common *packet_header_type = NULL;
144 struct bt_ctf_field_type_common *packet_context_type = NULL;
145 struct bt_ctf_field_type_common *event_header_type = NULL;
146 struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
147 struct bt_ctf_field_type_common *event_context_type = NULL;
148 struct bt_ctf_field_type_common *event_payload_type = NULL;
149 const enum bt_ctf_validation_flag validation_flags =
150 BT_CTF_VALIDATION_FLAG_EVENT;
151 struct bt_ctf_clock_class *expected_clock_class = NULL;
152 struct bt_ctf_search_query query = { .value = event_class, .found = 0 };
153
154 BT_ASSERT_DBG(copy_field_type_func);
155
156 if (!stream_class || !event_class) {
157 BT_LOGW("Invalid parameter: stream class or event class is NULL: "
158 "stream-class-addr=%p, event-class-addr=%p",
159 stream_class, event_class);
160 ret = -1;
161 goto end;
162 }
163
164 BT_LOGD("Adding event class to stream class: "
165 "stream-class-addr=%p, stream-class-name=\"%s\", "
166 "stream-class-id=%" PRId64 ", event-class-addr=%p, "
167 "event-class-name=\"%s\", event-class-id=%" PRId64,
168 stream_class, bt_ctf_stream_class_common_get_name(stream_class),
169 bt_ctf_stream_class_common_get_id(stream_class),
170 event_class,
171 bt_ctf_event_class_common_get_name(event_class),
172 bt_ctf_event_class_common_get_id(event_class));
173 trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
174
175 if (stream_class->frozen) {
176 /*
177 * We only check that the event class to be added has a
178 * single class which matches the stream class's
179 * expected clock class if the stream class is frozen.
180 * If it's not, then this event class is added "as is"
181 * and the validation will be performed when calling
182 * either bt_ctf_trace_add_stream_class() or
183 * bt_ctf_event_create(). This is because the stream class's
184 * field types (packet context, event header, event
185 * context) could change before the next call to one of
186 * those two functions.
187 */
188 expected_clock_class = bt_ctf_object_get_ref(stream_class->clock_class);
189
190 /*
191 * At this point, `expected_clock_class` can be NULL,
192 * and bt_ctf_event_class_validate_single_clock_class()
193 * below can set it.
194 */
195 ret = bt_ctf_event_class_common_validate_single_clock_class(
196 event_class, &expected_clock_class);
197 if (ret) {
198 BT_LOGW("Event class contains a field type which is not "
199 "recursively mapped to its stream class's "
200 "expected clock class: "
201 "stream-class-addr=%p, "
202 "stream-class-id=%" PRId64 ", "
203 "stream-class-name=\"%s\", "
204 "expected-clock-class-addr=%p, "
205 "expected-clock-class-name=\"%s\"",
206 stream_class,
207 bt_ctf_stream_class_common_get_id(stream_class),
208 bt_ctf_stream_class_common_get_name(stream_class),
209 expected_clock_class,
210 expected_clock_class ?
211 bt_ctf_clock_class_get_name(expected_clock_class) :
212 NULL);
213 goto end;
214 }
215 }
216
217 event_id = g_new(int64_t, 1);
218 if (!event_id) {
219 BT_LOGE_STR("Failed to allocate one int64_t.");
220 ret = -1;
221 goto end;
222 }
223
224 /* Check for duplicate event classes */
225 g_ptr_array_foreach(stream_class->event_classes, event_class_exists,
226 &query);
227 if (query.found) {
228 BT_LOGW_STR("Another event class part of this stream class has the same ID.");
229 ret = -1;
230 goto end;
231 }
232
233 old_stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class);
234 if (old_stream_class) {
235 /* Event class is already associated to a stream class. */
236 BT_LOGW("Event class is already part of another stream class: "
237 "event-class-stream-class-addr=%p, "
238 "event-class-stream-class-name=\"%s\", "
239 "event-class-stream-class-id=%" PRId64,
240 old_stream_class,
241 bt_ctf_stream_class_common_get_name(old_stream_class),
242 bt_ctf_stream_class_common_get_id(old_stream_class));
243 ret = -1;
244 goto end;
245 }
246
247 if (trace) {
248 /*
249 * If the stream class is associated with a trace, then
250 * both those objects are frozen. Also, this event class
251 * is about to be frozen.
252 *
253 * Therefore the event class must be validated here.
254 * The trace and stream class should be valid at this
255 * point.
256 */
257 BT_ASSERT_DBG(trace->valid);
258 BT_ASSERT_DBG(stream_class->valid);
259 packet_header_type =
260 bt_ctf_trace_common_borrow_packet_header_field_type(trace);
261 packet_context_type =
262 bt_ctf_stream_class_common_borrow_packet_context_field_type(
263 stream_class);
264 event_header_type =
265 bt_ctf_stream_class_common_borrow_event_header_field_type(
266 stream_class);
267 stream_event_ctx_type =
268 bt_ctf_stream_class_common_borrow_event_context_field_type(
269 stream_class);
270 event_context_type =
271 bt_ctf_event_class_common_borrow_context_field_type(
272 event_class);
273 event_payload_type =
274 bt_ctf_event_class_common_borrow_payload_field_type(
275 event_class);
276 ret = bt_ctf_validate_class_types(
277 trace->environment, packet_header_type,
278 packet_context_type, event_header_type,
279 stream_event_ctx_type, event_context_type,
280 event_payload_type, trace->valid,
281 stream_class->valid, event_class->valid,
282 &validation_output, validation_flags,
283 copy_field_type_func);
284
285 if (ret) {
286 /*
287 * This means something went wrong during the
288 * validation process, not that the objects are
289 * invalid.
290 */
291 BT_LOGE("Failed to validate event class: ret=%d", ret);
292 goto end;
293 }
294
295 if ((validation_output.valid_flags & validation_flags) !=
296 validation_flags) {
297 /* Invalid event class */
298 BT_LOGW("Invalid trace, stream class, or event class: "
299 "valid-flags=0x%x",
300 validation_output.valid_flags);
301 ret = -1;
302 goto end;
303 }
304 }
305
306 /* Only set an event ID if none was explicitly set before */
307 *event_id = bt_ctf_event_class_common_get_id(event_class);
308 if (*event_id < 0) {
309 BT_LOGT("Event class has no ID: automatically setting it: "
310 "id=%" PRId64, stream_class->next_event_id);
311
312 if (bt_ctf_event_class_common_set_id(event_class,
313 stream_class->next_event_id)) {
314 BT_LOGE("Cannot set event class's ID: id=%" PRId64,
315 stream_class->next_event_id);
316 ret = -1;
317 goto end;
318 }
319 stream_class->next_event_id++;
320 *event_id = stream_class->next_event_id;
321 }
322
323 bt_ctf_object_set_parent(&event_class->base, &stream_class->base);
324
325 if (trace) {
326 /*
327 * At this point we know that the function will be
328 * successful. Therefore we can replace the event
329 * class's field types with what's in the validation
330 * output structure and mark this event class as valid.
331 */
332 bt_ctf_validation_replace_types(NULL, NULL, event_class,
333 &validation_output, validation_flags);
334 event_class->valid = 1;
335
336 /*
337 * Put what was not moved in
338 * bt_ctf_validation_replace_types().
339 */
340 bt_ctf_validation_output_put_types(&validation_output);
341 }
342
343 /* Add to the event classes of the stream class */
344 g_ptr_array_add(stream_class->event_classes, event_class);
345 g_hash_table_insert(stream_class->event_classes_ht, event_id,
346 event_class);
347 event_id = NULL;
348
349 /* Freeze the event class */
350 bt_ctf_event_class_common_freeze(event_class);
351
352 /*
353 * It is safe to set the stream class's unique clock class
354 * now if the stream class is frozen.
355 */
356 if (stream_class->frozen && expected_clock_class) {
357 BT_ASSERT_DBG(!stream_class->clock_class ||
358 stream_class->clock_class == expected_clock_class);
359 BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class);
360 }
361
362 BT_LOGD("Added event class to stream class: "
363 "stream-class-addr=%p, stream-class-name=\"%s\", "
364 "stream-class-id=%" PRId64 ", event-class-addr=%p, "
365 "event-class-name=\"%s\", event-class-id=%" PRId64,
366 stream_class, bt_ctf_stream_class_common_get_name(stream_class),
367 bt_ctf_stream_class_common_get_id(stream_class),
368 event_class,
369 bt_ctf_event_class_common_get_name(event_class),
370 bt_ctf_event_class_common_get_id(event_class));
371
372 end:
373 bt_ctf_validation_output_put_types(&validation_output);
374 bt_ctf_object_put_ref(expected_clock_class);
375 g_free(event_id);
376 return ret;
377 }
378
379 static
380 int64_t get_event_class_count(void *element)
381 {
382 return bt_ctf_stream_class_get_event_class_count(
383 (struct bt_ctf_stream_class *) element);
384 }
385
386 static
387 void *get_event_class(void *element, int i)
388 {
389 return bt_ctf_stream_class_get_event_class_by_index(
390 (struct bt_ctf_stream_class *) element, i);
391 }
392
393 static
394 int visit_event_class(void *object, bt_ctf_visitor visitor,void *data)
395 {
396 struct bt_ctf_visitor_object obj = {
397 .object = object,
398 .type = BT_CTF_VISITOR_OBJECT_TYPE_EVENT_CLASS
399 };
400
401 return visitor(&obj, data);
402 }
403
404 BT_HIDDEN
405 int bt_ctf_stream_class_common_visit(struct bt_ctf_stream_class_common *stream_class,
406 bt_ctf_visitor visitor, void *data)
407 {
408 int ret;
409 struct bt_ctf_visitor_object obj = {
410 .object = stream_class,
411 .type = BT_CTF_VISITOR_OBJECT_TYPE_STREAM_CLASS
412 };
413
414 if (!stream_class || !visitor) {
415 BT_LOGW("Invalid parameter: stream class or visitor is NULL: "
416 "stream-class-addr=%p, visitor=%p",
417 stream_class, visitor);
418 ret = -1;
419 goto end;
420 }
421
422 ret = bt_ctf_visitor_helper(&obj, get_event_class_count,
423 get_event_class,
424 visit_event_class, visitor, data);
425 BT_LOGT("bt_ctf_visitor_helper() returned: ret=%d", ret);
426
427 end:
428 return ret;
429 }
430
431 BT_HIDDEN
432 int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class,
433 bt_ctf_visitor visitor, void *data)
434 {
435 return bt_ctf_stream_class_common_visit(BT_CTF_FROM_COMMON(stream_class),
436 visitor, data);
437 }
438
439 BT_HIDDEN
440 void bt_ctf_stream_class_common_freeze(struct bt_ctf_stream_class_common *stream_class)
441 {
442 if (!stream_class || stream_class->frozen) {
443 return;
444 }
445
446 BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64,
447 stream_class, bt_ctf_stream_class_common_get_name(stream_class),
448 bt_ctf_stream_class_common_get_id(stream_class));
449 stream_class->frozen = 1;
450 bt_ctf_field_type_common_freeze(stream_class->event_header_field_type);
451 bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type);
452 bt_ctf_field_type_common_freeze(stream_class->event_context_field_type);
453 bt_ctf_clock_class_freeze(stream_class->clock_class);
454 }
455
456 BT_HIDDEN
457 int bt_ctf_stream_class_common_validate_single_clock_class(
458 struct bt_ctf_stream_class_common *stream_class,
459 struct bt_ctf_clock_class **expected_clock_class)
460 {
461 int ret;
462 uint64_t i;
463
464 BT_ASSERT_DBG(stream_class);
465 BT_ASSERT_DBG(expected_clock_class);
466 ret = bt_ctf_field_type_common_validate_single_clock_class(
467 stream_class->packet_context_field_type,
468 expected_clock_class);
469 if (ret) {
470 BT_LOGW("Stream class's packet context field type "
471 "is not recursively mapped to the "
472 "expected clock class: "
473 "stream-class-addr=%p, "
474 "stream-class-name=\"%s\", "
475 "stream-class-id=%" PRId64 ", "
476 "ft-addr=%p",
477 stream_class,
478 bt_ctf_stream_class_common_get_name(stream_class),
479 stream_class->id,
480 stream_class->packet_context_field_type);
481 goto end;
482 }
483
484 ret = bt_ctf_field_type_common_validate_single_clock_class(
485 stream_class->event_header_field_type,
486 expected_clock_class);
487 if (ret) {
488 BT_LOGW("Stream class's event header field type "
489 "is not recursively mapped to the "
490 "expected clock class: "
491 "stream-class-addr=%p, "
492 "stream-class-name=\"%s\", "
493 "stream-class-id=%" PRId64 ", "
494 "ft-addr=%p",
495 stream_class,
496 bt_ctf_stream_class_common_get_name(stream_class),
497 stream_class->id,
498 stream_class->event_header_field_type);
499 goto end;
500 }
501
502 ret = bt_ctf_field_type_common_validate_single_clock_class(
503 stream_class->event_context_field_type,
504 expected_clock_class);
505 if (ret) {
506 BT_LOGW("Stream class's event context field type "
507 "is not recursively mapped to the "
508 "expected clock class: "
509 "stream-class-addr=%p, "
510 "stream-class-name=\"%s\", "
511 "stream-class-id=%" PRId64 ", "
512 "ft-addr=%p",
513 stream_class,
514 bt_ctf_stream_class_common_get_name(stream_class),
515 stream_class->id,
516 stream_class->event_context_field_type);
517 goto end;
518 }
519
520 for (i = 0; i < stream_class->event_classes->len; i++) {
521 struct bt_ctf_event_class_common *event_class =
522 g_ptr_array_index(stream_class->event_classes, i);
523
524 BT_ASSERT_DBG(event_class);
525 ret = bt_ctf_event_class_common_validate_single_clock_class(
526 event_class, expected_clock_class);
527 if (ret) {
528 BT_LOGW("Stream class's event class contains a "
529 "field type which is not recursively mapped to "
530 "the expected clock class: "
531 "stream-class-addr=%p, "
532 "stream-class-name=\"%s\", "
533 "stream-class-id=%" PRId64,
534 stream_class,
535 bt_ctf_stream_class_common_get_name(stream_class),
536 stream_class->id);
537 goto end;
538 }
539 }
540
541 end:
542 return ret;
543 }
544
545 static
546 int init_event_header(struct bt_ctf_stream_class *stream_class)
547 {
548 int ret = 0;
549 struct bt_ctf_field_type *event_header_type =
550 bt_ctf_field_type_structure_create();
551 struct bt_ctf_field_type *_uint32_t =
552 get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
553 struct bt_ctf_field_type *_uint64_t =
554 get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
555
556 if (!event_header_type) {
557 BT_LOGE_STR("Cannot create empty structure field type.");
558 ret = -1;
559 goto end;
560 }
561
562 ret = bt_ctf_field_type_structure_add_field(event_header_type,
563 _uint32_t, "id");
564 if (ret) {
565 BT_LOGE_STR("Cannot add `id` field to event header field type.");
566 goto end;
567 }
568
569 ret = bt_ctf_field_type_structure_add_field(event_header_type,
570 _uint64_t, "timestamp");
571 if (ret) {
572 BT_LOGE_STR("Cannot add `timestamp` field to event header field type.");
573 goto end;
574 }
575
576 bt_ctf_object_put_ref(stream_class->common.event_header_field_type);
577 stream_class->common.event_header_field_type =
578 (void *) event_header_type;
579 event_header_type = NULL;
580
581 end:
582 if (ret) {
583 bt_ctf_object_put_ref(event_header_type);
584 }
585
586 bt_ctf_object_put_ref(_uint32_t);
587 bt_ctf_object_put_ref(_uint64_t);
588 return ret;
589 }
590
591 static
592 int init_packet_context(struct bt_ctf_stream_class *stream_class)
593 {
594 int ret = 0;
595 struct bt_ctf_field_type *packet_context_type =
596 bt_ctf_field_type_structure_create();
597 struct bt_ctf_field_type *_uint64_t =
598 get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
599 struct bt_ctf_field_type *ts_begin_end_uint64_t = NULL;
600
601 if (!packet_context_type) {
602 BT_LOGE_STR("Cannot create empty structure field type.");
603 ret = -1;
604 goto end;
605 }
606
607 ts_begin_end_uint64_t = bt_ctf_field_type_copy(_uint64_t);
608 if (!ts_begin_end_uint64_t) {
609 BT_LOGE_STR("Cannot copy integer field type for `timestamp_begin` and `timestamp_end` fields.");
610 ret = -1;
611 goto end;
612 }
613
614 /*
615 * We create a stream packet context as proposed in the CTF
616 * specification.
617 */
618 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
619 ts_begin_end_uint64_t, "timestamp_begin");
620 if (ret) {
621 BT_LOGE_STR("Cannot add `timestamp_begin` field to event header field type.");
622 goto end;
623 }
624
625 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
626 ts_begin_end_uint64_t, "timestamp_end");
627 if (ret) {
628 BT_LOGE_STR("Cannot add `timestamp_end` field to event header field type.");
629 goto end;
630 }
631
632 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
633 _uint64_t, "content_size");
634 if (ret) {
635 BT_LOGE_STR("Cannot add `content_size` field to event header field type.");
636 goto end;
637 }
638
639 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
640 _uint64_t, "packet_size");
641 if (ret) {
642 BT_LOGE_STR("Cannot add `packet_size` field to event header field type.");
643 goto end;
644 }
645
646 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
647 _uint64_t, "events_discarded");
648 if (ret) {
649 BT_LOGE_STR("Cannot add `events_discarded` field to event header field type.");
650 goto end;
651 }
652
653 bt_ctf_object_put_ref(stream_class->common.packet_context_field_type);
654 stream_class->common.packet_context_field_type =
655 (void *) packet_context_type;
656 packet_context_type = NULL;
657
658 end:
659 if (ret) {
660 bt_ctf_object_put_ref(packet_context_type);
661 goto end;
662 }
663
664 bt_ctf_object_put_ref(_uint64_t);
665 bt_ctf_object_put_ref(ts_begin_end_uint64_t);
666 return ret;
667 }
668
669 static
670 void bt_ctf_stream_class_destroy(struct bt_ctf_object *obj)
671 {
672 struct bt_ctf_stream_class *stream_class;
673
674 stream_class = (void *) obj;
675 BT_LOGD("Destroying CTF writer stream class: addr=%p, name=\"%s\", id=%" PRId64,
676 stream_class, bt_ctf_stream_class_get_name(stream_class),
677 bt_ctf_stream_class_get_id(stream_class));
678 bt_ctf_stream_class_common_finalize(BT_CTF_TO_COMMON(stream_class));
679 bt_ctf_object_put_ref(stream_class->clock);
680 g_free(stream_class);
681 }
682
683 struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name)
684 {
685 struct bt_ctf_stream_class *stream_class;
686 int ret;
687
688 BT_LOGD("Creating CTF writer stream class object: name=\"%s\"", name);
689 stream_class = g_new0(struct bt_ctf_stream_class, 1);
690 if (!stream_class) {
691 BT_LOGE_STR("Failed to allocate one CTF writer stream class.");
692 goto error;
693 }
694
695 ret = bt_ctf_stream_class_common_initialize(BT_CTF_TO_COMMON(stream_class),
696 name, bt_ctf_stream_class_destroy);
697 if (ret) {
698 /* bt_ctf_stream_class_common_initialize() logs errors */
699 goto error;
700 }
701
702 ret = init_event_header(stream_class);
703 if (ret) {
704 BT_LOGE_STR("Cannot initialize stream class's event header field type.");
705 goto error;
706 }
707
708 ret = init_packet_context(stream_class);
709 if (ret) {
710 BT_LOGE_STR("Cannot initialize stream class's packet context field type.");
711 goto error;
712 }
713
714 BT_LOGD("Created CTF writer stream class object: addr=%p, name=\"%s\"",
715 stream_class, name);
716 return stream_class;
717
718 error:
719 BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_class);
720 return stream_class;
721 }
722
723 static
724 int try_map_clock_class(struct bt_ctf_stream_class *stream_class,
725 struct bt_ctf_field_type *parent_ft, const char *field_name)
726 {
727 struct bt_ctf_clock_class *mapped_clock_class = NULL;
728 int ret = 0;
729 struct bt_ctf_field_type *ft =
730 bt_ctf_field_type_structure_get_field_type_by_name(parent_ft,
731 field_name);
732
733 BT_ASSERT_DBG(stream_class->clock);
734
735 if (!ft) {
736 /* Field does not exist: not an error */
737 goto end;
738 }
739
740 BT_ASSERT_DBG(((struct bt_ctf_field_type_common *) ft)->id ==
741 BT_CTF_FIELD_TYPE_ID_INTEGER);
742 mapped_clock_class =
743 bt_ctf_field_type_integer_get_mapped_clock_class(ft);
744 if (!mapped_clock_class) {
745 struct bt_ctf_field_type *ft_copy;
746
747 if (!stream_class->clock) {
748 BT_LOGW("Cannot automatically set field's type mapped clock class: stream class's clock is not set: "
749 "stream-class-addr=%p, stream-class-name=\"%s\", "
750 "stream-class-id=%" PRId64 ", ft-addr=%p",
751 stream_class,
752 bt_ctf_stream_class_get_name(stream_class),
753 bt_ctf_stream_class_get_id(stream_class), ft);
754 ret = -1;
755 goto end;
756 }
757
758 ft_copy = bt_ctf_field_type_copy(ft);
759 if (!ft_copy) {
760 BT_LOGE("Failed to copy integer field type: ft-addr=%p",
761 ft);
762 ret = -1;
763 goto end;
764 }
765
766 ret = bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
767 (void *) ft_copy, stream_class->clock->clock_class);
768 BT_ASSERT_DBG(ret == 0);
769
770 ret = bt_ctf_field_type_common_structure_replace_field(
771 (void *) parent_ft, field_name, (void *) ft_copy);
772 bt_ctf_object_put_ref(ft_copy);
773 BT_LOGT("Automatically mapped field type to stream class's clock class: "
774 "stream-class-addr=%p, stream-class-name=\"%s\", "
775 "stream-class-id=%" PRId64 ", ft-addr=%p, "
776 "ft-copy-addr=%p",
777 stream_class,
778 bt_ctf_stream_class_get_name(stream_class),
779 bt_ctf_stream_class_get_id(stream_class), ft, ft_copy);
780 }
781
782 end:
783 bt_ctf_object_put_ref(ft);
784 bt_ctf_object_put_ref(mapped_clock_class);
785 return ret;
786 }
787
788 BT_HIDDEN
789 int bt_ctf_stream_class_map_clock_class(
790 struct bt_ctf_stream_class *stream_class,
791 struct bt_ctf_field_type *packet_context_type,
792 struct bt_ctf_field_type *event_header_type)
793 {
794 int ret = 0;
795
796 BT_ASSERT_DBG(stream_class);
797
798 if (!stream_class->clock) {
799 /* No clock class to map to */
800 goto end;
801 }
802
803 if (packet_context_type) {
804 if (try_map_clock_class(stream_class, packet_context_type,
805 "timestamp_begin")) {
806 BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_begin` field's mapped clock class.");
807 ret = -1;
808 goto end;
809 }
810
811 if (try_map_clock_class(stream_class, packet_context_type,
812 "timestamp_end")) {
813 BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_end` field's mapped clock class.");
814 ret = -1;
815 goto end;
816 }
817 }
818
819 if (event_header_type) {
820 if (try_map_clock_class(stream_class, event_header_type,
821 "timestamp")) {
822 BT_LOGE_STR("Cannot automatically set stream class's event header field type's `timestamp` field's mapped clock class.");
823 ret = -1;
824 goto end;
825 }
826 }
827
828 end:
829 return ret;
830 }
831
832 struct bt_ctf_clock *bt_ctf_stream_class_get_clock(
833 struct bt_ctf_stream_class *stream_class)
834 {
835 struct bt_ctf_clock *clock = NULL;
836
837 if (!stream_class) {
838 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
839 goto end;
840 }
841
842 if (!stream_class->clock) {
843 BT_LOGT("Stream class has no clock: "
844 "addr=%p, name=\"%s\", id=%" PRId64,
845 stream_class,
846 bt_ctf_stream_class_get_name(stream_class),
847 bt_ctf_stream_class_get_id(stream_class));
848 goto end;
849 }
850
851 clock = bt_ctf_object_get_ref(stream_class->clock);
852
853 end:
854 return clock;
855 }
856
857 int bt_ctf_stream_class_set_clock(
858 struct bt_ctf_stream_class *stream_class,
859 struct bt_ctf_clock *clock)
860 {
861 int ret = 0;
862
863 if (!stream_class || !clock) {
864 BT_LOGW("Invalid parameter: stream class or clock is NULL: "
865 "stream-class-addr=%p, clock-addr=%p",
866 stream_class, clock);
867 ret = -1;
868 goto end;
869 }
870
871 if (stream_class->common.frozen) {
872 BT_LOGW("Invalid parameter: stream class is frozen: "
873 "addr=%p, name=\"%s\", id=%" PRId64,
874 stream_class,
875 bt_ctf_stream_class_get_name(stream_class),
876 bt_ctf_stream_class_get_id(stream_class));
877 ret = -1;
878 goto end;
879 }
880
881 /* Replace the current clock of this stream class. */
882 bt_ctf_object_put_ref(stream_class->clock);
883 stream_class->clock = bt_ctf_object_get_ref(clock);
884 BT_LOGT("Set stream class's clock: "
885 "addr=%p, name=\"%s\", id=%" PRId64 ", "
886 "clock-addr=%p, clock-name=\"%s\"",
887 stream_class,
888 bt_ctf_stream_class_get_name(stream_class),
889 bt_ctf_stream_class_get_id(stream_class),
890 stream_class->clock,
891 bt_ctf_clock_get_name(stream_class->clock));
892
893 end:
894 return ret;
895 }
896
897 BT_HIDDEN
898 int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class,
899 struct metadata_context *context)
900 {
901 int ret = 0;
902 size_t i;
903 struct bt_ctf_trace *trace;
904 struct bt_ctf_field_type *packet_header_type = NULL;
905
906 BT_LOGD("Serializing stream class's metadata: "
907 "stream-class-addr=%p, stream-class-name=\"%s\", "
908 "stream-class-id=%" PRId64 ", metadata-context-addr=%p",
909 stream_class,
910 bt_ctf_stream_class_get_name(stream_class),
911 bt_ctf_stream_class_get_id(stream_class), context);
912 g_string_assign(context->field_name, "");
913 context->current_indentation_level = 1;
914 if (!stream_class->common.id_set) {
915 BT_LOGW_STR("Stream class's ID is not set.");
916 ret = -1;
917 goto end;
918 }
919
920 g_string_append(context->string, "stream {\n");
921
922 /*
923 * The reference to the trace is only borrowed since the
924 * serialization of the stream class might have been triggered
925 * by the trace's destruction. In such a case, the trace's
926 * reference count would, unexepectedly, go through the sequence
927 * 1 -> 0 -> 1 -> 0 -> ..., provoking an endless loop of destruction
928 * and serialization.
929 */
930 trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
931 BT_CTF_TO_COMMON(stream_class)));
932 BT_ASSERT_DBG(trace);
933 packet_header_type = bt_ctf_trace_get_packet_header_field_type(trace);
934 trace = NULL;
935 if (packet_header_type) {
936 struct bt_ctf_field_type *stream_id_type;
937
938 stream_id_type =
939 bt_ctf_field_type_structure_get_field_type_by_name(
940 packet_header_type, "stream_id");
941 if (stream_id_type) {
942 /*
943 * Only set the stream's id if the trace's packet header
944 * contains a stream_id field. This field is only
945 * needed if the trace contains only one stream
946 * class.
947 */
948 g_string_append_printf(context->string,
949 "\tid = %" PRId64 ";\n",
950 stream_class->common.id);
951 }
952 bt_ctf_object_put_ref(stream_id_type);
953 }
954 if (stream_class->common.event_header_field_type) {
955 BT_LOGD_STR("Serializing stream class's event header field type's metadata.");
956 g_string_append(context->string, "\tevent.header := ");
957 ret = bt_ctf_field_type_serialize_recursive(
958 (void *) stream_class->common.event_header_field_type,
959 context);
960 if (ret) {
961 BT_LOGW("Cannot serialize stream class's event header field type's metadata: "
962 "ret=%d", ret);
963 goto end;
964 }
965 g_string_append(context->string, ";");
966 }
967
968
969 if (stream_class->common.packet_context_field_type) {
970 BT_LOGD_STR("Serializing stream class's packet context field type's metadata.");
971 g_string_append(context->string, "\n\n\tpacket.context := ");
972 ret = bt_ctf_field_type_serialize_recursive(
973 (void *) stream_class->common.packet_context_field_type,
974 context);
975 if (ret) {
976 BT_LOGW("Cannot serialize stream class's packet context field type's metadata: "
977 "ret=%d", ret);
978 goto end;
979 }
980 g_string_append(context->string, ";");
981 }
982
983 if (stream_class->common.event_context_field_type) {
984 BT_LOGD_STR("Serializing stream class's event context field type's metadata.");
985 g_string_append(context->string, "\n\n\tevent.context := ");
986 ret = bt_ctf_field_type_serialize_recursive(
987 (void *) stream_class->common.event_context_field_type,
988 context);
989 if (ret) {
990 BT_LOGW("Cannot serialize stream class's event context field type's metadata: "
991 "ret=%d", ret);
992 goto end;
993 }
994 g_string_append(context->string, ";");
995 }
996
997 g_string_append(context->string, "\n};\n\n");
998
999 for (i = 0; i < stream_class->common.event_classes->len; i++) {
1000 struct bt_ctf_event_class *event_class =
1001 stream_class->common.event_classes->pdata[i];
1002
1003 ret = bt_ctf_event_class_serialize(event_class, context);
1004 if (ret) {
1005 BT_LOGW("Cannot serialize event class's metadata: "
1006 "event-class-addr=%p, event-class-name=\"%s\", "
1007 "event-class-id=%" PRId64,
1008 event_class,
1009 bt_ctf_event_class_get_name(event_class),
1010 bt_ctf_event_class_get_id(event_class));
1011 goto end;
1012 }
1013 }
1014
1015 end:
1016 bt_ctf_object_put_ref(packet_header_type);
1017 context->current_indentation_level = 0;
1018 return ret;
1019 }
1020
1021 struct bt_ctf_trace *bt_ctf_stream_class_get_trace(
1022 struct bt_ctf_stream_class *stream_class)
1023 {
1024 return bt_ctf_object_get_ref(bt_ctf_stream_class_common_borrow_trace(
1025 BT_CTF_TO_COMMON(stream_class)));
1026 }
1027
1028 const char *bt_ctf_stream_class_get_name(
1029 struct bt_ctf_stream_class *stream_class)
1030 {
1031 return bt_ctf_stream_class_common_get_name(BT_CTF_TO_COMMON(stream_class));
1032 }
1033
1034 int bt_ctf_stream_class_set_name(
1035 struct bt_ctf_stream_class *stream_class, const char *name)
1036 {
1037 return bt_ctf_stream_class_common_set_name(BT_CTF_TO_COMMON(stream_class),
1038 name);
1039 }
1040
1041 int64_t bt_ctf_stream_class_get_id(
1042 struct bt_ctf_stream_class *stream_class)
1043 {
1044 return bt_ctf_stream_class_common_get_id(BT_CTF_TO_COMMON(stream_class));
1045 }
1046
1047 int bt_ctf_stream_class_set_id(
1048 struct bt_ctf_stream_class *stream_class, uint64_t id)
1049 {
1050 return bt_ctf_stream_class_common_set_id(BT_CTF_TO_COMMON(stream_class), id);
1051 }
1052
1053 struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type(
1054 struct bt_ctf_stream_class *stream_class)
1055 {
1056 return bt_ctf_object_get_ref(
1057 bt_ctf_stream_class_common_borrow_packet_context_field_type(
1058 BT_CTF_TO_COMMON(stream_class)));
1059 }
1060
1061 int bt_ctf_stream_class_set_packet_context_type(
1062 struct bt_ctf_stream_class *stream_class,
1063 struct bt_ctf_field_type *packet_context_type)
1064 {
1065 return bt_ctf_stream_class_common_set_packet_context_field_type(
1066 BT_CTF_TO_COMMON(stream_class), (void *) packet_context_type);
1067 }
1068
1069 struct bt_ctf_field_type *
1070 bt_ctf_stream_class_get_event_header_type(
1071 struct bt_ctf_stream_class *stream_class)
1072 {
1073 return bt_ctf_object_get_ref(
1074 bt_ctf_stream_class_common_borrow_event_header_field_type(
1075 BT_CTF_TO_COMMON(stream_class)));
1076 }
1077
1078 int bt_ctf_stream_class_set_event_header_type(
1079 struct bt_ctf_stream_class *stream_class,
1080 struct bt_ctf_field_type *event_header_type)
1081 {
1082 return bt_ctf_stream_class_common_set_event_header_field_type(
1083 BT_CTF_TO_COMMON(stream_class), (void *) event_header_type);
1084 }
1085
1086 struct bt_ctf_field_type *
1087 bt_ctf_stream_class_get_event_context_type(
1088 struct bt_ctf_stream_class *stream_class)
1089 {
1090 return bt_ctf_object_get_ref(
1091 bt_ctf_stream_class_common_borrow_event_context_field_type(
1092 BT_CTF_TO_COMMON(stream_class)));
1093 }
1094
1095 int bt_ctf_stream_class_set_event_context_type(
1096 struct bt_ctf_stream_class *stream_class,
1097 struct bt_ctf_field_type *event_context_type)
1098 {
1099 return bt_ctf_stream_class_common_set_event_context_field_type(
1100 BT_CTF_TO_COMMON(stream_class), (void *) event_context_type);
1101 }
1102
1103 int64_t bt_ctf_stream_class_get_event_class_count(
1104 struct bt_ctf_stream_class *stream_class)
1105 {
1106 return bt_ctf_stream_class_common_get_event_class_count(
1107 BT_CTF_TO_COMMON(stream_class));
1108 }
1109
1110 struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_index(
1111 struct bt_ctf_stream_class *stream_class, uint64_t index)
1112 {
1113 return bt_ctf_object_get_ref(
1114 bt_ctf_stream_class_common_borrow_event_class_by_index(
1115 BT_CTF_TO_COMMON(stream_class), index));
1116 }
1117
1118 struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id(
1119 struct bt_ctf_stream_class *stream_class, uint64_t id)
1120 {
1121 return bt_ctf_object_get_ref(
1122 bt_ctf_stream_class_common_borrow_event_class_by_id(
1123 BT_CTF_TO_COMMON(stream_class), id));
1124 }
1125
1126 int bt_ctf_stream_class_add_event_class(
1127 struct bt_ctf_stream_class *stream_class,
1128 struct bt_ctf_event_class *event_class)
1129 {
1130 return bt_ctf_stream_class_common_add_event_class(
1131 BT_CTF_TO_COMMON(stream_class), BT_CTF_TO_COMMON(event_class),
1132 (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy);
1133 }
This page took 0.083873 seconds and 4 git commands to generate.