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