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