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