Fix: event, stream names can be strings
[babeltrace.git] / lib / ctf-ir / stream-class.c
1 /*
2 * stream-class.c
3 *
4 * Babeltrace CTF IR - Stream Class
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 #define BT_LOG_TAG "STREAM-CLASS"
30 #include <babeltrace/lib-logging-internal.h>
31
32 #include <babeltrace/ctf-writer/clock.h>
33 #include <babeltrace/ctf-writer/clock-internal.h>
34 #include <babeltrace/ctf-ir/clock-class-internal.h>
35 #include <babeltrace/ctf-writer/event.h>
36 #include <babeltrace/ctf-ir/event-class-internal.h>
37 #include <babeltrace/ctf-ir/event-internal.h>
38 #include <babeltrace/ctf-ir/field-types-internal.h>
39 #include <babeltrace/ctf-ir/fields-internal.h>
40 #include <babeltrace/ctf-writer/stream.h>
41 #include <babeltrace/ctf-ir/stream-class-internal.h>
42 #include <babeltrace/ctf-ir/validation-internal.h>
43 #include <babeltrace/ctf-ir/visitor-internal.h>
44 #include <babeltrace/ctf-writer/functor-internal.h>
45 #include <babeltrace/ctf-ir/utils.h>
46 #include <babeltrace/ref.h>
47 #include <babeltrace/compiler-internal.h>
48 #include <babeltrace/align-internal.h>
49 #include <babeltrace/endian-internal.h>
50 #include <inttypes.h>
51 #include <stdint.h>
52 #include <stdbool.h>
53
54 static
55 void bt_ctf_stream_class_destroy(struct bt_object *obj);
56 static
57 int init_event_header(struct bt_ctf_stream_class *stream_class);
58 static
59 int init_packet_context(struct bt_ctf_stream_class *stream_class);
60
61 struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name)
62 {
63 struct bt_ctf_stream_class *stream_class;
64 int ret;
65
66 BT_LOGD("Creating default stream class object: name=\"%s\"", name);
67 stream_class = bt_ctf_stream_class_create_empty(name);
68 if (!stream_class) {
69 BT_LOGD_STR("Cannot create empty stream class.");
70 goto error;
71 }
72
73 ret = init_event_header(stream_class);
74 if (ret) {
75 BT_LOGE_STR("Cannot initialize stream class's event header field type.");
76 goto error;
77 }
78
79 ret = init_packet_context(stream_class);
80 if (ret) {
81 BT_LOGE_STR("Cannot initialize stream class's packet context field type.");
82 goto error;
83 }
84
85 BT_LOGD("Created default stream class object: addr=%p, name=\"%s\"",
86 stream_class, name);
87 return stream_class;
88
89 error:
90 BT_PUT(stream_class);
91 return stream_class;
92 }
93
94 struct bt_ctf_stream_class *bt_ctf_stream_class_create_empty(const char *name)
95 {
96 struct bt_ctf_stream_class *stream_class = NULL;
97
98 BT_LOGD("Creating empty stream class object: name=\"%s\"", name);
99
100 stream_class = g_new0(struct bt_ctf_stream_class, 1);
101 if (!stream_class) {
102 BT_LOGE_STR("Failed to allocate one stream class.");
103 goto error;
104 }
105
106 stream_class->name = g_string_new(name);
107 stream_class->event_classes = g_ptr_array_new_with_free_func(
108 (GDestroyNotify) bt_object_release);
109 if (!stream_class->event_classes) {
110 BT_LOGE_STR("Failed to allocate a GPtrArray.");
111 goto error;
112 }
113
114 stream_class->event_classes_ht = g_hash_table_new_full(g_int64_hash,
115 g_int64_equal, g_free, NULL);
116 if (!stream_class->event_classes_ht) {
117 BT_LOGE_STR("Failed to allocate a GHashTable.");
118 goto error;
119 }
120
121 bt_object_init(stream_class, bt_ctf_stream_class_destroy);
122 BT_LOGD("Created empty stream class object: addr=%p, name=\"%s\"",
123 stream_class, name);
124 return stream_class;
125
126 error:
127 BT_PUT(stream_class);
128 return stream_class;
129 }
130
131 struct bt_ctf_trace *bt_ctf_stream_class_get_trace(
132 struct bt_ctf_stream_class *stream_class)
133 {
134 return stream_class ?
135 bt_get(bt_ctf_stream_class_borrow_trace(stream_class)) :
136 NULL;
137 }
138
139 const char *bt_ctf_stream_class_get_name(
140 struct bt_ctf_stream_class *stream_class)
141 {
142 const char *name = NULL;
143
144 if (!stream_class) {
145 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
146 goto end;
147 }
148
149 name = stream_class->name->str;
150 end:
151 return name;
152 }
153
154 int bt_ctf_stream_class_set_name(struct bt_ctf_stream_class *stream_class,
155 const char *name)
156 {
157 int ret = 0;
158
159 if (!stream_class) {
160 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
161 ret = -1;
162 goto end;
163 }
164
165 if (stream_class->frozen) {
166 BT_LOGW("Invalid parameter: stream class is frozen: "
167 "addr=%p, name=\"%s\", id=%" PRId64,
168 stream_class, bt_ctf_stream_class_get_name(stream_class),
169 bt_ctf_stream_class_get_id(stream_class));
170 ret = -1;
171 goto end;
172 }
173
174 g_string_assign(stream_class->name, name);
175 BT_LOGV("Set stream class's name: "
176 "addr=%p, name=\"%s\", id=%" PRId64,
177 stream_class, bt_ctf_stream_class_get_name(stream_class),
178 bt_ctf_stream_class_get_id(stream_class));
179 end:
180 return ret;
181 }
182
183 struct bt_ctf_clock *bt_ctf_stream_class_get_clock(
184 struct bt_ctf_stream_class *stream_class)
185 {
186 struct bt_ctf_clock *clock = NULL;
187
188 if (!stream_class) {
189 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
190 goto end;
191 }
192
193 if (!stream_class->clock) {
194 BT_LOGV("Stream class has no clock: "
195 "addr=%p, name=\"%s\", id=%" PRId64,
196 stream_class, bt_ctf_stream_class_get_name(stream_class),
197 bt_ctf_stream_class_get_id(stream_class));
198 goto end;
199 }
200
201 clock = bt_get(stream_class->clock);
202 end:
203 return clock;
204 }
205
206 int bt_ctf_stream_class_set_clock(struct bt_ctf_stream_class *stream_class,
207 struct bt_ctf_clock *clock)
208 {
209 int ret = 0;
210 struct bt_ctf_field_type *timestamp_field = NULL;
211
212 if (!stream_class || !clock) {
213 BT_LOGW("Invalid parameter: stream class or clock is NULL: "
214 "stream-class-addr=%p, clock-addr=%p",
215 stream_class, clock);
216 ret = -1;
217 goto end;
218 }
219
220 if (stream_class->frozen) {
221 BT_LOGW("Invalid parameter: stream class is frozen: "
222 "addr=%p, name=\"%s\", id=%" PRId64,
223 stream_class, bt_ctf_stream_class_get_name(stream_class),
224 bt_ctf_stream_class_get_id(stream_class));
225 ret = -1;
226 goto end;
227 }
228
229 /* Replace the current clock of this stream class. */
230 bt_put(stream_class->clock);
231 stream_class->clock = bt_get(clock);
232 BT_LOGV("Set stream class's clock: "
233 "addr=%p, name=\"%s\", id=%" PRId64 ", "
234 "clock-addr=%p, clock-name=\"%s\"",
235 stream_class, bt_ctf_stream_class_get_name(stream_class),
236 bt_ctf_stream_class_get_id(stream_class),
237 stream_class->clock,
238 bt_ctf_clock_get_name(stream_class->clock));
239
240 end:
241 bt_put(timestamp_field);
242 return ret;
243 }
244
245 int64_t bt_ctf_stream_class_get_id(struct bt_ctf_stream_class *stream_class)
246 {
247 int64_t ret;
248
249 if (!stream_class) {
250 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
251 ret = (int64_t) -1;
252 goto end;
253 }
254
255 if (!stream_class->id_set) {
256 BT_LOGV("Stream class's ID is not set: addr=%p, name=\"%s\"",
257 stream_class,
258 bt_ctf_stream_class_get_name(stream_class));
259 ret = (int64_t) -1;
260 goto end;
261 }
262
263 ret = stream_class->id;
264 end:
265 return ret;
266 }
267
268 BT_HIDDEN
269 void _bt_ctf_stream_class_set_id(
270 struct bt_ctf_stream_class *stream_class, int64_t id)
271 {
272 assert(stream_class);
273 stream_class->id = id;
274 stream_class->id_set = 1;
275 BT_LOGV("Set stream class's ID (internal): "
276 "addr=%p, name=\"%s\", id=%" PRId64,
277 stream_class, bt_ctf_stream_class_get_name(stream_class),
278 bt_ctf_stream_class_get_id(stream_class));
279 }
280
281 struct event_class_set_stream_class_id_data {
282 int64_t stream_class_id;
283 int ret;
284 };
285
286 static
287 void event_class_set_stream_id(gpointer event_class, gpointer data)
288 {
289 struct event_class_set_stream_class_id_data *typed_data = data;
290
291 typed_data->ret |= bt_ctf_event_class_set_stream_id(event_class,
292 typed_data->stream_class_id);
293 }
294
295 BT_HIDDEN
296 int bt_ctf_stream_class_set_id_no_check(
297 struct bt_ctf_stream_class *stream_class, int64_t id)
298 {
299 int ret = 0;
300 struct event_class_set_stream_class_id_data data =
301 { .stream_class_id = id, .ret = 0 };
302
303 /*
304 * Make sure all event classes have their "stream_id" attribute
305 * set to this value.
306 */
307 g_ptr_array_foreach(stream_class->event_classes,
308 event_class_set_stream_id, &data);
309 ret = data.ret;
310 if (ret) {
311 BT_LOGE("Cannot set the IDs of all stream class's event classes: "
312 "addr=%p, name=\"%s\", id=%" PRId64,
313 stream_class, bt_ctf_stream_class_get_name(stream_class),
314 bt_ctf_stream_class_get_id(stream_class));
315 goto end;
316 }
317
318 _bt_ctf_stream_class_set_id(stream_class, id);
319 end:
320 return ret;
321 }
322
323 int bt_ctf_stream_class_set_id(struct bt_ctf_stream_class *stream_class,
324 uint64_t id_param)
325 {
326 int ret = 0;
327 int64_t id = (int64_t) id_param;
328
329 if (!stream_class) {
330 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
331 ret = -1;
332 goto end;
333 }
334
335 if (stream_class->frozen) {
336 BT_LOGW("Invalid parameter: stream class is frozen: "
337 "addr=%p, name=\"%s\", id=%" PRId64,
338 stream_class, bt_ctf_stream_class_get_name(stream_class),
339 bt_ctf_stream_class_get_id(stream_class));
340 ret = -1;
341 goto end;
342 }
343
344 if (id < 0) {
345 BT_LOGW("Invalid parameter: invalid stream class's ID: "
346 "stream-class-addr=%p, stream-class-name=\"%s\", "
347 "stream-class-id=%" PRId64 ", id=%" PRIu64,
348 stream_class, bt_ctf_stream_class_get_name(stream_class),
349 bt_ctf_stream_class_get_id(stream_class),
350 id_param);
351 ret = -1;
352 goto end;
353 }
354
355 ret = bt_ctf_stream_class_set_id_no_check(stream_class, id);
356 if (ret == 0) {
357 BT_LOGV("Set stream class's ID: "
358 "addr=%p, name=\"%s\", id=%" PRId64,
359 stream_class, bt_ctf_stream_class_get_name(stream_class),
360 bt_ctf_stream_class_get_id(stream_class));
361 }
362 end:
363 return ret;
364 }
365
366 static
367 void event_class_exists(gpointer element, gpointer query)
368 {
369 struct bt_ctf_event_class *event_class_a = element;
370 struct search_query *search_query = query;
371 struct bt_ctf_event_class *event_class_b = search_query->value;
372 int64_t id_a, id_b;
373
374 if (search_query->value == element) {
375 search_query->found = 1;
376 goto end;
377 }
378
379 /*
380 * Two event classes cannot share the same ID in a given
381 * stream class.
382 */
383 id_a = bt_ctf_event_class_get_id(event_class_a);
384 id_b = bt_ctf_event_class_get_id(event_class_b);
385
386 if (id_a < 0 || id_b < 0) {
387 /* at least one ID is not set: will be automatically set later */
388 goto end;
389 }
390
391 if (id_a == id_b) {
392 BT_LOGW("Event class with this ID already exists in the stream class: "
393 "id=%" PRId64 ", name=\"%s\"",
394 id_a, bt_ctf_event_class_get_name(event_class_a));
395 search_query->found = 1;
396 goto end;
397 }
398
399 end:
400 return;
401 }
402
403 int bt_ctf_stream_class_add_event_class(
404 struct bt_ctf_stream_class *stream_class,
405 struct bt_ctf_event_class *event_class)
406 {
407 int ret = 0;
408 int64_t *event_id = NULL;
409 struct bt_ctf_trace *trace = NULL;
410 struct bt_ctf_stream_class *old_stream_class = NULL;
411 struct bt_ctf_validation_output validation_output = { 0 };
412 struct bt_ctf_field_type *packet_header_type = NULL;
413 struct bt_ctf_field_type *packet_context_type = NULL;
414 struct bt_ctf_field_type *event_header_type = NULL;
415 struct bt_ctf_field_type *stream_event_ctx_type = NULL;
416 struct bt_ctf_field_type *event_context_type = NULL;
417 struct bt_ctf_field_type *event_payload_type = NULL;
418 const enum bt_ctf_validation_flag validation_flags =
419 BT_CTF_VALIDATION_FLAG_EVENT;
420
421 if (!stream_class || !event_class) {
422 BT_LOGW("Invalid parameter: stream class or event class is NULL: "
423 "stream-class-addr=%p, event-class-addr=%p",
424 stream_class, event_class);
425 ret = -1;
426 goto end;
427 }
428
429 BT_LOGD("Adding event class to stream class: "
430 "stream-class-addr=%p, stream-class-name=\"%s\", "
431 "stream-class-id=%" PRId64 ", event-class-addr=%p, "
432 "event-class-name=\"%s\", event-class-id=%" PRId64,
433 stream_class, bt_ctf_stream_class_get_name(stream_class),
434 bt_ctf_stream_class_get_id(stream_class),
435 event_class,
436 bt_ctf_event_class_get_name(event_class),
437 bt_ctf_event_class_get_id(event_class));
438
439 trace = bt_ctf_stream_class_get_trace(stream_class);
440 if (trace && trace->is_static) {
441 ret = -1;
442 goto end;
443 }
444
445 event_id = g_new(int64_t, 1);
446 if (!event_id) {
447 BT_LOGE_STR("Failed to allocate one int64_t.");
448 ret = -1;
449 goto end;
450 }
451
452 /* Check for duplicate event classes */
453 struct search_query query = { .value = event_class, .found = 0 };
454 g_ptr_array_foreach(stream_class->event_classes, event_class_exists,
455 &query);
456 if (query.found) {
457 BT_LOGW_STR("Another event class part of this stream class has the same ID.");
458 ret = -1;
459 goto end;
460 }
461
462 old_stream_class = bt_ctf_event_class_get_stream_class(event_class);
463 if (old_stream_class) {
464 /* Event class is already associated to a stream class. */
465 BT_LOGW("Event class is already part of another stream class: "
466 "event-class-stream-class-addr=%p, "
467 "event-class-stream-class-name=\"%s\", "
468 "event-class-stream-class-id=%" PRId64,
469 old_stream_class,
470 bt_ctf_stream_class_get_name(old_stream_class),
471 bt_ctf_stream_class_get_id(old_stream_class));
472 ret = -1;
473 goto end;
474 }
475
476 if (trace) {
477 /*
478 * If the stream class is associated with a trace, then
479 * both those objects are frozen. Also, this event class
480 * is about to be frozen.
481 *
482 * Therefore the event class must be validated here.
483 * The trace and stream class should be valid at this
484 * point.
485 */
486 assert(trace->valid);
487 assert(stream_class->valid);
488 packet_header_type =
489 bt_ctf_trace_get_packet_header_type(trace);
490 packet_context_type =
491 bt_ctf_stream_class_get_packet_context_type(
492 stream_class);
493 event_header_type =
494 bt_ctf_stream_class_get_event_header_type(stream_class);
495 stream_event_ctx_type =
496 bt_ctf_stream_class_get_event_context_type(
497 stream_class);
498 event_context_type =
499 bt_ctf_event_class_get_context_type(event_class);
500 event_payload_type =
501 bt_ctf_event_class_get_payload_type(event_class);
502 ret = bt_ctf_validate_class_types(
503 trace->environment, packet_header_type,
504 packet_context_type, event_header_type,
505 stream_event_ctx_type, event_context_type,
506 event_payload_type, trace->valid,
507 stream_class->valid, event_class->valid,
508 &validation_output, validation_flags);
509 BT_PUT(packet_header_type);
510 BT_PUT(packet_context_type);
511 BT_PUT(event_header_type);
512 BT_PUT(stream_event_ctx_type);
513 BT_PUT(event_context_type);
514 BT_PUT(event_payload_type);
515
516 if (ret) {
517 /*
518 * This means something went wrong during the
519 * validation process, not that the objects are
520 * invalid.
521 */
522 BT_LOGE("Failed to validate event class: ret=%d", ret);
523 goto end;
524 }
525
526 if ((validation_output.valid_flags & validation_flags) !=
527 validation_flags) {
528 /* Invalid event class */
529 BT_LOGW("Invalid trace, stream class, or event class: "
530 "valid-flags=0x%x",
531 validation_output.valid_flags);
532 ret = -1;
533 goto end;
534 }
535 }
536
537 /* Only set an event ID if none was explicitly set before */
538 *event_id = bt_ctf_event_class_get_id(event_class);
539 if (*event_id < 0) {
540 BT_LOGV("Event class has no ID: automatically setting it: "
541 "id=%" PRId64, stream_class->next_event_id);
542
543 if (bt_ctf_event_class_set_id(event_class,
544 stream_class->next_event_id)) {
545 BT_LOGE("Cannot set event class's ID: id=%" PRId64,
546 stream_class->next_event_id);
547 ret = -1;
548 goto end;
549 }
550 stream_class->next_event_id++;
551 *event_id = stream_class->next_event_id;
552 }
553
554 ret = bt_ctf_event_class_set_stream_id(event_class, stream_class->id);
555 if (ret) {
556 BT_LOGE("Cannot set event class's stream class ID attribute: ret=%d",
557 ret);
558 goto end;
559 }
560
561 bt_object_set_parent(event_class, stream_class);
562
563 if (trace) {
564 /*
565 * At this point we know that the function will be
566 * successful. Therefore we can replace the event
567 * class's field types with what's in the validation
568 * output structure and mark this event class as valid.
569 */
570 bt_ctf_validation_replace_types(NULL, NULL, event_class,
571 &validation_output, validation_flags);
572 event_class->valid = 1;
573
574 /*
575 * Put what was not moved in
576 * bt_ctf_validation_replace_types().
577 */
578 bt_ctf_validation_output_put_types(&validation_output);
579 }
580
581 /* Add to the event classes of the stream class */
582 g_ptr_array_add(stream_class->event_classes, event_class);
583 g_hash_table_insert(stream_class->event_classes_ht, event_id,
584 event_class);
585 event_id = NULL;
586
587 /* Freeze the event class */
588 bt_ctf_event_class_freeze(event_class);
589
590 /* Notifiy listeners of the trace's schema modification. */
591 if (trace) {
592 struct bt_ctf_object obj = { .object = event_class,
593 .type = BT_CTF_OBJECT_TYPE_EVENT_CLASS };
594
595 (void) bt_ctf_trace_object_modification(&obj, trace);
596 }
597
598 BT_LOGD("Added event class to stream class: "
599 "stream-class-addr=%p, stream-class-name=\"%s\", "
600 "stream-class-id=%" PRId64 ", event-class-addr=%p, "
601 "event-class-name=\"%s\", event-class-id=%" PRId64,
602 stream_class, bt_ctf_stream_class_get_name(stream_class),
603 bt_ctf_stream_class_get_id(stream_class),
604 event_class,
605 bt_ctf_event_class_get_name(event_class),
606 bt_ctf_event_class_get_id(event_class));
607
608 end:
609 BT_PUT(trace);
610 BT_PUT(old_stream_class);
611 bt_ctf_validation_output_put_types(&validation_output);
612 assert(!packet_header_type);
613 assert(!packet_context_type);
614 assert(!event_header_type);
615 assert(!stream_event_ctx_type);
616 assert(!event_context_type);
617 assert(!event_payload_type);
618 g_free(event_id);
619
620 return ret;
621 }
622
623 int64_t bt_ctf_stream_class_get_event_class_count(
624 struct bt_ctf_stream_class *stream_class)
625 {
626 int64_t ret;
627
628 if (!stream_class) {
629 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
630 ret = (int64_t) -1;
631 goto end;
632 }
633
634 ret = (int64_t) stream_class->event_classes->len;
635 end:
636 return ret;
637 }
638
639 struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_index(
640 struct bt_ctf_stream_class *stream_class, uint64_t index)
641 {
642 struct bt_ctf_event_class *event_class = NULL;
643
644 if (!stream_class) {
645 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
646 goto end;
647 }
648
649 if (index >= stream_class->event_classes->len) {
650 BT_LOGW("Invalid parameter: index is out of bounds: "
651 "addr=%p, name=\"%s\", id=%" PRId64 ", "
652 "index=%" PRIu64 ", count=%u",
653 stream_class, bt_ctf_stream_class_get_name(stream_class),
654 bt_ctf_stream_class_get_id(stream_class),
655 index, stream_class->event_classes->len);
656 goto end;
657 }
658
659 event_class = g_ptr_array_index(stream_class->event_classes, index);
660 bt_get(event_class);
661 end:
662 return event_class;
663 }
664
665 struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id(
666 struct bt_ctf_stream_class *stream_class, uint64_t id)
667 {
668 int64_t id_key = (int64_t) id;
669 struct bt_ctf_event_class *event_class = NULL;
670
671 if (!stream_class) {
672 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
673 goto end;
674 }
675
676 if (id_key < 0) {
677 BT_LOGW("Invalid parameter: invalid event class's ID: "
678 "stream-class-addr=%p, stream-class-name=\"%s\", "
679 "stream-class-id=%" PRId64 ", event-class-id=%" PRIu64,
680 stream_class,
681 bt_ctf_stream_class_get_name(stream_class),
682 bt_ctf_stream_class_get_id(stream_class), id);
683 goto end;
684 }
685
686 event_class = g_hash_table_lookup(stream_class->event_classes_ht,
687 &id_key);
688 bt_get(event_class);
689 end:
690 return event_class;
691 }
692
693 struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type(
694 struct bt_ctf_stream_class *stream_class)
695 {
696 struct bt_ctf_field_type *ret = NULL;
697
698 if (!stream_class) {
699 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
700 goto end;
701 }
702
703 bt_get(stream_class->packet_context_type);
704 ret = stream_class->packet_context_type;
705 end:
706 return ret;
707 }
708
709 int bt_ctf_stream_class_set_packet_context_type(
710 struct bt_ctf_stream_class *stream_class,
711 struct bt_ctf_field_type *packet_context_type)
712 {
713 int ret = 0;
714
715 if (!stream_class) {
716 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
717 ret = -1;
718 goto end;
719 }
720
721 if (stream_class->frozen) {
722 BT_LOGW("Invalid parameter: stream class is frozen: "
723 "addr=%p, name=\"%s\", id=%" PRId64,
724 stream_class, bt_ctf_stream_class_get_name(stream_class),
725 bt_ctf_stream_class_get_id(stream_class));
726 ret = -1;
727 goto end;
728 }
729
730 if (packet_context_type &&
731 bt_ctf_field_type_get_type_id(packet_context_type) !=
732 BT_CTF_FIELD_TYPE_ID_STRUCT) {
733 /* A packet context must be a structure. */
734 BT_LOGW("Invalid parameter: stream class's packet context field type must be a structure: "
735 "addr=%p, name=\"%s\", id=%" PRId64 ", "
736 "packet-context-ft-addr=%p, packet-context-ft-id=%s",
737 stream_class, bt_ctf_stream_class_get_name(stream_class),
738 bt_ctf_stream_class_get_id(stream_class),
739 packet_context_type,
740 bt_ctf_field_type_id_string(
741 bt_ctf_field_type_get_type_id(packet_context_type)));
742 ret = -1;
743 goto end;
744 }
745
746 bt_put(stream_class->packet_context_type);
747 bt_get(packet_context_type);
748 stream_class->packet_context_type = packet_context_type;
749 BT_LOGV("Set stream class's packet context field type: "
750 "addr=%p, name=\"%s\", id=%" PRId64 ", "
751 "packet-context-ft-addr=%p",
752 stream_class, bt_ctf_stream_class_get_name(stream_class),
753 bt_ctf_stream_class_get_id(stream_class),
754 packet_context_type);
755
756 end:
757 return ret;
758 }
759
760 struct bt_ctf_field_type *bt_ctf_stream_class_get_event_header_type(
761 struct bt_ctf_stream_class *stream_class)
762 {
763 struct bt_ctf_field_type *ret = NULL;
764
765 if (!stream_class) {
766 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
767 goto end;
768 }
769
770 if (!stream_class->event_header_type) {
771 BT_LOGV("Stream class has no event header field type: "
772 "addr=%p, name=\"%s\", id=%" PRId64,
773 stream_class, bt_ctf_stream_class_get_name(stream_class),
774 bt_ctf_stream_class_get_id(stream_class));
775 goto end;
776 }
777
778 bt_get(stream_class->event_header_type);
779 ret = stream_class->event_header_type;
780 end:
781 return ret;
782 }
783
784 int bt_ctf_stream_class_set_event_header_type(
785 struct bt_ctf_stream_class *stream_class,
786 struct bt_ctf_field_type *event_header_type)
787 {
788 int ret = 0;
789
790 if (!stream_class) {
791 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
792 ret = -1;
793 goto end;
794 }
795
796 if (stream_class->frozen) {
797 BT_LOGW("Invalid parameter: stream class is frozen: "
798 "addr=%p, name=\"%s\", id=%" PRId64,
799 stream_class, bt_ctf_stream_class_get_name(stream_class),
800 bt_ctf_stream_class_get_id(stream_class));
801 ret = -1;
802 goto end;
803 }
804
805 if (event_header_type &&
806 bt_ctf_field_type_get_type_id(event_header_type) !=
807 BT_CTF_FIELD_TYPE_ID_STRUCT) {
808 /* An event header must be a structure. */
809 BT_LOGW("Invalid parameter: stream class's event header field type must be a structure: "
810 "addr=%p, name=\"%s\", id=%" PRId64 ", "
811 "event-header-ft-addr=%p, event-header-ft-id=%s",
812 stream_class, bt_ctf_stream_class_get_name(stream_class),
813 bt_ctf_stream_class_get_id(stream_class),
814 event_header_type,
815 bt_ctf_field_type_id_string(
816 bt_ctf_field_type_get_type_id(event_header_type)));
817 ret = -1;
818 goto end;
819 }
820
821 bt_put(stream_class->event_header_type);
822 stream_class->event_header_type = bt_get(event_header_type);
823 BT_LOGV("Set stream class's event header field type: "
824 "addr=%p, name=\"%s\", id=%" PRId64 ", "
825 "event-header-ft-addr=%p",
826 stream_class, bt_ctf_stream_class_get_name(stream_class),
827 bt_ctf_stream_class_get_id(stream_class),
828 event_header_type);
829 end:
830 return ret;
831 }
832
833 struct bt_ctf_field_type *bt_ctf_stream_class_get_event_context_type(
834 struct bt_ctf_stream_class *stream_class)
835 {
836 struct bt_ctf_field_type *ret = NULL;
837
838 if (!stream_class) {
839 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
840 goto end;
841 }
842
843 if (!stream_class->event_context_type) {
844 goto end;
845 }
846
847 bt_get(stream_class->event_context_type);
848 ret = stream_class->event_context_type;
849 end:
850 return ret;
851 }
852
853 int bt_ctf_stream_class_set_event_context_type(
854 struct bt_ctf_stream_class *stream_class,
855 struct bt_ctf_field_type *event_context_type)
856 {
857 int ret = 0;
858
859 if (!stream_class) {
860 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
861 ret = -1;
862 goto end;
863 }
864
865 if (stream_class->frozen) {
866 BT_LOGW("Invalid parameter: stream class is frozen: "
867 "addr=%p, name=\"%s\", id=%" PRId64,
868 stream_class, bt_ctf_stream_class_get_name(stream_class),
869 bt_ctf_stream_class_get_id(stream_class));
870 ret = -1;
871 goto end;
872 }
873
874 if (event_context_type &&
875 bt_ctf_field_type_get_type_id(event_context_type) !=
876 BT_CTF_FIELD_TYPE_ID_STRUCT) {
877 /* A packet context must be a structure. */
878 BT_LOGW("Invalid parameter: stream class's event context field type must be a structure: "
879 "addr=%p, name=\"%s\", id=%" PRId64 ", "
880 "event-context-ft-addr=%p, event-context-ft-id=%s",
881 stream_class, bt_ctf_stream_class_get_name(stream_class),
882 bt_ctf_stream_class_get_id(stream_class),
883 event_context_type,
884 bt_ctf_field_type_id_string(
885 bt_ctf_field_type_get_type_id(event_context_type)));
886 ret = -1;
887 goto end;
888 }
889
890 bt_put(stream_class->event_context_type);
891 stream_class->event_context_type = bt_get(event_context_type);
892 BT_LOGV("Set stream class's event context field type: "
893 "addr=%p, name=\"%s\", id=%" PRId64 ", "
894 "event-context-ft-addr=%p",
895 stream_class, bt_ctf_stream_class_get_name(stream_class),
896 bt_ctf_stream_class_get_id(stream_class),
897 event_context_type);
898 end:
899 return ret;
900 }
901
902 /* Pre-2.0 CTF writer backward compatibility */
903 void bt_ctf_stream_class_get(struct bt_ctf_stream_class *stream_class)
904 {
905 bt_get(stream_class);
906 }
907
908 /* Pre-2.0 CTF writer backward compatibility */
909 void bt_ctf_stream_class_put(struct bt_ctf_stream_class *stream_class)
910 {
911 bt_put(stream_class);
912 }
913
914 static
915 int64_t get_event_class_count(void *element)
916 {
917 return bt_ctf_stream_class_get_event_class_count(
918 (struct bt_ctf_stream_class *) element);
919 }
920
921 static
922 void *get_event_class(void *element, int i)
923 {
924 return bt_ctf_stream_class_get_event_class_by_index(
925 (struct bt_ctf_stream_class *) element, i);
926 }
927
928 static
929 int visit_event_class(void *object, bt_ctf_visitor visitor,void *data)
930 {
931 struct bt_ctf_object obj =
932 { .object = object,
933 .type = BT_CTF_OBJECT_TYPE_EVENT_CLASS };
934
935 return visitor(&obj, data);
936 }
937
938 int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class,
939 bt_ctf_visitor visitor, void *data)
940 {
941 int ret;
942 struct bt_ctf_object obj =
943 { .object = stream_class,
944 .type = BT_CTF_OBJECT_TYPE_STREAM_CLASS };
945
946 if (!stream_class || !visitor) {
947 BT_LOGW("Invalid parameter: stream class or visitor is NULL: "
948 "stream-class-addr=%p, visitor=%p",
949 stream_class, visitor);
950 ret = -1;
951 goto end;
952 }
953
954 ret = visitor_helper(&obj, get_event_class_count,
955 get_event_class,
956 visit_event_class, visitor, data);
957 BT_LOGV("visitor_helper() returned: ret=%d", ret);
958 end:
959 return ret;
960 }
961
962 BT_HIDDEN
963 void bt_ctf_stream_class_freeze(struct bt_ctf_stream_class *stream_class)
964 {
965 if (!stream_class || stream_class->frozen) {
966 return;
967 }
968
969 BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64,
970 stream_class, bt_ctf_stream_class_get_name(stream_class),
971 bt_ctf_stream_class_get_id(stream_class));
972 stream_class->frozen = 1;
973 bt_ctf_field_type_freeze(stream_class->event_header_type);
974 bt_ctf_field_type_freeze(stream_class->packet_context_type);
975 bt_ctf_field_type_freeze(stream_class->event_context_type);
976
977 if (stream_class->clock) {
978 bt_ctf_clock_class_freeze(stream_class->clock->clock_class);
979 }
980 }
981
982 BT_HIDDEN
983 int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class,
984 struct metadata_context *context)
985 {
986 int ret = 0;
987 size_t i;
988
989 BT_LOGD("Serializing stream class's metadata: "
990 "stream-class-addr=%p, stream-class-name=\"%s\", "
991 "stream-class-id=%" PRId64 ", metadata-context-addr=%p",
992 stream_class, bt_ctf_stream_class_get_name(stream_class),
993 bt_ctf_stream_class_get_id(stream_class), context);
994 g_string_assign(context->field_name, "");
995 context->current_indentation_level = 1;
996 if (!stream_class->id_set) {
997 BT_LOGW_STR("Stream class's ID is not set.");
998 ret = -1;
999 goto end;
1000 }
1001
1002 g_string_append_printf(context->string,
1003 "stream {\n\tid = %" PRId64 ";\n", stream_class->id);
1004 if (stream_class->event_header_type) {
1005 BT_LOGD_STR("Serializing stream class's event header field type's metadata.");
1006 g_string_append(context->string, "\tevent.header := ");
1007 ret = bt_ctf_field_type_serialize(stream_class->event_header_type,
1008 context);
1009 if (ret) {
1010 BT_LOGW("Cannot serialize stream class's event header field type's metadata: "
1011 "ret=%d", ret);
1012 goto end;
1013 }
1014 g_string_append(context->string, ";");
1015 }
1016
1017
1018 if (stream_class->packet_context_type) {
1019 BT_LOGD_STR("Serializing stream class's packet context field type's metadata.");
1020 g_string_append(context->string, "\n\n\tpacket.context := ");
1021 ret = bt_ctf_field_type_serialize(stream_class->packet_context_type,
1022 context);
1023 if (ret) {
1024 BT_LOGW("Cannot serialize stream class's packet context field type's metadata: "
1025 "ret=%d", ret);
1026 goto end;
1027 }
1028 g_string_append(context->string, ";");
1029 }
1030
1031 if (stream_class->event_context_type) {
1032 BT_LOGD_STR("Serializing stream class's event context field type's metadata.");
1033 g_string_append(context->string, "\n\n\tevent.context := ");
1034 ret = bt_ctf_field_type_serialize(
1035 stream_class->event_context_type, context);
1036 if (ret) {
1037 BT_LOGW("Cannot serialize stream class's event context field type's metadata: "
1038 "ret=%d", ret);
1039 goto end;
1040 }
1041 g_string_append(context->string, ";");
1042 }
1043
1044 g_string_append(context->string, "\n};\n\n");
1045
1046 for (i = 0; i < stream_class->event_classes->len; i++) {
1047 struct bt_ctf_event_class *event_class =
1048 stream_class->event_classes->pdata[i];
1049
1050 ret = bt_ctf_event_class_serialize(event_class, context);
1051 if (ret) {
1052 BT_LOGW("Cannot serialize event class's metadata: "
1053 "event-class-addr=%p, event-class-name=\"%s\", "
1054 "event-class-id=%" PRId64,
1055 event_class,
1056 bt_ctf_event_class_get_name(event_class),
1057 bt_ctf_event_class_get_id(event_class));
1058 goto end;
1059 }
1060 }
1061 end:
1062 context->current_indentation_level = 0;
1063 return ret;
1064 }
1065
1066 static
1067 void bt_ctf_stream_class_destroy(struct bt_object *obj)
1068 {
1069 struct bt_ctf_stream_class *stream_class;
1070
1071 stream_class = container_of(obj, struct bt_ctf_stream_class, base);
1072 BT_LOGD("Destroying stream class: addr=%p, name=\"%s\", id=%" PRId64,
1073 stream_class, bt_ctf_stream_class_get_name(stream_class),
1074 bt_ctf_stream_class_get_id(stream_class));
1075 bt_put(stream_class->clock);
1076
1077 if (stream_class->event_classes_ht) {
1078 g_hash_table_destroy(stream_class->event_classes_ht);
1079 }
1080 if (stream_class->event_classes) {
1081 BT_LOGD_STR("Destroying event classes.");
1082 g_ptr_array_free(stream_class->event_classes, TRUE);
1083 }
1084
1085 if (stream_class->name) {
1086 g_string_free(stream_class->name, TRUE);
1087 }
1088
1089 BT_LOGD_STR("Putting event header field type.");
1090 bt_put(stream_class->event_header_type);
1091 BT_LOGD_STR("Putting packet context field type.");
1092 bt_put(stream_class->packet_context_type);
1093 BT_LOGD_STR("Putting event context field type.");
1094 bt_put(stream_class->event_context_type);
1095 g_free(stream_class);
1096 }
1097
1098 static
1099 int init_event_header(struct bt_ctf_stream_class *stream_class)
1100 {
1101 int ret = 0;
1102 struct bt_ctf_field_type *event_header_type =
1103 bt_ctf_field_type_structure_create();
1104 struct bt_ctf_field_type *_uint32_t =
1105 get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
1106 struct bt_ctf_field_type *_uint64_t =
1107 get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
1108
1109 if (!event_header_type) {
1110 BT_LOGE_STR("Cannot create empty structure field type.");
1111 ret = -1;
1112 goto end;
1113 }
1114
1115 ret = bt_ctf_field_type_structure_add_field(event_header_type,
1116 _uint32_t, "id");
1117 if (ret) {
1118 BT_LOGE_STR("Cannot add `id` field to event header field type.");
1119 goto end;
1120 }
1121
1122 ret = bt_ctf_field_type_structure_add_field(event_header_type,
1123 _uint64_t, "timestamp");
1124 if (ret) {
1125 BT_LOGE_STR("Cannot add `timestamp` field to event header field type.");
1126 goto end;
1127 }
1128
1129 BT_MOVE(stream_class->event_header_type, event_header_type);
1130 end:
1131 if (ret) {
1132 bt_put(event_header_type);
1133 }
1134
1135 bt_put(_uint32_t);
1136 bt_put(_uint64_t);
1137 return ret;
1138 }
1139
1140 static
1141 int init_packet_context(struct bt_ctf_stream_class *stream_class)
1142 {
1143 int ret = 0;
1144 struct bt_ctf_field_type *packet_context_type =
1145 bt_ctf_field_type_structure_create();
1146 struct bt_ctf_field_type *_uint64_t =
1147 get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
1148 struct bt_ctf_field_type *ts_begin_end_uint64_t;
1149
1150 if (!packet_context_type) {
1151 BT_LOGE_STR("Cannot create empty structure field type.");
1152 ret = -1;
1153 goto end;
1154 }
1155
1156 ts_begin_end_uint64_t = bt_ctf_field_type_copy(_uint64_t);
1157 if (!ts_begin_end_uint64_t) {
1158 BT_LOGE_STR("Cannot copy integer field type for `timestamp_begin` and `timestamp_end` fields.");
1159 ret = -1;
1160 goto end;
1161 }
1162
1163 /*
1164 * We create a stream packet context as proposed in the CTF
1165 * specification.
1166 */
1167 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
1168 ts_begin_end_uint64_t, "timestamp_begin");
1169 if (ret) {
1170 BT_LOGE_STR("Cannot add `timestamp_begin` field to event header field type.");
1171 goto end;
1172 }
1173
1174 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
1175 ts_begin_end_uint64_t, "timestamp_end");
1176 if (ret) {
1177 BT_LOGE_STR("Cannot add `timestamp_end` field to event header field type.");
1178 goto end;
1179 }
1180
1181 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
1182 _uint64_t, "content_size");
1183 if (ret) {
1184 BT_LOGE_STR("Cannot add `content_size` field to event header field type.");
1185 goto end;
1186 }
1187
1188 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
1189 _uint64_t, "packet_size");
1190 if (ret) {
1191 BT_LOGE_STR("Cannot add `packet_size` field to event header field type.");
1192 goto end;
1193 }
1194
1195 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
1196 _uint64_t, "events_discarded");
1197 if (ret) {
1198 BT_LOGE_STR("Cannot add `events_discarded` field to event header field type.");
1199 goto end;
1200 }
1201
1202 BT_MOVE(stream_class->packet_context_type, packet_context_type);
1203 end:
1204 if (ret) {
1205 bt_put(packet_context_type);
1206 goto end;
1207 }
1208
1209 bt_put(_uint64_t);
1210 bt_put(ts_begin_end_uint64_t);
1211 return ret;
1212 }
1213
1214 static
1215 int try_map_clock_class(struct bt_ctf_stream_class *stream_class,
1216 struct bt_ctf_field_type *ft)
1217 {
1218 struct bt_ctf_clock_class *mapped_clock_class = NULL;
1219 int ret = 0;
1220
1221 if (!ft) {
1222 /* Field does not exist: not an error */
1223 goto end;
1224 }
1225
1226 assert(bt_ctf_field_type_is_integer(ft));
1227 mapped_clock_class =
1228 bt_ctf_field_type_integer_get_mapped_clock_class(ft);
1229 if (!mapped_clock_class) {
1230 if (!stream_class->clock) {
1231 BT_LOGW("Cannot automatically set field's type mapped clock class: stream class's clock is not set: "
1232 "stream-class-addr=%p, stream-class-name=\"%s\", "
1233 "stream-class-id=%" PRId64 ", ft-addr=%p",
1234 stream_class, bt_ctf_stream_class_get_name(stream_class),
1235 bt_ctf_stream_class_get_id(stream_class), ft);
1236 ret = -1;
1237 goto end;
1238 }
1239
1240 ret = bt_ctf_field_type_integer_set_mapped_clock_class_no_check(
1241 ft, stream_class->clock->clock_class);
1242 if (ret) {
1243 BT_LOGW("Cannot set field type's mapped clock class: "
1244 "stream-class-addr=%p, stream-class-name=\"%s\", "
1245 "stream-class-id=%" PRId64 ", ft-addr=%p",
1246 stream_class, bt_ctf_stream_class_get_name(stream_class),
1247 bt_ctf_stream_class_get_id(stream_class), ft);
1248 goto end;
1249 }
1250
1251 BT_LOGV("Automatically mapped field type to stream class's clock class: "
1252 "stream-class-addr=%p, stream-class-name=\"%s\", "
1253 "stream-class-id=%" PRId64 ", ft-addr=%p",
1254 stream_class, bt_ctf_stream_class_get_name(stream_class),
1255 bt_ctf_stream_class_get_id(stream_class), ft);
1256 }
1257
1258 end:
1259 bt_put(mapped_clock_class);
1260 return ret;
1261 }
1262
1263 BT_HIDDEN
1264 int bt_ctf_stream_class_map_clock_class(
1265 struct bt_ctf_stream_class *stream_class,
1266 struct bt_ctf_field_type *packet_context_type,
1267 struct bt_ctf_field_type *event_header_type)
1268 {
1269 struct bt_ctf_field_type *ft = NULL;
1270 int ret = 0;
1271
1272 assert(stream_class);
1273
1274 if (packet_context_type) {
1275 ft = bt_ctf_field_type_structure_get_field_type_by_name(
1276 packet_context_type, "timestamp_begin");
1277 if (try_map_clock_class(stream_class, ft)) {
1278 BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_begin` field's mapped clock class.");
1279 ret = -1;
1280 goto end;
1281 }
1282
1283 bt_put(ft);
1284 ft = bt_ctf_field_type_structure_get_field_type_by_name(
1285 packet_context_type, "timestamp_end");
1286 if (try_map_clock_class(stream_class, ft)) {
1287 BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_end` field's mapped clock class.");
1288 ret = -1;
1289 goto end;
1290 }
1291
1292 BT_PUT(ft);
1293 }
1294
1295 if (event_header_type) {
1296 ft = bt_ctf_field_type_structure_get_field_type_by_name(
1297 event_header_type, "timestamp");
1298 if (try_map_clock_class(stream_class, ft)) {
1299 BT_LOGE_STR("Cannot automatically set stream class's event header field type's `timestamp` field's mapped clock class.");
1300 ret = -1;
1301 goto end;
1302 }
1303
1304 BT_PUT(ft);
1305 }
1306
1307 end:
1308 return ret;
1309 }
This page took 0.067613 seconds and 4 git commands to generate.