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