Add bt_ctf_trace_add_is_static_listener() and ..._remove_is_static_listener()
[babeltrace.git] / lib / ctf-ir / trace.c
1 /*
2 * trace.c
3 *
4 * Babeltrace CTF IR - Trace
5 *
6 * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
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:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
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
26 * SOFTWARE.
27 */
28
29 #define BT_LOG_TAG "TRACE"
30 #include <babeltrace/lib-logging-internal.h>
31
32 #include <babeltrace/ctf-ir/trace-internal.h>
33 #include <babeltrace/ctf-ir/clock-class-internal.h>
34 #include <babeltrace/ctf-ir/stream-internal.h>
35 #include <babeltrace/ctf-ir/stream-class-internal.h>
36 #include <babeltrace/ctf-ir/event-internal.h>
37 #include <babeltrace/ctf-ir/event-class.h>
38 #include <babeltrace/ctf-ir/event-class-internal.h>
39 #include <babeltrace/ctf-writer/functor-internal.h>
40 #include <babeltrace/ctf-writer/clock-internal.h>
41 #include <babeltrace/ctf-ir/field-types-internal.h>
42 #include <babeltrace/ctf-ir/attributes-internal.h>
43 #include <babeltrace/ctf-ir/validation-internal.h>
44 #include <babeltrace/ctf-ir/visitor-internal.h>
45 #include <babeltrace/ctf-ir/utils.h>
46 #include <babeltrace/compiler-internal.h>
47 #include <babeltrace/values.h>
48 #include <babeltrace/values-internal.h>
49 #include <babeltrace/ref.h>
50 #include <babeltrace/types.h>
51 #include <babeltrace/endian-internal.h>
52 #include <inttypes.h>
53 #include <stdint.h>
54 #include <string.h>
55 #include <stdlib.h>
56
57 #define DEFAULT_IDENTIFIER_SIZE 128
58 #define DEFAULT_METADATA_STRING_SIZE 4096
59
60 struct listener_wrapper {
61 bt_ctf_listener_cb listener;
62 void *data;
63 };
64
65 struct bt_ctf_trace_is_static_listener_elem {
66 bt_ctf_trace_is_static_listener func;
67 void *data;
68 };
69
70 static
71 void bt_ctf_trace_destroy(struct bt_object *obj);
72 static
73 void bt_ctf_trace_freeze(struct bt_ctf_trace *trace);
74
75 static
76 const unsigned int field_type_aliases_alignments[] = {
77 [FIELD_TYPE_ALIAS_UINT5_T] = 1,
78 [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8,
79 [FIELD_TYPE_ALIAS_UINT27_T] = 1,
80 [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8,
81 };
82
83 static
84 const unsigned int field_type_aliases_sizes[] = {
85 [FIELD_TYPE_ALIAS_UINT5_T] = 5,
86 [FIELD_TYPE_ALIAS_UINT8_T] = 8,
87 [FIELD_TYPE_ALIAS_UINT16_T] = 16,
88 [FIELD_TYPE_ALIAS_UINT27_T] = 27,
89 [FIELD_TYPE_ALIAS_UINT32_T] = 32,
90 [FIELD_TYPE_ALIAS_UINT64_T] = 64,
91 };
92
93 struct bt_ctf_trace *bt_ctf_trace_create(void)
94 {
95 struct bt_ctf_trace *trace = NULL;
96 struct bt_ctf_field_type *packet_header_type = NULL;
97
98 trace = g_new0(struct bt_ctf_trace, 1);
99 if (!trace) {
100 BT_LOGE_STR("Failed to allocate one trace.");
101 goto error;
102 }
103
104 BT_LOGD_STR("Creating trace object.");
105 trace->native_byte_order = BT_CTF_BYTE_ORDER_NATIVE;
106 bt_object_init(trace, bt_ctf_trace_destroy);
107 trace->clocks = g_ptr_array_new_with_free_func(
108 (GDestroyNotify) bt_put);
109 if (!trace->clocks) {
110 BT_LOGE_STR("Failed to allocate one GPtrArray.");
111 goto error;
112 }
113
114 trace->streams = g_ptr_array_new_with_free_func(
115 (GDestroyNotify) bt_object_release);
116 if (!trace->streams) {
117 BT_LOGE_STR("Failed to allocate one GPtrArray.");
118 goto error;
119 }
120
121 trace->stream_classes = g_ptr_array_new_with_free_func(
122 (GDestroyNotify) bt_object_release);
123 if (!trace->stream_classes) {
124 BT_LOGE_STR("Failed to allocate one GPtrArray.");
125 goto error;
126 }
127
128 packet_header_type = bt_ctf_field_type_structure_create();
129 if (!packet_header_type) {
130 goto error;
131 }
132
133 BT_MOVE(trace->packet_header_type, packet_header_type);
134
135 /* Create the environment array object */
136 trace->environment = bt_ctf_attributes_create();
137 if (!trace->environment) {
138 BT_LOGE_STR("Cannot create empty attributes object.");
139 goto error;
140 }
141
142 trace->listeners = g_ptr_array_new_with_free_func(
143 (GDestroyNotify) g_free);
144 if (!trace->listeners) {
145 BT_LOGE_STR("Failed to allocate one GPtrArray.");
146 goto error;
147 }
148
149 trace->is_static_listeners = g_array_new(FALSE, TRUE,
150 sizeof(struct bt_ctf_trace_is_static_listener_elem));
151 if (!trace->is_static_listeners) {
152 BT_LOGE_STR("Failed to allocate one GArray.");
153 goto error;
154 }
155
156 BT_LOGD("Created trace object: addr=%p", trace);
157 return trace;
158
159 error:
160 BT_PUT(trace);
161 bt_put(packet_header_type);
162 return trace;
163 }
164
165 const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace)
166 {
167 const char *name = NULL;
168
169 if (!trace) {
170 BT_LOGW_STR("Invalid parameter: trace is NULL.");
171 goto end;
172 }
173
174 if (!trace->name) {
175 goto end;
176 }
177
178 name = trace->name->str;
179 end:
180 return name;
181 }
182
183 int bt_ctf_trace_set_name(struct bt_ctf_trace *trace, const char *name)
184 {
185 int ret = 0;
186
187 if (!trace) {
188 BT_LOGW_STR("Invalid parameter: trace is NULL.");
189 ret = -1;
190 goto end;
191 }
192
193 if (!name) {
194 BT_LOGW_STR("Invalid parameter: name is NULL.");
195 ret = -1;
196 goto end;
197 }
198
199 if (trace->frozen) {
200 BT_LOGW("Invalid parameter: trace is frozen: "
201 "addr=%p, name=\"%s\"",
202 trace, bt_ctf_trace_get_name(trace));
203 ret = -1;
204 goto end;
205 }
206
207 trace->name = trace->name ? g_string_assign(trace->name, name) :
208 g_string_new(name);
209 if (!trace->name) {
210 BT_LOGE_STR("Failed to allocate one GString.");
211 ret = -1;
212 goto end;
213 }
214
215 BT_LOGV("Set trace's name: addr=%p, name=\"%s\"", trace, name);
216
217 end:
218 return ret;
219 }
220
221 const unsigned char *bt_ctf_trace_get_uuid(struct bt_ctf_trace *trace)
222 {
223 return trace && trace->uuid_set ? trace->uuid : NULL;
224 }
225
226 int bt_ctf_trace_set_uuid(struct bt_ctf_trace *trace, const unsigned char *uuid)
227 {
228 int ret = 0;
229
230 if (!trace) {
231 BT_LOGW_STR("Invalid parameter: trace is NULL.");
232 ret = -1;
233 goto end;
234 }
235
236 if (!uuid) {
237 BT_LOGW_STR("Invalid parameter: UUID is NULL.");
238 ret = -1;
239 goto end;
240 }
241
242 if (trace->frozen) {
243 BT_LOGW("Invalid parameter: trace is frozen: "
244 "addr=%p, name=\"%s\"",
245 trace, bt_ctf_trace_get_name(trace));
246 ret = -1;
247 goto end;
248 }
249
250 memcpy(trace->uuid, uuid, sizeof(uuid_t));
251 trace->uuid_set = BT_TRUE;
252 BT_LOGV("Set trace's UUID: addr=%p, name=\"%s\", "
253 "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
254 trace, bt_ctf_trace_get_name(trace),
255 (unsigned int) uuid[0],
256 (unsigned int) uuid[1],
257 (unsigned int) uuid[2],
258 (unsigned int) uuid[3],
259 (unsigned int) uuid[4],
260 (unsigned int) uuid[5],
261 (unsigned int) uuid[6],
262 (unsigned int) uuid[7],
263 (unsigned int) uuid[8],
264 (unsigned int) uuid[9],
265 (unsigned int) uuid[10],
266 (unsigned int) uuid[11],
267 (unsigned int) uuid[12],
268 (unsigned int) uuid[13],
269 (unsigned int) uuid[14],
270 (unsigned int) uuid[15]);
271
272 end:
273 return ret;
274 }
275
276 void bt_ctf_trace_destroy(struct bt_object *obj)
277 {
278 struct bt_ctf_trace *trace;
279
280 trace = container_of(obj, struct bt_ctf_trace, base);
281
282 BT_LOGD("Destroying trace object: addr=%p, name=\"%s\"",
283 trace, bt_ctf_trace_get_name(trace));
284
285 if (trace->environment) {
286 BT_LOGD_STR("Destroying environment attributes.");
287 bt_ctf_attributes_destroy(trace->environment);
288 }
289
290 if (trace->name) {
291 g_string_free(trace->name, TRUE);
292 }
293
294 if (trace->clocks) {
295 BT_LOGD_STR("Putting clock classes.");
296 g_ptr_array_free(trace->clocks, TRUE);
297 }
298
299 if (trace->streams) {
300 BT_LOGD_STR("Destroying streams.");
301 g_ptr_array_free(trace->streams, TRUE);
302 }
303
304 if (trace->stream_classes) {
305 BT_LOGD_STR("Destroying stream classes.");
306 g_ptr_array_free(trace->stream_classes, TRUE);
307 }
308
309 if (trace->listeners) {
310 g_ptr_array_free(trace->listeners, TRUE);
311 }
312
313 if (trace->is_static_listeners) {
314 g_array_free(trace->is_static_listeners, TRUE);
315 }
316
317 BT_LOGD_STR("Putting packet header field type.");
318 bt_put(trace->packet_header_type);
319 g_free(trace);
320 }
321
322 int bt_ctf_trace_set_environment_field(struct bt_ctf_trace *trace,
323 const char *name, struct bt_value *value)
324 {
325 int ret = 0;
326
327 if (!trace) {
328 BT_LOGW_STR("Invalid parameter: trace is NULL.");
329 ret = -1;
330 goto end;
331 }
332
333 if (!name) {
334 BT_LOGW_STR("Invalid parameter: name is NULL.");
335 ret = -1;
336 goto end;
337 }
338
339 if (!value) {
340 BT_LOGW_STR("Invalid parameter: value is NULL.");
341 ret = -1;
342 goto end;
343 }
344
345 if (bt_ctf_validate_identifier(name)) {
346 BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: "
347 "trace-addr=%p, trace-name=\"%s\", "
348 "env-name=\"%s\"",
349 trace, bt_ctf_trace_get_name(trace), name);
350 ret = -1;
351 goto end;
352 }
353
354 if (!bt_value_is_integer(value) && !bt_value_is_string(value)) {
355 BT_LOGW("Invalid parameter: environment field's value is not an integer or string value: "
356 "trace-addr=%p, trace-name=\"%s\", "
357 "env-name=\"%s\", env-value-type=%s",
358 trace, bt_ctf_trace_get_name(trace), name,
359 bt_value_type_string(bt_value_get_type(value)));
360 ret = -1;
361 goto end;
362 }
363
364 if (trace->is_static) {
365 BT_LOGW("Invalid parameter: trace is static: "
366 "addr=%p, name=\"%s\"",
367 trace, bt_ctf_trace_get_name(trace));
368 ret = -1;
369 goto end;
370 }
371
372 if (trace->frozen) {
373 /*
374 * New environment fields may be added to a frozen trace,
375 * but existing fields may not be changed.
376 *
377 * The object passed is frozen like all other attributes.
378 */
379 struct bt_value *attribute =
380 bt_ctf_attributes_get_field_value_by_name(
381 trace->environment, name);
382
383 if (attribute) {
384 BT_LOGW("Invalid parameter: trace is frozen and environment field already exists with this name: "
385 "trace-addr=%p, trace-name=\"%s\", "
386 "env-name=\"%s\"",
387 trace, bt_ctf_trace_get_name(trace), name);
388 BT_PUT(attribute);
389 ret = -1;
390 goto end;
391 }
392
393 bt_value_freeze(value);
394 }
395
396 ret = bt_ctf_attributes_set_field_value(trace->environment, name,
397 value);
398 if (ret) {
399 BT_LOGE("Cannot set environment field's value: "
400 "trace-addr=%p, trace-name=\"%s\", "
401 "env-name=\"%s\"",
402 trace, bt_ctf_trace_get_name(trace), name);
403 } else {
404 BT_LOGV("Set environment field's value: "
405 "trace-addr=%p, trace-name=\"%s\", "
406 "env-name=\"%s\", value-addr=%p",
407 trace, bt_ctf_trace_get_name(trace), name, value);
408 }
409
410 end:
411 return ret;
412 }
413
414 int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace,
415 const char *name, const char *value)
416 {
417 int ret = 0;
418 struct bt_value *env_value_string_obj = NULL;
419
420 if (!value) {
421 BT_LOGW_STR("Invalid parameter: value is NULL.");
422 ret = -1;
423 goto end;
424 }
425
426 env_value_string_obj = bt_value_string_create_init(value);
427 if (!env_value_string_obj) {
428 BT_LOGE_STR("Cannot create string value object.");
429 ret = -1;
430 goto end;
431 }
432
433 /* bt_ctf_trace_set_environment_field() logs errors */
434 ret = bt_ctf_trace_set_environment_field(trace, name,
435 env_value_string_obj);
436
437 end:
438 bt_put(env_value_string_obj);
439 return ret;
440 }
441
442 int bt_ctf_trace_set_environment_field_integer(struct bt_ctf_trace *trace,
443 const char *name, int64_t value)
444 {
445 int ret = 0;
446 struct bt_value *env_value_integer_obj = NULL;
447
448 env_value_integer_obj = bt_value_integer_create_init(value);
449 if (!env_value_integer_obj) {
450 BT_LOGE_STR("Cannot create integer value object.");
451 ret = -1;
452 goto end;
453 }
454
455 /* bt_ctf_trace_set_environment_field() logs errors */
456 ret = bt_ctf_trace_set_environment_field(trace, name,
457 env_value_integer_obj);
458
459 end:
460 bt_put(env_value_integer_obj);
461 return ret;
462 }
463
464 int64_t bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace)
465 {
466 int64_t ret = 0;
467
468 if (!trace) {
469 BT_LOGW_STR("Invalid parameter: trace is NULL.");
470 ret = (int64_t) -1;
471 goto end;
472 }
473
474 ret = bt_ctf_attributes_get_count(trace->environment);
475 assert(ret >= 0);
476
477 end:
478 return ret;
479 }
480
481 const char *
482 bt_ctf_trace_get_environment_field_name_by_index(struct bt_ctf_trace *trace,
483 uint64_t index)
484 {
485 const char *ret = NULL;
486
487 if (!trace) {
488 BT_LOGW_STR("Invalid parameter: trace is NULL.");
489 goto end;
490 }
491
492 ret = bt_ctf_attributes_get_field_name(trace->environment, index);
493
494 end:
495 return ret;
496 }
497
498 struct bt_value *bt_ctf_trace_get_environment_field_value_by_index(
499 struct bt_ctf_trace *trace, uint64_t index)
500 {
501 struct bt_value *ret = NULL;
502
503 if (!trace) {
504 BT_LOGW_STR("Invalid parameter: trace is NULL.");
505 goto end;
506 }
507
508 ret = bt_ctf_attributes_get_field_value(trace->environment, index);
509
510 end:
511 return ret;
512 }
513
514 struct bt_value *bt_ctf_trace_get_environment_field_value_by_name(
515 struct bt_ctf_trace *trace, const char *name)
516 {
517 struct bt_value *ret = NULL;
518
519 if (!trace) {
520 BT_LOGW_STR("Invalid parameter: trace is NULL.");
521 goto end;
522 }
523
524 if (!name) {
525 BT_LOGW_STR("Invalid parameter: name is NULL.");
526 goto end;
527 }
528
529 ret = bt_ctf_attributes_get_field_value_by_name(trace->environment,
530 name);
531
532 end:
533 return ret;
534 }
535
536 int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace,
537 struct bt_ctf_clock_class *clock_class)
538 {
539 int ret = 0;
540
541 if (!trace) {
542 BT_LOGW_STR("Invalid parameter: trace is NULL.");
543 ret = -1;
544 goto end;
545 }
546
547 if (trace->is_static) {
548 BT_LOGW("Invalid parameter: trace is static: "
549 "addr=%p, name=\"%s\"",
550 trace, bt_ctf_trace_get_name(trace));
551 ret = -1;
552 goto end;
553 }
554
555 if (!bt_ctf_clock_class_is_valid(clock_class)) {
556 BT_LOGW("Invalid parameter: clock class is invalid: "
557 "trace-addr=%p, trace-name=\"%s\", "
558 "clock-class-addr=%p, clock-class-name=\"%s\"",
559 trace, bt_ctf_trace_get_name(trace),
560 clock_class, bt_ctf_clock_class_get_name(clock_class));
561 ret = -1;
562 goto end;
563 }
564
565 /* Check for duplicate clock classes */
566 if (bt_ctf_trace_has_clock_class(trace, clock_class)) {
567 BT_LOGW("Invalid parameter: clock class already exists in trace: "
568 "trace-addr=%p, trace-name=\"%s\", "
569 "clock-class-addr=%p, clock-class-name=\"%s\"",
570 trace, bt_ctf_trace_get_name(trace),
571 clock_class, bt_ctf_clock_class_get_name(clock_class));
572 ret = -1;
573 goto end;
574 }
575
576 bt_get(clock_class);
577 g_ptr_array_add(trace->clocks, clock_class);
578
579 if (trace->frozen) {
580 BT_LOGV_STR("Freezing added clock class because trace is frozen.");
581 bt_ctf_clock_class_freeze(clock_class);
582 }
583
584 BT_LOGV("Added clock class to trace: "
585 "trace-addr=%p, trace-name=\"%s\", "
586 "clock-class-addr=%p, clock-class-name=\"%s\"",
587 trace, bt_ctf_trace_get_name(trace),
588 clock_class, bt_ctf_clock_class_get_name(clock_class));
589
590 end:
591 return ret;
592 }
593
594 int64_t bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace)
595 {
596 int64_t ret = (int64_t) -1;
597
598 if (!trace) {
599 BT_LOGW_STR("Invalid parameter: trace is NULL.");
600 goto end;
601 }
602
603 ret = trace->clocks->len;
604 end:
605 return ret;
606 }
607
608 struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index(
609 struct bt_ctf_trace *trace, uint64_t index)
610 {
611 struct bt_ctf_clock_class *clock_class = NULL;
612
613 if (!trace) {
614 BT_LOGW_STR("Invalid parameter: trace is NULL.");
615 goto end;
616 }
617
618 if (index >= trace->clocks->len) {
619 BT_LOGW("Invalid parameter: index is out of bounds: "
620 "addr=%p, name=\"%s\", "
621 "index=%" PRIu64 ", count=%u",
622 trace, bt_ctf_trace_get_name(trace),
623 index, trace->clocks->len);
624 goto end;
625 }
626
627 clock_class = g_ptr_array_index(trace->clocks, index);
628 bt_get(clock_class);
629 end:
630 return clock_class;
631 }
632
633 static
634 bool packet_header_field_type_is_valid(struct bt_ctf_trace *trace,
635 struct bt_ctf_field_type *packet_header_type)
636 {
637 int ret;
638 bool is_valid = true;
639 struct bt_ctf_field_type *field_type = NULL;
640
641 if (!packet_header_type) {
642 /*
643 * No packet header field type: trace must have only
644 * one stream. At this point the stream class being
645 * added is not part of the trace yet, so we validate
646 * that the trace contains no stream classes yet.
647 */
648 if (trace->stream_classes->len >= 1) {
649 BT_LOGW_STR("Invalid packet header field type: "
650 "packet header field type does not exist but there's more than one stream class in the trace.");
651 goto invalid;
652 }
653
654 /* No packet header field type: valid at this point */
655 goto end;
656 }
657
658 /* Packet header field type, if it exists, must be a structure */
659 if (!bt_ctf_field_type_is_structure(packet_header_type)) {
660 BT_LOGW("Invalid packet header field type: must be a structure field type if it exists: "
661 "ft-addr=%p, ft-id=%s",
662 packet_header_type,
663 bt_ctf_field_type_id_string(packet_header_type->id));
664 goto invalid;
665 }
666
667 /*
668 * If there's a `magic` field, it must be a 32-bit unsigned
669 * integer field type. Also it must be the first field of the
670 * packet header field type.
671 */
672 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
673 packet_header_type, "magic");
674 if (field_type) {
675 const char *field_name;
676
677 if (!bt_ctf_field_type_is_integer(field_type)) {
678 BT_LOGW("Invalid packet header field type: `magic` field must be an integer field type: "
679 "magic-ft-addr=%p, magic-ft-id=%s",
680 field_type,
681 bt_ctf_field_type_id_string(field_type->id));
682 goto invalid;
683 }
684
685 if (bt_ctf_field_type_integer_is_signed(field_type)) {
686 BT_LOGW("Invalid packet header field type: `magic` field must be an unsigned integer field type: "
687 "magic-ft-addr=%p", field_type);
688 goto invalid;
689 }
690
691 if (bt_ctf_field_type_integer_get_size(field_type) != 32) {
692 BT_LOGW("Invalid packet header field type: `magic` field must be a 32-bit unsigned integer field type: "
693 "magic-ft-addr=%p, magic-ft-size=%u",
694 field_type,
695 bt_ctf_field_type_integer_get_size(field_type));
696 goto invalid;
697 }
698
699 ret = bt_ctf_field_type_structure_get_field_by_index(
700 packet_header_type, &field_name, NULL, 0);
701 assert(ret == 0);
702
703 if (strcmp(field_name, "magic") != 0) {
704 BT_LOGW("Invalid packet header field type: `magic` field must be the first field: "
705 "magic-ft-addr=%p, first-field-name=\"%s\"",
706 field_type, field_name);
707 goto invalid;
708 }
709
710 BT_PUT(field_type);
711 }
712
713 /*
714 * If there's a `uuid` field, it must be an array field type of
715 * length 16 with an 8-bit unsigned integer element field type.
716 */
717 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
718 packet_header_type, "uuid");
719 if (field_type) {
720 struct bt_ctf_field_type *elem_ft;
721
722 if (!bt_ctf_field_type_is_array(field_type)) {
723 BT_LOGW("Invalid packet header field type: `uuid` field must be an array field type: "
724 "uuid-ft-addr=%p, uuid-ft-id=%s",
725 field_type,
726 bt_ctf_field_type_id_string(field_type->id));
727 goto invalid;
728 }
729
730 if (bt_ctf_field_type_array_get_length(field_type) != 16) {
731 BT_LOGW("Invalid packet header field type: `uuid` array field type's length must be 16: "
732 "uuid-ft-addr=%p, uuid-ft-length=%" PRId64,
733 field_type,
734 bt_ctf_field_type_array_get_length(field_type));
735 goto invalid;
736 }
737
738 elem_ft = bt_ctf_field_type_array_get_element_type(field_type);
739 assert(elem_ft);
740
741 if (!bt_ctf_field_type_is_integer(elem_ft)) {
742 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: "
743 "elem-ft-addr=%p, elem-ft-id=%s",
744 elem_ft,
745 bt_ctf_field_type_id_string(elem_ft->id));
746 bt_put(elem_ft);
747 goto invalid;
748 }
749
750 if (bt_ctf_field_type_integer_is_signed(elem_ft)) {
751 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an unsigned integer field type: "
752 "elem-ft-addr=%p", elem_ft);
753 bt_put(elem_ft);
754 goto invalid;
755 }
756
757 if (bt_ctf_field_type_integer_get_size(elem_ft) != 8) {
758 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an 8-bit unsigned integer field type: "
759 "elem-ft-addr=%p, elem-ft-size=%u",
760 elem_ft,
761 bt_ctf_field_type_integer_get_size(elem_ft));
762 bt_put(elem_ft);
763 goto invalid;
764 }
765
766 bt_put(elem_ft);
767 BT_PUT(field_type);
768 }
769
770 /*
771 * The `stream_id` field must exist if there's more than one
772 * stream classes in the trace.
773 */
774 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
775 packet_header_type, "stream_id");
776
777 if (!field_type && trace->stream_classes->len >= 1) {
778 BT_LOGW_STR("Invalid packet header field type: "
779 "`stream_id` field does not exist but there's more than one stream class in the trace.");
780 goto invalid;
781 }
782
783 /*
784 * If there's a `stream_id` field, it must be an unsigned
785 * integer field type.
786 */
787 if (field_type) {
788 if (!bt_ctf_field_type_is_integer(field_type)) {
789 BT_LOGW("Invalid packet header field type: `stream_id` field must be an integer field type: "
790 "stream-id-ft-addr=%p, stream-id-ft-id=%s",
791 field_type,
792 bt_ctf_field_type_id_string(field_type->id));
793 goto invalid;
794 }
795
796 if (bt_ctf_field_type_integer_is_signed(field_type)) {
797 BT_LOGW("Invalid packet header field type: `stream_id` field must be an unsigned integer field type: "
798 "stream-id-ft-addr=%p", field_type);
799 goto invalid;
800 }
801
802 BT_PUT(field_type);
803 }
804
805 goto end;
806
807 invalid:
808 is_valid = false;
809
810 end:
811 bt_put(field_type);
812 return is_valid;
813 }
814
815 static
816 bool packet_context_field_type_is_valid(struct bt_ctf_trace *trace,
817 struct bt_ctf_stream_class *stream_class,
818 struct bt_ctf_field_type *packet_context_type)
819 {
820 bool is_valid = true;
821 struct bt_ctf_field_type *field_type = NULL;
822
823 if (!packet_context_type) {
824 /* No packet context field type: valid at this point */
825 goto end;
826 }
827
828 /* Packet context field type, if it exists, must be a structure */
829 if (!bt_ctf_field_type_is_structure(packet_context_type)) {
830 BT_LOGW("Invalid packet context field type: must be a structure field type if it exists: "
831 "ft-addr=%p, ft-id=%s",
832 packet_context_type,
833 bt_ctf_field_type_id_string(packet_context_type->id));
834 goto invalid;
835 }
836
837 /*
838 * If there's a `packet_size` field, it must be an unsigned
839 * integer field type.
840 */
841 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
842 packet_context_type, "packet_size");
843 if (field_type) {
844 if (!bt_ctf_field_type_is_integer(field_type)) {
845 BT_LOGW("Invalid packet context field type: `packet_size` field must be an integer field type: "
846 "packet-size-ft-addr=%p, packet-size-ft-id=%s",
847 field_type,
848 bt_ctf_field_type_id_string(field_type->id));
849 goto invalid;
850 }
851
852 if (bt_ctf_field_type_integer_is_signed(field_type)) {
853 BT_LOGW("Invalid packet context field type: `packet_size` field must be an unsigned integer field type: "
854 "packet-size-ft-addr=%p", field_type);
855 goto invalid;
856 }
857
858 BT_PUT(field_type);
859 }
860
861 /*
862 * If there's a `content_size` field, it must be an unsigned
863 * integer field type.
864 */
865 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
866 packet_context_type, "content_size");
867 if (field_type) {
868 if (!bt_ctf_field_type_is_integer(field_type)) {
869 BT_LOGW("Invalid packet context field type: `content_size` field must be an integer field type: "
870 "content-size-ft-addr=%p, content-size-ft-id=%s",
871 field_type,
872 bt_ctf_field_type_id_string(field_type->id));
873 goto invalid;
874 }
875
876 if (bt_ctf_field_type_integer_is_signed(field_type)) {
877 BT_LOGW("Invalid packet context field type: `content_size` field must be an unsigned integer field type: "
878 "content-size-ft-addr=%p", field_type);
879 goto invalid;
880 }
881
882 BT_PUT(field_type);
883 }
884
885 /*
886 * If there's a `events_discarded` field, it must be an unsigned
887 * integer field type.
888 */
889 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
890 packet_context_type, "events_discarded");
891 if (field_type) {
892 if (!bt_ctf_field_type_is_integer(field_type)) {
893 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an integer field type: "
894 "events-discarded-ft-addr=%p, events-discarded-ft-id=%s",
895 field_type,
896 bt_ctf_field_type_id_string(field_type->id));
897 goto invalid;
898 }
899
900 if (bt_ctf_field_type_integer_is_signed(field_type)) {
901 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an unsigned integer field type: "
902 "events-discarded-ft-addr=%p", field_type);
903 goto invalid;
904 }
905
906 BT_PUT(field_type);
907 }
908
909 /*
910 * If there's a `timestamp_begin` field, it must be an unsigned
911 * integer field type. Also, if the trace is not a CTF writer's
912 * trace, then we cannot automatically set the mapped clock
913 * class of this field, so it must have a mapped clock class.
914 */
915 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
916 packet_context_type, "timestamp_begin");
917 if (field_type) {
918 if (!bt_ctf_field_type_is_integer(field_type)) {
919 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an integer field type: "
920 "timestamp-begin-ft-addr=%p, timestamp-begin-ft-id=%s",
921 field_type,
922 bt_ctf_field_type_id_string(field_type->id));
923 goto invalid;
924 }
925
926 if (bt_ctf_field_type_integer_is_signed(field_type)) {
927 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an unsigned integer field type: "
928 "timestamp-begin-ft-addr=%p", field_type);
929 goto invalid;
930 }
931
932 if (!trace->is_created_by_writer) {
933 struct bt_ctf_clock_class *clock_class =
934 bt_ctf_field_type_integer_get_mapped_clock_class(
935 field_type);
936
937 bt_put(clock_class);
938 if (!clock_class) {
939 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be mapped to a clock class: "
940 "timestamp-begin-ft-addr=%p", field_type);
941 goto invalid;
942 }
943 }
944
945 BT_PUT(field_type);
946 }
947
948 /*
949 * If there's a `timestamp_end` field, it must be an unsigned
950 * integer field type. Also, if the trace is not a CTF writer's
951 * trace, then we cannot automatically set the mapped clock
952 * class of this field, so it must have a mapped clock class.
953 */
954 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
955 packet_context_type, "timestamp_end");
956 if (field_type) {
957 if (!bt_ctf_field_type_is_integer(field_type)) {
958 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an integer field type: "
959 "timestamp-end-ft-addr=%p, timestamp-end-ft-id=%s",
960 field_type,
961 bt_ctf_field_type_id_string(field_type->id));
962 goto invalid;
963 }
964
965 if (bt_ctf_field_type_integer_is_signed(field_type)) {
966 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an unsigned integer field type: "
967 "timestamp-end-ft-addr=%p", field_type);
968 goto invalid;
969 }
970
971 if (!trace->is_created_by_writer) {
972 struct bt_ctf_clock_class *clock_class =
973 bt_ctf_field_type_integer_get_mapped_clock_class(
974 field_type);
975
976 bt_put(clock_class);
977 if (!clock_class) {
978 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be mapped to a clock class: "
979 "timestamp-end-ft-addr=%p", field_type);
980 goto invalid;
981 }
982 }
983
984 BT_PUT(field_type);
985 }
986
987 goto end;
988
989 invalid:
990 is_valid = false;
991
992 end:
993 bt_put(field_type);
994 return is_valid;
995 }
996
997 static
998 bool event_header_field_type_is_valid(struct bt_ctf_trace *trace,
999 struct bt_ctf_stream_class *stream_class,
1000 struct bt_ctf_field_type *event_header_type)
1001 {
1002 bool is_valid = true;
1003 struct bt_ctf_field_type *field_type = NULL;
1004
1005 /*
1006 * We do not validate that the `timestamp` field exists here
1007 * because CTF does not require this exact name to be mapped to
1008 * a clock class.
1009 */
1010
1011 if (!event_header_type) {
1012 /*
1013 * No event header field type: stream class must have
1014 * only one event class.
1015 */
1016 if (bt_ctf_stream_class_get_event_class_count(stream_class) > 1) {
1017 BT_LOGW_STR("Invalid event header field type: "
1018 "event header field type does not exist but there's more than one event class in the stream class.");
1019 goto invalid;
1020 }
1021
1022 /* No event header field type: valid at this point */
1023 goto end;
1024 }
1025
1026 /* Event header field type, if it exists, must be a structure */
1027 if (!bt_ctf_field_type_is_structure(event_header_type)) {
1028 BT_LOGW("Invalid event header field type: must be a structure field type if it exists: "
1029 "ft-addr=%p, ft-id=%s",
1030 event_header_type,
1031 bt_ctf_field_type_id_string(event_header_type->id));
1032 goto invalid;
1033 }
1034
1035 /*
1036 * If there's an `id` field, it must be an unsigned integer
1037 * field type or an enumeration field type with an unsigned
1038 * integer container field type.
1039 */
1040 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
1041 event_header_type, "id");
1042 if (field_type) {
1043 struct bt_ctf_field_type *int_ft;
1044
1045 if (bt_ctf_field_type_is_integer(field_type)) {
1046 int_ft = bt_get(field_type);
1047 } else if (bt_ctf_field_type_is_enumeration(field_type)) {
1048 int_ft = bt_ctf_field_type_enumeration_get_container_type(
1049 field_type);
1050 } else {
1051 BT_LOGW("Invalid event header field type: `id` field must be an integer or enumeration field type: "
1052 "id-ft-addr=%p, id-ft-id=%s",
1053 field_type,
1054 bt_ctf_field_type_id_string(field_type->id));
1055 goto invalid;
1056 }
1057
1058 assert(int_ft);
1059 if (bt_ctf_field_type_integer_is_signed(int_ft)) {
1060 BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: "
1061 "id-ft-addr=%p", int_ft);
1062 goto invalid;
1063 }
1064
1065 bt_put(int_ft);
1066 BT_PUT(field_type);
1067 }
1068
1069 goto end;
1070
1071 invalid:
1072 is_valid = false;
1073
1074 end:
1075 bt_put(field_type);
1076 return is_valid;
1077 }
1078
1079 int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
1080 struct bt_ctf_stream_class *stream_class)
1081 {
1082 int ret;
1083 int64_t i;
1084 int64_t stream_id;
1085 struct bt_ctf_validation_output trace_sc_validation_output = { 0 };
1086 struct bt_ctf_validation_output *ec_validation_outputs = NULL;
1087 const enum bt_ctf_validation_flag trace_sc_validation_flags =
1088 BT_CTF_VALIDATION_FLAG_TRACE |
1089 BT_CTF_VALIDATION_FLAG_STREAM;
1090 const enum bt_ctf_validation_flag ec_validation_flags =
1091 BT_CTF_VALIDATION_FLAG_EVENT;
1092 struct bt_ctf_field_type *packet_header_type = NULL;
1093 struct bt_ctf_field_type *packet_context_type = NULL;
1094 struct bt_ctf_field_type *event_header_type = NULL;
1095 struct bt_ctf_field_type *stream_event_ctx_type = NULL;
1096 int64_t event_class_count;
1097 struct bt_ctf_trace *current_parent_trace = NULL;
1098
1099 if (!trace) {
1100 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1101 ret = -1;
1102 goto end;
1103 }
1104
1105 if (!stream_class) {
1106 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
1107 ret = -1;
1108 goto end;
1109 }
1110
1111 if (trace->is_static) {
1112 BT_LOGW_STR("Invalid parameter: trace is static.");
1113 ret = -1;
1114 goto end;
1115 }
1116
1117 BT_LOGD("Adding stream class to trace: "
1118 "trace-addr=%p, trace-name=\"%s\", "
1119 "stream-class-addr=%p, stream-class-name=\"%s\", "
1120 "stream-class-id=%" PRId64,
1121 trace, bt_ctf_trace_get_name(trace),
1122 stream_class, bt_ctf_stream_class_get_name(stream_class),
1123 bt_ctf_stream_class_get_id(stream_class));
1124
1125 /*
1126 * At the end of this function we freeze the trace, so its
1127 * native byte order must NOT be BT_CTF_BYTE_ORDER_NATIVE.
1128 */
1129 if (trace->native_byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
1130 BT_LOGW_STR("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE at this point; "
1131 "set it with bt_ctf_trace_set_native_byte_order().");
1132 ret = -1;
1133 goto end;
1134 }
1135
1136 current_parent_trace = bt_ctf_stream_class_get_trace(stream_class);
1137 if (current_parent_trace) {
1138 /* Stream class is already associated to a trace, abort. */
1139 BT_LOGW("Invalid parameter: stream class is already part of a trace: "
1140 "stream-class-trace-addr=%p, "
1141 "stream-class-trace-name=\"%s\"",
1142 current_parent_trace,
1143 bt_ctf_trace_get_name(current_parent_trace));
1144 ret = -1;
1145 goto end;
1146 }
1147
1148 event_class_count =
1149 bt_ctf_stream_class_get_event_class_count(stream_class);
1150 assert(event_class_count >= 0);
1151
1152 if (stream_class->clock) {
1153 struct bt_ctf_clock_class *stream_clock_class =
1154 stream_class->clock->clock_class;
1155
1156 if (trace->is_created_by_writer) {
1157 /*
1158 * Make sure this clock was also added to the
1159 * trace (potentially through its CTF writer
1160 * owner).
1161 */
1162 size_t i;
1163
1164 for (i = 0; i < trace->clocks->len; i++) {
1165 if (trace->clocks->pdata[i] ==
1166 stream_clock_class) {
1167 /* Found! */
1168 break;
1169 }
1170 }
1171
1172 if (i == trace->clocks->len) {
1173 /* Not found */
1174 BT_LOGW("Stream class's clock's class is not part of the trace: "
1175 "clock-class-addr=%p, clock-class-name=\"%s\"",
1176 stream_clock_class,
1177 bt_ctf_clock_class_get_name(stream_clock_class));
1178 ret = -1;
1179 goto end;
1180 }
1181 } else {
1182 /*
1183 * This trace was NOT created by a CTF writer,
1184 * thus do not allow the stream class to add to
1185 * have a clock at all. Those are two
1186 * independent APIs (non-writer and writer
1187 * APIs), and isolating them simplifies things.
1188 */
1189 BT_LOGW("Cannot add stream class with a clock to a trace which was not created by a CTF writer object: "
1190 "clock-class-addr=%p, clock-class-name=\"%s\"",
1191 stream_clock_class,
1192 bt_ctf_clock_class_get_name(stream_clock_class));
1193 ret = -1;
1194 goto end;
1195 }
1196 }
1197
1198 /*
1199 * We're about to freeze both the trace and the stream class.
1200 * Also, each event class contained in this stream class are
1201 * already frozen.
1202 *
1203 * This trace, this stream class, and all its event classes
1204 * should be valid at this point.
1205 *
1206 * Validate trace and stream class first, then each event
1207 * class of this stream class can be validated individually.
1208 */
1209 packet_header_type =
1210 bt_ctf_trace_get_packet_header_type(trace);
1211 packet_context_type =
1212 bt_ctf_stream_class_get_packet_context_type(stream_class);
1213 event_header_type =
1214 bt_ctf_stream_class_get_event_header_type(stream_class);
1215 stream_event_ctx_type =
1216 bt_ctf_stream_class_get_event_context_type(stream_class);
1217
1218 BT_LOGD("Validating trace and stream class field types.");
1219 ret = bt_ctf_validate_class_types(trace->environment,
1220 packet_header_type, packet_context_type, event_header_type,
1221 stream_event_ctx_type, NULL, NULL, trace->valid,
1222 stream_class->valid, 1, &trace_sc_validation_output,
1223 trace_sc_validation_flags);
1224 BT_PUT(packet_header_type);
1225 BT_PUT(packet_context_type);
1226 BT_PUT(event_header_type);
1227 BT_PUT(stream_event_ctx_type);
1228
1229 if (ret) {
1230 /*
1231 * This means something went wrong during the validation
1232 * process, not that the objects are invalid.
1233 */
1234 BT_LOGE("Failed to validate trace and stream class field types: "
1235 "ret=%d", ret);
1236 goto end;
1237 }
1238
1239 if ((trace_sc_validation_output.valid_flags &
1240 trace_sc_validation_flags) !=
1241 trace_sc_validation_flags) {
1242 /* Invalid trace/stream class */
1243 BT_LOGW("Invalid trace or stream class field types: "
1244 "valid-flags=0x%x",
1245 trace_sc_validation_output.valid_flags);
1246 ret = -1;
1247 goto end;
1248 }
1249
1250 if (event_class_count > 0) {
1251 ec_validation_outputs = g_new0(struct bt_ctf_validation_output,
1252 event_class_count);
1253 if (!ec_validation_outputs) {
1254 BT_LOGE_STR("Failed to allocate one validation output structure.");
1255 ret = -1;
1256 goto end;
1257 }
1258 }
1259
1260 /* Validate each event class individually */
1261 for (i = 0; i < event_class_count; i++) {
1262 struct bt_ctf_event_class *event_class =
1263 bt_ctf_stream_class_get_event_class_by_index(
1264 stream_class, i);
1265 struct bt_ctf_field_type *event_context_type = NULL;
1266 struct bt_ctf_field_type *event_payload_type = NULL;
1267
1268 event_context_type =
1269 bt_ctf_event_class_get_context_type(event_class);
1270 event_payload_type =
1271 bt_ctf_event_class_get_payload_type(event_class);
1272
1273 /*
1274 * It is important to use the field types returned by
1275 * the previous trace and stream class validation here
1276 * because copies could have been made.
1277 */
1278 BT_LOGD("Validating event class's field types: "
1279 "addr=%p, name=\"%s\", id=%" PRId64,
1280 event_class, bt_ctf_event_class_get_name(event_class),
1281 bt_ctf_event_class_get_id(event_class));
1282 ret = bt_ctf_validate_class_types(trace->environment,
1283 trace_sc_validation_output.packet_header_type,
1284 trace_sc_validation_output.packet_context_type,
1285 trace_sc_validation_output.event_header_type,
1286 trace_sc_validation_output.stream_event_ctx_type,
1287 event_context_type, event_payload_type,
1288 1, 1, event_class->valid, &ec_validation_outputs[i],
1289 ec_validation_flags);
1290 BT_PUT(event_context_type);
1291 BT_PUT(event_payload_type);
1292 BT_PUT(event_class);
1293
1294 if (ret) {
1295 BT_LOGE("Failed to validate event class field types: "
1296 "ret=%d", ret);
1297 goto end;
1298 }
1299
1300 if ((ec_validation_outputs[i].valid_flags &
1301 ec_validation_flags) != ec_validation_flags) {
1302 /* Invalid event class */
1303 BT_LOGW("Invalid event class field types: "
1304 "valid-flags=0x%x",
1305 ec_validation_outputs[i].valid_flags);
1306 ret = -1;
1307 goto end;
1308 }
1309 }
1310
1311 stream_id = bt_ctf_stream_class_get_id(stream_class);
1312 if (stream_id < 0) {
1313 stream_id = trace->next_stream_id++;
1314 if (stream_id < 0) {
1315 BT_LOGE_STR("No more stream class IDs available.");
1316 ret = -1;
1317 goto end;
1318 }
1319
1320 /* Try to assign a new stream id */
1321 for (i = 0; i < trace->stream_classes->len; i++) {
1322 if (stream_id == bt_ctf_stream_class_get_id(
1323 trace->stream_classes->pdata[i])) {
1324 /* Duplicate stream id found */
1325 BT_LOGW("Duplicate stream class ID: "
1326 "id=%" PRId64, (int64_t) stream_id);
1327 ret = -1;
1328 goto end;
1329 }
1330 }
1331
1332 if (bt_ctf_stream_class_set_id_no_check(stream_class,
1333 stream_id)) {
1334 /* TODO Should retry with a different stream id */
1335 BT_LOGE("Cannot set stream class's ID: "
1336 "id=%" PRId64, (int64_t) stream_id);
1337 ret = -1;
1338 goto end;
1339 }
1340 }
1341
1342 /*
1343 * At this point all the field types in the validation output
1344 * are valid. Validate the semantics of some scopes according to
1345 * the CTF specification.
1346 */
1347 if (!packet_header_field_type_is_valid(trace,
1348 trace_sc_validation_output.packet_header_type)) {
1349 BT_LOGW_STR("Invalid trace's packet header field type.");
1350 ret = -1;
1351 goto end;
1352 }
1353
1354 if (!packet_context_field_type_is_valid(trace,
1355 stream_class,
1356 trace_sc_validation_output.packet_context_type)) {
1357 BT_LOGW_STR("Invalid stream class's packet context field type.");
1358 ret = -1;
1359 goto end;
1360 }
1361
1362 if (!event_header_field_type_is_valid(trace,
1363 stream_class,
1364 trace_sc_validation_output.event_header_type)) {
1365 BT_LOGW_STR("Invalid steam class's event header field type.");
1366 ret = -1;
1367 goto end;
1368 }
1369
1370 /*
1371 * Now is the time to automatically map specific field types of
1372 * the stream class's packet context and event header field
1373 * types to the stream class's clock's class if they are not
1374 * mapped to a clock class yet. We do it here because we know
1375 * that after this point, everything is frozen so it won't be
1376 * possible for the user to modify the stream class's clock, or
1377 * to map those field types to other clock classes.
1378 */
1379 if (trace->is_created_by_writer) {
1380 if (bt_ctf_stream_class_map_clock_class(stream_class,
1381 trace_sc_validation_output.packet_context_type,
1382 trace_sc_validation_output.event_header_type)) {
1383 BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
1384 ret = -1;
1385 goto end;
1386 }
1387 }
1388
1389 bt_object_set_parent(stream_class, trace);
1390 g_ptr_array_add(trace->stream_classes, stream_class);
1391
1392 /*
1393 * At this point we know that the function will be successful.
1394 * Therefore we can replace the trace and stream class field
1395 * types with what's in their validation output structure and
1396 * mark them as valid. We can also replace the field types of
1397 * all the event classes of the stream class and mark them as
1398 * valid.
1399 */
1400 bt_ctf_validation_replace_types(trace, stream_class, NULL,
1401 &trace_sc_validation_output, trace_sc_validation_flags);
1402 trace->valid = 1;
1403 stream_class->valid = 1;
1404
1405 /*
1406 * Put what was not moved in bt_ctf_validation_replace_types().
1407 */
1408 bt_ctf_validation_output_put_types(&trace_sc_validation_output);
1409
1410 for (i = 0; i < event_class_count; i++) {
1411 struct bt_ctf_event_class *event_class =
1412 bt_ctf_stream_class_get_event_class_by_index(
1413 stream_class, i);
1414
1415 bt_ctf_validation_replace_types(NULL, NULL, event_class,
1416 &ec_validation_outputs[i], ec_validation_flags);
1417 event_class->valid = 1;
1418 BT_PUT(event_class);
1419
1420 /*
1421 * Put what was not moved in
1422 * bt_ctf_validation_replace_types().
1423 */
1424 bt_ctf_validation_output_put_types(&ec_validation_outputs[i]);
1425 }
1426
1427 /*
1428 * Freeze the trace and the stream class.
1429 */
1430 bt_ctf_stream_class_freeze(stream_class);
1431 bt_ctf_trace_freeze(trace);
1432
1433 /* Notifiy listeners of the trace's schema modification. */
1434 bt_ctf_stream_class_visit(stream_class,
1435 bt_ctf_trace_object_modification, trace);
1436 BT_LOGD("Added stream class to trace: "
1437 "trace-addr=%p, trace-name=\"%s\", "
1438 "stream-class-addr=%p, stream-class-name=\"%s\", "
1439 "stream-class-id=%" PRId64,
1440 trace, bt_ctf_trace_get_name(trace),
1441 stream_class, bt_ctf_stream_class_get_name(stream_class),
1442 bt_ctf_stream_class_get_id(stream_class));
1443
1444 end:
1445 if (ret) {
1446 bt_object_set_parent(stream_class, NULL);
1447
1448 if (ec_validation_outputs) {
1449 for (i = 0; i < event_class_count; i++) {
1450 bt_ctf_validation_output_put_types(
1451 &ec_validation_outputs[i]);
1452 }
1453 }
1454 }
1455
1456 g_free(ec_validation_outputs);
1457 bt_ctf_validation_output_put_types(&trace_sc_validation_output);
1458 bt_put(current_parent_trace);
1459 assert(!packet_header_type);
1460 assert(!packet_context_type);
1461 assert(!event_header_type);
1462 assert(!stream_event_ctx_type);
1463 return ret;
1464 }
1465
1466 int64_t bt_ctf_trace_get_stream_count(struct bt_ctf_trace *trace)
1467 {
1468 int64_t ret;
1469
1470 if (!trace) {
1471 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1472 ret = (int64_t) -1;
1473 goto end;
1474 }
1475
1476 ret = (int64_t) trace->streams->len;
1477
1478 end:
1479 return ret;
1480 }
1481
1482 struct bt_ctf_stream *bt_ctf_trace_get_stream_by_index(
1483 struct bt_ctf_trace *trace,
1484 uint64_t index)
1485 {
1486 struct bt_ctf_stream *stream = NULL;
1487
1488 if (!trace) {
1489 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1490 goto end;
1491 }
1492
1493 if (index >= trace->streams->len) {
1494 BT_LOGW("Invalid parameter: index is out of bounds: "
1495 "addr=%p, name=\"%s\", "
1496 "index=%" PRIu64 ", count=%u",
1497 trace, bt_ctf_trace_get_name(trace),
1498 index, trace->streams->len);
1499 goto end;
1500 }
1501
1502 stream = bt_get(g_ptr_array_index(trace->streams, index));
1503
1504 end:
1505 return stream;
1506 }
1507
1508 int64_t bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace)
1509 {
1510 int64_t ret;
1511
1512 if (!trace) {
1513 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1514 ret = (int64_t) -1;
1515 goto end;
1516 }
1517
1518 ret = (int64_t) trace->stream_classes->len;
1519 end:
1520 return ret;
1521 }
1522
1523 struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_index(
1524 struct bt_ctf_trace *trace, uint64_t index)
1525 {
1526 struct bt_ctf_stream_class *stream_class = NULL;
1527
1528 if (!trace) {
1529 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1530 goto end;
1531 }
1532
1533 if (index >= trace->stream_classes->len) {
1534 BT_LOGW("Invalid parameter: index is out of bounds: "
1535 "addr=%p, name=\"%s\", "
1536 "index=%" PRIu64 ", count=%u",
1537 trace, bt_ctf_trace_get_name(trace),
1538 index, trace->stream_classes->len);
1539 goto end;
1540 }
1541
1542 stream_class = g_ptr_array_index(trace->stream_classes, index);
1543 bt_get(stream_class);
1544 end:
1545 return stream_class;
1546 }
1547
1548 struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id(
1549 struct bt_ctf_trace *trace, uint64_t id_param)
1550 {
1551 int i;
1552 struct bt_ctf_stream_class *stream_class = NULL;
1553 int64_t id = (int64_t) id_param;
1554
1555 if (!trace) {
1556 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1557 goto end;
1558 }
1559
1560 if (id < 0) {
1561 BT_LOGW("Invalid parameter: invalid stream class's ID: "
1562 "trace-addr=%p, trace-name=\"%s\", id=%" PRIu64,
1563 trace, bt_ctf_trace_get_name(trace), id_param);
1564 goto end;
1565 }
1566
1567 for (i = 0; i < trace->stream_classes->len; i++) {
1568 struct bt_ctf_stream_class *stream_class_candidate;
1569
1570 stream_class_candidate =
1571 g_ptr_array_index(trace->stream_classes, i);
1572
1573 if (bt_ctf_stream_class_get_id(stream_class_candidate) ==
1574 (int64_t) id) {
1575 stream_class = stream_class_candidate;
1576 bt_get(stream_class);
1577 goto end;
1578 }
1579 }
1580
1581 end:
1582 return stream_class;
1583 }
1584
1585 struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name(
1586 struct bt_ctf_trace *trace, const char *name)
1587 {
1588 size_t i;
1589 struct bt_ctf_clock_class *clock_class = NULL;
1590
1591 if (!trace) {
1592 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1593 goto end;
1594 }
1595
1596 if (!name) {
1597 BT_LOGW_STR("Invalid parameter: name is NULL.");
1598 goto end;
1599 }
1600
1601 for (i = 0; i < trace->clocks->len; i++) {
1602 struct bt_ctf_clock_class *cur_clk =
1603 g_ptr_array_index(trace->clocks, i);
1604 const char *cur_clk_name = bt_ctf_clock_class_get_name(cur_clk);
1605
1606 if (!cur_clk_name) {
1607 goto end;
1608 }
1609
1610 if (!strcmp(cur_clk_name, name)) {
1611 clock_class = cur_clk;
1612 bt_get(clock_class);
1613 goto end;
1614 }
1615 }
1616
1617 end:
1618 return clock_class;
1619 }
1620
1621 BT_HIDDEN
1622 bt_bool bt_ctf_trace_has_clock_class(struct bt_ctf_trace *trace,
1623 struct bt_ctf_clock_class *clock_class)
1624 {
1625 struct search_query query = { .value = clock_class, .found = 0 };
1626
1627 assert(trace);
1628 assert(clock_class);
1629
1630 g_ptr_array_foreach(trace->clocks, value_exists, &query);
1631 return query.found;
1632 }
1633
1634 BT_HIDDEN
1635 const char *get_byte_order_string(enum bt_ctf_byte_order byte_order)
1636 {
1637 const char *string;
1638
1639 switch (byte_order) {
1640 case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
1641 string = "le";
1642 break;
1643 case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
1644 string = "be";
1645 break;
1646 case BT_CTF_BYTE_ORDER_NATIVE:
1647 string = "native";
1648 break;
1649 default:
1650 abort();
1651 }
1652
1653 return string;
1654 }
1655
1656 static
1657 int append_trace_metadata(struct bt_ctf_trace *trace,
1658 struct metadata_context *context)
1659 {
1660 unsigned char *uuid = trace->uuid;
1661 int ret = 0;
1662
1663 if (trace->native_byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
1664 BT_LOGW("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE at this point; "
1665 "set it with bt_ctf_trace_set_native_byte_order(): "
1666 "addr=%p, name=\"%s\"",
1667 trace, bt_ctf_trace_get_name(trace));
1668 ret = -1;
1669 goto end;
1670 }
1671
1672 g_string_append(context->string, "trace {\n");
1673 g_string_append(context->string, "\tmajor = 1;\n");
1674 g_string_append(context->string, "\tminor = 8;\n");
1675 assert(trace->native_byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
1676 trace->native_byte_order == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
1677 trace->native_byte_order == BT_CTF_BYTE_ORDER_NETWORK);
1678
1679 if (trace->uuid_set) {
1680 g_string_append_printf(context->string,
1681 "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
1682 uuid[0], uuid[1], uuid[2], uuid[3],
1683 uuid[4], uuid[5], uuid[6], uuid[7],
1684 uuid[8], uuid[9], uuid[10], uuid[11],
1685 uuid[12], uuid[13], uuid[14], uuid[15]);
1686 }
1687
1688 g_string_append_printf(context->string, "\tbyte_order = %s;\n",
1689 get_byte_order_string(trace->native_byte_order));
1690
1691 if (trace->packet_header_type) {
1692 g_string_append(context->string, "\tpacket.header := ");
1693 context->current_indentation_level++;
1694 g_string_assign(context->field_name, "");
1695 BT_LOGD_STR("Serializing trace's packet header field type's metadata.");
1696 ret = bt_ctf_field_type_serialize(trace->packet_header_type,
1697 context);
1698 if (ret) {
1699 goto end;
1700 }
1701 context->current_indentation_level--;
1702 }
1703
1704 g_string_append(context->string, ";\n};\n\n");
1705 end:
1706 return ret;
1707 }
1708
1709 static
1710 void append_env_metadata(struct bt_ctf_trace *trace,
1711 struct metadata_context *context)
1712 {
1713 int64_t i;
1714 int64_t env_size;
1715
1716 env_size = bt_ctf_attributes_get_count(trace->environment);
1717 if (env_size <= 0) {
1718 return;
1719 }
1720
1721 g_string_append(context->string, "env {\n");
1722
1723 for (i = 0; i < env_size; i++) {
1724 struct bt_value *env_field_value_obj = NULL;
1725 const char *entry_name;
1726
1727 entry_name = bt_ctf_attributes_get_field_name(
1728 trace->environment, i);
1729 env_field_value_obj = bt_ctf_attributes_get_field_value(
1730 trace->environment, i);
1731
1732 assert(entry_name);
1733 assert(env_field_value_obj);
1734
1735 switch (bt_value_get_type(env_field_value_obj)) {
1736 case BT_VALUE_TYPE_INTEGER:
1737 {
1738 int ret;
1739 int64_t int_value;
1740
1741 ret = bt_value_integer_get(env_field_value_obj,
1742 &int_value);
1743 assert(ret == 0);
1744 g_string_append_printf(context->string,
1745 "\t%s = %" PRId64 ";\n", entry_name,
1746 int_value);
1747 break;
1748 }
1749 case BT_VALUE_TYPE_STRING:
1750 {
1751 int ret;
1752 const char *str_value;
1753 char *escaped_str = NULL;
1754
1755 ret = bt_value_string_get(env_field_value_obj,
1756 &str_value);
1757 assert(ret == 0);
1758 escaped_str = g_strescape(str_value, NULL);
1759 if (!escaped_str) {
1760 BT_LOGE("Cannot escape string: string=\"%s\"",
1761 str_value);
1762 goto loop_next;
1763 }
1764
1765 g_string_append_printf(context->string,
1766 "\t%s = \"%s\";\n", entry_name, escaped_str);
1767 free(escaped_str);
1768 break;
1769 }
1770 default:
1771 goto loop_next;
1772 }
1773
1774 loop_next:
1775 BT_PUT(env_field_value_obj);
1776 }
1777
1778 g_string_append(context->string, "};\n\n");
1779 }
1780
1781 char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace)
1782 {
1783 char *metadata = NULL;
1784 struct metadata_context *context = NULL;
1785 int err = 0;
1786 size_t i;
1787
1788 if (!trace) {
1789 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1790 goto end;
1791 }
1792
1793 context = g_new0(struct metadata_context, 1);
1794 if (!context) {
1795 BT_LOGE_STR("Failed to allocate one metadata context.");
1796 goto end;
1797 }
1798
1799 context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE);
1800 context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE);
1801 g_string_append(context->string, "/* CTF 1.8 */\n\n");
1802 if (append_trace_metadata(trace, context)) {
1803 /* append_trace_metadata() logs errors */
1804 goto error;
1805 }
1806 append_env_metadata(trace, context);
1807 g_ptr_array_foreach(trace->clocks,
1808 (GFunc)bt_ctf_clock_class_serialize, context);
1809
1810 for (i = 0; i < trace->stream_classes->len; i++) {
1811 /* bt_ctf_stream_class_serialize() logs details */
1812 err = bt_ctf_stream_class_serialize(
1813 trace->stream_classes->pdata[i], context);
1814 if (err) {
1815 /* bt_ctf_stream_class_serialize() logs errors */
1816 goto error;
1817 }
1818 }
1819
1820 metadata = context->string->str;
1821
1822 error:
1823 g_string_free(context->string, err ? TRUE : FALSE);
1824 g_string_free(context->field_name, TRUE);
1825 g_free(context);
1826
1827 end:
1828 return metadata;
1829 }
1830
1831 enum bt_ctf_byte_order bt_ctf_trace_get_native_byte_order(
1832 struct bt_ctf_trace *trace)
1833 {
1834 enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN;
1835
1836 if (!trace) {
1837 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1838 goto end;
1839 }
1840
1841 ret = trace->native_byte_order;
1842
1843 end:
1844 return ret;
1845 }
1846
1847 int bt_ctf_trace_set_native_byte_order(struct bt_ctf_trace *trace,
1848 enum bt_ctf_byte_order byte_order)
1849 {
1850 int ret = 0;
1851
1852 if (!trace) {
1853 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1854 ret = -1;
1855 goto end;
1856 }
1857
1858 if (trace->frozen) {
1859 BT_LOGW("Invalid parameter: trace is frozen: "
1860 "addr=%p, name=\"%s\"",
1861 trace, bt_ctf_trace_get_name(trace));
1862 ret = -1;
1863 goto end;
1864 }
1865
1866 if (byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
1867 byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
1868 byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
1869 BT_LOGW("Invalid parameter: invalid byte order: "
1870 "addr=%p, name=\"%s\", bo=%s",
1871 trace, bt_ctf_trace_get_name(trace),
1872 bt_ctf_byte_order_string(byte_order));
1873 ret = -1;
1874 goto end;
1875 }
1876
1877 trace->native_byte_order = byte_order;
1878 BT_LOGV("Set trace's native byte order: "
1879 "addr=%p, name=\"%s\", bo=%s",
1880 trace, bt_ctf_trace_get_name(trace),
1881 bt_ctf_byte_order_string(byte_order));
1882
1883 end:
1884 return ret;
1885 }
1886
1887 struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_type(
1888 struct bt_ctf_trace *trace)
1889 {
1890 struct bt_ctf_field_type *field_type = NULL;
1891
1892 if (!trace) {
1893 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1894 goto end;
1895 }
1896
1897 bt_get(trace->packet_header_type);
1898 field_type = trace->packet_header_type;
1899 end:
1900 return field_type;
1901 }
1902
1903 int bt_ctf_trace_set_packet_header_type(struct bt_ctf_trace *trace,
1904 struct bt_ctf_field_type *packet_header_type)
1905 {
1906 int ret = 0;
1907
1908 if (!trace) {
1909 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1910 ret = -1;
1911 goto end;
1912 }
1913
1914 if (trace->frozen) {
1915 BT_LOGW("Invalid parameter: trace is frozen: "
1916 "addr=%p, name=\"%s\"",
1917 trace, bt_ctf_trace_get_name(trace));
1918 ret = -1;
1919 goto end;
1920 }
1921
1922 /* packet_header_type must be a structure. */
1923 if (packet_header_type &&
1924 !bt_ctf_field_type_is_structure(packet_header_type)) {
1925 BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: "
1926 "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s",
1927 trace, bt_ctf_trace_get_name(trace),
1928 packet_header_type,
1929 bt_ctf_field_type_id_string(packet_header_type->id));
1930 ret = -1;
1931 goto end;
1932 }
1933
1934 bt_put(trace->packet_header_type);
1935 trace->packet_header_type = bt_get(packet_header_type);
1936 BT_LOGV("Set trace's packet header field type: "
1937 "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
1938 trace, bt_ctf_trace_get_name(trace), packet_header_type);
1939 end:
1940 return ret;
1941 }
1942
1943 static
1944 int64_t get_stream_class_count(void *element)
1945 {
1946 return bt_ctf_trace_get_stream_class_count(
1947 (struct bt_ctf_trace *) element);
1948 }
1949
1950 static
1951 void *get_stream_class(void *element, int i)
1952 {
1953 return bt_ctf_trace_get_stream_class_by_index(
1954 (struct bt_ctf_trace *) element, i);
1955 }
1956
1957 static
1958 int visit_stream_class(void *object, bt_ctf_visitor visitor,void *data)
1959 {
1960 return bt_ctf_stream_class_visit(object, visitor, data);
1961 }
1962
1963 int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
1964 bt_ctf_visitor visitor, void *data)
1965 {
1966 int ret;
1967 struct bt_ctf_object obj =
1968 { .object = trace, .type = BT_CTF_OBJECT_TYPE_TRACE };
1969
1970 if (!trace) {
1971 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1972 ret = -1;
1973 goto end;
1974 }
1975
1976 if (!visitor) {
1977 BT_LOGW_STR("Invalid parameter: visitor is NULL.");
1978 ret = -1;
1979 goto end;
1980 }
1981
1982 BT_LOGV("Visiting trace: addr=%p, name=\"%s\"",
1983 trace, bt_ctf_trace_get_name(trace));
1984 ret = visitor_helper(&obj, get_stream_class_count,
1985 get_stream_class, visit_stream_class, visitor, data);
1986 end:
1987 return ret;
1988 }
1989
1990 static
1991 int invoke_listener(struct bt_ctf_object *object, void *data)
1992 {
1993 struct listener_wrapper *listener_wrapper = data;
1994
1995 listener_wrapper->listener(object, listener_wrapper->data);
1996 return 0;
1997 }
1998
1999 // TODO: add logging to this function once we use it internally.
2000 int bt_ctf_trace_add_listener(struct bt_ctf_trace *trace,
2001 bt_ctf_listener_cb listener, void *listener_data)
2002 {
2003 int ret = 0;
2004 struct listener_wrapper *listener_wrapper =
2005 g_new0(struct listener_wrapper, 1);
2006
2007 if (!trace || !listener || !listener_wrapper) {
2008 ret = -1;
2009 goto error;
2010 }
2011
2012 listener_wrapper->listener = listener;
2013 listener_wrapper->data = listener_data;
2014
2015 /* Visit the current schema. */
2016 ret = bt_ctf_trace_visit(trace, invoke_listener, listener_wrapper);
2017 if (ret) {
2018 goto error;
2019 }
2020
2021 /*
2022 * Add listener to the array of callbacks which will be invoked on
2023 * schema changes.
2024 */
2025 g_ptr_array_add(trace->listeners, listener_wrapper);
2026 return ret;
2027 error:
2028 g_free(listener_wrapper);
2029 return ret;
2030 }
2031
2032 BT_HIDDEN
2033 int bt_ctf_trace_object_modification(struct bt_ctf_object *object,
2034 void *trace_ptr)
2035 {
2036 size_t i;
2037 struct bt_ctf_trace *trace = trace_ptr;
2038
2039 assert(trace);
2040 assert(object);
2041
2042 if (trace->listeners->len == 0) {
2043 goto end;
2044 }
2045
2046 for (i = 0; i < trace->listeners->len; i++) {
2047 struct listener_wrapper *listener =
2048 g_ptr_array_index(trace->listeners, i);
2049
2050 listener->listener(object, listener->data);
2051 }
2052 end:
2053 return 0;
2054 }
2055
2056 BT_HIDDEN
2057 struct bt_ctf_field_type *get_field_type(enum field_type_alias alias)
2058 {
2059 int ret;
2060 unsigned int alignment, size;
2061 struct bt_ctf_field_type *field_type = NULL;
2062
2063 if (alias >= NR_FIELD_TYPE_ALIAS) {
2064 goto end;
2065 }
2066
2067 alignment = field_type_aliases_alignments[alias];
2068 size = field_type_aliases_sizes[alias];
2069 field_type = bt_ctf_field_type_integer_create(size);
2070 ret = bt_ctf_field_type_set_alignment(field_type, alignment);
2071 if (ret) {
2072 BT_PUT(field_type);
2073 }
2074 end:
2075 return field_type;
2076 }
2077
2078 static
2079 void bt_ctf_trace_freeze(struct bt_ctf_trace *trace)
2080 {
2081 int i;
2082
2083 if (trace->frozen) {
2084 return;
2085 }
2086
2087 BT_LOGD("Freezing trace: addr=%p, name=\"%s\"",
2088 trace, bt_ctf_trace_get_name(trace));
2089 BT_LOGD_STR("Freezing packet header field type.");
2090 bt_ctf_field_type_freeze(trace->packet_header_type);
2091 BT_LOGD_STR("Freezing environment attributes.");
2092 bt_ctf_attributes_freeze(trace->environment);
2093
2094 if (trace->clocks->len > 0) {
2095 BT_LOGD_STR("Freezing clock classes.");
2096 }
2097
2098 for (i = 0; i < trace->clocks->len; i++) {
2099 struct bt_ctf_clock_class *clock_class =
2100 g_ptr_array_index(trace->clocks, i);
2101
2102 bt_ctf_clock_class_freeze(clock_class);
2103 }
2104
2105 trace->frozen = 1;
2106 }
2107
2108 bt_bool bt_ctf_trace_is_static(struct bt_ctf_trace *trace)
2109 {
2110 bt_bool is_static = BT_FALSE;
2111
2112 if (!trace) {
2113 BT_LOGW_STR("Invalid parameter: trace is NULL.");
2114 goto end;
2115 }
2116
2117 is_static = trace->is_static;
2118
2119 end:
2120 return is_static;
2121 }
2122
2123 int bt_ctf_trace_set_is_static(struct bt_ctf_trace *trace)
2124 {
2125 int ret = 0;
2126 size_t i;
2127
2128 if (!trace) {
2129 BT_LOGW_STR("Invalid parameter: trace is NULL.");
2130 ret = -1;
2131 goto end;
2132 }
2133
2134 trace->is_static = BT_TRUE;
2135 bt_ctf_trace_freeze(trace);
2136 BT_LOGV("Set trace static: addr=%p, name=\"%s\"",
2137 trace, bt_ctf_trace_get_name(trace));
2138
2139 /* Call all the "trace is static" listeners */
2140 for (i = 0; i < trace->is_static_listeners->len; i++) {
2141 struct bt_ctf_trace_is_static_listener_elem elem =
2142 g_array_index(trace->is_static_listeners,
2143 struct bt_ctf_trace_is_static_listener_elem, i);
2144
2145 if (elem.func) {
2146 elem.func(trace, elem.data);
2147 }
2148 }
2149
2150 end:
2151 return ret;
2152 }
2153
2154 int bt_ctf_trace_add_is_static_listener(struct bt_ctf_trace *trace,
2155 bt_ctf_trace_is_static_listener listener, void *data)
2156 {
2157 int i;
2158 struct bt_ctf_trace_is_static_listener_elem new_elem = {
2159 .func = listener,
2160 .data = data,
2161 };
2162
2163 if (!trace) {
2164 BT_LOGW_STR("Invalid parameter: trace is NULL.");
2165 i = -1;
2166 goto end;
2167 }
2168
2169 if (!listener) {
2170 BT_LOGW_STR("Invalid parameter: listener is NULL.");
2171 i = -1;
2172 goto end;
2173 }
2174
2175 if (trace->is_static) {
2176 BT_LOGW("Invalid parameter: trace is already static: "
2177 "addr=%p, name=\"%s\"",
2178 trace, bt_ctf_trace_get_name(trace));
2179 i = -1;
2180 goto end;
2181 }
2182
2183 /* Find the next available spot */
2184 for (i = 0; i < trace->is_static_listeners->len; i++) {
2185 struct bt_ctf_trace_is_static_listener_elem elem =
2186 g_array_index(trace->is_static_listeners,
2187 struct bt_ctf_trace_is_static_listener_elem, i);
2188
2189 if (!elem.func) {
2190 break;
2191 }
2192 }
2193
2194 if (i == trace->is_static_listeners->len) {
2195 g_array_append_val(trace->is_static_listeners, new_elem);
2196 } else {
2197 g_array_insert_val(trace->is_static_listeners, i, new_elem);
2198 }
2199
2200 BT_LOGV("Added \"trace is static\" listener: "
2201 "trace-addr=%p, trace-name=\"%s\", func-addr=%p, "
2202 "data-addr=%p, listener-id=%d",
2203 trace, bt_ctf_trace_get_name(trace), listener, data, i);
2204
2205 end:
2206 return i;
2207 }
2208
2209 int bt_ctf_trace_remove_is_static_listener(
2210 struct bt_ctf_trace *trace, int listener_id)
2211 {
2212 int ret = 0;
2213 struct bt_ctf_trace_is_static_listener_elem *elem;
2214
2215 if (!trace) {
2216 BT_LOGW_STR("Invalid parameter: trace is NULL.");
2217 ret = -1;
2218 goto end;
2219 }
2220
2221 if (listener_id < 0) {
2222 BT_LOGW("Invalid listener ID: must be zero or positive: "
2223 "listener-id=%d", listener_id);
2224 ret = -1;
2225 goto end;
2226 }
2227
2228 if (listener_id >= trace->is_static_listeners->len) {
2229 BT_LOGW("Invalid parameter: no listener with this listener ID: "
2230 "addr=%p, name=\"%s\", listener-id=%d",
2231 trace, bt_ctf_trace_get_name(trace),
2232 listener_id);
2233 ret = -1;
2234 goto end;
2235 }
2236
2237 elem = &g_array_index(trace->is_static_listeners,
2238 struct bt_ctf_trace_is_static_listener_elem,
2239 listener_id);
2240 if (!elem->func) {
2241 BT_LOGW("Invalid parameter: no listener with this listener ID: "
2242 "addr=%p, name=\"%s\", listener-id=%d",
2243 trace, bt_ctf_trace_get_name(trace),
2244 listener_id);
2245 ret = -1;
2246 goto end;
2247 }
2248
2249 elem->func = NULL;
2250 elem->data = NULL;
2251 BT_LOGV("Removed \"trace is static\" listener: "
2252 "trace-addr=%p, trace-name=\"%s\", "
2253 "listener-id=%d", trace, bt_ctf_trace_get_name(trace),
2254 listener_id);
2255
2256 end:
2257 return ret;
2258 }
This page took 0.11704 seconds and 5 git commands to generate.