ccd7cc605bc797d01c3ab3df2fa8e644ed6aad27
[babeltrace.git] / src / ctf-writer / stream.c
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
6 */
7
8 #define BT_LOG_TAG "CTF-WRITER/STREAM"
9 #include "logging.h"
10
11 #include <inttypes.h>
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <unistd.h>
15
16 #include <babeltrace2-ctf-writer/field-types.h>
17 #include <babeltrace2-ctf-writer/object.h>
18 #include <babeltrace2-ctf-writer/stream-class.h>
19 #include <babeltrace2-ctf-writer/stream.h>
20 #include <babeltrace2-ctf-writer/trace.h>
21
22 #include "common/align.h"
23 #include "common/assert.h"
24 #include "compat/compiler.h"
25 #include "ctfser/ctfser.h"
26
27 #include "assert-pre.h"
28 #include "event-class.h"
29 #include "event.h"
30 #include "fields.h"
31 #include "stream-class.h"
32 #include "stream.h"
33 #include "trace.h"
34 #include "writer.h"
35
36 BT_HIDDEN
37 void bt_ctf_stream_common_finalize(struct bt_ctf_stream_common *stream)
38 {
39 BT_LOGD("Finalizing common stream object: addr=%p, name=\"%s\"",
40 stream, bt_ctf_stream_common_get_name(stream));
41
42 if (stream->name) {
43 g_string_free(stream->name, TRUE);
44 }
45 }
46
47 BT_HIDDEN
48 int bt_ctf_stream_common_initialize(
49 struct bt_ctf_stream_common *stream,
50 struct bt_ctf_stream_class_common *stream_class, const char *name,
51 uint64_t id, bt_ctf_object_release_func release_func)
52 {
53 int ret = 0;
54 struct bt_ctf_trace_common *trace = NULL;
55
56 bt_ctf_object_init_shared_with_parent(&stream->base, release_func);
57
58 if (!stream_class) {
59 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
60 goto error;
61 }
62
63 BT_LOGD("Initializing common stream object: stream-class-addr=%p, "
64 "stream-class-name=\"%s\", stream-name=\"%s\", "
65 "stream-id=%" PRIu64,
66 stream_class, bt_ctf_stream_class_common_get_name(stream_class),
67 name, id);
68 trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
69 if (!trace) {
70 BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: "
71 "stream-class-addr=%p, stream-class-name=\"%s\", "
72 "stream-name=\"%s\"",
73 stream_class,
74 bt_ctf_stream_class_common_get_name(stream_class), name);
75 goto error;
76 }
77
78 if (id != -1ULL) {
79 /*
80 * Validate that the given ID is unique amongst all the
81 * existing trace's streams created from the same stream
82 * class.
83 */
84 size_t i;
85
86 for (i = 0; i < trace->streams->len; i++) {
87 struct bt_ctf_stream_common *trace_stream =
88 g_ptr_array_index(trace->streams, i);
89
90 if (trace_stream->stream_class != (void *) stream_class) {
91 continue;
92 }
93
94 if (trace_stream->id == id) {
95 BT_LOGW_STR("Invalid parameter: another stream in the same trace already has this ID.");
96 goto error;
97 }
98 }
99 }
100
101 /*
102 * Acquire reference to parent since stream will become publicly
103 * reachable; it needs its parent to remain valid.
104 */
105 bt_ctf_object_set_parent(&stream->base, &trace->base);
106 stream->stream_class = stream_class;
107 stream->id = (int64_t) id;
108
109 if (name) {
110 stream->name = g_string_new(name);
111 if (!stream->name) {
112 BT_LOGE_STR("Failed to allocate a GString.");
113 goto error;
114 }
115 }
116
117 BT_LOGD("Set common stream's trace parent: trace-addr=%p", trace);
118
119 /* Add this stream to the trace's streams */
120 BT_LOGD("Created common stream object: addr=%p", stream);
121 goto end;
122
123 error:
124 ret = -1;
125
126 end:
127 return ret;
128 }
129
130 static
131 void bt_ctf_stream_destroy(struct bt_ctf_object *obj);
132
133 static
134 int try_set_structure_field_integer(struct bt_ctf_field *, const char *, uint64_t);
135
136 static
137 int set_integer_field_value(struct bt_ctf_field* field, uint64_t value)
138 {
139 int ret = 0;
140 struct bt_ctf_field_type *field_type = NULL;
141
142 if (!field) {
143 BT_LOGW_STR("Invalid parameter: field is NULL.");
144 ret = -1;
145 goto end;
146 }
147
148 field_type = bt_ctf_field_get_type(field);
149 BT_ASSERT_DBG(field_type);
150
151 if (bt_ctf_field_type_get_type_id(field_type) !=
152 BT_CTF_FIELD_TYPE_ID_INTEGER) {
153 /* Not an integer and the value is unset, error. */
154 BT_LOGW("Invalid parameter: field's type is not an integer field type: "
155 "field-addr=%p, ft-addr=%p, ft-id=%s",
156 field, field_type,
157 bt_ctf_field_type_id_string((int)
158 bt_ctf_field_type_get_type_id(field_type)));
159 ret = -1;
160 goto end;
161 }
162
163 if (bt_ctf_field_type_integer_is_signed(field_type)) {
164 ret = bt_ctf_field_integer_signed_set_value(field, (int64_t) value);
165 if (ret) {
166 /* Value is out of range, error. */
167 BT_LOGW("Cannot set signed integer field's value: "
168 "addr=%p, value=%" PRId64,
169 field, (int64_t) value);
170 goto end;
171 }
172 } else {
173 ret = bt_ctf_field_integer_unsigned_set_value(field, value);
174 if (ret) {
175 /* Value is out of range, error. */
176 BT_LOGW("Cannot set unsigned integer field's value: "
177 "addr=%p, value=%" PRIu64,
178 field, value);
179 goto end;
180 }
181 }
182 end:
183 bt_ctf_object_put_ref(field_type);
184 return ret;
185 }
186
187 static
188 int set_packet_header_magic(struct bt_ctf_stream *stream)
189 {
190 int ret = 0;
191 struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field_by_name(
192 stream->packet_header, "magic");
193 const uint32_t magic_value = 0xc1fc1fc1;
194
195 BT_ASSERT_DBG(stream);
196
197 if (!magic_field) {
198 /* No magic field found. Not an error, skip. */
199 BT_LOGT("No field named `magic` in packet header: skipping: "
200 "stream-addr=%p, stream-name=\"%s\"",
201 stream, bt_ctf_stream_get_name(stream));
202 goto end;
203 }
204
205 ret = bt_ctf_field_integer_unsigned_set_value(magic_field,
206 (uint64_t) magic_value);
207
208 if (ret) {
209 BT_LOGW("Cannot set packet header field's `magic` integer field's value: "
210 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
211 stream, bt_ctf_stream_get_name(stream),
212 magic_field, (uint64_t) magic_value);
213 } else {
214 BT_LOGT("Set packet header field's `magic` field's value: "
215 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
216 stream, bt_ctf_stream_get_name(stream),
217 magic_field, (uint64_t) magic_value);
218 }
219 end:
220 bt_ctf_object_put_ref(magic_field);
221 return ret;
222 }
223
224 static
225 int set_packet_header_uuid(struct bt_ctf_stream *stream)
226 {
227 int ret = 0;
228 int64_t i;
229 struct bt_ctf_trace *trace = NULL;
230 struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field_by_name(
231 stream->packet_header, "uuid");
232
233 BT_ASSERT_DBG(stream);
234
235 if (!uuid_field) {
236 /* No uuid field found. Not an error, skip. */
237 BT_LOGT("No field named `uuid` in packet header: skipping: "
238 "stream-addr=%p, stream-name=\"%s\"",
239 stream, bt_ctf_stream_get_name(stream));
240 goto end;
241 }
242
243 trace = (struct bt_ctf_trace *)
244 bt_ctf_object_get_parent(&stream->common.base);
245
246 for (i = 0; i < 16; i++) {
247 struct bt_ctf_field *uuid_element =
248 bt_ctf_field_array_get_field(uuid_field, i);
249
250 ret = bt_ctf_field_integer_unsigned_set_value(
251 uuid_element, (uint64_t) trace->common.uuid[i]);
252 bt_ctf_object_put_ref(uuid_element);
253 if (ret) {
254 BT_LOGW("Cannot set integer field's value (for `uuid` packet header field): "
255 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
256 "value=%" PRIu64 ", index=%" PRId64,
257 stream, bt_ctf_stream_get_name(stream),
258 uuid_element, (uint64_t) trace->common.uuid[i], i);
259 goto end;
260 }
261 }
262
263 BT_LOGT("Set packet header field's `uuid` field's value: "
264 "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
265 stream, bt_ctf_stream_get_name(stream), uuid_field);
266
267 end:
268 bt_ctf_object_put_ref(uuid_field);
269 BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
270 return ret;
271 }
272 static
273 int set_packet_header_stream_id(struct bt_ctf_stream *stream)
274 {
275 int ret = 0;
276 uint32_t stream_id;
277 struct bt_ctf_field *stream_id_field =
278 bt_ctf_field_structure_get_field_by_name(
279 stream->packet_header, "stream_id");
280
281 if (!stream_id_field) {
282 /* No stream_id field found. Not an error, skip. */
283 BT_LOGT("No field named `stream_id` in packet header: skipping: "
284 "stream-addr=%p, stream-name=\"%s\"",
285 stream, bt_ctf_stream_get_name(stream));
286 goto end;
287 }
288
289 stream_id = stream->common.stream_class->id;
290 ret = bt_ctf_field_integer_unsigned_set_value(stream_id_field,
291 (uint64_t) stream_id);
292 if (ret) {
293 BT_LOGW("Cannot set packet header field's `stream_id` integer field's value: "
294 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
295 stream, bt_ctf_stream_get_name(stream),
296 stream_id_field, (uint64_t) stream_id);
297 } else {
298 BT_LOGT("Set packet header field's `stream_id` field's value: "
299 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
300 stream, bt_ctf_stream_get_name(stream),
301 stream_id_field, (uint64_t) stream_id);
302 }
303
304 end:
305 bt_ctf_object_put_ref(stream_id_field);
306 return ret;
307 }
308
309 static
310 int auto_populate_packet_header(struct bt_ctf_stream *stream)
311 {
312 int ret = 0;
313
314 if (!stream->packet_header) {
315 goto end;
316 }
317
318 ret = set_packet_header_magic(stream);
319 if (ret) {
320 BT_LOGW("Cannot set packet header's magic number field: "
321 "stream-addr=%p, stream-name=\"%s\"",
322 stream, bt_ctf_stream_get_name(stream));
323 goto end;
324 }
325
326 ret = set_packet_header_uuid(stream);
327 if (ret) {
328 BT_LOGW("Cannot set packet header's UUID field: "
329 "stream-addr=%p, stream-name=\"%s\"",
330 stream, bt_ctf_stream_get_name(stream));
331 goto end;
332 }
333
334 ret = set_packet_header_stream_id(stream);
335 if (ret) {
336 BT_LOGW("Cannot set packet header's stream class ID field: "
337 "stream-addr=%p, stream-name=\"%s\"",
338 stream, bt_ctf_stream_get_name(stream));
339 goto end;
340 }
341
342 BT_LOGT("Automatically populated stream's packet header's known fields: "
343 "stream-addr=%p, stream-name=\"%s\"",
344 stream, bt_ctf_stream_get_name(stream));
345
346 end:
347 return ret;
348 }
349
350 static
351 int set_packet_context_packet_size(struct bt_ctf_stream *stream,
352 uint64_t packet_size_bits)
353 {
354 int ret = 0;
355 struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
356 stream->packet_context, "packet_size");
357
358 ret = bt_ctf_field_integer_unsigned_set_value(field, packet_size_bits);
359 if (ret) {
360 BT_LOGW("Cannot set packet context field's `packet_size` integer field's value: "
361 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
362 stream, bt_ctf_stream_get_name(stream),
363 field, packet_size_bits);
364 } else {
365 BT_LOGT("Set packet context field's `packet_size` field's value: "
366 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
367 stream, bt_ctf_stream_get_name(stream),
368 field, packet_size_bits);
369 }
370
371 bt_ctf_object_put_ref(field);
372 return ret;
373 }
374
375 static
376 int set_packet_context_content_size(struct bt_ctf_stream *stream,
377 uint64_t content_size_bits)
378 {
379 int ret = 0;
380 struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
381 stream->packet_context, "content_size");
382
383 BT_ASSERT_DBG(stream);
384
385 if (!field) {
386 /* No content size field found. Not an error, skip. */
387 BT_LOGT("No field named `content_size` in packet context: skipping: "
388 "stream-addr=%p, stream-name=\"%s\"",
389 stream, bt_ctf_stream_get_name(stream));
390 goto end;
391 }
392
393 ret = bt_ctf_field_integer_unsigned_set_value(field, content_size_bits);
394 if (ret) {
395 BT_LOGW("Cannot set packet context field's `content_size` integer field's value: "
396 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
397 stream, bt_ctf_stream_get_name(stream),
398 field, content_size_bits);
399 } else {
400 BT_LOGT("Set packet context field's `content_size` field's value: "
401 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
402 stream, bt_ctf_stream_get_name(stream),
403 field, content_size_bits);
404 }
405
406 end:
407 bt_ctf_object_put_ref(field);
408 return ret;
409 }
410
411 static
412 int set_packet_context_events_discarded(struct bt_ctf_stream *stream)
413 {
414 int ret = 0;
415 struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
416 stream->packet_context, "events_discarded");
417
418 BT_ASSERT_DBG(stream);
419
420 if (!field) {
421 /* No discarded events count field found. Not an error, skip. */
422 BT_LOGT("No field named `events_discarded` in packet context: skipping: "
423 "stream-addr=%p, stream-name=\"%s\"",
424 stream, bt_ctf_stream_get_name(stream));
425 goto end;
426 }
427
428 /*
429 * If the field is set by the user, make sure that the value is
430 * greater than or equal to the stream's current count of
431 * discarded events. We do not allow wrapping here. If it's
432 * valid, update the stream's current count.
433 */
434 if (bt_ctf_field_is_set_recursive(field)) {
435 uint64_t user_val;
436
437 ret = bt_ctf_field_integer_unsigned_get_value(field,
438 &user_val);
439 if (ret) {
440 BT_LOGW("Cannot get packet context `events_discarded` field's unsigned value: "
441 "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
442 stream, bt_ctf_stream_get_name(stream), field);
443 goto end;
444 }
445
446 if (user_val < stream->discarded_events) {
447 BT_LOGW("Invalid packet context `events_discarded` field's unsigned value: "
448 "value is lesser than the stream's current discarded events count: "
449 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
450 "value=%" PRIu64 ", "
451 "stream-discarded-events-count=%" PRIu64,
452 stream, bt_ctf_stream_get_name(stream), field,
453 user_val, stream->discarded_events);
454 goto end;
455 }
456
457 stream->discarded_events = user_val;
458 } else {
459 ret = bt_ctf_field_integer_unsigned_set_value(field,
460 stream->discarded_events);
461 if (ret) {
462 BT_LOGW("Cannot set packet context field's `events_discarded` integer field's value: "
463 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
464 stream, bt_ctf_stream_get_name(stream),
465 field, stream->discarded_events);
466 } else {
467 BT_LOGT("Set packet context field's `events_discarded` field's value: "
468 "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
469 stream, bt_ctf_stream_get_name(stream),
470 field, stream->discarded_events);
471 }
472 }
473
474 end:
475 bt_ctf_object_put_ref(field);
476 return ret;
477 }
478
479 static
480 void update_clock_value(uint64_t *val, uint64_t new_val,
481 unsigned int new_val_size)
482 {
483 const uint64_t pow2 = 1ULL << new_val_size;
484 const uint64_t mask = pow2 - 1;
485 uint64_t val_masked;
486
487 #ifdef BT_LOG_ENABLED_TRACE
488 uint64_t old_val = *val;
489 #endif
490
491 if (new_val_size == 64) {
492 *val = new_val;
493 goto end;
494 }
495
496 val_masked = *val & mask;
497
498 if (new_val < val_masked) {
499 /* Wrapped once */
500 new_val |= pow2;
501 }
502
503 *val &= ~mask;
504 *val |= new_val;
505
506 end:
507 BT_LOGT("Updated clock value: old-val=%" PRIu64 ", new-val=%" PRIu64,
508 old_val, *val);
509 return;
510 }
511
512 static
513 int visit_field_update_clock_value(struct bt_ctf_field *field, uint64_t *val)
514 {
515 int ret = 0;
516 struct bt_ctf_field_common *field_common = (void *) field;
517
518 if (!field) {
519 goto end;
520 }
521
522 switch (bt_ctf_field_get_type_id(field)) {
523 case BT_CTF_FIELD_TYPE_ID_INTEGER:
524 {
525 struct bt_ctf_clock_class *cc =
526 bt_ctf_field_type_integer_get_mapped_clock_class(
527 (void *) field_common->type);
528 int val_size;
529 uint64_t uval;
530
531 if (!cc) {
532 goto end;
533 }
534
535 bt_ctf_object_put_ref(cc);
536 val_size = bt_ctf_field_type_integer_get_size(
537 (void *) field_common->type);
538 BT_ASSERT_DBG(val_size >= 1);
539
540 if (bt_ctf_field_type_integer_is_signed(
541 (void *) field_common->type)) {
542 int64_t ival;
543
544 ret = bt_ctf_field_integer_signed_get_value(field, &ival);
545 uval = (uint64_t) ival;
546 } else {
547 ret = bt_ctf_field_integer_unsigned_get_value(field, &uval);
548 }
549
550 if (ret) {
551 /* Not set */
552 goto end;
553 }
554
555 update_clock_value(val, uval, val_size);
556 break;
557 }
558 case BT_CTF_FIELD_TYPE_ID_ENUM:
559 {
560 struct bt_ctf_field *int_field =
561 bt_ctf_field_enumeration_get_container(field);
562
563 BT_ASSERT_DBG(int_field);
564 ret = visit_field_update_clock_value(int_field, val);
565 bt_ctf_object_put_ref(int_field);
566 break;
567 }
568 case BT_CTF_FIELD_TYPE_ID_ARRAY:
569 {
570 uint64_t i;
571 int64_t len = bt_ctf_field_type_array_get_length(
572 (void *) field_common->type);
573
574 BT_ASSERT_DBG(len >= 0);
575
576 for (i = 0; i < len; i++) {
577 struct bt_ctf_field *elem_field =
578 bt_ctf_field_array_get_field(field, i);
579
580 BT_ASSERT_DBG(elem_field);
581 ret = visit_field_update_clock_value(elem_field, val);
582 bt_ctf_object_put_ref(elem_field);
583 if (ret) {
584 goto end;
585 }
586 }
587 break;
588 }
589 case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
590 {
591 uint64_t i;
592 int64_t len = bt_ctf_field_common_sequence_get_length(
593 (void *) field);
594
595 if (len < 0) {
596 ret = -1;
597 goto end;
598 }
599
600 for (i = 0; i < len; i++) {
601 struct bt_ctf_field *elem_field =
602 bt_ctf_field_sequence_get_field(field, i);
603
604 BT_ASSERT_DBG(elem_field);
605 ret = visit_field_update_clock_value(elem_field, val);
606 bt_ctf_object_put_ref(elem_field);
607 if (ret) {
608 goto end;
609 }
610 }
611 break;
612 }
613 case BT_CTF_FIELD_TYPE_ID_STRUCT:
614 {
615 uint64_t i;
616 int64_t len = bt_ctf_field_type_structure_get_field_count(
617 (void *) field_common->type);
618
619 BT_ASSERT_DBG(len >= 0);
620
621 for (i = 0; i < len; i++) {
622 struct bt_ctf_field *member_field =
623 bt_ctf_field_structure_get_field_by_index(field, i);
624
625 BT_ASSERT_DBG(member_field);
626 ret = visit_field_update_clock_value(member_field, val);
627 bt_ctf_object_put_ref(member_field);
628 if (ret) {
629 goto end;
630 }
631 }
632 break;
633 }
634 case BT_CTF_FIELD_TYPE_ID_VARIANT:
635 {
636 struct bt_ctf_field *cur_field =
637 bt_ctf_field_variant_get_current_field(field);
638
639 if (!cur_field) {
640 ret = -1;
641 goto end;
642 }
643
644 ret = visit_field_update_clock_value(cur_field, val);
645 bt_ctf_object_put_ref(cur_field);
646 break;
647 }
648 default:
649 break;
650 }
651
652 end:
653 return ret;
654 }
655
656 static
657 int visit_event_update_clock_value(struct bt_ctf_event *event, uint64_t *val)
658 {
659 int ret = 0;
660 struct bt_ctf_field *field;
661
662 field = bt_ctf_event_get_header(event);
663 ret = visit_field_update_clock_value(field, val);
664 bt_ctf_object_put_ref(field);
665 if (ret) {
666 BT_LOGW_STR("Cannot automatically update clock value in "
667 "event's header.");
668 goto end;
669 }
670
671 field = bt_ctf_event_get_stream_event_context(event);
672 ret = visit_field_update_clock_value(field, val);
673 bt_ctf_object_put_ref(field);
674 if (ret) {
675 BT_LOGW_STR("Cannot automatically update clock value in "
676 "event's stream event context.");
677 goto end;
678 }
679
680 field = bt_ctf_event_get_context(event);
681 ret = visit_field_update_clock_value(field, val);
682 bt_ctf_object_put_ref(field);
683 if (ret) {
684 BT_LOGW_STR("Cannot automatically update clock value in "
685 "event's context.");
686 goto end;
687 }
688
689 field = bt_ctf_event_get_payload_field(event);
690 ret = visit_field_update_clock_value(field, val);
691 bt_ctf_object_put_ref(field);
692 if (ret) {
693 BT_LOGW_STR("Cannot automatically update clock value in "
694 "event's payload.");
695 goto end;
696 }
697
698 end:
699 return ret;
700 }
701
702 static
703 int set_packet_context_timestamps(struct bt_ctf_stream *stream)
704 {
705 int ret = 0;
706 uint64_t val;
707 uint64_t cur_clock_value;
708 uint64_t init_clock_value = 0;
709 struct bt_ctf_field *ts_begin_field = bt_ctf_field_structure_get_field_by_name(
710 stream->packet_context, "timestamp_begin");
711 struct bt_ctf_field *ts_end_field = bt_ctf_field_structure_get_field_by_name(
712 stream->packet_context, "timestamp_end");
713 struct bt_ctf_field_common *packet_context =
714 (void *) stream->packet_context;
715 uint64_t i;
716 int64_t len;
717
718 if (ts_begin_field && bt_ctf_field_is_set_recursive(ts_begin_field)) {
719 /* Use provided `timestamp_begin` value as starting value */
720 ret = bt_ctf_field_integer_unsigned_get_value(ts_begin_field, &val);
721 BT_ASSERT_DBG(ret == 0);
722 init_clock_value = val;
723 } else if (stream->last_ts_end != -1ULL) {
724 /* Use last packet's ending timestamp as starting value */
725 init_clock_value = stream->last_ts_end;
726 }
727
728 cur_clock_value = init_clock_value;
729
730 if (stream->last_ts_end != -1ULL &&
731 cur_clock_value < stream->last_ts_end) {
732 BT_LOGW("Packet's initial timestamp is less than previous "
733 "packet's final timestamp: "
734 "stream-addr=%p, stream-name=\"%s\", "
735 "cur-packet-ts-begin=%" PRIu64 ", "
736 "prev-packet-ts-end=%" PRIu64,
737 stream, bt_ctf_stream_get_name(stream),
738 cur_clock_value, stream->last_ts_end);
739 ret = -1;
740 goto end;
741 }
742
743 /*
744 * Visit all the packet context fields, followed by all the
745 * fields of all the events, in order, updating our current
746 * clock value as we visit.
747 *
748 * While visiting the packet context fields, do not consider
749 * `timestamp_begin` and `timestamp_end` because this function's
750 * purpose is to set them anyway. Also do not consider
751 * `packet_size`, `content_size`, `events_discarded`, and
752 * `packet_seq_num` if they are not set because those are
753 * autopopulating fields.
754 */
755 len = bt_ctf_field_type_structure_get_field_count(
756 (void *) packet_context->type);
757 BT_ASSERT_DBG(len >= 0);
758
759 for (i = 0; i < len; i++) {
760 const char *member_name;
761 struct bt_ctf_field *member_field;
762
763 ret = bt_ctf_field_type_structure_get_field_by_index(
764 (void *) packet_context->type, &member_name, NULL, i);
765 BT_ASSERT_DBG(ret == 0);
766
767 if (strcmp(member_name, "timestamp_begin") == 0 ||
768 strcmp(member_name, "timestamp_end") == 0) {
769 continue;
770 }
771
772 member_field = bt_ctf_field_structure_get_field_by_index(
773 stream->packet_context, i);
774 BT_ASSERT_DBG(member_field);
775
776 if (strcmp(member_name, "packet_size") == 0 &&
777 !bt_ctf_field_is_set_recursive(member_field)) {
778 bt_ctf_object_put_ref(member_field);
779 continue;
780 }
781
782 if (strcmp(member_name, "content_size") == 0 &&
783 !bt_ctf_field_is_set_recursive(member_field)) {
784 bt_ctf_object_put_ref(member_field);
785 continue;
786 }
787
788 if (strcmp(member_name, "events_discarded") == 0 &&
789 !bt_ctf_field_is_set_recursive(member_field)) {
790 bt_ctf_object_put_ref(member_field);
791 continue;
792 }
793
794 if (strcmp(member_name, "packet_seq_num") == 0 &&
795 !bt_ctf_field_is_set_recursive(member_field)) {
796 bt_ctf_object_put_ref(member_field);
797 continue;
798 }
799
800 ret = visit_field_update_clock_value(member_field,
801 &cur_clock_value);
802 bt_ctf_object_put_ref(member_field);
803 if (ret) {
804 BT_LOGW("Cannot automatically update clock value "
805 "in stream's packet context: "
806 "stream-addr=%p, stream-name=\"%s\", "
807 "field-name=\"%s\"",
808 stream, bt_ctf_stream_get_name(stream),
809 member_name);
810 goto end;
811 }
812 }
813
814 for (i = 0; i < stream->events->len; i++) {
815 struct bt_ctf_event *event = g_ptr_array_index(stream->events, i);
816
817 BT_ASSERT_DBG(event);
818 ret = visit_event_update_clock_value(event, &cur_clock_value);
819 if (ret) {
820 BT_LOGW("Cannot automatically update clock value "
821 "in stream's packet context: "
822 "stream-addr=%p, stream-name=\"%s\", "
823 "index=%" PRIu64 ", event-addr=%p, "
824 "event-class-id=%" PRId64 ", "
825 "event-class-name=\"%s\"",
826 stream, bt_ctf_stream_get_name(stream),
827 i, event,
828 bt_ctf_event_class_common_get_id(event->common.class),
829 bt_ctf_event_class_common_get_name(event->common.class));
830 goto end;
831 }
832 }
833
834 /*
835 * Everything is visited, thus the current clock value
836 * corresponds to the ending timestamp. Validate this value
837 * against the provided value of `timestamp_end`, if any,
838 * otherwise set it.
839 */
840 if (ts_end_field && bt_ctf_field_is_set_recursive(ts_end_field)) {
841 ret = bt_ctf_field_integer_unsigned_get_value(ts_end_field, &val);
842 BT_ASSERT_DBG(ret == 0);
843
844 if (val < cur_clock_value) {
845 BT_LOGW("Packet's final timestamp is less than "
846 "computed packet's final timestamp: "
847 "stream-addr=%p, stream-name=\"%s\", "
848 "cur-packet-ts-end=%" PRIu64 ", "
849 "computed-packet-ts-end=%" PRIu64,
850 stream, bt_ctf_stream_get_name(stream),
851 val, cur_clock_value);
852 ret = -1;
853 goto end;
854 }
855
856 stream->last_ts_end = val;
857 }
858
859 if (ts_end_field && !bt_ctf_field_is_set_recursive(ts_end_field)) {
860 ret = set_integer_field_value(ts_end_field, cur_clock_value);
861 BT_ASSERT_DBG(ret == 0);
862 stream->last_ts_end = cur_clock_value;
863 }
864
865 if (!ts_end_field) {
866 stream->last_ts_end = cur_clock_value;
867 }
868
869 /* Set `timestamp_begin` field to initial clock value */
870 if (ts_begin_field && !bt_ctf_field_is_set_recursive(ts_begin_field)) {
871 ret = set_integer_field_value(ts_begin_field, init_clock_value);
872 BT_ASSERT_DBG(ret == 0);
873 }
874
875 end:
876 bt_ctf_object_put_ref(ts_begin_field);
877 bt_ctf_object_put_ref(ts_end_field);
878 return ret;
879 }
880
881 static
882 int auto_populate_packet_context(struct bt_ctf_stream *stream, bool set_ts,
883 uint64_t packet_size_bits, uint64_t content_size_bits)
884 {
885 int ret = 0;
886
887 if (!stream->packet_context) {
888 goto end;
889 }
890
891 ret = set_packet_context_packet_size(stream, packet_size_bits);
892 if (ret) {
893 BT_LOGW("Cannot set packet context's packet size field: "
894 "stream-addr=%p, stream-name=\"%s\"",
895 stream, bt_ctf_stream_get_name(stream));
896 goto end;
897 }
898
899 ret = set_packet_context_content_size(stream, content_size_bits);
900 if (ret) {
901 BT_LOGW("Cannot set packet context's content size field: "
902 "stream-addr=%p, stream-name=\"%s\"",
903 stream, bt_ctf_stream_get_name(stream));
904 goto end;
905 }
906
907 if (set_ts) {
908 ret = set_packet_context_timestamps(stream);
909 if (ret) {
910 BT_LOGW("Cannot set packet context's timestamp fields: "
911 "stream-addr=%p, stream-name=\"%s\"",
912 stream, bt_ctf_stream_get_name(stream));
913 goto end;
914 }
915 }
916
917 ret = set_packet_context_events_discarded(stream);
918 if (ret) {
919 BT_LOGW("Cannot set packet context's discarded events count field: "
920 "stream-addr=%p, stream-name=\"%s\"",
921 stream, bt_ctf_stream_get_name(stream));
922 goto end;
923 }
924
925 BT_LOGT("Automatically populated stream's packet context's known fields: "
926 "stream-addr=%p, stream-name=\"%s\"",
927 stream, bt_ctf_stream_get_name(stream));
928
929 end:
930 return ret;
931 }
932
933 static
934 void release_event(struct bt_ctf_event *event)
935 {
936 if (bt_ctf_object_get_ref_count(&event->common.base)) {
937 /*
938 * The event is being orphaned, but it must guarantee the
939 * existence of its event class for the duration of its
940 * lifetime.
941 */
942 bt_ctf_object_get_ref(event->common.class);
943 BT_CTF_OBJECT_PUT_REF_AND_RESET(event->common.base.parent);
944 } else {
945 bt_ctf_object_try_spec_release(&event->common.base);
946 }
947 }
948
949 static
950 int create_stream_file(struct bt_ctf_writer *writer,
951 struct bt_ctf_stream *stream)
952 {
953 int ret = 0;
954 GString *filename = g_string_new(NULL);
955 int64_t stream_class_id;
956 char *file_path = NULL;
957
958 BT_LOGD("Creating stream file: writer-addr=%p, stream-addr=%p, "
959 "stream-name=\"%s\", stream-class-addr=%p, stream-class-name=\"%s\"",
960 writer, stream, bt_ctf_stream_get_name(stream),
961 stream->common.stream_class,
962 stream->common.stream_class->name->str);
963
964 if (stream->common.name && stream->common.name->len > 0) {
965 /* Use stream name's base name as prefix */
966 gchar *basename = g_path_get_basename(stream->common.name->str);
967
968 BT_ASSERT_DBG(basename);
969
970 if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) {
971 g_string_assign(filename, "stream");
972 } else {
973 g_string_assign(filename, basename);
974 }
975
976 g_free(basename);
977 goto append_ids;
978 }
979
980 if (stream->common.stream_class->name &&
981 stream->common.stream_class->name->len > 0) {
982 /* Use stream class name's base name as prefix */
983 gchar *basename =
984 g_path_get_basename(
985 stream->common.stream_class->name->str);
986
987 BT_ASSERT_DBG(basename);
988
989 if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) {
990 g_string_assign(filename, "stream");
991 } else {
992 g_string_assign(filename, basename);
993 }
994
995 g_free(basename);
996 goto append_ids;
997 }
998
999 /* Default to using `stream-` as prefix */
1000 g_string_assign(filename, "stream");
1001
1002 append_ids:
1003 stream_class_id = bt_ctf_stream_class_common_get_id(stream->common.stream_class);
1004 BT_ASSERT_DBG(stream_class_id >= 0);
1005 BT_ASSERT_DBG(stream->common.id >= 0);
1006 g_string_append_printf(filename, "-%" PRId64 "-%" PRId64,
1007 stream_class_id, stream->common.id);
1008
1009 file_path = g_build_filename(writer->path->str, filename->str, NULL);
1010 if (!file_path) {
1011 ret = -1;
1012 goto end;
1013 }
1014
1015 ret = bt_ctfser_init(&stream->ctfser, file_path,
1016 BT_LOG_OUTPUT_LEVEL);
1017 g_free(file_path);
1018 if (ret) {
1019 /* bt_ctfser_init() logs errors */
1020 goto end;
1021 }
1022
1023 BT_LOGD("Created stream file for writing: "
1024 "stream-addr=%p, stream-name=\"%s\", "
1025 "filename=\"%s\"", stream, bt_ctf_stream_get_name(stream),
1026 filename->str);
1027
1028 end:
1029 g_string_free(filename, TRUE);
1030 return ret;
1031 }
1032
1033 BT_HIDDEN
1034 struct bt_ctf_stream *bt_ctf_stream_create_with_id(
1035 struct bt_ctf_stream_class *stream_class,
1036 const char *name, uint64_t id)
1037 {
1038 int ret;
1039 int fd;
1040 struct bt_ctf_stream *stream = NULL;
1041 struct bt_ctf_trace *trace = NULL;
1042 struct bt_ctf_writer *writer = NULL;
1043
1044 BT_LOGD("Creating CTF writer stream object: stream-class-addr=%p, "
1045 "stream-class-name=\"%s\", stream-name=\"%s\", "
1046 "stream-id=%" PRIu64,
1047 stream_class, bt_ctf_stream_class_get_name(stream_class),
1048 name, id);
1049 stream = g_new0(struct bt_ctf_stream, 1);
1050 if (!stream) {
1051 BT_LOGE_STR("Failed to allocate one stream.");
1052 goto error;
1053 }
1054
1055 if (id == -1ULL) {
1056 id = stream_class->next_stream_id;
1057 }
1058
1059 ret = bt_ctf_stream_common_initialize(BT_CTF_TO_COMMON(stream),
1060 BT_CTF_TO_COMMON(stream_class), name, id, bt_ctf_stream_destroy);
1061 if (ret) {
1062 /* bt_ctf_stream_common_initialize() logs errors */
1063 goto error;
1064 }
1065
1066 trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
1067 BT_CTF_TO_COMMON(stream_class)));
1068 if (!trace) {
1069 BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: "
1070 "stream-class-addr=%p, stream-class-name=\"%s\", "
1071 "stream-name=\"%s\"",
1072 stream_class, bt_ctf_stream_class_get_name(stream_class),
1073 name);
1074 goto error;
1075 }
1076
1077 writer = (struct bt_ctf_writer *)
1078 bt_ctf_object_get_parent(&trace->common.base);
1079 stream->last_ts_end = -1ULL;
1080 BT_LOGD("CTF writer stream object belongs writer's trace: "
1081 "writer-addr=%p", writer);
1082 BT_ASSERT_DBG(writer);
1083
1084 if (stream_class->common.packet_context_field_type) {
1085 BT_LOGD("Creating stream's packet context field: "
1086 "ft-addr=%p",
1087 stream_class->common.packet_context_field_type);
1088 stream->packet_context = bt_ctf_field_create(
1089 (void *) stream_class->common.packet_context_field_type);
1090 if (!stream->packet_context) {
1091 BT_LOGW_STR("Cannot create stream's packet context field.");
1092 goto error;
1093 }
1094
1095 /* Initialize events_discarded */
1096 ret = try_set_structure_field_integer(
1097 stream->packet_context, "events_discarded", 0);
1098 if (ret < 0) {
1099 BT_LOGW("Cannot set `events_discarded` field in packet context: "
1100 "ret=%d, packet-context-field-addr=%p",
1101 ret, stream->packet_context);
1102 goto error;
1103 }
1104 }
1105
1106 stream->events = g_ptr_array_new_with_free_func(
1107 (GDestroyNotify) release_event);
1108 if (!stream->events) {
1109 BT_LOGE_STR("Failed to allocate a GPtrArray.");
1110 goto error;
1111 }
1112
1113 if (trace->common.packet_header_field_type) {
1114 BT_LOGD("Creating stream's packet header field: "
1115 "ft-addr=%p", trace->common.packet_header_field_type);
1116 stream->packet_header =
1117 bt_ctf_field_create(
1118 (void *) trace->common.packet_header_field_type);
1119 if (!stream->packet_header) {
1120 BT_LOGW_STR("Cannot create stream's packet header field.");
1121 goto error;
1122 }
1123 }
1124
1125 /*
1126 * Attempt to populate the default trace packet header fields
1127 * (magic, uuid and stream_id). This will _not_ fail shall the
1128 * fields not be found or be of an incompatible type; they will
1129 * simply not be populated automatically. The user will have to
1130 * make sure to set the trace packet header fields himself
1131 * before flushing.
1132 */
1133 ret = auto_populate_packet_header(stream);
1134 if (ret) {
1135 BT_LOGW_STR("Cannot automatically populate the stream's packet header.");
1136 goto error;
1137 }
1138
1139 /* Create file associated with this stream */
1140 fd = create_stream_file(writer, stream);
1141 if (fd < 0) {
1142 BT_LOGW_STR("Cannot create stream file.");
1143 goto error;
1144 }
1145
1146 /* Freeze the writer */
1147 BT_LOGD_STR("Freezing stream's CTF writer.");
1148 bt_ctf_writer_freeze(writer);
1149
1150 /* Add this stream to the trace's streams */
1151 g_ptr_array_add(trace->common.streams, stream);
1152 stream_class->next_stream_id++;
1153 BT_LOGD("Created stream object: addr=%p", stream);
1154 goto end;
1155
1156 error:
1157 BT_CTF_OBJECT_PUT_REF_AND_RESET(stream);
1158
1159 end:
1160 bt_ctf_object_put_ref(writer);
1161 return stream;
1162 }
1163
1164 struct bt_ctf_stream *bt_ctf_stream_create(
1165 struct bt_ctf_stream_class *stream_class,
1166 const char *name, uint64_t id_param)
1167 {
1168 return bt_ctf_stream_create_with_id(stream_class,
1169 name, id_param);
1170 }
1171
1172 int bt_ctf_stream_get_discarded_events_count(
1173 struct bt_ctf_stream *stream, uint64_t *count)
1174 {
1175 int ret = 0;
1176
1177 if (!stream) {
1178 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1179 ret = -1;
1180 goto end;
1181 }
1182
1183 if (!count) {
1184 BT_LOGW_STR("Invalid parameter: count is NULL.");
1185 ret = -1;
1186 goto end;
1187 }
1188
1189 *count = (uint64_t) stream->discarded_events;
1190
1191 end:
1192 return ret;
1193 }
1194
1195 static
1196 int set_packet_context_events_discarded_field(struct bt_ctf_stream *stream,
1197 uint64_t count)
1198 {
1199 int ret = 0;
1200 struct bt_ctf_field *events_discarded_field = NULL;
1201
1202 if (!stream->packet_context) {
1203 goto end;
1204 }
1205
1206 events_discarded_field = bt_ctf_field_structure_get_field_by_name(
1207 stream->packet_context, "events_discarded");
1208 if (!events_discarded_field) {
1209 goto end;
1210 }
1211
1212 ret = bt_ctf_field_integer_unsigned_set_value(
1213 events_discarded_field, count);
1214 if (ret) {
1215 BT_LOGW("Cannot set packet context's `events_discarded` field: "
1216 "field-addr=%p, value=%" PRIu64,
1217 events_discarded_field, count);
1218 goto end;
1219 }
1220
1221 end:
1222 bt_ctf_object_put_ref(events_discarded_field);
1223 return ret;
1224 }
1225
1226 void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
1227 uint64_t event_count)
1228 {
1229 int ret;
1230 uint64_t new_count;
1231 struct bt_ctf_field *events_discarded_field = NULL;
1232
1233 if (!stream) {
1234 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1235 goto end;
1236 }
1237
1238 BT_LOGT("Appending discarded events to stream: "
1239 "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64,
1240 stream, bt_ctf_stream_get_name(stream), event_count);
1241
1242 if (!stream->packet_context) {
1243 BT_LOGW_STR("Invalid parameter: stream has no packet context field.");
1244 goto end;
1245 }
1246
1247 events_discarded_field = bt_ctf_field_structure_get_field_by_name(
1248 stream->packet_context, "events_discarded");
1249 if (!events_discarded_field) {
1250 BT_LOGW_STR("No field named `events_discarded` in stream's packet context.");
1251 goto end;
1252 }
1253
1254 new_count = stream->discarded_events + event_count;
1255 if (new_count < stream->discarded_events) {
1256 BT_LOGW("New discarded events count is less than the stream's current discarded events count: "
1257 "cur-count=%" PRIu64 ", new-count=%" PRIu64,
1258 stream->discarded_events, new_count);
1259 goto end;
1260 }
1261
1262 ret = set_packet_context_events_discarded_field(stream, new_count);
1263 if (ret) {
1264 /* set_packet_context_events_discarded_field() logs errors */
1265 goto end;
1266 }
1267
1268 stream->discarded_events = new_count;
1269 BT_LOGT("Appended discarded events to stream: "
1270 "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64,
1271 stream, bt_ctf_stream_get_name(stream), event_count);
1272
1273 end:
1274 bt_ctf_object_put_ref(events_discarded_field);
1275 }
1276
1277 static int auto_populate_event_header(struct bt_ctf_stream *stream,
1278 struct bt_ctf_event *event)
1279 {
1280 int ret = 0;
1281 struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL;
1282 struct bt_ctf_clock_class *mapped_clock_class = NULL;
1283 struct bt_ctf_stream_class *stream_class =
1284 BT_CTF_FROM_COMMON(bt_ctf_stream_common_borrow_class(
1285 BT_CTF_TO_COMMON(stream)));
1286 int64_t event_class_id;
1287
1288 BT_ASSERT_DBG(event);
1289
1290 if (!event->common.header_field) {
1291 goto end;
1292 }
1293
1294 if (event->common.frozen) {
1295 BT_LOGW_STR("Cannot populate event header field: event is frozen.");
1296 ret = -1;
1297 goto end;
1298 }
1299
1300 BT_LOGT("Automatically populating event's header field: "
1301 "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
1302 stream, bt_ctf_stream_get_name(stream), event);
1303
1304 id_field = bt_ctf_field_structure_get_field_by_name(
1305 (void *) event->common.header_field->field, "id");
1306 event_class_id = bt_ctf_event_class_common_get_id(event->common.class);
1307 BT_ASSERT_DBG(event_class_id >= 0);
1308
1309 if (id_field && bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER) {
1310 ret = set_integer_field_value(id_field, event_class_id);
1311 if (ret) {
1312 BT_LOGW("Cannot set event header's `id` field's value: "
1313 "addr=%p, value=%" PRIu64, id_field,
1314 event_class_id);
1315 goto end;
1316 }
1317 }
1318
1319 /*
1320 * The conditions to automatically set the timestamp are:
1321 *
1322 * 1. The event header field "timestamp" exists and is an
1323 * integer field.
1324 * 2. This stream's class has a registered clock (set with
1325 * bt_ctf_stream_class_set_clock()).
1326 * 3. The "timestamp" field is not set.
1327 */
1328 timestamp_field = bt_ctf_field_structure_get_field_by_name(
1329 (void *) event->common.header_field->field, "timestamp");
1330 if (timestamp_field && stream_class->clock &&
1331 bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER &&
1332 !bt_ctf_field_is_set_recursive(timestamp_field)) {
1333 mapped_clock_class =
1334 bt_ctf_field_type_integer_get_mapped_clock_class(
1335 (void *) ((struct bt_ctf_field_common *) timestamp_field)->type);
1336 if (mapped_clock_class) {
1337 uint64_t timestamp;
1338
1339 BT_ASSERT_DBG(mapped_clock_class ==
1340 stream_class->clock->clock_class);
1341 ret = bt_ctf_clock_get_value(
1342 stream_class->clock,
1343 &timestamp);
1344 BT_ASSERT_DBG(ret == 0);
1345 ret = set_integer_field_value(timestamp_field,
1346 timestamp);
1347 if (ret) {
1348 BT_LOGW("Cannot set event header's `timestamp` field's value: "
1349 "addr=%p, value=%" PRIu64,
1350 timestamp_field, timestamp);
1351 goto end;
1352 }
1353 }
1354 }
1355
1356 BT_LOGT("Automatically populated event's header field: "
1357 "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
1358 stream, bt_ctf_stream_get_name(stream), event);
1359
1360 end:
1361 bt_ctf_object_put_ref(id_field);
1362 bt_ctf_object_put_ref(timestamp_field);
1363 bt_ctf_object_put_ref(mapped_clock_class);
1364 return ret;
1365 }
1366
1367 int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
1368 struct bt_ctf_event *event)
1369 {
1370 int ret = 0;
1371
1372 if (!stream) {
1373 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1374 ret = -1;
1375 goto end;
1376 }
1377
1378 if (!event) {
1379 BT_LOGW_STR("Invalid parameter: event is NULL.");
1380 ret = -1;
1381 goto end;
1382 }
1383
1384 BT_LOGT("Appending event to stream: "
1385 "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
1386 "event-class-name=\"%s\", event-class-id=%" PRId64,
1387 stream, bt_ctf_stream_get_name(stream), event,
1388 bt_ctf_event_class_common_get_name(
1389 bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))),
1390 bt_ctf_event_class_common_get_id(
1391 bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))));
1392
1393 /*
1394 * The event is not supposed to have a parent stream at this
1395 * point. The only other way an event can have a parent stream
1396 * is if it was assigned when setting a packet to the event,
1397 * in which case the packet's stream is not a writer stream,
1398 * and thus the user is trying to append an event which belongs
1399 * to another stream.
1400 */
1401 if (event->common.base.parent) {
1402 ret = -1;
1403 goto end;
1404 }
1405
1406 bt_ctf_object_set_parent(&event->common.base, &stream->common.base);
1407 BT_LOGT_STR("Automatically populating the header of the event to append.");
1408 ret = auto_populate_event_header(stream, event);
1409 if (ret) {
1410 /* auto_populate_event_header() reports errors */
1411 goto error;
1412 }
1413
1414 /* Make sure the various scopes of the event are set */
1415 BT_LOGT_STR("Validating event to append.");
1416 BT_CTF_ASSERT_PRE(bt_ctf_event_common_validate(BT_CTF_TO_COMMON(event)) == 0,
1417 "Invalid event: event-addr=%p", event);
1418
1419 /* Save the new event and freeze it */
1420 BT_LOGT_STR("Freezing the event to append.");
1421 bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true);
1422 g_ptr_array_add(stream->events, event);
1423
1424 /*
1425 * Event had to hold a reference to its event class as long as it wasn't
1426 * part of the same trace hierarchy. From now on, the event and its
1427 * class share the same lifetime guarantees and the reference is no
1428 * longer needed.
1429 */
1430 BT_LOGT_STR("Putting the event's class.");
1431 bt_ctf_object_put_ref(event->common.class);
1432 BT_LOGT("Appended event to stream: "
1433 "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
1434 "event-class-name=\"%s\", event-class-id=%" PRId64,
1435 stream, bt_ctf_stream_get_name(stream), event,
1436 bt_ctf_event_class_common_get_name(
1437 bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))),
1438 bt_ctf_event_class_common_get_id(
1439 bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))));
1440
1441 end:
1442 return ret;
1443
1444 error:
1445 /*
1446 * Orphan the event; we were not successful in associating it to
1447 * a stream.
1448 */
1449 bt_ctf_object_set_parent(&event->common.base, NULL);
1450 return ret;
1451 }
1452
1453 struct bt_ctf_field *bt_ctf_stream_get_packet_context(struct bt_ctf_stream *stream)
1454 {
1455 struct bt_ctf_field *packet_context = NULL;
1456
1457 if (!stream) {
1458 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1459 goto end;
1460 }
1461
1462 packet_context = stream->packet_context;
1463 if (packet_context) {
1464 bt_ctf_object_get_ref(packet_context);
1465 }
1466 end:
1467 return packet_context;
1468 }
1469
1470 int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream,
1471 struct bt_ctf_field *field)
1472 {
1473 int ret = 0;
1474 struct bt_ctf_field_type *field_type;
1475
1476 if (!stream) {
1477 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1478 ret = -1;
1479 goto end;
1480 }
1481
1482 field_type = bt_ctf_field_get_type(field);
1483 if (bt_ctf_field_type_common_compare((void *) field_type,
1484 stream->common.stream_class->packet_context_field_type)) {
1485 BT_LOGW("Invalid parameter: packet context's field type is different from the stream's packet context field type: "
1486 "stream-addr=%p, stream-name=\"%s\", "
1487 "packet-context-field-addr=%p, "
1488 "packet-context-ft-addr=%p",
1489 stream, bt_ctf_stream_get_name(stream),
1490 field, field_type);
1491 ret = -1;
1492 goto end;
1493 }
1494
1495 bt_ctf_object_put_ref(field_type);
1496 bt_ctf_object_put_ref(stream->packet_context);
1497 stream->packet_context = bt_ctf_object_get_ref(field);
1498 BT_LOGT("Set stream's packet context field: "
1499 "stream-addr=%p, stream-name=\"%s\", "
1500 "packet-context-field-addr=%p",
1501 stream, bt_ctf_stream_get_name(stream), field);
1502 end:
1503 return ret;
1504 }
1505
1506 struct bt_ctf_field *bt_ctf_stream_get_packet_header(struct bt_ctf_stream *stream)
1507 {
1508 struct bt_ctf_field *packet_header = NULL;
1509
1510 if (!stream) {
1511 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1512 goto end;
1513 }
1514
1515 packet_header = stream->packet_header;
1516 if (packet_header) {
1517 bt_ctf_object_get_ref(packet_header);
1518 }
1519 end:
1520 return packet_header;
1521 }
1522
1523 int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream,
1524 struct bt_ctf_field *field)
1525 {
1526 int ret = 0;
1527 struct bt_ctf_trace *trace = NULL;
1528 struct bt_ctf_field_type *field_type = NULL;
1529
1530 if (!stream) {
1531 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1532 ret = -1;
1533 goto end;
1534 }
1535
1536 trace = (struct bt_ctf_trace *)
1537 bt_ctf_object_get_parent(&stream->common.base);
1538
1539 if (!field) {
1540 if (trace->common.packet_header_field_type) {
1541 BT_LOGW("Invalid parameter: setting no packet header but packet header field type is not NULL: "
1542 "stream-addr=%p, stream-name=\"%s\", "
1543 "packet-header-field-addr=%p, "
1544 "expected-ft-addr=%p",
1545 stream, bt_ctf_stream_get_name(stream),
1546 field, trace->common.packet_header_field_type);
1547 ret = -1;
1548 goto end;
1549 }
1550
1551 goto skip_validation;
1552 }
1553
1554 field_type = bt_ctf_field_get_type(field);
1555 BT_ASSERT_DBG(field_type);
1556
1557 if (bt_ctf_field_type_common_compare((void *) field_type,
1558 trace->common.packet_header_field_type)) {
1559 BT_LOGW("Invalid parameter: packet header's field type is different from the stream's packet header field type: "
1560 "stream-addr=%p, stream-name=\"%s\", "
1561 "packet-header-field-addr=%p, "
1562 "packet-header-ft-addr=%p",
1563 stream, bt_ctf_stream_get_name(stream),
1564 field, field_type);
1565 ret = -1;
1566 goto end;
1567 }
1568
1569 skip_validation:
1570 bt_ctf_object_put_ref(stream->packet_header);
1571 stream->packet_header = bt_ctf_object_get_ref(field);
1572 BT_LOGT("Set stream's packet header field: "
1573 "stream-addr=%p, stream-name=\"%s\", "
1574 "packet-header-field-addr=%p",
1575 stream, bt_ctf_stream_get_name(stream), field);
1576 end:
1577 BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
1578 bt_ctf_object_put_ref(field_type);
1579 return ret;
1580 }
1581
1582 static
1583 void reset_structure_field(struct bt_ctf_field *structure, const char *name)
1584 {
1585 struct bt_ctf_field *member;
1586
1587 member = bt_ctf_field_structure_get_field_by_name(structure, name);
1588 if (member) {
1589 bt_ctf_field_common_reset_recursive((void *) member);
1590 bt_ctf_object_put_ref(member);
1591 }
1592 }
1593
1594 int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
1595 {
1596 int ret = 0;
1597 size_t i;
1598 uint64_t packet_context_offset_bits = 0;
1599 struct bt_ctf_trace *trace;
1600 enum bt_ctf_byte_order native_byte_order;
1601 bool has_packet_size = false;
1602 uint64_t packet_size_bits = 0;
1603 uint64_t content_size_bits = 0;
1604
1605 if (!stream) {
1606 BT_LOGW_STR("Invalid parameter: stream is NULL.");
1607 ret = -1;
1608 goto end_no_stream;
1609 }
1610
1611 if (stream->packet_context) {
1612 struct bt_ctf_field *packet_size_field;
1613
1614 packet_size_field = bt_ctf_field_structure_get_field_by_name(
1615 stream->packet_context, "packet_size");
1616 has_packet_size = packet_size_field;
1617 bt_ctf_object_put_ref(packet_size_field);
1618 }
1619
1620 if (stream->flushed_packet_count == 1) {
1621 if (!stream->packet_context) {
1622 BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once.");
1623 ret = -1;
1624 goto end;
1625 }
1626
1627 if (!has_packet_size) {
1628 BT_LOGW_STR("Cannot flush a stream which has no packet context's `packet_size` field more than once.");
1629 ret = -1;
1630 goto end;
1631 }
1632 }
1633
1634 BT_LOGT("Flushing stream's current packet: stream-addr=%p, "
1635 "stream-name=\"%s\", packet-index=%u", stream,
1636 bt_ctf_stream_get_name(stream), stream->flushed_packet_count);
1637 trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
1638 stream->common.stream_class));
1639 BT_ASSERT_DBG(trace);
1640 native_byte_order = bt_ctf_trace_get_native_byte_order(trace);
1641
1642 ret = auto_populate_packet_header(stream);
1643 if (ret) {
1644 BT_LOGW_STR("Cannot automatically populate the stream's packet header field.");
1645 ret = -1;
1646 goto end;
1647 }
1648
1649 /* Initialize packet/content sizes to `0`; we will overwrite later */
1650 ret = auto_populate_packet_context(stream, true, 0, 0);
1651 if (ret) {
1652 BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
1653 ret = -1;
1654 goto end;
1655 }
1656
1657 ret = bt_ctfser_open_packet(&stream->ctfser);
1658 if (ret) {
1659 /* bt_ctfser_open_packet() logs errors */
1660 ret = -1;
1661 goto end;
1662 }
1663
1664 if (stream->packet_header) {
1665 BT_LOGT_STR("Serializing packet header field (initial).");
1666 ret = bt_ctf_field_serialize_recursive(stream->packet_header,
1667 &stream->ctfser, native_byte_order);
1668 if (ret) {
1669 BT_LOGW("Cannot serialize stream's packet header field: "
1670 "field-addr=%p", stream->packet_header);
1671 goto end;
1672 }
1673 }
1674
1675 if (stream->packet_context) {
1676 /* Save packet context's position to overwrite it later */
1677 packet_context_offset_bits =
1678 bt_ctfser_get_offset_in_current_packet_bits(
1679 &stream->ctfser);
1680
1681 /* Write packet context */
1682 BT_LOGT_STR("Serializing packet context field (initial).");
1683 ret = bt_ctf_field_serialize_recursive(stream->packet_context,
1684 &stream->ctfser, native_byte_order);
1685 if (ret) {
1686 BT_LOGW("Cannot serialize stream's packet context field: "
1687 "field-addr=%p", stream->packet_context);
1688 goto end;
1689 }
1690 }
1691
1692 BT_LOGT("Serializing events: count=%u", stream->events->len);
1693
1694 for (i = 0; i < stream->events->len; i++) {
1695 struct bt_ctf_event *event = g_ptr_array_index(
1696 stream->events, i);
1697 struct bt_ctf_event_class *event_class =
1698 BT_CTF_FROM_COMMON(bt_ctf_event_common_borrow_class(
1699 BT_CTF_TO_COMMON(event)));
1700
1701 BT_LOGT("Serializing event: index=%zu, event-addr=%p, "
1702 "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
1703 "ser-offset=%" PRIu64,
1704 i, event, bt_ctf_event_class_get_name(event_class),
1705 bt_ctf_event_class_get_id(event_class),
1706 bt_ctfser_get_offset_in_current_packet_bits(
1707 &stream->ctfser));
1708
1709 /* Write event header */
1710 if (event->common.header_field) {
1711 BT_LOGT_STR("Serializing event's header field.");
1712 ret = bt_ctf_field_serialize_recursive(
1713 (void *) event->common.header_field->field,
1714 &stream->ctfser, native_byte_order);
1715 if (ret) {
1716 BT_LOGW("Cannot serialize event's header field: "
1717 "field-addr=%p",
1718 event->common.header_field->field);
1719 goto end;
1720 }
1721 }
1722
1723 /* Write stream event context */
1724 if (event->common.stream_event_context_field) {
1725 BT_LOGT_STR("Serializing event's stream event context field.");
1726 ret = bt_ctf_field_serialize_recursive(
1727 (void *) event->common.stream_event_context_field,
1728 &stream->ctfser, native_byte_order);
1729 if (ret) {
1730 BT_LOGW("Cannot serialize event's stream event context field: "
1731 "field-addr=%p",
1732 event->common.stream_event_context_field);
1733 goto end;
1734 }
1735 }
1736
1737 /* Write event content */
1738 ret = bt_ctf_event_serialize(event, &stream->ctfser,
1739 native_byte_order);
1740 if (ret) {
1741 /* bt_ctf_event_serialize() logs errors */
1742 goto end;
1743 }
1744 }
1745
1746 content_size_bits = bt_ctfser_get_offset_in_current_packet_bits(
1747 &stream->ctfser);
1748
1749 if (!has_packet_size && content_size_bits % 8 != 0) {
1750 BT_LOGW("Stream's packet context field type has no `packet_size` field, "
1751 "but current content size is not a multiple of 8 bits: "
1752 "content-size=%" PRIu64 ", "
1753 "packet-size=%" PRIu64,
1754 content_size_bits,
1755 packet_size_bits);
1756 ret = -1;
1757 goto end;
1758 }
1759
1760 /* Set packet size; make it a multiple of 8 */
1761 packet_size_bits = (content_size_bits + 7) & ~UINT64_C(7);
1762
1763 if (stream->packet_context) {
1764 /*
1765 * The whole packet is serialized at this point. Make
1766 * sure that, if `packet_size` is missing, the current
1767 * content size is equal to the current packet size.
1768 */
1769 struct bt_ctf_field *field =
1770 bt_ctf_field_structure_get_field_by_name(
1771 stream->packet_context, "content_size");
1772
1773 bt_ctf_object_put_ref(field);
1774 if (!field) {
1775 if (content_size_bits != packet_size_bits) {
1776 BT_LOGW("Stream's packet context's `content_size` field is missing, "
1777 "but current packet's content size is not equal to its packet size: "
1778 "content-size=%" PRIu64 ", "
1779 "packet-size=%" PRIu64,
1780 bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser),
1781 packet_size_bits);
1782 ret = -1;
1783 goto end;
1784 }
1785 }
1786
1787 /*
1788 * Overwrite the packet context now that the stream
1789 * position's packet and content sizes have the correct
1790 * values.
1791 */
1792 bt_ctfser_set_offset_in_current_packet_bits(&stream->ctfser,
1793 packet_context_offset_bits);
1794 ret = auto_populate_packet_context(stream, false,
1795 packet_size_bits, content_size_bits);
1796 if (ret) {
1797 BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
1798 ret = -1;
1799 goto end;
1800 }
1801
1802 BT_LOGT("Rewriting (serializing) packet context field.");
1803 ret = bt_ctf_field_serialize_recursive(stream->packet_context,
1804 &stream->ctfser, native_byte_order);
1805 if (ret) {
1806 BT_LOGW("Cannot serialize stream's packet context field: "
1807 "field-addr=%p", stream->packet_context);
1808 goto end;
1809 }
1810 }
1811
1812 g_ptr_array_set_size(stream->events, 0);
1813 stream->flushed_packet_count++;
1814 bt_ctfser_close_current_packet(&stream->ctfser, packet_size_bits / 8);
1815
1816 end:
1817 /* Reset automatically-set fields. */
1818 if (stream->packet_context) {
1819 reset_structure_field(stream->packet_context, "timestamp_begin");
1820 reset_structure_field(stream->packet_context, "timestamp_end");
1821 reset_structure_field(stream->packet_context, "packet_size");
1822 reset_structure_field(stream->packet_context, "content_size");
1823 reset_structure_field(stream->packet_context, "events_discarded");
1824 }
1825
1826 if (ret == 0) {
1827 BT_LOGT("Flushed stream's current packet: "
1828 "content-size=%" PRIu64 ", packet-size=%" PRIu64,
1829 content_size_bits, packet_size_bits);
1830 }
1831
1832 end_no_stream:
1833 return ret;
1834 }
1835
1836 static
1837 void bt_ctf_stream_destroy(struct bt_ctf_object *obj)
1838 {
1839 struct bt_ctf_stream *stream = (void *) obj;
1840
1841 BT_LOGD("Destroying CTF writer stream object: addr=%p, name=\"%s\"",
1842 stream, bt_ctf_stream_get_name(stream));
1843
1844 bt_ctf_stream_common_finalize(BT_CTF_TO_COMMON(stream));
1845 bt_ctfser_fini(&stream->ctfser);
1846
1847 if (stream->events) {
1848 BT_LOGD_STR("Putting events.");
1849 g_ptr_array_free(stream->events, TRUE);
1850 }
1851
1852 BT_LOGD_STR("Putting packet header field.");
1853 bt_ctf_object_put_ref(stream->packet_header);
1854 BT_LOGD_STR("Putting packet context field.");
1855 bt_ctf_object_put_ref(stream->packet_context);
1856 g_free(stream);
1857 }
1858
1859 static
1860 int _set_structure_field_integer(struct bt_ctf_field *structure, const char *name,
1861 uint64_t value, bt_ctf_bool force)
1862 {
1863 int ret = 0;
1864 struct bt_ctf_field_type *field_type = NULL;
1865 struct bt_ctf_field *integer;
1866
1867 BT_ASSERT_DBG(structure);
1868 BT_ASSERT_DBG(name);
1869
1870 integer = bt_ctf_field_structure_get_field_by_name(structure, name);
1871 if (!integer) {
1872 /* Field not found, not an error. */
1873 BT_LOGT("Field not found: struct-field-addr=%p, "
1874 "name=\"%s\", force=%d", structure, name, force);
1875 goto end;
1876 }
1877
1878 /* Make sure the payload has not already been set. */
1879 if (!force && bt_ctf_field_is_set_recursive(integer)) {
1880 /* Payload already set, not an error */
1881 BT_LOGT("Field's payload is already set: struct-field-addr=%p, "
1882 "name=\"%s\", force=%d", structure, name, force);
1883 goto end;
1884 }
1885
1886 field_type = bt_ctf_field_get_type(integer);
1887 BT_ASSERT_DBG(field_type);
1888 if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) {
1889 /*
1890 * The user most likely meant for us to populate this field
1891 * automatically. However, we can only do this if the field
1892 * is an integer. Return an error.
1893 */
1894 BT_LOGW("Invalid parameter: field's type is not an integer field type: "
1895 "field-addr=%p, ft-addr=%p, ft-id=%s",
1896 integer, field_type,
1897 bt_ctf_field_type_id_string((int)
1898 bt_ctf_field_type_get_type_id(field_type)));
1899 ret = -1;
1900 goto end;
1901 }
1902
1903 if (bt_ctf_field_type_integer_is_signed(field_type)) {
1904 ret = bt_ctf_field_integer_signed_set_value(integer,
1905 (int64_t) value);
1906 } else {
1907 ret = bt_ctf_field_integer_unsigned_set_value(integer, value);
1908 }
1909 ret = !ret ? 1 : ret;
1910 end:
1911 bt_ctf_object_put_ref(integer);
1912 bt_ctf_object_put_ref(field_type);
1913 return ret;
1914 }
1915
1916 /*
1917 * Returns the following codes:
1918 * 1 if the field was found and set,
1919 * 0 if nothing was done (field not found, or was already set),
1920 * <0 if an error was encoutered
1921 */
1922 static
1923 int try_set_structure_field_integer(struct bt_ctf_field *structure, const char *name,
1924 uint64_t value)
1925 {
1926 return _set_structure_field_integer(structure, name, value, BT_CTF_FALSE);
1927 }
1928
1929 struct bt_ctf_stream_class *bt_ctf_stream_get_class(
1930 struct bt_ctf_stream *stream)
1931 {
1932 return bt_ctf_object_get_ref(bt_ctf_stream_common_borrow_class(BT_CTF_TO_COMMON(stream)));
1933 }
1934
1935 const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream)
1936 {
1937 return bt_ctf_stream_common_get_name(BT_CTF_TO_COMMON(stream));
1938 }
1939
1940 int64_t bt_ctf_stream_get_id(struct bt_ctf_stream *stream)
1941 {
1942 return bt_ctf_stream_common_get_id(BT_CTF_TO_COMMON(stream));
1943 }
This page took 0.107638 seconds and 4 git commands to generate.