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