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