Add event header accessors and support for custom event headers
[babeltrace.git] / formats / ctf / ir / event.c
1 /*
2 * event.c
3 *
4 * Babeltrace CTF IR - Event
5 *
6 * Copyright 2013, 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-writer/event.h>
30 #include <babeltrace/ctf-writer/event-types.h>
31 #include <babeltrace/ctf-writer/event-fields.h>
32 #include <babeltrace/ctf-ir/event-fields-internal.h>
33 #include <babeltrace/ctf-ir/event-types-internal.h>
34 #include <babeltrace/ctf-ir/event-internal.h>
35 #include <babeltrace/ctf-ir/stream-class.h>
36 #include <babeltrace/ctf-ir/stream-class-internal.h>
37 #include <babeltrace/ctf-ir/trace-internal.h>
38 #include <babeltrace/compiler.h>
39
40 static
41 void bt_ctf_event_class_destroy(struct bt_ctf_ref *ref);
42 static
43 void bt_ctf_event_destroy(struct bt_ctf_ref *ref);
44 static
45 int set_integer_field_value(struct bt_ctf_field *field, uint64_t value);
46
47 struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name)
48 {
49 struct bt_ctf_event_class *event_class = NULL;
50
51 if (validate_identifier(name)) {
52 goto end;
53 }
54
55 event_class = g_new0(struct bt_ctf_event_class, 1);
56 if (!event_class) {
57 goto end;
58 }
59
60 bt_ctf_ref_init(&event_class->ref_count);
61 event_class->name = g_quark_from_string(name);
62 end:
63 return event_class;
64 }
65
66 const char *bt_ctf_event_class_get_name(struct bt_ctf_event_class *event_class)
67 {
68 const char *name = NULL;
69
70 if (!event_class) {
71 goto end;
72 }
73
74 name = g_quark_to_string(event_class->name);
75 end:
76 return name;
77 }
78
79 int64_t bt_ctf_event_class_get_id(struct bt_ctf_event_class *event_class)
80 {
81 int64_t ret;
82
83 if (!event_class || !event_class->id_set) {
84 ret = -1;
85 goto end;
86 }
87
88 ret = (int64_t) event_class->id;
89 end:
90 return ret;
91 }
92
93 int bt_ctf_event_class_set_id(struct bt_ctf_event_class *event_class,
94 uint32_t id)
95 {
96 int ret = 0;
97
98 if (!event_class) {
99 ret = -1;
100 goto end;
101 }
102
103 if (event_class->stream_class) {
104 /*
105 * We don't allow changing the id if the event class has already
106 * been added to a stream class.
107 */
108 ret = -1;
109 goto end;
110 }
111
112 event_class->id = id;
113 event_class->id_set = 1;
114 end:
115 return ret;
116 }
117
118 struct bt_ctf_stream_class *bt_ctf_event_class_get_stream_class(
119 struct bt_ctf_event_class *event_class)
120 {
121 struct bt_ctf_stream_class *stream_class = NULL;
122
123 if (!event_class) {
124 goto end;
125 }
126
127 stream_class = event_class->stream_class;
128 bt_ctf_stream_class_get(stream_class);
129 end:
130 return stream_class;
131 }
132
133 int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class,
134 struct bt_ctf_field_type *type,
135 const char *name)
136 {
137 int ret = 0;
138
139 if (!event_class || !type || validate_identifier(name) ||
140 event_class->frozen) {
141 ret = -1;
142 goto end;
143 }
144
145 if (!event_class->fields) {
146 event_class->fields = bt_ctf_field_type_structure_create();
147 if (!event_class->fields) {
148 ret = -1;
149 goto end;
150 }
151 }
152
153 ret = bt_ctf_field_type_structure_add_field(event_class->fields,
154 type, name);
155 end:
156 return ret;
157 }
158
159 int bt_ctf_event_class_get_field_count(
160 struct bt_ctf_event_class *event_class)
161 {
162 int ret;
163
164 if (!event_class) {
165 ret = -1;
166 goto end;
167 }
168
169 ret = bt_ctf_field_type_structure_get_field_count(event_class->fields);
170 end:
171 return ret;
172 }
173
174 int bt_ctf_event_class_get_field(struct bt_ctf_event_class *event_class,
175 const char **field_name, struct bt_ctf_field_type **field_type,
176 int index)
177 {
178 int ret;
179
180 if (!event_class || index < 0) {
181 ret = -1;
182 goto end;
183 }
184
185 ret = bt_ctf_field_type_structure_get_field(event_class->fields,
186 field_name, field_type, index);
187 end:
188 return ret;
189 }
190
191 struct bt_ctf_field_type *bt_ctf_event_class_get_field_by_name(
192 struct bt_ctf_event_class *event_class, const char *name)
193 {
194 GQuark name_quark;
195 struct bt_ctf_field_type *field_type = NULL;
196
197 if (!event_class || !name) {
198 goto end;
199 }
200
201 name_quark = g_quark_try_string(name);
202 if (!name_quark) {
203 goto end;
204 }
205
206 /*
207 * No need to increment field_type's reference count since getting it
208 * from the structure already does.
209 */
210 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
211 event_class->fields, name);
212 end:
213 return field_type;
214 }
215
216 struct bt_ctf_field_type *bt_ctf_event_class_get_context_type(
217 struct bt_ctf_event_class *event_class)
218 {
219 struct bt_ctf_field_type *context_type = NULL;
220
221 if (!event_class || !event_class->context) {
222 goto end;
223 }
224
225 bt_ctf_field_type_get(event_class->context);
226 context_type = event_class->context;
227 end:
228 return context_type;
229 }
230
231 int bt_ctf_event_class_set_context_type(
232 struct bt_ctf_event_class *event_class,
233 struct bt_ctf_field_type *context)
234 {
235 int ret = 0;
236
237 if (!event_class || !context || event_class->frozen) {
238 ret = -1;
239 goto end;
240 }
241
242 if (bt_ctf_field_type_get_type_id(context) != CTF_TYPE_STRUCT) {
243 ret = -1;
244 goto end;
245 }
246
247 bt_ctf_field_type_get(context);
248 bt_ctf_field_type_put(event_class->context);
249 event_class->context = context;
250 end:
251 return ret;
252
253 }
254
255 void bt_ctf_event_class_get(struct bt_ctf_event_class *event_class)
256 {
257 if (!event_class) {
258 return;
259 }
260
261 bt_ctf_ref_get(&event_class->ref_count);
262 }
263
264 void bt_ctf_event_class_put(struct bt_ctf_event_class *event_class)
265 {
266 if (!event_class) {
267 return;
268 }
269
270 bt_ctf_ref_put(&event_class->ref_count, bt_ctf_event_class_destroy);
271 }
272
273 struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class)
274 {
275 struct bt_ctf_event *event = NULL;
276
277 if (!event_class) {
278 goto end;
279 }
280
281 event = g_new0(struct bt_ctf_event, 1);
282 if (!event) {
283 goto end;
284 }
285
286 bt_ctf_ref_init(&event->ref_count);
287 bt_ctf_event_class_get(event_class);
288 bt_ctf_event_class_freeze(event_class);
289 event->event_class = event_class;
290
291 assert(event_class->stream_class);
292 assert(event_class->stream_class->event_header_type);
293
294 event->event_header = bt_ctf_field_create(
295 event_class->stream_class->event_header_type);
296 if (!event->event_header) {
297 goto error_destroy;
298 }
299 if (event_class->context) {
300 event->context_payload = bt_ctf_field_create(
301 event_class->context);
302 if (!event->context_payload) {
303 goto error_destroy;
304 }
305 }
306 event->fields_payload = bt_ctf_field_create(event_class->fields);
307 if (!event->fields_payload) {
308 goto error_destroy;
309 }
310 end:
311 /*
312 * Freeze the stream class since the event header must not be changed
313 * anymore.
314 */
315 bt_ctf_stream_class_freeze(event_class->stream_class);
316 return event;
317 error_destroy:
318 bt_ctf_event_destroy(&event->ref_count);
319 return NULL;
320 }
321
322 struct bt_ctf_event_class *bt_ctf_event_get_class(struct bt_ctf_event *event)
323 {
324 struct bt_ctf_event_class *event_class = NULL;
325
326 if (!event) {
327 goto end;
328 }
329
330 event_class = event->event_class;
331 bt_ctf_event_class_get(event_class);
332 end:
333 return event_class;
334 }
335
336 struct bt_ctf_clock *bt_ctf_event_get_clock(struct bt_ctf_event *event)
337 {
338 struct bt_ctf_clock *clock = NULL;
339 struct bt_ctf_event_class *event_class;
340 struct bt_ctf_stream_class *stream_class;
341
342 if (!event) {
343 goto end;
344 }
345
346 event_class = bt_ctf_event_get_class(event);
347 if (!event_class) {
348 goto end;
349 }
350
351 stream_class = bt_ctf_event_class_get_stream_class(event_class);
352 if (!stream_class) {
353 goto error_put_event_class;
354 }
355
356 clock = bt_ctf_stream_class_get_clock(stream_class);
357 if (!clock) {
358 goto error_put_stream_class;
359 }
360
361 error_put_stream_class:
362 bt_ctf_stream_class_put(stream_class);
363 error_put_event_class:
364 bt_ctf_event_class_put(event_class);
365 end:
366 return clock;
367 }
368
369 int bt_ctf_event_set_payload(struct bt_ctf_event *event,
370 const char *name,
371 struct bt_ctf_field *value)
372 {
373 int ret = 0;
374
375 if (!event || !value || validate_identifier(name)) {
376 ret = -1;
377 goto end;
378 }
379
380 ret = bt_ctf_field_structure_set_field(event->fields_payload,
381 name, value);
382 end:
383 return ret;
384 }
385
386
387 struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event,
388 const char *name)
389 {
390 struct bt_ctf_field *field = NULL;
391
392 if (!event || !name) {
393 goto end;
394 }
395
396 field = bt_ctf_field_structure_get_field(event->fields_payload, name);
397 end:
398 return field;
399 }
400
401 struct bt_ctf_field *bt_ctf_event_get_payload_by_index(
402 struct bt_ctf_event *event, int index)
403 {
404 struct bt_ctf_field *field = NULL;
405
406 if (!event || index < 0) {
407 goto end;
408 }
409
410 field = bt_ctf_field_structure_get_field_by_index(event->fields_payload,
411 index);
412 end:
413 return field;
414 }
415
416 struct bt_ctf_field *bt_ctf_event_get_event_header(
417 struct bt_ctf_event *event)
418 {
419 struct bt_ctf_field *header = NULL;
420
421 if (!event || !event->event_header) {
422 goto end;
423 }
424
425 header = event->event_header;
426 bt_ctf_field_get(header);
427 end:
428 return header;
429 }
430
431 int bt_ctf_event_set_event_header(struct bt_ctf_event *event,
432 struct bt_ctf_field *header)
433 {
434 int ret = 0;
435 struct bt_ctf_field_type *field_type = NULL;
436
437 if (!event || !header) {
438 ret = -1;
439 goto end;
440 }
441
442 /* Could be NULL since an event class doesn't own a stream class */
443 if (!event->event_class->stream_class) {
444 ret = -1;
445 goto end;
446 }
447
448 /*
449 * Ensure the provided header's type matches the one registered to the
450 * stream class.
451 */
452 field_type = bt_ctf_field_get_type(header);
453 if (field_type != event->event_class->stream_class->event_header_type) {
454 ret = -1;
455 goto end;
456 }
457
458 bt_ctf_field_get(header);
459 bt_ctf_field_put(event->event_header);
460 event->event_header = header;
461 end:
462 if (field_type) {
463 bt_ctf_field_type_put(field_type);
464 }
465 return ret;
466 }
467
468 struct bt_ctf_field *bt_ctf_event_get_event_context(
469 struct bt_ctf_event *event)
470 {
471 struct bt_ctf_field *context = NULL;
472
473 if (!event || !event->context_payload) {
474 goto end;
475 }
476
477 context = event->context_payload;
478 bt_ctf_field_get(context);
479 end:
480 return context;
481 }
482
483 int bt_ctf_event_set_event_context(struct bt_ctf_event *event,
484 struct bt_ctf_field *context)
485 {
486 int ret = 0;
487 struct bt_ctf_field_type *field_type = NULL;
488
489 if (!event || !context) {
490 ret = -1;
491 goto end;
492 }
493
494 field_type = bt_ctf_field_get_type(context);
495 if (field_type != event->event_class->context) {
496 ret = -1;
497 goto end;
498 }
499
500 bt_ctf_field_get(context);
501 bt_ctf_field_put(event->context_payload);
502 event->context_payload = context;
503 end:
504 if (field_type) {
505 bt_ctf_field_type_put(field_type);
506 }
507 return ret;
508 }
509
510 void bt_ctf_event_get(struct bt_ctf_event *event)
511 {
512 if (!event) {
513 return;
514 }
515
516 bt_ctf_ref_get(&event->ref_count);
517 }
518
519 void bt_ctf_event_put(struct bt_ctf_event *event)
520 {
521 if (!event) {
522 return;
523 }
524
525 bt_ctf_ref_put(&event->ref_count, bt_ctf_event_destroy);
526 }
527
528 static
529 void bt_ctf_event_class_destroy(struct bt_ctf_ref *ref)
530 {
531 struct bt_ctf_event_class *event_class;
532
533 if (!ref) {
534 return;
535 }
536
537 /*
538 * Don't call put() on the stream class. See comment in
539 * bt_ctf_event_class_set_stream_class for explanation.
540 */
541 event_class = container_of(ref, struct bt_ctf_event_class, ref_count);
542 if (event_class->context) {
543 bt_ctf_field_type_put(event_class->context);
544 }
545 if (event_class->fields) {
546 bt_ctf_field_type_put(event_class->fields);
547 }
548 g_free(event_class);
549 }
550
551 static
552 void bt_ctf_event_destroy(struct bt_ctf_ref *ref)
553 {
554 struct bt_ctf_event *event;
555
556 if (!ref) {
557 return;
558 }
559
560 event = container_of(ref, struct bt_ctf_event,
561 ref_count);
562 if (event->event_class) {
563 bt_ctf_event_class_put(event->event_class);
564 }
565 if (event->event_header) {
566 bt_ctf_field_put(event->event_header);
567 }
568 if (event->context_payload) {
569 bt_ctf_field_put(event->context_payload);
570 }
571 if (event->fields_payload) {
572 bt_ctf_field_put(event->fields_payload);
573 }
574 g_free(event);
575 }
576
577 static
578 int set_integer_field_value(struct bt_ctf_field* field, uint64_t value)
579 {
580 int ret = 0;
581 struct bt_ctf_field_type *field_type = NULL;
582
583 if (!field) {
584 ret = -1;
585 goto end;
586 }
587
588 if (!bt_ctf_field_validate(field)) {
589 /* Payload already set, skip! (not an error) */
590 goto end;
591 }
592
593 field_type = bt_ctf_field_get_type(field);
594 assert(field_type);
595
596 if (bt_ctf_field_type_get_type_id(field_type) != CTF_TYPE_INTEGER) {
597 /* Not an integer and the value is unset, error. */
598 ret = -1;
599 goto end;
600 }
601
602 if (bt_ctf_field_type_integer_get_signed(field_type)) {
603 ret = bt_ctf_field_signed_integer_set_value(field, (int64_t) value);
604 if (ret) {
605 /* Value is out of range, error. */
606 goto end;
607 }
608 } else {
609 ret = bt_ctf_field_unsigned_integer_set_value(field, value);
610 if (ret) {
611 /* Value is out of range, error. */
612 goto end;
613 }
614 }
615 end:
616 bt_ctf_field_type_put(field_type);
617 return ret;
618 }
619
620 BT_HIDDEN
621 void bt_ctf_event_class_freeze(struct bt_ctf_event_class *event_class)
622 {
623 assert(event_class);
624 event_class->frozen = 1;
625 bt_ctf_field_type_freeze(event_class->context);
626 bt_ctf_field_type_freeze(event_class->fields);
627 }
628
629 BT_HIDDEN
630 int bt_ctf_event_class_set_stream_class(struct bt_ctf_event_class *event_class,
631 struct bt_ctf_stream_class *stream_class)
632 {
633 int ret = 0;
634
635 if (!event_class) {
636 ret = -1;
637 goto end;
638 }
639
640 /* Allow a NULL stream_class to unset the current stream_class */
641 if (stream_class && event_class->stream_class) {
642 ret = -1;
643 goto end;
644 }
645
646 event_class->stream_class = stream_class;
647 /*
648 * We don't get() the stream_class since doing so would introduce
649 * a circular ownership between event classes and stream classes.
650 *
651 * A stream class will always unset itself from its events before
652 * being destroyed. This ensures that a user won't get a pointer
653 * to a stale stream class instance from an event class.
654 */
655 end:
656 return ret;
657 }
658
659 BT_HIDDEN
660 int bt_ctf_event_class_serialize(struct bt_ctf_event_class *event_class,
661 struct metadata_context *context)
662 {
663 int ret = 0;
664 int64_t stream_id;
665
666 assert(event_class);
667 assert(context);
668 stream_id = bt_ctf_stream_class_get_id(event_class->stream_class);
669 if (stream_id < 0) {
670 ret = -1;
671 goto end;
672 }
673
674 context->current_indentation_level = 1;
675 g_string_assign(context->field_name, "");
676 g_string_append_printf(context->string,
677 "event {\n\tname = \"%s\";\n\tid = %u;\n\tstream_id = %" PRId64 ";\n",
678 g_quark_to_string(event_class->name),
679 event_class->id,
680 stream_id);
681
682 if (event_class->context) {
683 g_string_append(context->string, "\tcontext := ");
684 ret = bt_ctf_field_type_serialize(event_class->context,
685 context);
686 if (ret) {
687 goto end;
688 }
689 g_string_append(context->string, ";\n");
690 }
691
692 if (event_class->fields) {
693 g_string_append(context->string, "\tfields := ");
694 ret = bt_ctf_field_type_serialize(event_class->fields, context);
695 if (ret) {
696 goto end;
697 }
698 g_string_append(context->string, ";\n");
699 }
700
701 g_string_append(context->string, "};\n\n");
702 end:
703 context->current_indentation_level = 0;
704 return ret;
705 }
706
707 BT_HIDDEN
708 int bt_ctf_event_validate(struct bt_ctf_event *event)
709 {
710 /* Make sure each field's payload has been set */
711 int ret;
712
713 assert(event);
714 ret = bt_ctf_field_validate(event->event_header);
715 if (ret) {
716 goto end;
717 }
718
719 ret = bt_ctf_field_validate(event->fields_payload);
720 if (ret) {
721 goto end;
722 }
723
724 if (event->event_class->context) {
725 ret = bt_ctf_field_validate(event->context_payload);
726 }
727 end:
728 return ret;
729 }
730
731 BT_HIDDEN
732 int bt_ctf_event_serialize(struct bt_ctf_event *event,
733 struct ctf_stream_pos *pos)
734 {
735 int ret = 0;
736
737 assert(event);
738 assert(pos);
739 if (event->context_payload) {
740 ret = bt_ctf_field_serialize(event->context_payload, pos);
741 if (ret) {
742 goto end;
743 }
744 }
745
746 if (event->fields_payload) {
747 ret = bt_ctf_field_serialize(event->fields_payload, pos);
748 if (ret) {
749 goto end;
750 }
751 }
752 end:
753 return ret;
754 }
755
756 BT_HIDDEN
757 int bt_ctf_event_set_timestamp(struct bt_ctf_event *event,
758 uint64_t timestamp)
759 {
760 int ret = 0;
761
762 assert(event);
763 if (event->timestamp) {
764 ret = -1;
765 goto end;
766 }
767
768 event->timestamp = timestamp;
769 end:
770 return ret;
771 }
772
773 BT_HIDDEN
774 uint64_t bt_ctf_event_get_timestamp(struct bt_ctf_event *event)
775 {
776 assert(event);
777 return event->timestamp;
778 }
779
780 BT_HIDDEN
781 int bt_ctf_event_populate_event_header(struct bt_ctf_event *event)
782 {
783 int ret = 0;
784 struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL;
785
786 if (!event) {
787 ret = -1;
788 goto end;
789 }
790
791 id_field = bt_ctf_field_structure_get_field(event->event_header, "id");
792 if (id_field) {
793 ret = set_integer_field_value(id_field,
794 (uint64_t) event->event_class->id);
795 if (ret) {
796 goto end;
797 }
798 }
799
800 timestamp_field = bt_ctf_field_structure_get_field(event->event_header,
801 "timestamp");
802 if (timestamp_field) {
803 ret = set_integer_field_value(timestamp_field,
804 (uint64_t) event->timestamp);
805 if (ret) {
806 goto end;
807 }
808 }
809 end:
810 if (id_field) {
811 bt_ctf_field_put(id_field);
812 }
813 if (timestamp_field) {
814 bt_ctf_field_put(timestamp_field);
815 }
816 return ret;
817 }
This page took 0.046368 seconds and 5 git commands to generate.