Add trace name attribute
[babeltrace.git] / formats / 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 #include <babeltrace/ctf-ir/trace-internal.h>
30 #include <babeltrace/ctf-ir/clock-internal.h>
31 #include <babeltrace/ctf-ir/stream-internal.h>
32 #include <babeltrace/ctf-ir/stream-class-internal.h>
33 #include <babeltrace/ctf-ir/event-internal.h>
34 #include <babeltrace/ctf-ir/event-class.h>
35 #include <babeltrace/ctf-ir/event-class-internal.h>
36 #include <babeltrace/ctf-writer/functor-internal.h>
37 #include <babeltrace/ctf-ir/field-types-internal.h>
38 #include <babeltrace/ctf-ir/attributes-internal.h>
39 #include <babeltrace/ctf-ir/validation-internal.h>
40 #include <babeltrace/ctf-ir/visitor-internal.h>
41 #include <babeltrace/ctf-ir/utils.h>
42 #include <babeltrace/plugin/notification/schema.h>
43 #include <babeltrace/compiler.h>
44 #include <babeltrace/values.h>
45 #include <babeltrace/ref.h>
46 #include <babeltrace/endian.h>
47
48 #define DEFAULT_IDENTIFIER_SIZE 128
49 #define DEFAULT_METADATA_STRING_SIZE 4096
50
51 struct listener_wrapper {
52 bt_ctf_listener_cb listener;
53 void *data;
54 };
55
56 static
57 void bt_ctf_trace_destroy(struct bt_object *obj);
58 static
59 int init_trace_packet_header(struct bt_ctf_trace *trace);
60 static
61 void bt_ctf_trace_freeze(struct bt_ctf_trace *trace);
62
63 static
64 const unsigned int field_type_aliases_alignments[] = {
65 [FIELD_TYPE_ALIAS_UINT5_T] = 1,
66 [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8,
67 [FIELD_TYPE_ALIAS_UINT27_T] = 1,
68 [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8,
69 };
70
71 static
72 const unsigned int field_type_aliases_sizes[] = {
73 [FIELD_TYPE_ALIAS_UINT5_T] = 5,
74 [FIELD_TYPE_ALIAS_UINT8_T] = 8,
75 [FIELD_TYPE_ALIAS_UINT16_T] = 16,
76 [FIELD_TYPE_ALIAS_UINT27_T] = 27,
77 [FIELD_TYPE_ALIAS_UINT32_T] = 32,
78 [FIELD_TYPE_ALIAS_UINT64_T] = 64,
79 };
80
81 struct bt_ctf_trace *bt_ctf_trace_create(void)
82 {
83 struct bt_ctf_trace *trace = NULL;
84
85 trace = g_new0(struct bt_ctf_trace, 1);
86 if (!trace) {
87 goto error;
88 }
89
90 bt_ctf_trace_set_byte_order(trace, BT_CTF_BYTE_ORDER_NATIVE);
91 bt_object_init(trace, bt_ctf_trace_destroy);
92 trace->clocks = g_ptr_array_new_with_free_func(
93 (GDestroyNotify) bt_put);
94 trace->streams = g_ptr_array_new_with_free_func(
95 (GDestroyNotify) bt_object_release);
96 trace->stream_classes = g_ptr_array_new_with_free_func(
97 (GDestroyNotify) bt_object_release);
98 if (!trace->clocks || !trace->stream_classes || !trace->streams) {
99 goto error;
100 }
101
102 /* Generate a trace UUID */
103 uuid_generate(trace->uuid);
104 if (init_trace_packet_header(trace)) {
105 goto error;
106 }
107
108 /* Create the environment array object */
109 trace->environment = bt_ctf_attributes_create();
110 if (!trace->environment) {
111 goto error;
112 }
113
114 trace->listeners = g_ptr_array_new_with_free_func(
115 (GDestroyNotify) g_free);
116 if (!trace->listeners) {
117 goto error;
118 }
119
120 return trace;
121
122 error:
123 BT_PUT(trace);
124 return trace;
125 }
126
127 const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace)
128 {
129 const char *name = NULL;
130
131 if (!trace || !trace->name) {
132 goto end;
133 }
134
135 name = trace->name->str;
136 end:
137 return name;
138 }
139
140 int bt_ctf_trace_set_name(struct bt_ctf_trace *trace, const char *name)
141 {
142 int ret = 0;
143
144 if (!trace || !name || trace->frozen) {
145 ret = -1;
146 goto end;
147 }
148
149 trace->name = trace->name ? g_string_assign(trace->name, name) :
150 g_string_new(name);
151 if (!trace->name) {
152 ret = -1;
153 goto end;
154 }
155 end:
156 return ret;
157 }
158
159 void bt_ctf_trace_destroy(struct bt_object *obj)
160 {
161 struct bt_ctf_trace *trace;
162
163 trace = container_of(obj, struct bt_ctf_trace, base);
164 if (trace->environment) {
165 bt_ctf_attributes_destroy(trace->environment);
166 }
167
168 if (trace->name) {
169 g_string_free(trace->name, TRUE);
170 }
171
172 if (trace->clocks) {
173 g_ptr_array_free(trace->clocks, TRUE);
174 }
175
176 if (trace->streams) {
177 g_ptr_array_free(trace->streams, TRUE);
178 }
179
180 if (trace->stream_classes) {
181 g_ptr_array_free(trace->stream_classes, TRUE);
182 }
183
184 if (trace->listeners) {
185 g_ptr_array_free(trace->listeners, TRUE);
186 }
187
188 bt_put(trace->packet_header_type);
189 g_free(trace);
190 }
191
192 int bt_ctf_trace_set_environment_field(struct bt_ctf_trace *trace,
193 const char *name, struct bt_value *value)
194 {
195 int ret = 0;
196
197 if (!trace || !name || !value ||
198 bt_ctf_validate_identifier(name) ||
199 !(bt_value_is_integer(value) || bt_value_is_string(value))) {
200 ret = -1;
201 goto end;
202 }
203
204 if (strchr(name, ' ')) {
205 ret = -1;
206 goto end;
207 }
208
209 if (trace->frozen) {
210 /*
211 * New environment fields may be added to a frozen trace,
212 * but existing fields may not be changed.
213 *
214 * The object passed is frozen like all other attributes.
215 */
216 struct bt_value *attribute =
217 bt_ctf_attributes_get_field_value_by_name(
218 trace->environment, name);
219
220 if (attribute) {
221 BT_PUT(attribute);
222 ret = -1;
223 goto end;
224 }
225
226 bt_value_freeze(value);
227 }
228
229 ret = bt_ctf_attributes_set_field_value(trace->environment, name,
230 value);
231
232 end:
233 return ret;
234 }
235
236 int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace,
237 const char *name, const char *value)
238 {
239 int ret = 0;
240 struct bt_value *env_value_string_obj = NULL;
241
242 if (!trace || !name || !value) {
243 ret = -1;
244 goto end;
245 }
246
247 if (trace->frozen) {
248 /*
249 * New environment fields may be added to a frozen trace,
250 * but existing fields may not be changed.
251 */
252 struct bt_value *attribute =
253 bt_ctf_attributes_get_field_value_by_name(
254 trace->environment, name);
255
256 if (attribute) {
257 BT_PUT(attribute);
258 ret = -1;
259 goto end;
260 }
261 }
262
263 env_value_string_obj = bt_value_string_create_init(value);
264
265 if (!env_value_string_obj) {
266 ret = -1;
267 goto end;
268 }
269
270 if (trace->frozen) {
271 bt_value_freeze(env_value_string_obj);
272 }
273 ret = bt_ctf_trace_set_environment_field(trace, name,
274 env_value_string_obj);
275
276 end:
277 BT_PUT(env_value_string_obj);
278 return ret;
279 }
280
281 int bt_ctf_trace_set_environment_field_integer(struct bt_ctf_trace *trace,
282 const char *name, int64_t value)
283 {
284 int ret = 0;
285 struct bt_value *env_value_integer_obj = NULL;
286
287 if (!trace || !name) {
288 ret = -1;
289 goto end;
290 }
291
292 if (trace->frozen) {
293 /*
294 * New environment fields may be added to a frozen trace,
295 * but existing fields may not be changed.
296 */
297 struct bt_value *attribute =
298 bt_ctf_attributes_get_field_value_by_name(
299 trace->environment, name);
300
301 if (attribute) {
302 BT_PUT(attribute);
303 ret = -1;
304 goto end;
305 }
306 }
307
308 env_value_integer_obj = bt_value_integer_create_init(value);
309 if (!env_value_integer_obj) {
310 ret = -1;
311 goto end;
312 }
313
314 ret = bt_ctf_trace_set_environment_field(trace, name,
315 env_value_integer_obj);
316 if (trace->frozen) {
317 bt_value_freeze(env_value_integer_obj);
318 }
319 end:
320 BT_PUT(env_value_integer_obj);
321 return ret;
322 }
323
324 int bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace)
325 {
326 int ret = 0;
327
328 if (!trace) {
329 ret = -1;
330 goto end;
331 }
332
333 ret = bt_ctf_attributes_get_count(trace->environment);
334
335 end:
336 return ret;
337 }
338
339 const char *
340 bt_ctf_trace_get_environment_field_name(struct bt_ctf_trace *trace,
341 int index)
342 {
343 const char *ret = NULL;
344
345 if (!trace) {
346 goto end;
347 }
348
349 ret = bt_ctf_attributes_get_field_name(trace->environment, index);
350
351 end:
352 return ret;
353 }
354
355 struct bt_value *bt_ctf_trace_get_environment_field_value(
356 struct bt_ctf_trace *trace, int index)
357 {
358 struct bt_value *ret = NULL;
359
360 if (!trace) {
361 goto end;
362 }
363
364 ret = bt_ctf_attributes_get_field_value(trace->environment, index);
365
366 end:
367 return ret;
368 }
369
370 struct bt_value *bt_ctf_trace_get_environment_field_value_by_name(
371 struct bt_ctf_trace *trace, const char *name)
372 {
373 struct bt_value *ret = NULL;
374
375 if (!trace || !name) {
376 goto end;
377 }
378
379 ret = bt_ctf_attributes_get_field_value_by_name(trace->environment,
380 name);
381
382 end:
383 return ret;
384 }
385
386 int bt_ctf_trace_add_clock(struct bt_ctf_trace *trace,
387 struct bt_ctf_clock *clock)
388 {
389 int ret = 0;
390 struct search_query query = { .value = clock, .found = 0 };
391
392 if (!trace || !bt_ctf_clock_is_valid(clock)) {
393 ret = -1;
394 goto end;
395 }
396
397 /* Check for duplicate clocks */
398 g_ptr_array_foreach(trace->clocks, value_exists, &query);
399 if (query.found) {
400 ret = -1;
401 goto end;
402 }
403
404 bt_get(clock);
405 g_ptr_array_add(trace->clocks, clock);
406
407 if (!trace->is_created_by_writer) {
408 /*
409 * Non-writer mode trace: disable clock value functions
410 * because clock values are per-stream in that
411 * situation.
412 */
413 clock->has_value = 0;
414 }
415
416 if (trace->frozen) {
417 bt_ctf_clock_freeze(clock);
418 }
419 end:
420 return ret;
421 }
422
423 int bt_ctf_trace_get_clock_count(struct bt_ctf_trace *trace)
424 {
425 int ret = -1;
426
427 if (!trace) {
428 goto end;
429 }
430
431 ret = trace->clocks->len;
432 end:
433 return ret;
434 }
435
436 struct bt_ctf_clock *bt_ctf_trace_get_clock(struct bt_ctf_trace *trace,
437 int index)
438 {
439 struct bt_ctf_clock *clock = NULL;
440
441 if (!trace || index < 0 || index >= trace->clocks->len) {
442 goto end;
443 }
444
445 clock = g_ptr_array_index(trace->clocks, index);
446 bt_get(clock);
447 end:
448 return clock;
449 }
450
451 int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
452 struct bt_ctf_stream_class *stream_class)
453 {
454 int ret, i;
455 int64_t stream_id;
456 struct bt_ctf_validation_output trace_sc_validation_output = { 0 };
457 struct bt_ctf_validation_output *ec_validation_outputs = NULL;
458 const enum bt_ctf_validation_flag trace_sc_validation_flags =
459 BT_CTF_VALIDATION_FLAG_TRACE |
460 BT_CTF_VALIDATION_FLAG_STREAM;
461 const enum bt_ctf_validation_flag ec_validation_flags =
462 BT_CTF_VALIDATION_FLAG_EVENT;
463 struct bt_ctf_field_type *packet_header_type = NULL;
464 struct bt_ctf_field_type *packet_context_type = NULL;
465 struct bt_ctf_field_type *event_header_type = NULL;
466 struct bt_ctf_field_type *stream_event_ctx_type = NULL;
467 int event_class_count;
468 struct bt_ctf_clock *clock_to_add_to_trace = NULL;
469 struct bt_ctf_trace *current_parent_trace = NULL;
470
471 if (!trace || !stream_class) {
472 ret = -1;
473 goto end;
474 }
475
476 current_parent_trace = bt_ctf_stream_class_get_trace(stream_class);
477 if (current_parent_trace) {
478 /* Stream class is already associated to a trace, abort. */
479 ret = -1;
480 goto end;
481 }
482
483 event_class_count =
484 bt_ctf_stream_class_get_event_class_count(stream_class);
485 assert(event_class_count >= 0);
486
487 /* Check for duplicate stream classes */
488 for (i = 0; i < trace->stream_classes->len; i++) {
489 if (trace->stream_classes->pdata[i] == stream_class) {
490 /* Stream class already registered to the trace */
491 ret = -1;
492 goto end;
493 }
494 }
495
496 /*
497 * If the stream class has a clock, register this clock to this
498 * trace if not already done.
499 */
500 if (stream_class->clock) {
501 const char *clock_name =
502 bt_ctf_clock_get_name(stream_class->clock);
503 struct bt_ctf_clock *trace_clock;
504
505 assert(clock_name);
506 trace_clock = bt_ctf_trace_get_clock_by_name(trace, clock_name);
507 bt_put(trace_clock);
508 if (trace_clock) {
509 if (trace_clock != stream_class->clock) {
510 /*
511 * Error: two different clocks in the
512 * trace would share the same name.
513 */
514 ret = -1;
515 goto end;
516 }
517 } else {
518 clock_to_add_to_trace = bt_get(stream_class->clock);
519 }
520 }
521
522 /*
523 * We're about to freeze both the trace and the stream class.
524 * Also, each event class contained in this stream class are
525 * already frozen.
526 *
527 * This trace, this stream class, and all its event classes
528 * should be valid at this point.
529 *
530 * Validate trace and stream class first, then each event
531 * class of this stream class can be validated individually.
532 */
533 packet_header_type =
534 bt_ctf_trace_get_packet_header_type(trace);
535 packet_context_type =
536 bt_ctf_stream_class_get_packet_context_type(stream_class);
537 event_header_type =
538 bt_ctf_stream_class_get_event_header_type(stream_class);
539 stream_event_ctx_type =
540 bt_ctf_stream_class_get_event_context_type(stream_class);
541 ret = bt_ctf_validate_class_types(trace->environment,
542 packet_header_type, packet_context_type, event_header_type,
543 stream_event_ctx_type, NULL, NULL, trace->valid,
544 stream_class->valid, 1, &trace_sc_validation_output,
545 trace_sc_validation_flags);
546 BT_PUT(packet_header_type);
547 BT_PUT(packet_context_type);
548 BT_PUT(event_header_type);
549 BT_PUT(stream_event_ctx_type);
550
551 if (ret) {
552 /*
553 * This means something went wrong during the validation
554 * process, not that the objects are invalid.
555 */
556 goto end;
557 }
558
559 if ((trace_sc_validation_output.valid_flags &
560 trace_sc_validation_flags) !=
561 trace_sc_validation_flags) {
562 /* Invalid trace/stream class */
563 ret = -1;
564 goto end;
565 }
566
567 if (event_class_count > 0) {
568 ec_validation_outputs = g_new0(struct bt_ctf_validation_output,
569 event_class_count);
570 if (!ec_validation_outputs) {
571 ret = -1;
572 goto end;
573 }
574 }
575
576 /* Validate each event class individually */
577 for (i = 0; i < event_class_count; i++) {
578 struct bt_ctf_event_class *event_class =
579 bt_ctf_stream_class_get_event_class(stream_class, i);
580 struct bt_ctf_field_type *event_context_type = NULL;
581 struct bt_ctf_field_type *event_payload_type = NULL;
582
583 event_context_type =
584 bt_ctf_event_class_get_context_type(event_class);
585 event_payload_type =
586 bt_ctf_event_class_get_payload_type(event_class);
587
588 /*
589 * It is important to use the field types returned by
590 * the previous trace and stream class validation here
591 * because copies could have been made.
592 */
593 ret = bt_ctf_validate_class_types(trace->environment,
594 trace_sc_validation_output.packet_header_type,
595 trace_sc_validation_output.packet_context_type,
596 trace_sc_validation_output.event_header_type,
597 trace_sc_validation_output.stream_event_ctx_type,
598 event_context_type, event_payload_type,
599 1, 1, event_class->valid, &ec_validation_outputs[i],
600 ec_validation_flags);
601 BT_PUT(event_context_type);
602 BT_PUT(event_payload_type);
603 BT_PUT(event_class);
604
605 if (ret) {
606 goto end;
607 }
608
609 if ((ec_validation_outputs[i].valid_flags &
610 ec_validation_flags) != ec_validation_flags) {
611 /* Invalid event class */
612 ret = -1;
613 goto end;
614 }
615 }
616
617 stream_id = bt_ctf_stream_class_get_id(stream_class);
618 if (stream_id < 0) {
619 stream_id = trace->next_stream_id++;
620
621 /* Try to assign a new stream id */
622 for (i = 0; i < trace->stream_classes->len; i++) {
623 if (stream_id == bt_ctf_stream_class_get_id(
624 trace->stream_classes->pdata[i])) {
625 /* Duplicate stream id found */
626 ret = -1;
627 goto end;
628 }
629 }
630
631 if (bt_ctf_stream_class_set_id_no_check(stream_class,
632 stream_id)) {
633 /* TODO Should retry with a different stream id */
634 ret = -1;
635 goto end;
636 }
637 }
638
639 bt_object_set_parent(stream_class, trace);
640 g_ptr_array_add(trace->stream_classes, stream_class);
641
642 /*
643 * At this point we know that the function will be successful.
644 * Therefore we can replace the trace and stream class field
645 * types with what's in their validation output structure and
646 * mark them as valid. We can also replace the field types of
647 * all the event classes of the stream class and mark them as
648 * valid.
649 */
650 bt_ctf_validation_replace_types(trace, stream_class, NULL,
651 &trace_sc_validation_output, trace_sc_validation_flags);
652 trace->valid = 1;
653 stream_class->valid = 1;
654
655 /*
656 * Put what was not moved in bt_ctf_validation_replace_types().
657 */
658 bt_ctf_validation_output_put_types(&trace_sc_validation_output);
659
660 for (i = 0; i < event_class_count; i++) {
661 struct bt_ctf_event_class *event_class =
662 bt_ctf_stream_class_get_event_class(stream_class, i);
663
664 bt_ctf_validation_replace_types(NULL, NULL, event_class,
665 &ec_validation_outputs[i], ec_validation_flags);
666 event_class->valid = 1;
667 BT_PUT(event_class);
668
669 /*
670 * Put what was not moved in
671 * bt_ctf_validation_replace_types().
672 */
673 bt_ctf_validation_output_put_types(&ec_validation_outputs[i]);
674 }
675
676 /*
677 * All field type byte orders set as "native" byte ordering can now be
678 * safely set to trace's own endianness, including the stream class'.
679 */
680 bt_ctf_field_type_set_native_byte_order(trace->packet_header_type,
681 trace->byte_order);
682 bt_ctf_stream_class_set_byte_order(stream_class, trace->byte_order);
683
684 /* Add stream class's clock if it exists */
685 if (clock_to_add_to_trace) {
686 int add_clock_ret =
687 bt_ctf_trace_add_clock(trace, clock_to_add_to_trace);
688 assert(add_clock_ret == 0);
689 }
690
691 /*
692 * Freeze the trace and the stream class.
693 */
694 bt_ctf_stream_class_freeze(stream_class);
695 bt_ctf_trace_freeze(trace);
696
697 /* Notifiy listeners of the trace's schema modification. */
698 bt_ctf_stream_class_visit(stream_class,
699 bt_ctf_trace_element_modification, trace);
700 end:
701 if (ret) {
702 bt_object_set_parent(stream_class, NULL);
703
704 if (ec_validation_outputs) {
705 for (i = 0; i < event_class_count; i++) {
706 bt_ctf_validation_output_put_types(
707 &ec_validation_outputs[i]);
708 }
709 }
710 }
711
712 g_free(ec_validation_outputs);
713 bt_ctf_validation_output_put_types(&trace_sc_validation_output);
714 BT_PUT(clock_to_add_to_trace);
715 bt_put(current_parent_trace);
716 assert(!packet_header_type);
717 assert(!packet_context_type);
718 assert(!event_header_type);
719 assert(!stream_event_ctx_type);
720
721 return ret;
722 }
723
724 int bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace)
725 {
726 int ret;
727
728 if (!trace) {
729 ret = -1;
730 goto end;
731 }
732
733 ret = trace->stream_classes->len;
734 end:
735 return ret;
736 }
737
738 struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class(
739 struct bt_ctf_trace *trace, int index)
740 {
741 struct bt_ctf_stream_class *stream_class = NULL;
742
743 if (!trace || index < 0 || index >= trace->stream_classes->len) {
744 goto end;
745 }
746
747 stream_class = g_ptr_array_index(trace->stream_classes, index);
748 bt_get(stream_class);
749 end:
750 return stream_class;
751 }
752
753 struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id(
754 struct bt_ctf_trace *trace, uint32_t id)
755 {
756 int i;
757 struct bt_ctf_stream_class *stream_class = NULL;
758
759 if (!trace) {
760 goto end;
761 }
762
763 for (i = 0; i < trace->stream_classes->len; i++) {
764 struct bt_ctf_stream_class *stream_class_candidate;
765
766 stream_class_candidate =
767 g_ptr_array_index(trace->stream_classes, i);
768
769 if (bt_ctf_stream_class_get_id(stream_class_candidate) ==
770 (int64_t) id) {
771 stream_class = stream_class_candidate;
772 bt_get(stream_class);
773 goto end;
774 }
775 }
776
777 end:
778 return stream_class;
779 }
780
781 struct bt_ctf_clock *bt_ctf_trace_get_clock_by_name(
782 struct bt_ctf_trace *trace, const char *name)
783 {
784 size_t i;
785 struct bt_ctf_clock *clock = NULL;
786
787 if (!trace || !name) {
788 goto end;
789 }
790
791 for (i = 0; i < trace->clocks->len; i++) {
792 struct bt_ctf_clock *cur_clk =
793 g_ptr_array_index(trace->clocks, i);
794 const char *cur_clk_name = bt_ctf_clock_get_name(cur_clk);
795
796 if (!cur_clk_name) {
797 goto end;
798 }
799
800 if (!strcmp(cur_clk_name, name)) {
801 clock = cur_clk;
802 bt_get(clock);
803 goto end;
804 }
805 }
806
807 end:
808 return clock;
809 }
810
811 BT_HIDDEN
812 const char *get_byte_order_string(int byte_order)
813 {
814 const char *string;
815
816 switch (byte_order) {
817 case LITTLE_ENDIAN:
818 string = "le";
819 break;
820 case BIG_ENDIAN:
821 string = "be";
822 break;
823 default:
824 string = "unknown";
825 break;
826 }
827
828 return string;
829 }
830
831 static
832 int append_trace_metadata(struct bt_ctf_trace *trace,
833 struct metadata_context *context)
834 {
835 unsigned char *uuid = trace->uuid;
836 int ret;
837
838 g_string_append(context->string, "trace {\n");
839
840 g_string_append(context->string, "\tmajor = 1;\n");
841 g_string_append(context->string, "\tminor = 8;\n");
842
843 g_string_append_printf(context->string,
844 "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
845 uuid[0], uuid[1], uuid[2], uuid[3],
846 uuid[4], uuid[5], uuid[6], uuid[7],
847 uuid[8], uuid[9], uuid[10], uuid[11],
848 uuid[12], uuid[13], uuid[14], uuid[15]);
849 g_string_append_printf(context->string, "\tbyte_order = %s;\n",
850 get_byte_order_string(trace->byte_order));
851
852 g_string_append(context->string, "\tpacket.header := ");
853 context->current_indentation_level++;
854 g_string_assign(context->field_name, "");
855 ret = bt_ctf_field_type_serialize(trace->packet_header_type,
856 context);
857 if (ret) {
858 goto end;
859 }
860 context->current_indentation_level--;
861
862 g_string_append(context->string, ";\n};\n\n");
863 end:
864 return ret;
865 }
866
867 static
868 void append_env_metadata(struct bt_ctf_trace *trace,
869 struct metadata_context *context)
870 {
871 int i;
872 int env_size;
873
874 env_size = bt_ctf_attributes_get_count(trace->environment);
875
876 if (env_size <= 0) {
877 return;
878 }
879
880 g_string_append(context->string, "env {\n");
881
882 for (i = 0; i < env_size; i++) {
883 struct bt_value *env_field_value_obj = NULL;
884 const char *entry_name;
885
886 entry_name = bt_ctf_attributes_get_field_name(
887 trace->environment, i);
888 env_field_value_obj = bt_ctf_attributes_get_field_value(
889 trace->environment, i);
890
891 if (!entry_name || !env_field_value_obj) {
892 goto loop_next;
893 }
894
895 switch (bt_value_get_type(env_field_value_obj)) {
896 case BT_VALUE_TYPE_INTEGER:
897 {
898 int ret;
899 int64_t int_value;
900
901 ret = bt_value_integer_get(env_field_value_obj,
902 &int_value);
903
904 if (ret) {
905 goto loop_next;
906 }
907
908 g_string_append_printf(context->string,
909 "\t%s = %" PRId64 ";\n", entry_name,
910 int_value);
911 break;
912 }
913 case BT_VALUE_TYPE_STRING:
914 {
915 int ret;
916 const char *str_value;
917 char *escaped_str = NULL;
918
919 ret = bt_value_string_get(env_field_value_obj,
920 &str_value);
921
922 if (ret) {
923 goto loop_next;
924 }
925
926 escaped_str = g_strescape(str_value, NULL);
927
928 if (!escaped_str) {
929 goto loop_next;
930 }
931
932 g_string_append_printf(context->string,
933 "\t%s = \"%s\";\n", entry_name, escaped_str);
934 free(escaped_str);
935 break;
936 }
937
938 default:
939 goto loop_next;
940 }
941
942 loop_next:
943 BT_PUT(env_field_value_obj);
944 }
945
946 g_string_append(context->string, "};\n\n");
947 }
948
949 char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace)
950 {
951 char *metadata = NULL;
952 struct metadata_context *context = NULL;
953 int err = 0;
954 size_t i;
955
956 if (!trace) {
957 goto end;
958 }
959
960 context = g_new0(struct metadata_context, 1);
961 if (!context) {
962 goto end;
963 }
964
965 context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE);
966 context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE);
967 g_string_append(context->string, "/* CTF 1.8 */\n\n");
968 if (append_trace_metadata(trace, context)) {
969 goto error;
970 }
971 append_env_metadata(trace, context);
972 g_ptr_array_foreach(trace->clocks,
973 (GFunc)bt_ctf_clock_serialize, context);
974
975 for (i = 0; i < trace->stream_classes->len; i++) {
976 err = bt_ctf_stream_class_serialize(
977 trace->stream_classes->pdata[i], context);
978 if (err) {
979 goto error;
980 }
981 }
982
983 metadata = context->string->str;
984 error:
985 g_string_free(context->string, err ? TRUE : FALSE);
986 g_string_free(context->field_name, TRUE);
987 g_free(context);
988 end:
989 return metadata;
990 }
991
992 enum bt_ctf_byte_order bt_ctf_trace_get_byte_order(struct bt_ctf_trace *trace)
993 {
994 enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN;
995
996 if (!trace) {
997 goto end;
998 }
999
1000 switch (trace->byte_order) {
1001 case BIG_ENDIAN:
1002 ret = BT_CTF_BYTE_ORDER_BIG_ENDIAN;
1003 break;
1004 case LITTLE_ENDIAN:
1005 ret = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN;
1006 break;
1007 default:
1008 break;
1009 }
1010 end:
1011 return ret;
1012 }
1013
1014 int bt_ctf_trace_set_byte_order(struct bt_ctf_trace *trace,
1015 enum bt_ctf_byte_order byte_order)
1016 {
1017 int ret = 0;
1018 int internal_byte_order;
1019
1020 if (!trace || trace->frozen) {
1021 ret = -1;
1022 goto end;
1023 }
1024
1025 switch (byte_order) {
1026 case BT_CTF_BYTE_ORDER_NATIVE:
1027 /*
1028 * This doesn't make sense since the CTF specification defines
1029 * the "native" byte order as "the byte order described in the
1030 * trace description". However, this behavior had been
1031 * implemented as part of v1.2 and is kept to maintain
1032 * compatibility.
1033 *
1034 * This may be changed on a major version bump only.
1035 */
1036 internal_byte_order = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ?
1037 LITTLE_ENDIAN : BIG_ENDIAN;
1038 break;
1039 case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
1040 internal_byte_order = LITTLE_ENDIAN;
1041 break;
1042 case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
1043 case BT_CTF_BYTE_ORDER_NETWORK:
1044 internal_byte_order = BIG_ENDIAN;
1045 break;
1046 default:
1047 ret = -1;
1048 goto end;
1049 }
1050
1051 trace->byte_order = internal_byte_order;
1052 end:
1053 return ret;
1054 }
1055
1056 struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_type(
1057 struct bt_ctf_trace *trace)
1058 {
1059 struct bt_ctf_field_type *field_type = NULL;
1060
1061 if (!trace) {
1062 goto end;
1063 }
1064
1065 bt_get(trace->packet_header_type);
1066 field_type = trace->packet_header_type;
1067 end:
1068 return field_type;
1069 }
1070
1071 int bt_ctf_trace_set_packet_header_type(struct bt_ctf_trace *trace,
1072 struct bt_ctf_field_type *packet_header_type)
1073 {
1074 int ret = 0;
1075
1076 if (!trace || !packet_header_type || trace->frozen) {
1077 ret = -1;
1078 goto end;
1079 }
1080
1081 /* packet_header_type must be a structure */
1082 if (bt_ctf_field_type_get_type_id(packet_header_type) !=
1083 BT_CTF_TYPE_ID_STRUCT) {
1084 ret = -1;
1085 goto end;
1086 }
1087
1088 bt_get(packet_header_type);
1089 bt_put(trace->packet_header_type);
1090 trace->packet_header_type = packet_header_type;
1091 end:
1092 return ret;
1093 }
1094
1095 static
1096 int get_stream_class_count(void *element)
1097 {
1098 return bt_ctf_trace_get_stream_class_count(
1099 (struct bt_ctf_trace *) element);
1100 }
1101
1102 static
1103 void *get_stream_class(void *element, int i)
1104 {
1105 return bt_ctf_trace_get_stream_class(
1106 (struct bt_ctf_trace *) element, i);
1107 }
1108
1109 static
1110 int visit_stream_class(void *element, bt_ctf_ir_visitor visitor,void *data)
1111 {
1112 return bt_ctf_stream_class_visit(element, visitor, data);
1113 }
1114
1115 int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
1116 bt_ctf_ir_visitor visitor, void *data)
1117 {
1118 int ret;
1119 struct bt_ctf_ir_element element =
1120 { .element = trace, .type = BT_CTF_IR_TYPE_TRACE };
1121
1122 if (!trace || !visitor) {
1123 ret = -1;
1124 goto end;
1125 }
1126
1127 ret = visitor_helper(&element, get_stream_class_count,
1128 get_stream_class, visit_stream_class, visitor, data);
1129 end:
1130 return ret;
1131 }
1132
1133 static
1134 int invoke_listener(struct bt_ctf_ir_element *element, void *data)
1135 {
1136 struct listener_wrapper *listener_wrapper = data;
1137
1138 listener_wrapper->listener(element, listener_wrapper->data);
1139 return 0;
1140 }
1141
1142 int bt_ctf_trace_add_listener(struct bt_ctf_trace *trace,
1143 bt_ctf_listener_cb listener, void *listener_data)
1144 {
1145 int ret = 0;
1146 struct listener_wrapper *listener_wrapper =
1147 g_new0(struct listener_wrapper, 1);
1148
1149 if (!trace || !listener || !listener_wrapper) {
1150 ret = -1;
1151 goto error;
1152 }
1153
1154 listener_wrapper->listener = listener;
1155 listener_wrapper->data = listener_data;
1156
1157 /* Visit the current schema. */
1158 ret = bt_ctf_trace_visit(trace, invoke_listener, listener_wrapper);
1159 if (ret) {
1160 goto error;
1161 }
1162
1163 /*
1164 * Add listener to the array of callbacks which will be invoked on
1165 * schema changes.
1166 */
1167 g_ptr_array_add(trace->listeners, listener_wrapper);
1168 return ret;
1169 error:
1170 g_free(listener_wrapper);
1171 return ret;
1172 }
1173
1174 BT_HIDDEN
1175 int bt_ctf_trace_element_modification(struct bt_ctf_ir_element *element,
1176 void *trace_ptr)
1177 {
1178 size_t i;
1179 struct bt_ctf_trace *trace = trace_ptr;
1180
1181 assert(trace);
1182 assert(element);
1183
1184 if (trace->listeners->len == 0) {
1185 goto end;
1186 }
1187
1188 for (i = 0; i < trace->listeners->len; i++) {
1189 struct listener_wrapper *listener =
1190 g_ptr_array_index(trace->listeners, i);
1191
1192 listener->listener(element, listener->data);
1193 }
1194 end:
1195 return 0;
1196 }
1197
1198 BT_HIDDEN
1199 struct bt_ctf_field_type *get_field_type(enum field_type_alias alias)
1200 {
1201 int ret;
1202 unsigned int alignment, size;
1203 struct bt_ctf_field_type *field_type = NULL;
1204
1205 if (alias >= NR_FIELD_TYPE_ALIAS) {
1206 goto end;
1207 }
1208
1209 alignment = field_type_aliases_alignments[alias];
1210 size = field_type_aliases_sizes[alias];
1211 field_type = bt_ctf_field_type_integer_create(size);
1212 ret = bt_ctf_field_type_set_alignment(field_type, alignment);
1213 if (ret) {
1214 BT_PUT(field_type);
1215 }
1216 end:
1217 return field_type;
1218 }
1219
1220 static
1221 void bt_ctf_trace_freeze(struct bt_ctf_trace *trace)
1222 {
1223 int i;
1224
1225 bt_ctf_field_type_freeze(trace->packet_header_type);
1226 bt_ctf_attributes_freeze(trace->environment);
1227
1228 for (i = 0; i < trace->clocks->len; i++) {
1229 struct bt_ctf_clock *clock =
1230 g_ptr_array_index(trace->clocks, i);
1231
1232 bt_ctf_clock_freeze(clock);
1233 }
1234
1235 trace->frozen = 1;
1236 }
1237
1238 static
1239 int init_trace_packet_header(struct bt_ctf_trace *trace)
1240 {
1241 int ret = 0;
1242 struct bt_ctf_field *magic = NULL, *uuid_array = NULL;
1243 struct bt_ctf_field_type *_uint32_t =
1244 get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
1245 struct bt_ctf_field_type *_uint8_t =
1246 get_field_type(FIELD_TYPE_ALIAS_UINT8_T);
1247 struct bt_ctf_field_type *trace_packet_header_type =
1248 bt_ctf_field_type_structure_create();
1249 struct bt_ctf_field_type *uuid_array_type =
1250 bt_ctf_field_type_array_create(_uint8_t, 16);
1251
1252 if (!trace_packet_header_type || !uuid_array_type) {
1253 ret = -1;
1254 goto end;
1255 }
1256
1257 ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
1258 _uint32_t, "magic");
1259 if (ret) {
1260 goto end;
1261 }
1262
1263 ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
1264 uuid_array_type, "uuid");
1265 if (ret) {
1266 goto end;
1267 }
1268
1269 ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
1270 _uint32_t, "stream_id");
1271 if (ret) {
1272 goto end;
1273 }
1274
1275 ret = bt_ctf_trace_set_packet_header_type(trace,
1276 trace_packet_header_type);
1277 if (ret) {
1278 goto end;
1279 }
1280 end:
1281 bt_put(uuid_array_type);
1282 bt_put(_uint32_t);
1283 bt_put(_uint8_t);
1284 bt_put(magic);
1285 bt_put(uuid_array);
1286 bt_put(trace_packet_header_type);
1287 return ret;
1288 }
This page took 0.061188 seconds and 4 git commands to generate.