Writer: set the discarded events's value before serializing
[babeltrace.git] / formats / 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
ac0c6bdd
PP
29#include <babeltrace/ctf-ir/clock-class.h>
30#include <babeltrace/ctf-writer/clock.h>
31#include <babeltrace/ctf-writer/clock-internal.h>
273b65be 32#include <babeltrace/ctf-writer/event.h>
adc315b8 33#include <babeltrace/ctf-ir/event-internal.h>
2e33ac5a
PP
34#include <babeltrace/ctf-ir/field-types-internal.h>
35#include <babeltrace/ctf-ir/fields-internal.h>
3f043b05
JG
36#include <babeltrace/ctf-ir/stream.h>
37#include <babeltrace/ctf-ir/stream-internal.h>
adc315b8 38#include <babeltrace/ctf-ir/stream-class-internal.h>
319fd969
PP
39#include <babeltrace/ctf-ir/trace-internal.h>
40#include <babeltrace/ctf-writer/writer-internal.h>
83509119 41#include <babeltrace/ref.h>
273b65be
JG
42#include <babeltrace/ctf-writer/functor-internal.h>
43#include <babeltrace/compiler.h>
44#include <babeltrace/align.h>
d246b111 45#include <babeltrace/ctf/ctf-index.h>
273b65be
JG
46
47static
83509119 48void bt_ctf_stream_destroy(struct bt_object *obj);
273b65be 49static
273b65be
JG
50int set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t);
51
ac0c6bdd
PP
52static
53int set_integer_field_value(struct bt_ctf_field* field, uint64_t value)
54{
55 int ret = 0;
56 struct bt_ctf_field_type *field_type = NULL;
57
58 if (!field) {
59 ret = -1;
60 goto end;
61 }
62
63 field_type = bt_ctf_field_get_type(field);
64 assert(field_type);
65
66 if (bt_ctf_field_type_get_type_id(field_type) !=
67 BT_CTF_TYPE_ID_INTEGER) {
68 /* Not an integer and the value is unset, error. */
69 ret = -1;
70 goto end;
71 }
72
73 if (bt_ctf_field_type_integer_get_signed(field_type)) {
74 ret = bt_ctf_field_signed_integer_set_value(field, (int64_t) value);
75 if (ret) {
76 /* Value is out of range, error. */
77 goto end;
78 }
79 } else {
80 ret = bt_ctf_field_unsigned_integer_set_value(field, value);
81 if (ret) {
82 /* Value is out of range, error. */
83 goto end;
84 }
85 }
86end:
87 bt_put(field_type);
88 return ret;
89}
90
d246b111
JG
91static
92int set_packet_header_magic(struct bt_ctf_stream *stream)
93{
94 int ret = 0;
95 struct bt_ctf_field_type *magic_field_type = NULL;
96 struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field(
97 stream->packet_header, "magic");
98
99 if (!magic_field) {
100 /* No magic field found. Not an error, skip. */
101 goto end;
102 }
103
fc47320a 104 if (bt_ctf_field_is_set(magic_field)) {
d246b111
JG
105 /* Value already set. Not an error, skip. */
106 goto end;
107 }
108
109 magic_field_type = bt_ctf_field_get_type(magic_field);
110 assert(magic_field_type);
111
112 if (bt_ctf_field_type_get_type_id(magic_field_type) !=
9a19a512 113 BT_CTF_TYPE_ID_INTEGER) {
d246b111
JG
114 /* Magic field is not an integer. Not an error, skip. */
115 goto end;
116 }
117
118 if (bt_ctf_field_type_integer_get_size(magic_field_type) != 32) {
119 /*
120 * Magic field is not of the expected size.
121 * Not an error, skip.
122 */
123 goto end;
124 }
125
126 ret = bt_ctf_field_type_integer_get_signed(magic_field_type);
127 assert(ret >= 0);
128 if (ret) {
129 ret = bt_ctf_field_signed_integer_set_value(magic_field,
130 (int64_t) 0xC1FC1FC1);
131 } else {
132 ret = bt_ctf_field_unsigned_integer_set_value(magic_field,
133 (uint64_t) 0xC1FC1FC1);
134 }
135end:
83509119
JG
136 bt_put(magic_field);
137 bt_put(magic_field_type);
d246b111
JG
138 return ret;
139}
140
141static
142int set_packet_header_uuid(struct bt_ctf_stream *stream)
143{
144 int i, ret = 0;
e6a8e8e4 145 struct bt_ctf_trace *trace = NULL;
d246b111
JG
146 struct bt_ctf_field_type *uuid_field_type = NULL;
147 struct bt_ctf_field_type *element_field_type = NULL;
148 struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field(
149 stream->packet_header, "uuid");
150
151 if (!uuid_field) {
152 /* No uuid field found. Not an error, skip. */
153 goto end;
154 }
155
fc47320a 156 if (bt_ctf_field_is_set(uuid_field)) {
d246b111
JG
157 /* Value already set. Not an error, skip. */
158 goto end;
159 }
160
161 uuid_field_type = bt_ctf_field_get_type(uuid_field);
162 assert(uuid_field_type);
163 if (bt_ctf_field_type_get_type_id(uuid_field_type) !=
9a19a512 164 BT_CTF_TYPE_ID_ARRAY) {
d246b111
JG
165 /* UUID field is not an array. Not an error, skip. */
166 goto end;
167 }
168
169 if (bt_ctf_field_type_array_get_length(uuid_field_type) != 16) {
170 /*
171 * UUID field is not of the expected size.
172 * Not an error, skip.
173 */
174 goto end;
175 }
176
177 element_field_type = bt_ctf_field_type_array_get_element_type(
178 uuid_field_type);
179 assert(element_field_type);
180 if (bt_ctf_field_type_get_type_id(element_field_type) !=
9a19a512 181 BT_CTF_TYPE_ID_INTEGER) {
d246b111
JG
182 /* UUID array elements are not integers. Not an error, skip */
183 goto end;
184 }
185
e6a8e8e4 186 trace = (struct bt_ctf_trace *) bt_object_get_parent(stream);
d246b111
JG
187 for (i = 0; i < 16; i++) {
188 struct bt_ctf_field *uuid_element =
189 bt_ctf_field_array_get_field(uuid_field, i);
190
191 ret = bt_ctf_field_type_integer_get_signed(element_field_type);
192 assert(ret >= 0);
193
194 if (ret) {
195 ret = bt_ctf_field_signed_integer_set_value(
e6a8e8e4 196 uuid_element, (int64_t) trace->uuid[i]);
d246b111
JG
197 } else {
198 ret = bt_ctf_field_unsigned_integer_set_value(
199 uuid_element,
e6a8e8e4 200 (uint64_t) trace->uuid[i]);
d246b111 201 }
83509119 202 bt_put(uuid_element);
d246b111
JG
203 if (ret) {
204 goto end;
205 }
206 }
207
208end:
83509119
JG
209 bt_put(uuid_field);
210 bt_put(uuid_field_type);
211 bt_put(element_field_type);
e6a8e8e4 212 BT_PUT(trace);
d246b111
JG
213 return ret;
214}
215static
216int set_packet_header_stream_id(struct bt_ctf_stream *stream)
217{
218 int ret = 0;
219 uint32_t stream_id;
220 struct bt_ctf_field_type *stream_id_field_type = NULL;
221 struct bt_ctf_field *stream_id_field = bt_ctf_field_structure_get_field(
222 stream->packet_header, "stream_id");
223
224 if (!stream_id_field) {
225 /* No stream_id field found. Not an error, skip. */
226 goto end;
227 }
228
fc47320a 229 if (bt_ctf_field_is_set(stream_id_field)) {
d246b111
JG
230 /* Value already set. Not an error, skip. */
231 goto end;
232 }
233
234 stream_id_field_type = bt_ctf_field_get_type(stream_id_field);
235 assert(stream_id_field_type);
236 if (bt_ctf_field_type_get_type_id(stream_id_field_type) !=
9a19a512 237 BT_CTF_TYPE_ID_INTEGER) {
d246b111
JG
238 /* stream_id field is not an integer. Not an error, skip. */
239 goto end;
240 }
241
242 stream_id = stream->stream_class->id;
243 ret = bt_ctf_field_type_integer_get_signed(stream_id_field_type);
244 assert(ret >= 0);
245 if (ret) {
246 ret = bt_ctf_field_signed_integer_set_value(stream_id_field,
247 (int64_t) stream_id);
248 } else {
249 ret = bt_ctf_field_unsigned_integer_set_value(stream_id_field,
250 (uint64_t) stream_id);
251 }
252end:
83509119
JG
253 bt_put(stream_id_field);
254 bt_put(stream_id_field_type);
d246b111
JG
255 return ret;
256}
257
258static
259int set_packet_header(struct bt_ctf_stream *stream)
260{
261 int ret;
262
263 ret = set_packet_header_magic(stream);
264 if (ret) {
265 goto end;
266 }
267
268 ret = set_packet_header_uuid(stream);
269 if (ret) {
270 goto end;
271 }
272
273 ret = set_packet_header_stream_id(stream);
274 if (ret) {
275 goto end;
276 }
277end:
278 return ret;
279}
280
123fbdec 281static
e6a8e8e4 282void release_event(struct bt_ctf_event *event)
123fbdec 283{
e6a8e8e4
JG
284 if (bt_object_get_ref_count(event)) {
285 /*
286 * The event is being orphaned, but it must guarantee the
287 * existence of its event class for the duration of its
288 * lifetime.
289 */
290 bt_get(event->event_class);
291 BT_PUT(event->base.parent);
292 } else {
293 bt_object_release(event);
294 }
123fbdec
JG
295}
296
319fd969
PP
297static
298int create_stream_file(struct bt_ctf_writer *writer,
299 struct bt_ctf_stream *stream)
300{
301 int fd;
302 GString *filename = g_string_new(stream->stream_class->name->str);
303
304 if (stream->stream_class->name->len == 0) {
305 int64_t ret;
306
307 ret = bt_ctf_stream_class_get_id(stream->stream_class);
308 if (ret < 0) {
309 fd = -1;
310 goto error;
311 }
312
313 g_string_printf(filename, "stream_%" PRId64, ret);
314 }
315
316 g_string_append_printf(filename, "_%" PRIu32, stream->id);
317 fd = openat(writer->trace_dir_fd, filename->str,
318 O_RDWR | O_CREAT | O_TRUNC,
319 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
320error:
321 g_string_free(filename, TRUE);
322 return fd;
323}
324
325static
326int set_stream_fd(struct bt_ctf_stream *stream, int fd)
327{
328 int ret = 0;
329
330 if (stream->pos.fd != -1) {
331 ret = -1;
332 goto end;
333 }
334
335 ctf_init_pos(&stream->pos, NULL, fd, O_RDWR);
336 stream->pos.fd = fd;
337end:
338 return ret;
339}
340
273b65be 341struct bt_ctf_stream *bt_ctf_stream_create(
b71d7298
PP
342 struct bt_ctf_stream_class *stream_class,
343 const char *name)
273b65be 344{
12c8a1a3 345 int ret;
273b65be 346 struct bt_ctf_stream *stream = NULL;
319fd969
PP
347 struct bt_ctf_trace *trace = NULL;
348 struct bt_ctf_writer *writer = NULL;
273b65be 349
319fd969 350 if (!stream_class) {
b71d7298 351 goto error;
319fd969
PP
352 }
353
354 trace = bt_ctf_stream_class_get_trace(stream_class);
355 if (!trace) {
b71d7298 356 goto error;
273b65be
JG
357 }
358
359 stream = g_new0(struct bt_ctf_stream, 1);
360 if (!stream) {
b71d7298 361 goto error;
273b65be
JG
362 }
363
83509119 364 bt_object_init(stream, bt_ctf_stream_destroy);
e6a8e8e4
JG
365 /*
366 * Acquire reference to parent since stream will become publicly
367 * reachable; it needs its parent to remain valid.
368 */
369 bt_object_set_parent(stream, trace);
273b65be
JG
370 stream->id = stream_class->next_stream_id++;
371 stream->stream_class = stream_class;
319fd969 372 stream->pos.fd = -1;
d246b111 373
b71d7298
PP
374 if (name) {
375 stream->name = g_string_new(name);
376 if (!stream->name) {
377 goto error;
378 }
379 }
380
319fd969
PP
381 if (trace->is_created_by_writer) {
382 int fd;
383 writer = (struct bt_ctf_writer *)
384 bt_object_get_parent(trace);
385
386 assert(writer);
98edd02c
JG
387 if (stream_class->packet_context_type) {
388 stream->packet_context = bt_ctf_field_create(
389 stream_class->packet_context_type);
390 if (!stream->packet_context) {
391 goto error;
392 }
319fd969 393
98edd02c
JG
394 /* Initialize events_discarded */
395 ret = set_structure_field_integer(stream->packet_context,
396 "events_discarded", 0);
397 if (ret) {
398 goto error;
399 }
319fd969
PP
400 }
401
402 stream->events = g_ptr_array_new_with_free_func(
403 (GDestroyNotify) release_event);
404 if (!stream->events) {
405 goto error;
406 }
407
408 /* A trace is not allowed to have a NULL packet header */
409 assert(trace->packet_header_type);
410 stream->packet_header =
411 bt_ctf_field_create(trace->packet_header_type);
412 if (!stream->packet_header) {
413 goto error;
414 }
415
416 /*
417 * Attempt to populate the default trace packet header fields
418 * (magic, uuid and stream_id). This will _not_ fail shall the
419 * fields not be found or be of an incompatible type; they will
420 * simply not be populated automatically. The user will have to
421 * make sure to set the trace packet header fields himself
422 * before flushing.
423 */
424 ret = set_packet_header(stream);
425 if (ret) {
426 goto error;
427 }
428
429 /* Create file associated with this stream */
430 fd = create_stream_file(writer, stream);
431 if (fd < 0) {
432 goto error;
433 }
434
435 ret = set_stream_fd(stream, fd);
436 if (ret) {
437 goto error;
438 }
439
440 /* Freeze the writer */
441 bt_ctf_writer_freeze(writer);
442 } else {
443 /* Non-writer stream indicated by a negative FD */
444 ret = set_stream_fd(stream, -1);
445 if (ret) {
446 goto error;
447 }
d246b111 448 }
319fd969
PP
449
450 /* Add this stream to the trace's streams */
451 g_ptr_array_add(trace->streams, stream);
452
319fd969
PP
453 BT_PUT(trace);
454 BT_PUT(writer);
273b65be 455 return stream;
83509119
JG
456error:
457 BT_PUT(stream);
319fd969
PP
458 BT_PUT(trace);
459 BT_PUT(writer);
83509119 460 return stream;
273b65be
JG
461}
462
3baf0856
JG
463struct bt_ctf_stream_class *bt_ctf_stream_get_class(
464 struct bt_ctf_stream *stream)
465{
466 struct bt_ctf_stream_class *stream_class = NULL;
467
468 if (!stream) {
469 goto end;
470 }
471
472 stream_class = stream->stream_class;
83509119 473 bt_get(stream_class);
3baf0856
JG
474end:
475 return stream_class;
476}
477
a78a2e25
JG
478int bt_ctf_stream_get_discarded_events_count(
479 struct bt_ctf_stream *stream, uint64_t *count)
480{
481 int64_t ret = 0;
12c8a1a3
JG
482 int field_signed;
483 struct bt_ctf_field *events_discarded_field = NULL;
484 struct bt_ctf_field_type *events_discarded_field_type = NULL;
a78a2e25 485
1579cde5
PP
486 if (!stream || !count || !stream->packet_context ||
487 stream->pos.fd < 0) {
a78a2e25
JG
488 ret = -1;
489 goto end;
490 }
491
12c8a1a3
JG
492 events_discarded_field = bt_ctf_field_structure_get_field(
493 stream->packet_context, "events_discarded");
494 if (!events_discarded_field) {
495 ret = -1;
496 goto end;
497 }
498
499 events_discarded_field_type = bt_ctf_field_get_type(
500 events_discarded_field);
501 if (!events_discarded_field_type) {
502 ret = -1;
503 goto end;
504 }
505
506 field_signed = bt_ctf_field_type_integer_get_signed(
507 events_discarded_field_type);
508 if (field_signed < 0) {
509 ret = field_signed;
510 goto end;
511 }
512
513 if (field_signed) {
514 int64_t signed_count;
515
516 ret = bt_ctf_field_signed_integer_get_value(
517 events_discarded_field, &signed_count);
518 if (ret) {
519 goto end;
520 }
521 if (signed_count < 0) {
522 /* Invalid value */
523 ret = -1;
524 goto end;
525 }
526 *count = (uint64_t) signed_count;
527 } else {
528 ret = bt_ctf_field_unsigned_integer_get_value(
529 events_discarded_field, count);
530 if (ret) {
531 goto end;
532 }
533 }
a78a2e25 534end:
83509119
JG
535 bt_put(events_discarded_field);
536 bt_put(events_discarded_field_type);
a78a2e25
JG
537 return ret;
538}
539
273b65be
JG
540void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
541 uint64_t event_count)
542{
12c8a1a3
JG
543 int ret;
544 int field_signed;
545 uint64_t previous_count;
546 uint64_t new_count;
547 struct bt_ctf_field *events_discarded_field = NULL;
548 struct bt_ctf_field_type *events_discarded_field_type = NULL;
549
1579cde5 550 if (!stream || !stream->packet_context || stream->pos.fd < 0) {
12c8a1a3
JG
551 goto end;
552 }
553
554 ret = bt_ctf_stream_get_discarded_events_count(stream,
555 &previous_count);
556 if (ret) {
557 goto end;
558 }
559
560 events_discarded_field = bt_ctf_field_structure_get_field(
561 stream->packet_context, "events_discarded");
562 if (!events_discarded_field) {
563 goto end;
564 }
565
566 events_discarded_field_type = bt_ctf_field_get_type(
567 events_discarded_field);
568 if (!events_discarded_field_type) {
569 goto end;
570 }
571
572 field_signed = bt_ctf_field_type_integer_get_signed(
573 events_discarded_field_type);
574 if (field_signed < 0) {
575 goto end;
273b65be
JG
576 }
577
12c8a1a3
JG
578 new_count = previous_count + event_count;
579 if (field_signed) {
580 ret = bt_ctf_field_signed_integer_set_value(
581 events_discarded_field, (int64_t) new_count);
582 if (ret) {
583 goto end;
584 }
585 } else {
586 ret = bt_ctf_field_unsigned_integer_set_value(
587 events_discarded_field, new_count);
588 if (ret) {
589 goto end;
590 }
591 }
592
593end:
83509119
JG
594 bt_put(events_discarded_field);
595 bt_put(events_discarded_field_type);
273b65be
JG
596}
597
ac0c6bdd
PP
598static int auto_populate_event_header(struct bt_ctf_stream *stream,
599 struct bt_ctf_event *event)
600{
601 int ret = 0;
602 struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL;
603 struct bt_ctf_clock_class *mapped_clock_class = NULL;
604
605 if (!event || event->frozen) {
606 ret = -1;
607 goto end;
608 }
609
610 /*
611 * The condition to automatically set the ID are:
612 *
613 * 1. The event header field "id" exists and is an integer
614 * field.
615 * 2. The event header field "id" is NOT set.
616 */
617 id_field = bt_ctf_field_structure_get_field(event->event_header, "id");
618 if (id_field && !bt_ctf_field_is_set(id_field)) {
619 ret = set_integer_field_value(id_field,
620 (uint64_t) bt_ctf_event_class_get_id(
621 event->event_class));
622 if (ret) {
623 goto end;
624 }
625 }
626
627 /*
628 * The conditions to automatically set the timestamp are:
629 *
630 * 1. The event header field "timestamp" exists and is an
631 * integer field.
632 * 2. This stream's class has a registered clock (set with
633 * bt_ctf_stream_class_set_clock()).
634 * 3. The event header field "timestamp" has its type mapped to
635 * a clock class which is also the clock class of this
636 * stream's class's registered clock.
637 * 4. The event header field "timestamp" is NOT set.
638 */
639 timestamp_field = bt_ctf_field_structure_get_field(event->event_header,
640 "timestamp");
641 if (timestamp_field && !bt_ctf_field_is_set(timestamp_field) &&
642 stream->stream_class->clock) {
643 struct bt_ctf_clock_class *stream_class_clock_class =
644 stream->stream_class->clock->clock_class;
645 struct bt_ctf_field_type *timestamp_field_type =
646 bt_ctf_field_get_type(timestamp_field);
647
648 assert(timestamp_field_type);
649 mapped_clock_class =
650 bt_ctf_field_type_integer_get_mapped_clock_class(
651 timestamp_field_type);
652 BT_PUT(timestamp_field_type);
653 if (mapped_clock_class == stream_class_clock_class) {
654 uint64_t timestamp;
655
656 ret = bt_ctf_clock_get_value(
657 stream->stream_class->clock,
658 &timestamp);
659 if (ret) {
660 goto end;
661 }
662
663 ret = set_integer_field_value(timestamp_field,
664 timestamp);
665 if (ret) {
666 goto end;
667 }
668 }
669 }
670
671end:
672 bt_put(id_field);
673 bt_put(timestamp_field);
674 bt_put(mapped_clock_class);
675 return ret;
676}
677
273b65be
JG
678int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
679 struct bt_ctf_event *event)
680{
681 int ret = 0;
273b65be 682
1579cde5 683 if (!stream || !event || stream->pos.fd < 0) {
273b65be
JG
684 ret = -1;
685 goto end;
686 }
687
fa29ba83
PP
688 /*
689 * The event is not supposed to have a parent stream at this
690 * point. The only other way an event can have a parent stream
691 * is if it was assigned when setting a packet to the event,
692 * in which case the packet's stream is not a writer stream,
693 * and thus the user is trying to append an event which belongs
694 * to another stream.
695 */
696 if (event->base.parent) {
697 ret = -1;
698 goto end;
699 }
700
e6a8e8e4 701 bt_object_set_parent(event, stream);
ac0c6bdd 702 ret = auto_populate_event_header(stream, event);
662e778c 703 if (ret) {
37f30168 704 goto error;
662e778c
JG
705 }
706
5fd2e9fd 707 /* Make sure the various scopes of the event are set */
273b65be
JG
708 ret = bt_ctf_event_validate(event);
709 if (ret) {
37f30168 710 goto error;
273b65be
JG
711 }
712
0d688c15
PP
713 /* Save the new event and freeze it */
714 bt_ctf_event_freeze(event);
273b65be 715 g_ptr_array_add(stream->events, event);
5fd2e9fd 716
e6a8e8e4
JG
717 /*
718 * Event had to hold a reference to its event class as long as it wasn't
719 * part of the same trace hierarchy. From now on, the event and its
720 * class share the same lifetime guarantees and the reference is no
721 * longer needed.
722 */
723 bt_put(event->event_class);
37f30168 724
273b65be 725end:
37f30168
PP
726 return ret;
727
728error:
729 /*
730 * Orphan the event; we were not successful in associating it to
731 * a stream.
732 */
733 bt_object_set_parent(event, NULL);
734
273b65be
JG
735 return ret;
736}
737
12c8a1a3
JG
738struct bt_ctf_field *bt_ctf_stream_get_packet_context(
739 struct bt_ctf_stream *stream)
740{
741 struct bt_ctf_field *packet_context = NULL;
742
1579cde5 743 if (!stream || stream->pos.fd < 0) {
12c8a1a3
JG
744 goto end;
745 }
746
747 packet_context = stream->packet_context;
12c8a1a3 748 if (packet_context) {
83509119 749 bt_get(packet_context);
12c8a1a3 750 }
34629a55 751end:
12c8a1a3
JG
752 return packet_context;
753}
754
755int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream,
756 struct bt_ctf_field *field)
757{
758 int ret = 0;
759 struct bt_ctf_field_type *field_type;
760
835b2d10 761 if (!stream || stream->pos.fd < 0) {
12c8a1a3
JG
762 ret = -1;
763 goto end;
764 }
765
766 field_type = bt_ctf_field_get_type(field);
09840de5
PP
767 if (bt_ctf_field_type_compare(field_type,
768 stream->stream_class->packet_context_type)) {
12c8a1a3
JG
769 ret = -1;
770 goto end;
771 }
772
83509119 773 bt_put(field_type);
83509119 774 bt_put(stream->packet_context);
835b2d10 775 stream->packet_context = bt_get(field);
12c8a1a3
JG
776end:
777 return ret;
778}
779
263a7df5
JG
780struct bt_ctf_field *bt_ctf_stream_get_packet_header(
781 struct bt_ctf_stream *stream)
782{
783 struct bt_ctf_field *packet_header = NULL;
784
1579cde5 785 if (!stream || stream->pos.fd < 0) {
263a7df5
JG
786 goto end;
787 }
788
789 packet_header = stream->packet_header;
790 if (packet_header) {
83509119 791 bt_get(packet_header);
263a7df5
JG
792 }
793end:
794 return packet_header;
795}
796
797int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream,
798 struct bt_ctf_field *field)
799{
800 int ret = 0;
e6a8e8e4 801 struct bt_ctf_trace *trace = NULL;
263a7df5
JG
802 struct bt_ctf_field_type *field_type = NULL;
803
835b2d10 804 if (!stream || stream->pos.fd < 0) {
263a7df5
JG
805 ret = -1;
806 goto end;
807 }
808
e6a8e8e4 809 trace = (struct bt_ctf_trace *) bt_object_get_parent(stream);
263a7df5 810 field_type = bt_ctf_field_get_type(field);
09840de5 811 if (bt_ctf_field_type_compare(field_type, trace->packet_header_type)) {
263a7df5
JG
812 ret = -1;
813 goto end;
814 }
815
83509119 816 bt_put(stream->packet_header);
835b2d10 817 stream->packet_header = bt_get(field);
263a7df5 818end:
e6a8e8e4 819 BT_PUT(trace);
83509119 820 bt_put(field_type);
263a7df5
JG
821 return ret;
822}
823
9a220c32
JG
824static
825int get_event_header_timestamp(struct bt_ctf_field *event_header, uint64_t *timestamp)
826{
827 int ret = 0;
828 struct bt_ctf_field *timestamp_field = NULL;
829 struct bt_ctf_field_type *timestamp_field_type = NULL;
830
831 timestamp_field = bt_ctf_field_structure_get_field(event_header,
832 "timestamp");
833 if (!timestamp_field) {
834 ret = -1;
835 goto end;
836 }
837
838 timestamp_field_type = bt_ctf_field_get_type(timestamp_field);
839 assert(timestamp_field_type);
840 if (bt_ctf_field_type_get_type_id(timestamp_field_type) !=
9a19a512 841 BT_CTF_TYPE_ID_INTEGER) {
9a220c32
JG
842 ret = -1;
843 goto end;
844 }
845
846 if (bt_ctf_field_type_integer_get_signed(timestamp_field_type)) {
847 int64_t val;
848
849 ret = bt_ctf_field_signed_integer_get_value(timestamp_field,
850 &val);
851 if (ret) {
852 goto end;
853 }
854 *timestamp = (uint64_t) val;
855 } else {
856 ret = bt_ctf_field_unsigned_integer_get_value(timestamp_field,
857 timestamp);
858 if (ret) {
859 goto end;
860 }
861 }
862end:
83509119
JG
863 bt_put(timestamp_field);
864 bt_put(timestamp_field_type);
9a220c32
JG
865 return ret;
866}
867
273b65be
JG
868int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
869{
870 int ret = 0;
871 size_t i;
12c8a1a3 872 uint64_t timestamp_begin, timestamp_end, events_discarded;
273b65be
JG
873 struct bt_ctf_field *integer = NULL;
874 struct ctf_stream_pos packet_context_pos;
98edd02c 875 bool empty_packet;
0686ef94 876 uint64_t packet_size_bits;
273b65be 877
bc37ae52
JG
878 if (!stream || stream->pos.fd < 0) {
879 /*
880 * Stream does not have an associated fd. It is,
881 * therefore, not a stream being used to write events.
882 */
273b65be
JG
883 ret = -1;
884 goto end;
885 }
886
664f50c8
JG
887 if (!stream->packet_context && stream->flushed_packet_count > 0) {
888 /*
889 * A stream without a packet context, and thus without
890 * content and packet size members, can't have more than
891 * one packet.
892 */
893 ret = -1;
894 goto end;
895 }
896
98edd02c 897 empty_packet = (stream->events->len == 0);
d246b111 898
28362f2b
JG
899 /* mmap the next packet */
900 ctf_packet_seek(&stream->pos.parent, 0, SEEK_CUR);
d246b111
JG
901
902 ret = bt_ctf_field_serialize(stream->packet_header, &stream->pos);
903 if (ret) {
904 goto end;
273b65be
JG
905 }
906
98edd02c
JG
907 if (stream->packet_context) {
908 /* Set the default context attributes if present and unset. */
909 if (!empty_packet && !get_event_header_timestamp(
910 ((struct bt_ctf_event *) g_ptr_array_index(
911 stream->events, 0))->event_header, &timestamp_begin)) {
912 ret = set_structure_field_integer(stream->packet_context,
913 "timestamp_begin", timestamp_begin);
914 if (ret) {
915 goto end;
916 }
917 }
918
919 if (!empty_packet && !get_event_header_timestamp(
920 ((struct bt_ctf_event *) g_ptr_array_index(
921 stream->events, stream->events->len - 1))->event_header,
922 &timestamp_end)) {
923
924 ret = set_structure_field_integer(stream->packet_context,
925 "timestamp_end", timestamp_end);
926 if (ret) {
927 goto end;
928 }
929 }
9a220c32 930 ret = set_structure_field_integer(stream->packet_context,
98edd02c 931 "content_size", UINT64_MAX);
9a220c32
JG
932 if (ret) {
933 goto end;
934 }
273b65be 935
9a220c32 936 ret = set_structure_field_integer(stream->packet_context,
98edd02c 937 "packet_size", UINT64_MAX);
9a220c32
JG
938 if (ret) {
939 goto end;
940 }
273b65be 941
98edd02c
JG
942 ret = bt_ctf_stream_get_discarded_events_count(stream,
943 &events_discarded);
944 if (ret) {
945 goto end;
946 }
12c8a1a3 947
10cb7b41
JG
948 ret = set_structure_field_integer(stream->packet_context,
949 "events_discarded", events_discarded);
98edd02c
JG
950 if (ret) {
951 goto end;
952 }
12c8a1a3 953
10cb7b41
JG
954 /* Write packet context */
955 memcpy(&packet_context_pos, &stream->pos,
956 sizeof(struct ctf_stream_pos));
957 ret = bt_ctf_field_serialize(stream->packet_context,
958 &stream->pos);
98edd02c
JG
959 if (ret) {
960 goto end;
961 }
12c8a1a3
JG
962 }
963
273b65be
JG
964 for (i = 0; i < stream->events->len; i++) {
965 struct bt_ctf_event *event = g_ptr_array_index(
966 stream->events, i);
273b65be 967
662e778c 968 ret = bt_ctf_field_reset(event->event_header);
12c8a1a3
JG
969 if (ret) {
970 goto end;
971 }
972
273b65be 973 /* Write event header */
662e778c 974 ret = bt_ctf_field_serialize(event->event_header,
273b65be
JG
975 &stream->pos);
976 if (ret) {
977 goto end;
978 }
979
8bfa3f9c 980 /* Write stream event context */
5fd2e9fd 981 if (event->stream_event_context) {
8bfa3f9c 982 ret = bt_ctf_field_serialize(
5fd2e9fd 983 event->stream_event_context, &stream->pos);
8bfa3f9c
JG
984 if (ret) {
985 goto end;
986 }
987 }
988
273b65be
JG
989 /* Write event content */
990 ret = bt_ctf_event_serialize(event, &stream->pos);
991 if (ret) {
992 goto end;
993 }
994 }
995
0686ef94
JG
996 /* Rounded-up in case content_size is not byte-aligned. */
997 packet_size_bits = (stream->pos.offset + (CHAR_BIT - 1)) &
998 ~(CHAR_BIT - 1);
999 stream->pos.packet_size = packet_size_bits;
1000
98edd02c
JG
1001 if (stream->packet_context) {
1002 /*
1003 * Update the packet total size and content size and overwrite
1004 * the packet context.
1005 * Copy base_mma as the packet may have been remapped (e.g. when
1006 * a packet is resized).
1007 */
1008 packet_context_pos.base_mma = stream->pos.base_mma;
1009 ret = set_structure_field_integer(stream->packet_context,
1010 "content_size", stream->pos.offset);
1011 if (ret) {
1012 goto end;
1013 }
273b65be 1014
98edd02c 1015 ret = set_structure_field_integer(stream->packet_context,
0686ef94 1016 "packet_size", packet_size_bits);
98edd02c
JG
1017 if (ret) {
1018 goto end;
1019 }
273b65be 1020
98edd02c
JG
1021 ret = bt_ctf_field_serialize(stream->packet_context,
1022 &packet_context_pos);
1023 if (ret) {
1024 goto end;
1025 }
273b65be
JG
1026 }
1027
1028 g_ptr_array_set_size(stream->events, 0);
1029 stream->flushed_packet_count++;
0686ef94 1030 stream->size += packet_size_bits / CHAR_BIT;
273b65be 1031end:
83509119 1032 bt_put(integer);
273b65be
JG
1033 return ret;
1034}
1035
1036void bt_ctf_stream_get(struct bt_ctf_stream *stream)
1037{
83509119 1038 bt_get(stream);
273b65be
JG
1039}
1040
1041void bt_ctf_stream_put(struct bt_ctf_stream *stream)
1042{
83509119 1043 bt_put(stream);
273b65be
JG
1044}
1045
1046static
83509119 1047void bt_ctf_stream_destroy(struct bt_object *obj)
273b65be
JG
1048{
1049 struct bt_ctf_stream *stream;
273b65be 1050
83509119 1051 stream = container_of(obj, struct bt_ctf_stream, base);
273b65be 1052 ctf_fini_pos(&stream->pos);
0686ef94
JG
1053 if (stream->pos.fd >= 0) {
1054 int ret;
1055
1056 /*
1057 * Truncate the file's size to the minimum required to fit the
1058 * last packet as we might have grown it too much on the last
1059 * mmap.
1060 */
1061 do {
1062 ret = ftruncate(stream->pos.fd, stream->size);
1063 } while (ret == -1 && errno == EINTR);
1064 if (ret) {
1065 perror("ftruncate");
1066 }
1067
1068 if (close(stream->pos.fd)) {
1069 perror("close");
1070 }
9f56e450 1071 }
12c8a1a3 1072
12c8a1a3
JG
1073 if (stream->events) {
1074 g_ptr_array_free(stream->events, TRUE);
1075 }
b71d7298
PP
1076
1077 if (stream->name) {
1078 g_string_free(stream->name, TRUE);
1079 }
41ac640a 1080
83509119
JG
1081 bt_put(stream->packet_header);
1082 bt_put(stream->packet_context);
273b65be
JG
1083 g_free(stream);
1084}
1085
273b65be
JG
1086static
1087int set_structure_field_integer(struct bt_ctf_field *structure, char *name,
1088 uint64_t value)
1089{
1090 int ret = 0;
d7b1ea66 1091 struct bt_ctf_field_type *field_type = NULL;
273b65be
JG
1092 struct bt_ctf_field *integer =
1093 bt_ctf_field_structure_get_field(structure, name);
12c8a1a3
JG
1094
1095 if (!structure || !name) {
273b65be
JG
1096 ret = -1;
1097 goto end;
1098 }
1099
12c8a1a3
JG
1100 if (!integer) {
1101 /* Field not found, not an error. */
1102 goto end;
1103 }
1104
1105 /* Make sure the payload has not already been set. */
fc47320a 1106 if (bt_ctf_field_is_set(integer)) {
12c8a1a3
JG
1107 /* Payload already set, not an error */
1108 goto end;
1109 }
1110
d7b1ea66
JG
1111 field_type = bt_ctf_field_get_type(integer);
1112 /* Something is serioulsly wrong */
1113 assert(field_type);
9a19a512 1114 if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_TYPE_ID_INTEGER) {
d7b1ea66
JG
1115 /*
1116 * The user most likely meant for us to populate this field
1117 * automatically. However, we can only do this if the field
1118 * is an integer. Return an error.
1119 */
1120 ret = -1;
1121 goto end;
1122 }
1123
1124 if (bt_ctf_field_type_integer_get_signed(field_type)) {
1125 ret = bt_ctf_field_signed_integer_set_value(integer,
1126 (int64_t) value);
1127 } else {
1128 ret = bt_ctf_field_unsigned_integer_set_value(integer, value);
1129 }
273b65be 1130end:
83509119
JG
1131 bt_put(integer);
1132 bt_put(field_type);
273b65be
JG
1133 return ret;
1134}
b71d7298
PP
1135
1136const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream)
1137{
1138 const char *name = NULL;
1139
1140 if (!stream) {
1141 goto end;
1142 }
1143
1144 name = stream->name ? stream->name->str : NULL;
1145
1146end:
1147 return name;
1148}
98a4cbef
PP
1149
1150int bt_ctf_stream_is_writer(struct bt_ctf_stream *stream)
1151{
1152 int ret = -1;
1153
1154 if (!stream) {
1155 goto end;
1156 }
1157
1158 ret = (stream->pos.fd >= 0);
1159
1160end:
1161 return ret;
1162}
This page took 0.086058 seconds and 4 git commands to generate.