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