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