Remove the concept of event class attributes
[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 BT_HIDDEN
287 int bt_ctf_stream_class_set_id_no_check(
288 struct bt_ctf_stream_class *stream_class, int64_t id)
289 {
290 _bt_ctf_stream_class_set_id(stream_class, id);
291 return 0;
292 }
293
294 int bt_ctf_stream_class_set_id(struct bt_ctf_stream_class *stream_class,
295 uint64_t id_param)
296 {
297 int ret = 0;
298 int64_t id = (int64_t) id_param;
299
300 if (!stream_class) {
301 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
302 ret = -1;
303 goto end;
304 }
305
306 if (stream_class->frozen) {
307 BT_LOGW("Invalid parameter: stream class is frozen: "
308 "addr=%p, name=\"%s\", id=%" PRId64,
309 stream_class, bt_ctf_stream_class_get_name(stream_class),
310 bt_ctf_stream_class_get_id(stream_class));
311 ret = -1;
312 goto end;
313 }
314
315 if (id < 0) {
316 BT_LOGW("Invalid parameter: invalid stream class's ID: "
317 "stream-class-addr=%p, stream-class-name=\"%s\", "
318 "stream-class-id=%" PRId64 ", id=%" PRIu64,
319 stream_class, bt_ctf_stream_class_get_name(stream_class),
320 bt_ctf_stream_class_get_id(stream_class),
321 id_param);
322 ret = -1;
323 goto end;
324 }
325
326 ret = bt_ctf_stream_class_set_id_no_check(stream_class, id);
327 if (ret == 0) {
328 BT_LOGV("Set stream class's ID: "
329 "addr=%p, name=\"%s\", id=%" PRId64,
330 stream_class, bt_ctf_stream_class_get_name(stream_class),
331 bt_ctf_stream_class_get_id(stream_class));
332 }
333 end:
334 return ret;
335 }
336
337 static
338 void event_class_exists(gpointer element, gpointer query)
339 {
340 struct bt_ctf_event_class *event_class_a = element;
341 struct search_query *search_query = query;
342 struct bt_ctf_event_class *event_class_b = search_query->value;
343 int64_t id_a, id_b;
344
345 if (search_query->value == element) {
346 search_query->found = 1;
347 goto end;
348 }
349
350 /*
351 * Two event classes cannot share the same ID in a given
352 * stream class.
353 */
354 id_a = bt_ctf_event_class_get_id(event_class_a);
355 id_b = bt_ctf_event_class_get_id(event_class_b);
356
357 if (id_a < 0 || id_b < 0) {
358 /* at least one ID is not set: will be automatically set later */
359 goto end;
360 }
361
362 if (id_a == id_b) {
363 BT_LOGW("Event class with this ID already exists in the stream class: "
364 "id=%" PRId64 ", name=\"%s\"",
365 id_a, bt_ctf_event_class_get_name(event_class_a));
366 search_query->found = 1;
367 goto end;
368 }
369
370 end:
371 return;
372 }
373
374 int bt_ctf_stream_class_add_event_class(
375 struct bt_ctf_stream_class *stream_class,
376 struct bt_ctf_event_class *event_class)
377 {
378 int ret = 0;
379 int64_t *event_id = NULL;
380 struct bt_ctf_trace *trace = NULL;
381 struct bt_ctf_stream_class *old_stream_class = NULL;
382 struct bt_ctf_validation_output validation_output = { 0 };
383 struct bt_ctf_field_type *packet_header_type = NULL;
384 struct bt_ctf_field_type *packet_context_type = NULL;
385 struct bt_ctf_field_type *event_header_type = NULL;
386 struct bt_ctf_field_type *stream_event_ctx_type = NULL;
387 struct bt_ctf_field_type *event_context_type = NULL;
388 struct bt_ctf_field_type *event_payload_type = NULL;
389 const enum bt_ctf_validation_flag validation_flags =
390 BT_CTF_VALIDATION_FLAG_EVENT;
391
392 if (!stream_class || !event_class) {
393 BT_LOGW("Invalid parameter: stream class or event class is NULL: "
394 "stream-class-addr=%p, event-class-addr=%p",
395 stream_class, event_class);
396 ret = -1;
397 goto end;
398 }
399
400 BT_LOGD("Adding event class to stream class: "
401 "stream-class-addr=%p, stream-class-name=\"%s\", "
402 "stream-class-id=%" PRId64 ", event-class-addr=%p, "
403 "event-class-name=\"%s\", event-class-id=%" PRId64,
404 stream_class, bt_ctf_stream_class_get_name(stream_class),
405 bt_ctf_stream_class_get_id(stream_class),
406 event_class,
407 bt_ctf_event_class_get_name(event_class),
408 bt_ctf_event_class_get_id(event_class));
409
410 trace = bt_ctf_stream_class_get_trace(stream_class);
411 if (trace && trace->is_static) {
412 ret = -1;
413 goto end;
414 }
415
416 event_id = g_new(int64_t, 1);
417 if (!event_id) {
418 BT_LOGE_STR("Failed to allocate one int64_t.");
419 ret = -1;
420 goto end;
421 }
422
423 /* Check for duplicate event classes */
424 struct search_query query = { .value = event_class, .found = 0 };
425 g_ptr_array_foreach(stream_class->event_classes, event_class_exists,
426 &query);
427 if (query.found) {
428 BT_LOGW_STR("Another event class part of this stream class has the same ID.");
429 ret = -1;
430 goto end;
431 }
432
433 old_stream_class = bt_ctf_event_class_get_stream_class(event_class);
434 if (old_stream_class) {
435 /* Event class is already associated to a stream class. */
436 BT_LOGW("Event class is already part of another stream class: "
437 "event-class-stream-class-addr=%p, "
438 "event-class-stream-class-name=\"%s\", "
439 "event-class-stream-class-id=%" PRId64,
440 old_stream_class,
441 bt_ctf_stream_class_get_name(old_stream_class),
442 bt_ctf_stream_class_get_id(old_stream_class));
443 ret = -1;
444 goto end;
445 }
446
447 if (trace) {
448 /*
449 * If the stream class is associated with a trace, then
450 * both those objects are frozen. Also, this event class
451 * is about to be frozen.
452 *
453 * Therefore the event class must be validated here.
454 * The trace and stream class should be valid at this
455 * point.
456 */
457 assert(trace->valid);
458 assert(stream_class->valid);
459 packet_header_type =
460 bt_ctf_trace_get_packet_header_type(trace);
461 packet_context_type =
462 bt_ctf_stream_class_get_packet_context_type(
463 stream_class);
464 event_header_type =
465 bt_ctf_stream_class_get_event_header_type(stream_class);
466 stream_event_ctx_type =
467 bt_ctf_stream_class_get_event_context_type(
468 stream_class);
469 event_context_type =
470 bt_ctf_event_class_get_context_type(event_class);
471 event_payload_type =
472 bt_ctf_event_class_get_payload_type(event_class);
473 ret = bt_ctf_validate_class_types(
474 trace->environment, packet_header_type,
475 packet_context_type, event_header_type,
476 stream_event_ctx_type, event_context_type,
477 event_payload_type, trace->valid,
478 stream_class->valid, event_class->valid,
479 &validation_output, validation_flags);
480 BT_PUT(packet_header_type);
481 BT_PUT(packet_context_type);
482 BT_PUT(event_header_type);
483 BT_PUT(stream_event_ctx_type);
484 BT_PUT(event_context_type);
485 BT_PUT(event_payload_type);
486
487 if (ret) {
488 /*
489 * This means something went wrong during the
490 * validation process, not that the objects are
491 * invalid.
492 */
493 BT_LOGE("Failed to validate event class: ret=%d", ret);
494 goto end;
495 }
496
497 if ((validation_output.valid_flags & validation_flags) !=
498 validation_flags) {
499 /* Invalid event class */
500 BT_LOGW("Invalid trace, stream class, or event class: "
501 "valid-flags=0x%x",
502 validation_output.valid_flags);
503 ret = -1;
504 goto end;
505 }
506 }
507
508 /* Only set an event ID if none was explicitly set before */
509 *event_id = bt_ctf_event_class_get_id(event_class);
510 if (*event_id < 0) {
511 BT_LOGV("Event class has no ID: automatically setting it: "
512 "id=%" PRId64, stream_class->next_event_id);
513
514 if (bt_ctf_event_class_set_id(event_class,
515 stream_class->next_event_id)) {
516 BT_LOGE("Cannot set event class's ID: id=%" PRId64,
517 stream_class->next_event_id);
518 ret = -1;
519 goto end;
520 }
521 stream_class->next_event_id++;
522 *event_id = stream_class->next_event_id;
523 }
524
525 bt_object_set_parent(event_class, stream_class);
526
527 if (trace) {
528 /*
529 * At this point we know that the function will be
530 * successful. Therefore we can replace the event
531 * class's field types with what's in the validation
532 * output structure and mark this event class as valid.
533 */
534 bt_ctf_validation_replace_types(NULL, NULL, event_class,
535 &validation_output, validation_flags);
536 event_class->valid = 1;
537
538 /*
539 * Put what was not moved in
540 * bt_ctf_validation_replace_types().
541 */
542 bt_ctf_validation_output_put_types(&validation_output);
543 }
544
545 /* Add to the event classes of the stream class */
546 g_ptr_array_add(stream_class->event_classes, event_class);
547 g_hash_table_insert(stream_class->event_classes_ht, event_id,
548 event_class);
549 event_id = NULL;
550
551 /* Freeze the event class */
552 bt_ctf_event_class_freeze(event_class);
553
554 /* Notifiy listeners of the trace's schema modification. */
555 if (trace) {
556 struct bt_ctf_object obj = { .object = event_class,
557 .type = BT_CTF_OBJECT_TYPE_EVENT_CLASS };
558
559 (void) bt_ctf_trace_object_modification(&obj, trace);
560 }
561
562 BT_LOGD("Added event class to stream class: "
563 "stream-class-addr=%p, stream-class-name=\"%s\", "
564 "stream-class-id=%" PRId64 ", event-class-addr=%p, "
565 "event-class-name=\"%s\", event-class-id=%" PRId64,
566 stream_class, bt_ctf_stream_class_get_name(stream_class),
567 bt_ctf_stream_class_get_id(stream_class),
568 event_class,
569 bt_ctf_event_class_get_name(event_class),
570 bt_ctf_event_class_get_id(event_class));
571
572 end:
573 BT_PUT(trace);
574 BT_PUT(old_stream_class);
575 bt_ctf_validation_output_put_types(&validation_output);
576 assert(!packet_header_type);
577 assert(!packet_context_type);
578 assert(!event_header_type);
579 assert(!stream_event_ctx_type);
580 assert(!event_context_type);
581 assert(!event_payload_type);
582 g_free(event_id);
583
584 return ret;
585 }
586
587 int64_t bt_ctf_stream_class_get_event_class_count(
588 struct bt_ctf_stream_class *stream_class)
589 {
590 int64_t ret;
591
592 if (!stream_class) {
593 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
594 ret = (int64_t) -1;
595 goto end;
596 }
597
598 ret = (int64_t) stream_class->event_classes->len;
599 end:
600 return ret;
601 }
602
603 struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_index(
604 struct bt_ctf_stream_class *stream_class, uint64_t index)
605 {
606 struct bt_ctf_event_class *event_class = NULL;
607
608 if (!stream_class) {
609 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
610 goto end;
611 }
612
613 if (index >= stream_class->event_classes->len) {
614 BT_LOGW("Invalid parameter: index is out of bounds: "
615 "addr=%p, name=\"%s\", id=%" PRId64 ", "
616 "index=%" PRIu64 ", count=%u",
617 stream_class, bt_ctf_stream_class_get_name(stream_class),
618 bt_ctf_stream_class_get_id(stream_class),
619 index, stream_class->event_classes->len);
620 goto end;
621 }
622
623 event_class = g_ptr_array_index(stream_class->event_classes, index);
624 bt_get(event_class);
625 end:
626 return event_class;
627 }
628
629 struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id(
630 struct bt_ctf_stream_class *stream_class, uint64_t id)
631 {
632 int64_t id_key = (int64_t) id;
633 struct bt_ctf_event_class *event_class = NULL;
634
635 if (!stream_class) {
636 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
637 goto end;
638 }
639
640 if (id_key < 0) {
641 BT_LOGW("Invalid parameter: invalid event class's ID: "
642 "stream-class-addr=%p, stream-class-name=\"%s\", "
643 "stream-class-id=%" PRId64 ", event-class-id=%" PRIu64,
644 stream_class,
645 bt_ctf_stream_class_get_name(stream_class),
646 bt_ctf_stream_class_get_id(stream_class), id);
647 goto end;
648 }
649
650 event_class = g_hash_table_lookup(stream_class->event_classes_ht,
651 &id_key);
652 bt_get(event_class);
653 end:
654 return event_class;
655 }
656
657 struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type(
658 struct bt_ctf_stream_class *stream_class)
659 {
660 struct bt_ctf_field_type *ret = NULL;
661
662 if (!stream_class) {
663 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
664 goto end;
665 }
666
667 bt_get(stream_class->packet_context_type);
668 ret = stream_class->packet_context_type;
669 end:
670 return ret;
671 }
672
673 int bt_ctf_stream_class_set_packet_context_type(
674 struct bt_ctf_stream_class *stream_class,
675 struct bt_ctf_field_type *packet_context_type)
676 {
677 int ret = 0;
678
679 if (!stream_class) {
680 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
681 ret = -1;
682 goto end;
683 }
684
685 if (stream_class->frozen) {
686 BT_LOGW("Invalid parameter: stream class is frozen: "
687 "addr=%p, name=\"%s\", id=%" PRId64,
688 stream_class, bt_ctf_stream_class_get_name(stream_class),
689 bt_ctf_stream_class_get_id(stream_class));
690 ret = -1;
691 goto end;
692 }
693
694 if (packet_context_type &&
695 bt_ctf_field_type_get_type_id(packet_context_type) !=
696 BT_CTF_FIELD_TYPE_ID_STRUCT) {
697 /* A packet context must be a structure. */
698 BT_LOGW("Invalid parameter: stream class's packet context field type must be a structure: "
699 "addr=%p, name=\"%s\", id=%" PRId64 ", "
700 "packet-context-ft-addr=%p, packet-context-ft-id=%s",
701 stream_class, bt_ctf_stream_class_get_name(stream_class),
702 bt_ctf_stream_class_get_id(stream_class),
703 packet_context_type,
704 bt_ctf_field_type_id_string(
705 bt_ctf_field_type_get_type_id(packet_context_type)));
706 ret = -1;
707 goto end;
708 }
709
710 bt_put(stream_class->packet_context_type);
711 bt_get(packet_context_type);
712 stream_class->packet_context_type = packet_context_type;
713 BT_LOGV("Set stream class's packet context field type: "
714 "addr=%p, name=\"%s\", id=%" PRId64 ", "
715 "packet-context-ft-addr=%p",
716 stream_class, bt_ctf_stream_class_get_name(stream_class),
717 bt_ctf_stream_class_get_id(stream_class),
718 packet_context_type);
719
720 end:
721 return ret;
722 }
723
724 struct bt_ctf_field_type *bt_ctf_stream_class_get_event_header_type(
725 struct bt_ctf_stream_class *stream_class)
726 {
727 struct bt_ctf_field_type *ret = NULL;
728
729 if (!stream_class) {
730 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
731 goto end;
732 }
733
734 if (!stream_class->event_header_type) {
735 BT_LOGV("Stream class has no event header field type: "
736 "addr=%p, name=\"%s\", id=%" PRId64,
737 stream_class, bt_ctf_stream_class_get_name(stream_class),
738 bt_ctf_stream_class_get_id(stream_class));
739 goto end;
740 }
741
742 bt_get(stream_class->event_header_type);
743 ret = stream_class->event_header_type;
744 end:
745 return ret;
746 }
747
748 int bt_ctf_stream_class_set_event_header_type(
749 struct bt_ctf_stream_class *stream_class,
750 struct bt_ctf_field_type *event_header_type)
751 {
752 int ret = 0;
753
754 if (!stream_class) {
755 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
756 ret = -1;
757 goto end;
758 }
759
760 if (stream_class->frozen) {
761 BT_LOGW("Invalid parameter: stream class is frozen: "
762 "addr=%p, name=\"%s\", id=%" PRId64,
763 stream_class, bt_ctf_stream_class_get_name(stream_class),
764 bt_ctf_stream_class_get_id(stream_class));
765 ret = -1;
766 goto end;
767 }
768
769 if (event_header_type &&
770 bt_ctf_field_type_get_type_id(event_header_type) !=
771 BT_CTF_FIELD_TYPE_ID_STRUCT) {
772 /* An event header must be a structure. */
773 BT_LOGW("Invalid parameter: stream class's event header field type must be a structure: "
774 "addr=%p, name=\"%s\", id=%" PRId64 ", "
775 "event-header-ft-addr=%p, event-header-ft-id=%s",
776 stream_class, bt_ctf_stream_class_get_name(stream_class),
777 bt_ctf_stream_class_get_id(stream_class),
778 event_header_type,
779 bt_ctf_field_type_id_string(
780 bt_ctf_field_type_get_type_id(event_header_type)));
781 ret = -1;
782 goto end;
783 }
784
785 bt_put(stream_class->event_header_type);
786 stream_class->event_header_type = bt_get(event_header_type);
787 BT_LOGV("Set stream class's event header field type: "
788 "addr=%p, name=\"%s\", id=%" PRId64 ", "
789 "event-header-ft-addr=%p",
790 stream_class, bt_ctf_stream_class_get_name(stream_class),
791 bt_ctf_stream_class_get_id(stream_class),
792 event_header_type);
793 end:
794 return ret;
795 }
796
797 struct bt_ctf_field_type *bt_ctf_stream_class_get_event_context_type(
798 struct bt_ctf_stream_class *stream_class)
799 {
800 struct bt_ctf_field_type *ret = NULL;
801
802 if (!stream_class) {
803 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
804 goto end;
805 }
806
807 if (!stream_class->event_context_type) {
808 goto end;
809 }
810
811 bt_get(stream_class->event_context_type);
812 ret = stream_class->event_context_type;
813 end:
814 return ret;
815 }
816
817 int bt_ctf_stream_class_set_event_context_type(
818 struct bt_ctf_stream_class *stream_class,
819 struct bt_ctf_field_type *event_context_type)
820 {
821 int ret = 0;
822
823 if (!stream_class) {
824 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
825 ret = -1;
826 goto end;
827 }
828
829 if (stream_class->frozen) {
830 BT_LOGW("Invalid parameter: stream class is frozen: "
831 "addr=%p, name=\"%s\", id=%" PRId64,
832 stream_class, bt_ctf_stream_class_get_name(stream_class),
833 bt_ctf_stream_class_get_id(stream_class));
834 ret = -1;
835 goto end;
836 }
837
838 if (event_context_type &&
839 bt_ctf_field_type_get_type_id(event_context_type) !=
840 BT_CTF_FIELD_TYPE_ID_STRUCT) {
841 /* A packet context must be a structure. */
842 BT_LOGW("Invalid parameter: stream class's event context field type must be a structure: "
843 "addr=%p, name=\"%s\", id=%" PRId64 ", "
844 "event-context-ft-addr=%p, event-context-ft-id=%s",
845 stream_class, bt_ctf_stream_class_get_name(stream_class),
846 bt_ctf_stream_class_get_id(stream_class),
847 event_context_type,
848 bt_ctf_field_type_id_string(
849 bt_ctf_field_type_get_type_id(event_context_type)));
850 ret = -1;
851 goto end;
852 }
853
854 bt_put(stream_class->event_context_type);
855 stream_class->event_context_type = bt_get(event_context_type);
856 BT_LOGV("Set stream class's event context field type: "
857 "addr=%p, name=\"%s\", id=%" PRId64 ", "
858 "event-context-ft-addr=%p",
859 stream_class, bt_ctf_stream_class_get_name(stream_class),
860 bt_ctf_stream_class_get_id(stream_class),
861 event_context_type);
862 end:
863 return ret;
864 }
865
866 /* Pre-2.0 CTF writer backward compatibility */
867 void bt_ctf_stream_class_get(struct bt_ctf_stream_class *stream_class)
868 {
869 bt_get(stream_class);
870 }
871
872 /* Pre-2.0 CTF writer backward compatibility */
873 void bt_ctf_stream_class_put(struct bt_ctf_stream_class *stream_class)
874 {
875 bt_put(stream_class);
876 }
877
878 static
879 int64_t get_event_class_count(void *element)
880 {
881 return bt_ctf_stream_class_get_event_class_count(
882 (struct bt_ctf_stream_class *) element);
883 }
884
885 static
886 void *get_event_class(void *element, int i)
887 {
888 return bt_ctf_stream_class_get_event_class_by_index(
889 (struct bt_ctf_stream_class *) element, i);
890 }
891
892 static
893 int visit_event_class(void *object, bt_ctf_visitor visitor,void *data)
894 {
895 struct bt_ctf_object obj =
896 { .object = object,
897 .type = BT_CTF_OBJECT_TYPE_EVENT_CLASS };
898
899 return visitor(&obj, data);
900 }
901
902 int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class,
903 bt_ctf_visitor visitor, void *data)
904 {
905 int ret;
906 struct bt_ctf_object obj =
907 { .object = stream_class,
908 .type = BT_CTF_OBJECT_TYPE_STREAM_CLASS };
909
910 if (!stream_class || !visitor) {
911 BT_LOGW("Invalid parameter: stream class or visitor is NULL: "
912 "stream-class-addr=%p, visitor=%p",
913 stream_class, visitor);
914 ret = -1;
915 goto end;
916 }
917
918 ret = visitor_helper(&obj, get_event_class_count,
919 get_event_class,
920 visit_event_class, visitor, data);
921 BT_LOGV("visitor_helper() returned: ret=%d", ret);
922 end:
923 return ret;
924 }
925
926 BT_HIDDEN
927 void bt_ctf_stream_class_freeze(struct bt_ctf_stream_class *stream_class)
928 {
929 if (!stream_class || stream_class->frozen) {
930 return;
931 }
932
933 BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64,
934 stream_class, bt_ctf_stream_class_get_name(stream_class),
935 bt_ctf_stream_class_get_id(stream_class));
936 stream_class->frozen = 1;
937 bt_ctf_field_type_freeze(stream_class->event_header_type);
938 bt_ctf_field_type_freeze(stream_class->packet_context_type);
939 bt_ctf_field_type_freeze(stream_class->event_context_type);
940
941 if (stream_class->clock) {
942 bt_ctf_clock_class_freeze(stream_class->clock->clock_class);
943 }
944 }
945
946 BT_HIDDEN
947 int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class,
948 struct metadata_context *context)
949 {
950 int ret = 0;
951 size_t i;
952 struct bt_ctf_trace *trace;
953 struct bt_ctf_field_type *packet_header_type = NULL;
954
955 BT_LOGD("Serializing stream class's metadata: "
956 "stream-class-addr=%p, stream-class-name=\"%s\", "
957 "stream-class-id=%" PRId64 ", metadata-context-addr=%p",
958 stream_class, bt_ctf_stream_class_get_name(stream_class),
959 bt_ctf_stream_class_get_id(stream_class), context);
960 g_string_assign(context->field_name, "");
961 context->current_indentation_level = 1;
962 if (!stream_class->id_set) {
963 BT_LOGW_STR("Stream class's ID is not set.");
964 ret = -1;
965 goto end;
966 }
967
968 g_string_append(context->string, "stream {\n");
969
970 /*
971 * The reference to the trace is only borrowed since the
972 * serialization of the stream class might have been triggered
973 * by the trace's destruction. In such a case, the trace's
974 * reference count would, unexepectedly, go through the sequence
975 * 1 -> 0 -> 1 -> 0 -> ..., provoking an endless loop of destruction
976 * and serialization.
977 */
978 trace = bt_ctf_stream_class_borrow_trace(stream_class);
979 assert(trace);
980 packet_header_type = bt_ctf_trace_get_packet_header_type(trace);
981 trace = NULL;
982 if (packet_header_type) {
983 struct bt_ctf_field_type *stream_id_type;
984
985 stream_id_type =
986 bt_ctf_field_type_structure_get_field_type_by_name(
987 packet_header_type, "stream_id");
988 if (stream_id_type) {
989 /*
990 * Only set the stream's id if the trace's packet header
991 * contains a stream_id field. This field is only
992 * needed if the trace contains only one stream
993 * class.
994 */
995 g_string_append_printf(context->string,
996 "\tid = %" PRId64 ";\n", stream_class->id);
997 }
998 bt_put(stream_id_type);
999 }
1000 if (stream_class->event_header_type) {
1001 BT_LOGD_STR("Serializing stream class's event header field type's metadata.");
1002 g_string_append(context->string, "\tevent.header := ");
1003 ret = bt_ctf_field_type_serialize(stream_class->event_header_type,
1004 context);
1005 if (ret) {
1006 BT_LOGW("Cannot serialize stream class's event header field type's metadata: "
1007 "ret=%d", ret);
1008 goto end;
1009 }
1010 g_string_append(context->string, ";");
1011 }
1012
1013
1014 if (stream_class->packet_context_type) {
1015 BT_LOGD_STR("Serializing stream class's packet context field type's metadata.");
1016 g_string_append(context->string, "\n\n\tpacket.context := ");
1017 ret = bt_ctf_field_type_serialize(stream_class->packet_context_type,
1018 context);
1019 if (ret) {
1020 BT_LOGW("Cannot serialize stream class's packet context field type's metadata: "
1021 "ret=%d", ret);
1022 goto end;
1023 }
1024 g_string_append(context->string, ";");
1025 }
1026
1027 if (stream_class->event_context_type) {
1028 BT_LOGD_STR("Serializing stream class's event context field type's metadata.");
1029 g_string_append(context->string, "\n\n\tevent.context := ");
1030 ret = bt_ctf_field_type_serialize(
1031 stream_class->event_context_type, context);
1032 if (ret) {
1033 BT_LOGW("Cannot serialize stream class's event context field type's metadata: "
1034 "ret=%d", ret);
1035 goto end;
1036 }
1037 g_string_append(context->string, ";");
1038 }
1039
1040 g_string_append(context->string, "\n};\n\n");
1041
1042 for (i = 0; i < stream_class->event_classes->len; i++) {
1043 struct bt_ctf_event_class *event_class =
1044 stream_class->event_classes->pdata[i];
1045
1046 ret = bt_ctf_event_class_serialize(event_class, context);
1047 if (ret) {
1048 BT_LOGW("Cannot serialize event class's metadata: "
1049 "event-class-addr=%p, event-class-name=\"%s\", "
1050 "event-class-id=%" PRId64,
1051 event_class,
1052 bt_ctf_event_class_get_name(event_class),
1053 bt_ctf_event_class_get_id(event_class));
1054 goto end;
1055 }
1056 }
1057 end:
1058 bt_put(packet_header_type);
1059 context->current_indentation_level = 0;
1060 return ret;
1061 }
1062
1063 static
1064 void bt_ctf_stream_class_destroy(struct bt_object *obj)
1065 {
1066 struct bt_ctf_stream_class *stream_class;
1067
1068 stream_class = container_of(obj, struct bt_ctf_stream_class, base);
1069 BT_LOGD("Destroying stream class: addr=%p, name=\"%s\", id=%" PRId64,
1070 stream_class, bt_ctf_stream_class_get_name(stream_class),
1071 bt_ctf_stream_class_get_id(stream_class));
1072 bt_put(stream_class->clock);
1073
1074 if (stream_class->event_classes_ht) {
1075 g_hash_table_destroy(stream_class->event_classes_ht);
1076 }
1077 if (stream_class->event_classes) {
1078 BT_LOGD_STR("Destroying event classes.");
1079 g_ptr_array_free(stream_class->event_classes, TRUE);
1080 }
1081
1082 if (stream_class->name) {
1083 g_string_free(stream_class->name, TRUE);
1084 }
1085
1086 BT_LOGD_STR("Putting event header field type.");
1087 bt_put(stream_class->event_header_type);
1088 BT_LOGD_STR("Putting packet context field type.");
1089 bt_put(stream_class->packet_context_type);
1090 BT_LOGD_STR("Putting event context field type.");
1091 bt_put(stream_class->event_context_type);
1092 g_free(stream_class);
1093 }
1094
1095 static
1096 int init_event_header(struct bt_ctf_stream_class *stream_class)
1097 {
1098 int ret = 0;
1099 struct bt_ctf_field_type *event_header_type =
1100 bt_ctf_field_type_structure_create();
1101 struct bt_ctf_field_type *_uint32_t =
1102 get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
1103 struct bt_ctf_field_type *_uint64_t =
1104 get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
1105
1106 if (!event_header_type) {
1107 BT_LOGE_STR("Cannot create empty structure field type.");
1108 ret = -1;
1109 goto end;
1110 }
1111
1112 ret = bt_ctf_field_type_structure_add_field(event_header_type,
1113 _uint32_t, "id");
1114 if (ret) {
1115 BT_LOGE_STR("Cannot add `id` field to event header field type.");
1116 goto end;
1117 }
1118
1119 ret = bt_ctf_field_type_structure_add_field(event_header_type,
1120 _uint64_t, "timestamp");
1121 if (ret) {
1122 BT_LOGE_STR("Cannot add `timestamp` field to event header field type.");
1123 goto end;
1124 }
1125
1126 BT_MOVE(stream_class->event_header_type, event_header_type);
1127 end:
1128 if (ret) {
1129 bt_put(event_header_type);
1130 }
1131
1132 bt_put(_uint32_t);
1133 bt_put(_uint64_t);
1134 return ret;
1135 }
1136
1137 static
1138 int init_packet_context(struct bt_ctf_stream_class *stream_class)
1139 {
1140 int ret = 0;
1141 struct bt_ctf_field_type *packet_context_type =
1142 bt_ctf_field_type_structure_create();
1143 struct bt_ctf_field_type *_uint64_t =
1144 get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
1145 struct bt_ctf_field_type *ts_begin_end_uint64_t;
1146
1147 if (!packet_context_type) {
1148 BT_LOGE_STR("Cannot create empty structure field type.");
1149 ret = -1;
1150 goto end;
1151 }
1152
1153 ts_begin_end_uint64_t = bt_ctf_field_type_copy(_uint64_t);
1154 if (!ts_begin_end_uint64_t) {
1155 BT_LOGE_STR("Cannot copy integer field type for `timestamp_begin` and `timestamp_end` fields.");
1156 ret = -1;
1157 goto end;
1158 }
1159
1160 /*
1161 * We create a stream packet context as proposed in the CTF
1162 * specification.
1163 */
1164 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
1165 ts_begin_end_uint64_t, "timestamp_begin");
1166 if (ret) {
1167 BT_LOGE_STR("Cannot add `timestamp_begin` field to event header field type.");
1168 goto end;
1169 }
1170
1171 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
1172 ts_begin_end_uint64_t, "timestamp_end");
1173 if (ret) {
1174 BT_LOGE_STR("Cannot add `timestamp_end` field to event header field type.");
1175 goto end;
1176 }
1177
1178 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
1179 _uint64_t, "content_size");
1180 if (ret) {
1181 BT_LOGE_STR("Cannot add `content_size` field to event header field type.");
1182 goto end;
1183 }
1184
1185 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
1186 _uint64_t, "packet_size");
1187 if (ret) {
1188 BT_LOGE_STR("Cannot add `packet_size` field to event header field type.");
1189 goto end;
1190 }
1191
1192 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
1193 _uint64_t, "events_discarded");
1194 if (ret) {
1195 BT_LOGE_STR("Cannot add `events_discarded` field to event header field type.");
1196 goto end;
1197 }
1198
1199 BT_MOVE(stream_class->packet_context_type, packet_context_type);
1200 end:
1201 if (ret) {
1202 bt_put(packet_context_type);
1203 goto end;
1204 }
1205
1206 bt_put(_uint64_t);
1207 bt_put(ts_begin_end_uint64_t);
1208 return ret;
1209 }
1210
1211 static
1212 int try_map_clock_class(struct bt_ctf_stream_class *stream_class,
1213 struct bt_ctf_field_type *ft)
1214 {
1215 struct bt_ctf_clock_class *mapped_clock_class = NULL;
1216 int ret = 0;
1217
1218 if (!ft) {
1219 /* Field does not exist: not an error */
1220 goto end;
1221 }
1222
1223 assert(bt_ctf_field_type_is_integer(ft));
1224 mapped_clock_class =
1225 bt_ctf_field_type_integer_get_mapped_clock_class(ft);
1226 if (!mapped_clock_class) {
1227 if (!stream_class->clock) {
1228 BT_LOGW("Cannot automatically set field's type mapped clock class: stream class's clock is not set: "
1229 "stream-class-addr=%p, stream-class-name=\"%s\", "
1230 "stream-class-id=%" PRId64 ", ft-addr=%p",
1231 stream_class, bt_ctf_stream_class_get_name(stream_class),
1232 bt_ctf_stream_class_get_id(stream_class), ft);
1233 ret = -1;
1234 goto end;
1235 }
1236
1237 ret = bt_ctf_field_type_integer_set_mapped_clock_class_no_check(
1238 ft, stream_class->clock->clock_class);
1239 if (ret) {
1240 BT_LOGW("Cannot set field type's mapped clock class: "
1241 "stream-class-addr=%p, stream-class-name=\"%s\", "
1242 "stream-class-id=%" PRId64 ", ft-addr=%p",
1243 stream_class, bt_ctf_stream_class_get_name(stream_class),
1244 bt_ctf_stream_class_get_id(stream_class), ft);
1245 goto end;
1246 }
1247
1248 BT_LOGV("Automatically mapped field type to stream class's clock class: "
1249 "stream-class-addr=%p, stream-class-name=\"%s\", "
1250 "stream-class-id=%" PRId64 ", ft-addr=%p",
1251 stream_class, bt_ctf_stream_class_get_name(stream_class),
1252 bt_ctf_stream_class_get_id(stream_class), ft);
1253 }
1254
1255 end:
1256 bt_put(mapped_clock_class);
1257 return ret;
1258 }
1259
1260 BT_HIDDEN
1261 int bt_ctf_stream_class_map_clock_class(
1262 struct bt_ctf_stream_class *stream_class,
1263 struct bt_ctf_field_type *packet_context_type,
1264 struct bt_ctf_field_type *event_header_type)
1265 {
1266 struct bt_ctf_field_type *ft = NULL;
1267 int ret = 0;
1268
1269 assert(stream_class);
1270
1271 if (packet_context_type) {
1272 ft = bt_ctf_field_type_structure_get_field_type_by_name(
1273 packet_context_type, "timestamp_begin");
1274 if (try_map_clock_class(stream_class, ft)) {
1275 BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_begin` field's mapped clock class.");
1276 ret = -1;
1277 goto end;
1278 }
1279
1280 bt_put(ft);
1281 ft = bt_ctf_field_type_structure_get_field_type_by_name(
1282 packet_context_type, "timestamp_end");
1283 if (try_map_clock_class(stream_class, ft)) {
1284 BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_end` field's mapped clock class.");
1285 ret = -1;
1286 goto end;
1287 }
1288
1289 BT_PUT(ft);
1290 }
1291
1292 if (event_header_type) {
1293 ft = bt_ctf_field_type_structure_get_field_type_by_name(
1294 event_header_type, "timestamp");
1295 if (try_map_clock_class(stream_class, ft)) {
1296 BT_LOGE_STR("Cannot automatically set stream class's event header field type's `timestamp` field's mapped clock class.");
1297 ret = -1;
1298 goto end;
1299 }
1300
1301 BT_PUT(ft);
1302 }
1303
1304 end:
1305 return ret;
1306 }
This page took 0.059344 seconds and 5 git commands to generate.