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