Add clock accessor to CTF IR Trace
[babeltrace.git] / formats / ctf / ir / trace.c
CommitLineData
bc37ae52
JG
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-writer/functor-internal.h>
34#include <babeltrace/ctf-ir/event-types-internal.h>
35#include <babeltrace/compiler.h>
36
37#define DEFAULT_IDENTIFIER_SIZE 128
38#define DEFAULT_METADATA_STRING_SIZE 4096
39
40static
41void environment_variable_destroy(struct environment_variable *var);
42static
43void bt_ctf_trace_destroy(struct bt_ctf_ref *ref);
44static
45int init_trace_packet_header(struct bt_ctf_trace *trace);
46
47static
48const char * const reserved_keywords_str[] = {"align", "callsite",
49 "const", "char", "clock", "double", "enum", "env", "event",
50 "floating_point", "float", "integer", "int", "long", "short", "signed",
51 "stream", "string", "struct", "trace", "typealias", "typedef",
52 "unsigned", "variant", "void" "_Bool", "_Complex", "_Imaginary"};
53
54static
55const unsigned int field_type_aliases_alignments[] = {
56 [FIELD_TYPE_ALIAS_UINT5_T] = 1,
57 [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8,
58 [FIELD_TYPE_ALIAS_UINT27_T] = 1,
59 [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8,
60};
61
62static
63const unsigned int field_type_aliases_sizes[] = {
64 [FIELD_TYPE_ALIAS_UINT5_T] = 5,
65 [FIELD_TYPE_ALIAS_UINT8_T] = 8,
66 [FIELD_TYPE_ALIAS_UINT16_T] = 16,
67 [FIELD_TYPE_ALIAS_UINT27_T] = 27,
68 [FIELD_TYPE_ALIAS_UINT32_T] = 32,
69 [FIELD_TYPE_ALIAS_UINT64_T] = 64,
70};
71
72static GHashTable *reserved_keywords_set;
73static int init_done;
74static int global_data_refcount;
75
76struct bt_ctf_trace *bt_ctf_trace_create(void)
77{
78 struct bt_ctf_trace *trace = NULL;
79
80 trace = g_new0(struct bt_ctf_trace, 1);
81 if (!trace) {
82 goto error;
83 }
84
85 bt_ctf_trace_set_byte_order(trace, BT_CTF_BYTE_ORDER_NATIVE);
86 bt_ctf_ref_init(&trace->ref_count);
87 trace->environment = g_ptr_array_new_with_free_func(
88 (GDestroyNotify)environment_variable_destroy);
89 trace->clocks = g_ptr_array_new_with_free_func(
90 (GDestroyNotify)bt_ctf_clock_put);
91 trace->streams = g_ptr_array_new_with_free_func(
92 (GDestroyNotify)bt_ctf_stream_put);
93 trace->stream_classes = g_ptr_array_new_with_free_func(
94 (GDestroyNotify)bt_ctf_stream_class_put);
95 if (!trace->environment || !trace->clocks ||
96 !trace->stream_classes || !trace->streams) {
97 goto error_destroy;
98 }
99
100 /* Generate a trace UUID */
101 uuid_generate(trace->uuid);
102 if (init_trace_packet_header(trace)) {
103 goto error_destroy;
104 }
105
106 return trace;
107
108error_destroy:
109 bt_ctf_trace_destroy(&trace->ref_count);
110 trace = NULL;
111error:
112 return trace;
113}
114
115void bt_ctf_trace_destroy(struct bt_ctf_ref *ref)
116{
117 struct bt_ctf_trace *trace;
118
119 if (!ref) {
120 return;
121 }
122
123 trace = container_of(ref, struct bt_ctf_trace, ref_count);
124 if (trace->environment) {
125 g_ptr_array_free(trace->environment, TRUE);
126 }
127
128 if (trace->clocks) {
129 g_ptr_array_free(trace->clocks, TRUE);
130 }
131
132 if (trace->streams) {
133 g_ptr_array_free(trace->streams, TRUE);
134 }
135
136 if (trace->stream_classes) {
137 g_ptr_array_free(trace->stream_classes, TRUE);
138 }
139
140 bt_ctf_field_type_put(trace->trace_packet_header_type);
141 bt_ctf_field_put(trace->trace_packet_header);
142 g_free(trace);
143}
144
145struct bt_ctf_stream *bt_ctf_trace_create_stream(struct bt_ctf_trace *trace,
146 struct bt_ctf_stream_class *stream_class)
147{
148 int ret;
149 int stream_class_found = 0;
150 size_t i;
151 struct bt_ctf_stream *stream = NULL;
152
153 if (!trace || !stream_class) {
154 goto error;
155 }
156
157 ret = bt_ctf_stream_class_set_byte_order(stream_class,
158 trace->byte_order == LITTLE_ENDIAN ?
159 BT_CTF_BYTE_ORDER_LITTLE_ENDIAN : BT_CTF_BYTE_ORDER_BIG_ENDIAN);
160 if (ret) {
161 goto error;
162 }
163
164 stream = bt_ctf_stream_create(stream_class);
165 if (!stream) {
166 goto error;
167 }
168
169 for (i = 0; i < trace->stream_classes->len; i++) {
170 if (trace->stream_classes->pdata[i] == stream_class) {
171 stream_class_found = 1;
172 }
173 }
174
175 if (!stream_class_found) {
176 int64_t stream_id = bt_ctf_stream_class_get_id(stream_class);
177
178 if (stream_id < 0) {
179 /* Try to assign a new stream id */
180 if (bt_ctf_stream_class_set_id(stream->stream_class,
181 trace->next_stream_id++)) {
182 goto error;
183 }
184 }
185
186 for (i = 0; i < trace->stream_classes->len; i++) {
187 if (stream_id == bt_ctf_stream_class_get_id(
188 trace->stream_classes->pdata[i])) {
189 /* Duplicate stream id found */
190 goto error;
191 }
192 }
193 bt_ctf_stream_class_get(stream->stream_class);
194 g_ptr_array_add(trace->stream_classes, stream->stream_class);
195 }
196
197 bt_ctf_stream_get(stream);
198 g_ptr_array_add(trace->streams, stream);
199 trace->frozen = 1;
200 return stream;
201
202error:
203 bt_ctf_stream_put(stream);
204 return NULL;
205}
206
207int bt_ctf_trace_add_environment_field(struct bt_ctf_trace *trace,
208 const char *name,
209 const char *value)
210{
211 struct environment_variable *var = NULL;
212 char *escaped_value = NULL;
213 int ret = 0;
214
215 if (!trace || !name || !value || validate_identifier(name)) {
216 ret = -1;
217 goto error;
218 }
219
220 if (strchr(name, ' ')) {
221 ret = -1;
222 goto error;
223 }
224
225 var = g_new0(struct environment_variable, 1);
226 if (!var) {
227 ret = -1;
228 goto error;
229 }
230
231 escaped_value = g_strescape(value, NULL);
232 if (!escaped_value) {
233 ret = -1;
234 goto error;
235 }
236
237 var->name = g_string_new(name);
238 var->value = g_string_new(escaped_value);
239 g_free(escaped_value);
240 if (!var->name || !var->value) {
241 ret = -1;
242 goto error;
243 }
244
245 g_ptr_array_add(trace->environment, var);
246 return ret;
247
248error:
249 if (var && var->name) {
250 g_string_free(var->name, TRUE);
251 }
252
253 if (var && var->value) {
254 g_string_free(var->value, TRUE);
255 }
256
257 g_free(var);
258 return ret;
259}
260
261int bt_ctf_trace_add_clock(struct bt_ctf_trace *trace,
262 struct bt_ctf_clock *clock)
263{
264 int ret = 0;
265 struct search_query query = { .value = clock, .found = 0 };
266
267 if (!trace || !clock) {
268 ret = -1;
269 goto end;
270 }
271
272 /* Check for duplicate clocks */
273 g_ptr_array_foreach(trace->clocks, value_exists, &query);
274 if (query.found) {
275 ret = -1;
276 goto end;
277 }
278
279 bt_ctf_clock_get(clock);
280 g_ptr_array_add(trace->clocks, clock);
281end:
282 return ret;
283}
284
884cd6c3
JG
285int bt_ctf_trace_get_clock_count(struct bt_ctf_trace *trace)
286{
287 int ret = -1;
288
289 if (!trace) {
290 goto end;
291 }
292
293 ret = trace->clocks->len;
294end:
295 return ret;
296}
297
298struct bt_ctf_clock *bt_ctf_trace_get_clock(struct bt_ctf_trace *trace,
299 int index)
300{
301 struct bt_ctf_clock *clock = NULL;
302
303 if (!trace || index < 0 || index >= trace->clocks->len) {
304 goto end;
305 }
306
307 clock = g_ptr_array_index(trace->clocks, index);
308 bt_ctf_clock_get(clock);
309end:
310 return clock;
311}
312
bc37ae52
JG
313BT_HIDDEN
314const char *get_byte_order_string(int byte_order)
315{
316 const char *string;
317
318 switch (byte_order) {
319 case LITTLE_ENDIAN:
320 string = "le";
321 break;
322 case BIG_ENDIAN:
323 string = "be";
324 break;
325 default:
326 string = "unknown";
327 break;
328 }
329
330 return string;
331}
332
333static
334int append_trace_metadata(struct bt_ctf_trace *trace,
335 struct metadata_context *context)
336{
337 unsigned char *uuid = trace->uuid;
338 int ret;
339
340 g_string_append(context->string, "trace {\n");
341
342 g_string_append(context->string, "\tmajor = 1;\n");
343 g_string_append(context->string, "\tminor = 8;\n");
344
345 g_string_append_printf(context->string,
346 "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
347 uuid[0], uuid[1], uuid[2], uuid[3],
348 uuid[4], uuid[5], uuid[6], uuid[7],
349 uuid[8], uuid[9], uuid[10], uuid[11],
350 uuid[12], uuid[13], uuid[14], uuid[15]);
351 g_string_append_printf(context->string, "\tbyte_order = %s;\n",
352 get_byte_order_string(trace->byte_order));
353
354 g_string_append(context->string, "\tpacket.header := ");
355 context->current_indentation_level++;
356 g_string_assign(context->field_name, "");
357 ret = bt_ctf_field_type_serialize(trace->trace_packet_header_type,
358 context);
359 if (ret) {
360 goto end;
361 }
362 context->current_indentation_level--;
363
364 g_string_append(context->string, ";\n};\n\n");
365end:
366 return ret;
367}
368
369static
370void append_env_field_metadata(struct environment_variable *var,
371 struct metadata_context *context)
372{
373 g_string_append_printf(context->string, "\t%s = \"%s\";\n",
374 var->name->str, var->value->str);
375}
376
377static
378void append_env_metadata(struct bt_ctf_trace *trace,
379 struct metadata_context *context)
380{
381 if (trace->environment->len == 0) {
382 return;
383 }
384
385 g_string_append(context->string, "env {\n");
386 g_ptr_array_foreach(trace->environment,
387 (GFunc)append_env_field_metadata, context);
388 g_string_append(context->string, "};\n\n");
389}
390
391char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace)
392{
393 char *metadata = NULL;
394 struct metadata_context *context = NULL;
395 int err = 0;
396 size_t i;
397
398 if (!trace) {
399 goto end;
400 }
401
402 context = g_new0(struct metadata_context, 1);
403 if (!context) {
404 goto end;
405 }
406
407 context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE);
408 context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE);
409 g_string_append(context->string, "/* CTF 1.8 */\n\n");
410 if (append_trace_metadata(trace, context)) {
411 goto error;
412 }
413 append_env_metadata(trace, context);
414 g_ptr_array_foreach(trace->clocks,
415 (GFunc)bt_ctf_clock_serialize, context);
416
417 for (i = 0; i < trace->stream_classes->len; i++) {
418 err = bt_ctf_stream_class_serialize(
419 trace->stream_classes->pdata[i], context);
420 if (err) {
421 goto error;
422 }
423 }
424
425 metadata = context->string->str;
426error:
427 g_string_free(context->string, err ? TRUE : FALSE);
428 g_string_free(context->field_name, TRUE);
429 g_free(context);
430end:
431 return metadata;
432}
433
434int bt_ctf_trace_set_byte_order(struct bt_ctf_trace *trace,
435 enum bt_ctf_byte_order byte_order)
436{
437 int ret = 0;
438 int internal_byte_order;
439
440 if (!trace || trace->frozen) {
441 ret = -1;
442 goto end;
443 }
444
445 switch (byte_order) {
446 case BT_CTF_BYTE_ORDER_NATIVE:
447 internal_byte_order = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ?
448 LITTLE_ENDIAN : BIG_ENDIAN;
449 break;
450 case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
451 internal_byte_order = LITTLE_ENDIAN;
452 break;
453 case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
454 case BT_CTF_BYTE_ORDER_NETWORK:
455 internal_byte_order = BIG_ENDIAN;
456 break;
457 default:
458 ret = -1;
459 goto end;
460 }
461
462 trace->byte_order = internal_byte_order;
463 if (trace->trace_packet_header_type ||
464 trace->trace_packet_header) {
465 init_trace_packet_header(trace);
466 }
467end:
468 return ret;
469}
470
471void bt_ctf_trace_get(struct bt_ctf_trace *trace)
472{
473 if (!trace) {
474 return;
475 }
476
477 bt_ctf_ref_get(&trace->ref_count);
478}
479
480void bt_ctf_trace_put(struct bt_ctf_trace *trace)
481{
482 if (!trace) {
483 return;
484 }
485
486 bt_ctf_ref_put(&trace->ref_count, bt_ctf_trace_destroy);
487}
488
489BT_HIDDEN
490int validate_identifier(const char *input_string)
491{
492 int ret = 0;
493 char *string = NULL;
494 char *save_ptr, *token;
495
496 if (!input_string || input_string[0] == '\0') {
497 ret = -1;
498 goto end;
499 }
500
501 string = strdup(input_string);
502 if (!string) {
503 ret = -1;
504 goto end;
505 }
506
507 token = strtok_r(string, " ", &save_ptr);
508 while (token) {
509 if (g_hash_table_lookup_extended(reserved_keywords_set,
510 GINT_TO_POINTER(g_quark_from_string(token)),
511 NULL, NULL)) {
512 ret = -1;
513 goto end;
514 }
515
516 token = strtok_r(NULL, " ", &save_ptr);
517 }
518end:
519 free(string);
520 return ret;
521}
522
523BT_HIDDEN
524struct bt_ctf_field_type *get_field_type(enum field_type_alias alias)
525{
526 unsigned int alignment, size;
527 struct bt_ctf_field_type *field_type;
528
529 if (alias >= NR_FIELD_TYPE_ALIAS) {
530 return NULL;
531 }
532
533 alignment = field_type_aliases_alignments[alias];
534 size = field_type_aliases_sizes[alias];
535 field_type = bt_ctf_field_type_integer_create(size);
536 bt_ctf_field_type_set_alignment(field_type, alignment);
537 return field_type;
538}
539
540static
541int init_trace_packet_header(struct bt_ctf_trace *trace)
542{
543 size_t i;
544 int ret = 0;
545 struct bt_ctf_field *trace_packet_header = NULL,
546 *magic = NULL, *uuid_array = NULL;
547 struct bt_ctf_field_type *_uint32_t =
548 get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
549 struct bt_ctf_field_type *_uint8_t =
550 get_field_type(FIELD_TYPE_ALIAS_UINT8_T);
551 struct bt_ctf_field_type *trace_packet_header_type =
552 bt_ctf_field_type_structure_create();
553 struct bt_ctf_field_type *uuid_array_type =
554 bt_ctf_field_type_array_create(_uint8_t, 16);
555
556 if (!trace_packet_header_type || !uuid_array_type) {
557 ret = -1;
558 goto end;
559 }
560
561 ret = bt_ctf_field_type_set_byte_order(_uint32_t,
562 (trace->byte_order == LITTLE_ENDIAN ?
563 BT_CTF_BYTE_ORDER_LITTLE_ENDIAN :
564 BT_CTF_BYTE_ORDER_BIG_ENDIAN));
565 if (ret) {
566 goto end;
567 }
568
569 ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
570 _uint32_t, "magic");
571 if (ret) {
572 goto end;
573 }
574
575 ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
576 uuid_array_type, "uuid");
577 if (ret) {
578 goto end;
579 }
580
581 ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
582 _uint32_t, "stream_id");
583 if (ret) {
584 goto end;
585 }
586
587 trace_packet_header = bt_ctf_field_create(trace_packet_header_type);
588 if (!trace_packet_header) {
589 ret = -1;
590 goto end;
591 }
592
593 magic = bt_ctf_field_structure_get_field(trace_packet_header, "magic");
594 ret = bt_ctf_field_unsigned_integer_set_value(magic, 0xC1FC1FC1);
595 if (ret) {
596 goto end;
597 }
598
599 uuid_array = bt_ctf_field_structure_get_field(trace_packet_header,
600 "uuid");
601 for (i = 0; i < 16; i++) {
602 struct bt_ctf_field *uuid_element =
603 bt_ctf_field_array_get_field(uuid_array, i);
604 ret = bt_ctf_field_unsigned_integer_set_value(uuid_element,
605 trace->uuid[i]);
606 bt_ctf_field_put(uuid_element);
607 if (ret) {
608 goto end;
609 }
610 }
611
612 bt_ctf_field_type_put(trace->trace_packet_header_type);
613 bt_ctf_field_put(trace->trace_packet_header);
614 trace->trace_packet_header_type = trace_packet_header_type;
615 trace->trace_packet_header = trace_packet_header;
616end:
617 bt_ctf_field_type_put(uuid_array_type);
618 bt_ctf_field_type_put(_uint32_t);
619 bt_ctf_field_type_put(_uint8_t);
620 bt_ctf_field_put(magic);
621 bt_ctf_field_put(uuid_array);
622 if (ret) {
623 bt_ctf_field_type_put(trace_packet_header_type);
624 bt_ctf_field_put(trace_packet_header);
625 }
626
627 return ret;
628}
629
630static
631void environment_variable_destroy(struct environment_variable *var)
632{
633 g_string_free(var->name, TRUE);
634 g_string_free(var->value, TRUE);
635 g_free(var);
636}
637
638static __attribute__((constructor))
639void trace_init(void)
640{
641 size_t i;
642 const size_t reserved_keywords_count =
643 sizeof(reserved_keywords_str) / sizeof(char *);
644
645 global_data_refcount++;
646 if (init_done) {
647 return;
648 }
649
650 reserved_keywords_set = g_hash_table_new(g_direct_hash, g_direct_equal);
651 for (i = 0; i < reserved_keywords_count; i++) {
652 gpointer quark = GINT_TO_POINTER(g_quark_from_string(
653 reserved_keywords_str[i]));
654
655 g_hash_table_insert(reserved_keywords_set, quark, quark);
656 }
657
658 init_done = 1;
659}
660
661static __attribute__((destructor))
662void trace_finalize(void)
663{
664 if (--global_data_refcount == 0) {
665 g_hash_table_destroy(reserved_keywords_set);
666 }
667}
This page took 0.045903 seconds and 4 git commands to generate.