Validate CTF semantics in selected CTF IR functions
[babeltrace.git] / lib / ctf-ir / stream.c
CommitLineData
273b65be
JG
1/*
2 * stream.c
3 *
d2dc44b6 4 * Babeltrace CTF IR - Stream
273b65be 5 *
de9dd397 6 * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
273b65be
JG
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
19abc2c6
PP
29#define BT_LOG_TAG "STREAM"
30#include <babeltrace/lib-logging-internal.h>
31
ac0c6bdd
PP
32#include <babeltrace/ctf-ir/clock-class.h>
33#include <babeltrace/ctf-writer/clock.h>
34#include <babeltrace/ctf-writer/clock-internal.h>
273b65be 35#include <babeltrace/ctf-writer/event.h>
adc315b8 36#include <babeltrace/ctf-ir/event-internal.h>
2e33ac5a
PP
37#include <babeltrace/ctf-ir/field-types-internal.h>
38#include <babeltrace/ctf-ir/fields-internal.h>
3f043b05
JG
39#include <babeltrace/ctf-ir/stream.h>
40#include <babeltrace/ctf-ir/stream-internal.h>
adc315b8 41#include <babeltrace/ctf-ir/stream-class-internal.h>
5acf2ae6 42#include <babeltrace/ctf-ir/trace.h>
319fd969
PP
43#include <babeltrace/ctf-ir/trace-internal.h>
44#include <babeltrace/ctf-writer/writer-internal.h>
3230ee6b 45#include <babeltrace/graph/component-internal.h>
83509119 46#include <babeltrace/ref.h>
273b65be 47#include <babeltrace/ctf-writer/functor-internal.h>
3d9990ac
PP
48#include <babeltrace/compiler-internal.h>
49#include <babeltrace/align-internal.h>
dc3fffef 50#include <inttypes.h>
273b65be
JG
51
52static
83509119 53void bt_ctf_stream_destroy(struct bt_object *obj);
273b65be 54static
af9296f3
JG
55int try_set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t);
56static
273b65be
JG
57int set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t);
58
ac0c6bdd
PP
59static
60int 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) {
19abc2c6 66 BT_LOGW_STR("Invalid parameter: field is NULL.");
ac0c6bdd
PP
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) !=
1487a16a 75 BT_CTF_FIELD_TYPE_ID_INTEGER) {
ac0c6bdd 76 /* Not an integer and the value is unset, error. */
19abc2c6
PP
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));
ac0c6bdd
PP
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. */
19abc2c6
PP
89 BT_LOGW("Cannot set signed integer field's value: "
90 "addr=%p, value=%" PRId64,
91 field, (int64_t) value);
ac0c6bdd
PP
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. */
19abc2c6
PP
98 BT_LOGW("Cannot set unsigned integer field's value: "
99 "addr=%p, value=%" PRIu64,
100 field, value);
ac0c6bdd
PP
101 goto end;
102 }
103 }
104end:
105 bt_put(field_type);
106 return ret;
107}
108
d246b111
JG
109static
110int 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");
19abc2c6
PP
116 const uint32_t magic_value = 0xc1fc1fc1;
117
118 assert(stream);
d246b111
JG
119
120 if (!magic_field) {
121 /* No magic field found. Not an error, skip. */
19abc2c6
PP
122 BT_LOGV("No field named `magic` in packet header: skipping: "
123 "stream-addr=%p, stream-name=\"%s\"",
124 stream, bt_ctf_stream_get_name(stream));
d246b111
JG
125 goto end;
126 }
127
fc47320a 128 if (bt_ctf_field_is_set(magic_field)) {
d246b111 129 /* Value already set. Not an error, skip. */
19abc2c6
PP
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));
d246b111
JG
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) !=
19abc2c6 140 BT_CTF_FIELD_TYPE_ID_INTEGER) {
d246b111 141 /* Magic field is not an integer. Not an error, skip. */
19abc2c6
PP
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));
d246b111
JG
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 */
19abc2c6
PP
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));
d246b111
JG
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,
19abc2c6 166 (int64_t) magic_value);
d246b111
JG
167 } else {
168 ret = bt_ctf_field_unsigned_integer_set_value(magic_field,
19abc2c6
PP
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);
d246b111
JG
182 }
183end:
83509119
JG
184 bt_put(magic_field);
185 bt_put(magic_field_type);
d246b111
JG
186 return ret;
187}
188
189static
190int set_packet_header_uuid(struct bt_ctf_stream *stream)
191{
19abc2c6
PP
192 int ret = 0;
193 int64_t i;
e6a8e8e4 194 struct bt_ctf_trace *trace = NULL;
d246b111
JG
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
19abc2c6
PP
200 assert(stream);
201
d246b111
JG
202 if (!uuid_field) {
203 /* No uuid field found. Not an error, skip. */
19abc2c6
PP
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));
d246b111
JG
207 goto end;
208 }
209
fc47320a 210 if (bt_ctf_field_is_set(uuid_field)) {
d246b111 211 /* Value already set. Not an error, skip. */
19abc2c6
PP
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));
d246b111
JG
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) !=
19abc2c6 221 BT_CTF_FIELD_TYPE_ID_ARRAY) {
d246b111 222 /* UUID field is not an array. Not an error, skip. */
19abc2c6
PP
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));
d246b111
JG
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 */
19abc2c6
PP
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));
d246b111
JG
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) !=
19abc2c6 248 BT_CTF_FIELD_TYPE_ID_INTEGER) {
d246b111 249 /* UUID array elements are not integers. Not an error, skip */
19abc2c6
PP
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));
d246b111
JG
256 goto end;
257 }
258
e6a8e8e4 259 trace = (struct bt_ctf_trace *) bt_object_get_parent(stream);
d246b111
JG
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(
e6a8e8e4 269 uuid_element, (int64_t) trace->uuid[i]);
d246b111
JG
270 } else {
271 ret = bt_ctf_field_unsigned_integer_set_value(
9ac68eb1 272 uuid_element, (uint64_t) trace->uuid[i]);
d246b111 273 }
83509119 274 bt_put(uuid_element);
d246b111 275 if (ret) {
19abc2c6
PP
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);
d246b111
JG
281 goto end;
282 }
283 }
284
19abc2c6
PP
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
d246b111 289end:
83509119
JG
290 bt_put(uuid_field);
291 bt_put(uuid_field_type);
292 bt_put(element_field_type);
e6a8e8e4 293 BT_PUT(trace);
d246b111
JG
294 return ret;
295}
296static
297int 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. */
19abc2c6
PP
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));
d246b111
JG
310 goto end;
311 }
312
fc47320a 313 if (bt_ctf_field_is_set(stream_id_field)) {
d246b111 314 /* Value already set. Not an error, skip. */
19abc2c6
PP
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));
d246b111
JG
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) !=
19abc2c6 324 BT_CTF_FIELD_TYPE_ID_INTEGER) {
d246b111 325 /* stream_id field is not an integer. Not an error, skip. */
19abc2c6
PP
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));
d246b111
JG
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 }
19abc2c6
PP
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
d246b111 357end:
83509119
JG
358 bt_put(stream_id_field);
359 bt_put(stream_id_field_type);
d246b111
JG
360 return ret;
361}
362
363static
364int set_packet_header(struct bt_ctf_stream *stream)
365{
366 int ret;
367
368 ret = set_packet_header_magic(stream);
369 if (ret) {
19abc2c6
PP
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));
d246b111
JG
373 goto end;
374 }
375
376 ret = set_packet_header_uuid(stream);
377 if (ret) {
19abc2c6
PP
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));
d246b111
JG
381 goto end;
382 }
383
384 ret = set_packet_header_stream_id(stream);
385 if (ret) {
19abc2c6
PP
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));
d246b111
JG
389 goto end;
390 }
19abc2c6
PP
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
d246b111
JG
396end:
397 return ret;
398}
399
123fbdec 400static
e6a8e8e4 401void release_event(struct bt_ctf_event *event)
123fbdec 402{
e6a8e8e4
JG
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 }
123fbdec
JG
414}
415
319fd969
PP
416static
417int 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
19abc2c6
PP
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
319fd969
PP
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) {
19abc2c6
PP
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);
319fd969 438 fd = -1;
19abc2c6 439 goto end;
319fd969
PP
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);
19abc2c6
PP
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
461end:
319fd969
PP
462 g_string_free(filename, TRUE);
463 return fd;
464}
465
466static
19abc2c6 467void set_stream_fd(struct bt_ctf_stream *stream, int fd)
319fd969 468{
dc3fffef 469 (void) bt_ctf_stream_pos_init(&stream->pos, fd, O_RDWR);
319fd969 470 stream->pos.fd = fd;
319fd969
PP
471}
472
3230ee6b
PP
473static
474void component_destroy_listener(struct bt_component *component, void *data)
475{
476 struct bt_ctf_stream *stream = data;
477
19abc2c6
PP
478 BT_LOGD("Component is being destroyed, stream is notified: "
479 "comp-addr=%p, stream-addr=%p", component, stream);
3230ee6b
PP
480 g_hash_table_remove(stream->comp_cur_port, component);
481}
482
273b65be 483struct bt_ctf_stream *bt_ctf_stream_create(
b71d7298
PP
484 struct bt_ctf_stream_class *stream_class,
485 const char *name)
273b65be 486{
12c8a1a3 487 int ret;
273b65be 488 struct bt_ctf_stream *stream = NULL;
319fd969
PP
489 struct bt_ctf_trace *trace = NULL;
490 struct bt_ctf_writer *writer = NULL;
273b65be 491
319fd969 492 if (!stream_class) {
19abc2c6 493 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
b71d7298 494 goto error;
319fd969
PP
495 }
496
19abc2c6
PP
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);
319fd969
PP
501 trace = bt_ctf_stream_class_get_trace(stream_class);
502 if (!trace) {
19abc2c6
PP
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);
b71d7298 507 goto error;
273b65be
JG
508 }
509
5acf2ae6
PP
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 */
19abc2c6
PP
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);;
5acf2ae6
PP
521 goto error;
522 }
523
273b65be
JG
524 stream = g_new0(struct bt_ctf_stream, 1);
525 if (!stream) {
19abc2c6 526 BT_LOGE_STR("Failed to allocate one stream.");
b71d7298 527 goto error;
273b65be
JG
528 }
529
83509119 530 bt_object_init(stream, bt_ctf_stream_destroy);
e6a8e8e4
JG
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);
273b65be
JG
536 stream->id = stream_class->next_stream_id++;
537 stream->stream_class = stream_class;
319fd969 538 stream->pos.fd = -1;
d246b111 539
3230ee6b
PP
540 stream->destroy_listeners = g_array_new(FALSE, TRUE,
541 sizeof(struct bt_ctf_stream_destroy_listener));
542 if (!stream->destroy_listeners) {
19abc2c6 543 BT_LOGE_STR("Failed to allocate a GArray.");
3230ee6b
PP
544 goto error;
545 }
546
b71d7298
PP
547 if (name) {
548 stream->name = g_string_new(name);
549 if (!stream->name) {
19abc2c6 550 BT_LOGE_STR("Failed to allocate a GString.");
b71d7298
PP
551 goto error;
552 }
553 }
554
19abc2c6
PP
555 BT_LOGD("Set stream's trace parent: trace-addr=%p", trace);
556
319fd969
PP
557 if (trace->is_created_by_writer) {
558 int fd;
559 writer = (struct bt_ctf_writer *)
560 bt_object_get_parent(trace);
561
19abc2c6
PP
562 BT_LOGD("Stream object belongs to a writer's trace: "
563 "writer-addr=%p", writer);
564
319fd969 565 assert(writer);
98edd02c 566 if (stream_class->packet_context_type) {
19abc2c6
PP
567 BT_LOGD("Creating stream's packet context field: "
568 "ft-addr=%p", stream_class->packet_context_type);
98edd02c
JG
569 stream->packet_context = bt_ctf_field_create(
570 stream_class->packet_context_type);
571 if (!stream->packet_context) {
19abc2c6 572 BT_LOGW_STR("Cannot create stream's packet context field.");
98edd02c
JG
573 goto error;
574 }
319fd969 575
98edd02c 576 /* Initialize events_discarded */
af9296f3 577 ret = try_set_structure_field_integer(
19abc2c6 578 stream->packet_context, "events_discarded", 0);
af9296f3 579 if (ret != 1) {
19abc2c6
PP
580 BT_LOGW("Cannot set `events_discarded` field in packet context: "
581 "ret=%d, packet-context-field-addr=%p",
582 ret, stream->packet_context);
98edd02c
JG
583 goto error;
584 }
319fd969
PP
585 }
586
587 stream->events = g_ptr_array_new_with_free_func(
588 (GDestroyNotify) release_event);
589 if (!stream->events) {
19abc2c6 590 BT_LOGE_STR("Failed to allocate a GPtrArray.");
319fd969
PP
591 goto error;
592 }
593
594 /* A trace is not allowed to have a NULL packet header */
595 assert(trace->packet_header_type);
19abc2c6
PP
596 BT_LOGD("Creating stream's packet header field: "
597 "ft-addr=%p", trace->packet_header_type);
319fd969
PP
598 stream->packet_header =
599 bt_ctf_field_create(trace->packet_header_type);
600 if (!stream->packet_header) {
19abc2c6 601 BT_LOGW_STR("Cannot create stream's packet header field.");
319fd969
PP
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) {
19abc2c6 615 BT_LOGW_STR("Cannot populate the stream's packet header.");
319fd969
PP
616 goto error;
617 }
618
619 /* Create file associated with this stream */
620 fd = create_stream_file(writer, stream);
621 if (fd < 0) {
19abc2c6 622 BT_LOGW_STR("Cannot create stream file.");
319fd969
PP
623 goto error;
624 }
625
19abc2c6 626 set_stream_fd(stream, fd);
319fd969
PP
627
628 /* Freeze the writer */
19abc2c6 629 BT_LOGD_STR("Freezing stream's CTF writer.");
319fd969
PP
630 bt_ctf_writer_freeze(writer);
631 } else {
632 /* Non-writer stream indicated by a negative FD */
19abc2c6 633 set_stream_fd(stream, -1);
3230ee6b
PP
634 stream->comp_cur_port = g_hash_table_new(g_direct_hash,
635 g_direct_equal);
636 if (!stream->comp_cur_port) {
19abc2c6 637 BT_LOGE_STR("Failed to allocate a GHashTable.");
3230ee6b
PP
638 goto error;
639 }
d246b111 640 }
319fd969
PP
641
642 /* Add this stream to the trace's streams */
643 g_ptr_array_add(trace->streams, stream);
644
319fd969
PP
645 BT_PUT(trace);
646 BT_PUT(writer);
19abc2c6 647 BT_LOGD("Created stream object: addr=%p", stream);
273b65be 648 return stream;
83509119
JG
649error:
650 BT_PUT(stream);
319fd969
PP
651 BT_PUT(trace);
652 BT_PUT(writer);
83509119 653 return stream;
273b65be
JG
654}
655
3baf0856
JG
656struct 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) {
19abc2c6 662 BT_LOGW_STR("Invalid parameter: stream is NULL.");
3baf0856
JG
663 goto end;
664 }
665
666 stream_class = stream->stream_class;
83509119 667 bt_get(stream_class);
3baf0856
JG
668end:
669 return stream_class;
670}
671
a78a2e25
JG
672int bt_ctf_stream_get_discarded_events_count(
673 struct bt_ctf_stream *stream, uint64_t *count)
674{
675 int64_t ret = 0;
12c8a1a3
JG
676 int field_signed;
677 struct bt_ctf_field *events_discarded_field = NULL;
678 struct bt_ctf_field_type *events_discarded_field_type = NULL;
a78a2e25 679
19abc2c6
PP
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));
a78a2e25
JG
705 ret = -1;
706 goto end;
707 }
708
12c8a1a3
JG
709 events_discarded_field = bt_ctf_field_structure_get_field(
710 stream->packet_context, "events_discarded");
711 if (!events_discarded_field) {
19abc2c6
PP
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);
12c8a1a3
JG
717 ret = -1;
718 goto end;
719 }
720
721 events_discarded_field_type = bt_ctf_field_get_type(
722 events_discarded_field);
19abc2c6 723 assert(events_discarded_field_type);
12c8a1a3
JG
724 field_signed = bt_ctf_field_type_integer_get_signed(
725 events_discarded_field_type);
19abc2c6 726 assert(field_signed >= 0);
12c8a1a3
JG
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) {
19abc2c6
PP
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);
12c8a1a3
JG
738 goto end;
739 }
740 if (signed_count < 0) {
741 /* Invalid value */
19abc2c6
PP
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);
12c8a1a3
JG
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) {
19abc2c6
PP
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);
12c8a1a3
JG
759 goto end;
760 }
761 }
a78a2e25 762end:
83509119
JG
763 bt_put(events_discarded_field);
764 bt_put(events_discarded_field_type);
a78a2e25
JG
765 return ret;
766}
767
273b65be
JG
768void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
769 uint64_t event_count)
770{
12c8a1a3
JG
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
19abc2c6
PP
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.");
12c8a1a3
JG
794 goto end;
795 }
796
797 ret = bt_ctf_stream_get_discarded_events_count(stream,
798 &previous_count);
799 if (ret) {
19abc2c6 800 BT_LOGW_STR("Cannot get stream's number of discarded events.");
12c8a1a3
JG
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) {
19abc2c6 807 BT_LOGW_STR("No field named `events_discarded` in packet context.");
12c8a1a3
JG
808 goto end;
809 }
810
811 events_discarded_field_type = bt_ctf_field_get_type(
812 events_discarded_field);
19abc2c6 813 assert(events_discarded_field_type);
12c8a1a3
JG
814 field_signed = bt_ctf_field_type_integer_get_signed(
815 events_discarded_field_type);
19abc2c6 816 assert(field_signed >= 0);
12c8a1a3 817 new_count = previous_count + event_count;
9ac68eb1 818 assert(new_count >= previous_count);
12c8a1a3
JG
819 if (field_signed) {
820 ret = bt_ctf_field_signed_integer_set_value(
821 events_discarded_field, (int64_t) new_count);
822 if (ret) {
19abc2c6
PP
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);
12c8a1a3
JG
826 goto end;
827 }
828 } else {
829 ret = bt_ctf_field_unsigned_integer_set_value(
830 events_discarded_field, new_count);
831 if (ret) {
19abc2c6
PP
832 BT_LOGW("Cannot set packet context's `events_discarded` field: "
833 "field-addr=%p, value=%" PRIu64,
834 events_discarded_field, new_count);
12c8a1a3
JG
835 goto end;
836 }
837 }
838
19abc2c6
PP
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
12c8a1a3 844end:
83509119
JG
845 bt_put(events_discarded_field);
846 bt_put(events_discarded_field_type);
273b65be
JG
847}
848
ac0c6bdd
PP
849static 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;
19abc2c6 855 uint64_t event_class_id;
ac0c6bdd 856
19abc2c6
PP
857 assert(event);
858
859 if (event->frozen) {
860 BT_LOGW_STR("Cannot populate event header field: event is frozen.");
ac0c6bdd
PP
861 ret = -1;
862 goto end;
863 }
864
19abc2c6
PP
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
ac0c6bdd
PP
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");
19abc2c6
PP
877 event_class_id = (uint64_t) bt_ctf_event_class_get_id(event->event_class);
878 assert(event_class_id >= 0);
ac0c6bdd 879 if (id_field && !bt_ctf_field_is_set(id_field)) {
19abc2c6 880 ret = set_integer_field_value(id_field, event_class_id);
ac0c6bdd 881 if (ret) {
19abc2c6
PP
882 BT_LOGW("Cannot set event header's `id` field's value: "
883 "addr=%p, value=%" PRIu64, id_field,
884 event_class_id);
ac0c6bdd
PP
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);
19abc2c6 921 assert(ret == 0);
ac0c6bdd
PP
922 ret = set_integer_field_value(timestamp_field,
923 timestamp);
924 if (ret) {
19abc2c6
PP
925 BT_LOGW("Cannot set event header's `timestamp` field's value: "
926 "addr=%p, value=%" PRIu64,
927 timestamp_field, timestamp);
ac0c6bdd
PP
928 goto end;
929 }
930 }
931 }
932
19abc2c6
PP
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
ac0c6bdd
PP
937end:
938 bt_put(id_field);
939 bt_put(timestamp_field);
940 bt_put(mapped_clock_class);
941 return ret;
942}
943
273b65be
JG
944int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
945 struct bt_ctf_event *event)
946{
947 int ret = 0;
273b65be 948
19abc2c6
PP
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.");
273b65be
JG
963 ret = -1;
964 goto end;
965 }
966
19abc2c6
PP
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
fa29ba83
PP
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
e6a8e8e4 987 bt_object_set_parent(event, stream);
19abc2c6 988 BT_LOGV_STR("Automatically populating the header of the event to append.");
ac0c6bdd 989 ret = auto_populate_event_header(stream, event);
662e778c 990 if (ret) {
19abc2c6 991 /* auto_populate_event_header() reports errors */
37f30168 992 goto error;
662e778c
JG
993 }
994
5fd2e9fd 995 /* Make sure the various scopes of the event are set */
19abc2c6 996 BT_LOGV_STR("Validating event to append.");
273b65be
JG
997 ret = bt_ctf_event_validate(event);
998 if (ret) {
37f30168 999 goto error;
273b65be
JG
1000 }
1001
0d688c15 1002 /* Save the new event and freeze it */
19abc2c6 1003 BT_LOGV_STR("Freezing the event to append.");
0d688c15 1004 bt_ctf_event_freeze(event);
273b65be 1005 g_ptr_array_add(stream->events, event);
5fd2e9fd 1006
e6a8e8e4
JG
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 */
19abc2c6 1013 BT_LOGV_STR("Putting the event's class.");
e6a8e8e4 1014 bt_put(event->event_class);
19abc2c6
PP
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)));
37f30168 1021
273b65be 1022end:
37f30168
PP
1023 return ret;
1024
1025error:
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
273b65be
JG
1032 return ret;
1033}
1034
12c8a1a3
JG
1035struct 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
19abc2c6
PP
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));
12c8a1a3
JG
1049 goto end;
1050 }
1051
1052 packet_context = stream->packet_context;
12c8a1a3 1053 if (packet_context) {
83509119 1054 bt_get(packet_context);
12c8a1a3 1055 }
34629a55 1056end:
12c8a1a3
JG
1057 return packet_context;
1058}
1059
1060int 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
19abc2c6
PP
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.");
12c8a1a3
JG
1074 ret = -1;
1075 goto end;
1076 }
1077
1078 field_type = bt_ctf_field_get_type(field);
09840de5
PP
1079 if (bt_ctf_field_type_compare(field_type,
1080 stream->stream_class->packet_context_type)) {
19abc2c6
PP
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);
12c8a1a3
JG
1087 ret = -1;
1088 goto end;
1089 }
1090
83509119 1091 bt_put(field_type);
83509119 1092 bt_put(stream->packet_context);
835b2d10 1093 stream->packet_context = bt_get(field);
19abc2c6
PP
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);
12c8a1a3
JG
1098end:
1099 return ret;
1100}
1101
263a7df5
JG
1102struct 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
19abc2c6
PP
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));
263a7df5
JG
1116 goto end;
1117 }
1118
1119 packet_header = stream->packet_header;
1120 if (packet_header) {
83509119 1121 bt_get(packet_header);
263a7df5
JG
1122 }
1123end:
1124 return packet_header;
1125}
1126
1127int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream,
1128 struct bt_ctf_field *field)
1129{
1130 int ret = 0;
e6a8e8e4 1131 struct bt_ctf_trace *trace = NULL;
263a7df5
JG
1132 struct bt_ctf_field_type *field_type = NULL;
1133
19abc2c6
PP
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.");
263a7df5
JG
1142 ret = -1;
1143 goto end;
1144 }
1145
e6a8e8e4 1146 trace = (struct bt_ctf_trace *) bt_object_get_parent(stream);
263a7df5 1147 field_type = bt_ctf_field_get_type(field);
09840de5 1148 if (bt_ctf_field_type_compare(field_type, trace->packet_header_type)) {
19abc2c6
PP
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);
263a7df5
JG
1155 ret = -1;
1156 goto end;
1157 }
1158
83509119 1159 bt_put(stream->packet_header);
835b2d10 1160 stream->packet_header = bt_get(field);
19abc2c6
PP
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);
263a7df5 1165end:
e6a8e8e4 1166 BT_PUT(trace);
83509119 1167 bt_put(field_type);
263a7df5
JG
1168 return ret;
1169}
1170
9a220c32
JG
1171static
1172int 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) {
19abc2c6
PP
1181 BT_LOGV("Cannot get event header's `timestamp` field: "
1182 "field-addr=%p", timestamp_field);
9a220c32
JG
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) !=
19abc2c6
PP
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));
9a220c32
JG
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) {
19abc2c6
PP
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);
9a220c32
JG
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) {
19abc2c6
PP
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);
9a220c32
JG
1222 goto end;
1223 }
1224 }
1225end:
83509119
JG
1226 bt_put(timestamp_field);
1227 bt_put(timestamp_field_type);
9a220c32
JG
1228 return ret;
1229}
1230
c9af50d1
JG
1231static
1232void 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);
e027ff8c 1239 bt_put(member);
c9af50d1
JG
1240}
1241
273b65be
JG
1242int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
1243{
1244 int ret = 0;
1245 size_t i;
c9af50d1 1246 uint64_t timestamp_begin, timestamp_end;
273b65be 1247 struct bt_ctf_field *integer = NULL;
dc3fffef
PP
1248 struct bt_ctf_stream_pos packet_context_pos;
1249 struct bt_ctf_trace *trace;
1250 enum bt_ctf_byte_order native_byte_order;
c55a9f58 1251 bt_bool empty_packet;
0686ef94 1252 uint64_t packet_size_bits;
c9af50d1 1253 struct {
c55a9f58
PP
1254 bt_bool timestamp_begin;
1255 bt_bool timestamp_end;
1256 bt_bool content_size;
1257 bt_bool packet_size;
c9af50d1 1258 } auto_set_fields = { 0 };
273b65be 1259
19abc2c6
PP
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.");
273b65be
JG
1268 ret = -1;
1269 goto end;
1270 }
1271
664f50c8
JG
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 */
19abc2c6 1278 BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once.");
664f50c8
JG
1279 ret = -1;
1280 goto end;
1281 }
1282
19abc2c6
PP
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);
dc3fffef
PP
1286 trace = bt_ctf_stream_class_borrow_trace(stream->stream_class);
1287 assert(trace);
8a716c8d 1288 native_byte_order = bt_ctf_trace_get_native_byte_order(trace);
98edd02c 1289 empty_packet = (stream->events->len == 0);
d246b111 1290
28362f2b 1291 /* mmap the next packet */
19abc2c6
PP
1292 BT_LOGV("Seeking to the next packet: pos-offset=%" PRId64,
1293 stream->pos.offset);
dc3fffef 1294 bt_ctf_stream_pos_packet_seek(&stream->pos, 0, SEEK_CUR);
19abc2c6 1295 BT_LOGV_STR("Serializing packet header field.");
dc3fffef
PP
1296 ret = bt_ctf_field_serialize(stream->packet_header, &stream->pos,
1297 native_byte_order);
d246b111 1298 if (ret) {
19abc2c6
PP
1299 BT_LOGE("Cannot serialize stream's packet header field: "
1300 "field-addr=%p", stream->packet_header);
d246b111 1301 goto end;
273b65be
JG
1302 }
1303
98edd02c
JG
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)) {
af9296f3
JG
1309 ret = try_set_structure_field_integer(
1310 stream->packet_context,
98edd02c 1311 "timestamp_begin", timestamp_begin);
af9296f3 1312 if (ret < 0) {
19abc2c6
PP
1313 BT_LOGW("Cannot set `timestamp_begin` field in packet context: "
1314 "ret=%d, packet-context-field-addr=%p",
1315 ret, stream->packet_context);
98edd02c
JG
1316 goto end;
1317 }
c9af50d1 1318 auto_set_fields.timestamp_begin = ret == 1;
98edd02c
JG
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
af9296f3
JG
1326 ret = try_set_structure_field_integer(
1327 stream->packet_context,
98edd02c 1328 "timestamp_end", timestamp_end);
af9296f3 1329 if (ret < 0) {
19abc2c6
PP
1330 BT_LOGW("Cannot set `timestamp_end` field in packet context: "
1331 "ret=%d, packet-context-field-addr=%p",
1332 ret, stream->packet_context);
98edd02c
JG
1333 goto end;
1334 }
c9af50d1 1335 auto_set_fields.timestamp_end = ret == 1;
98edd02c 1336 }
af9296f3 1337 ret = try_set_structure_field_integer(stream->packet_context,
98edd02c 1338 "content_size", UINT64_MAX);
af9296f3 1339 if (ret < 0) {
19abc2c6
PP
1340 BT_LOGW("Cannot set `content_size` field in packet context: "
1341 "ret=%d, packet-context-field-addr=%p",
1342 ret, stream->packet_context);
9a220c32
JG
1343 goto end;
1344 }
c9af50d1 1345 auto_set_fields.content_size = ret == 1;
273b65be 1346
af9296f3 1347 ret = try_set_structure_field_integer(stream->packet_context,
98edd02c 1348 "packet_size", UINT64_MAX);
af9296f3 1349 if (ret < 0) {
19abc2c6
PP
1350 BT_LOGW("Cannot set `packet_size` field in packet context: "
1351 "ret=%d, packet-context-field-addr=%p",
1352 ret, stream->packet_context);
98edd02c
JG
1353 goto end;
1354 }
c9af50d1 1355 auto_set_fields.packet_size = ret == 1;
12c8a1a3 1356
10cb7b41
JG
1357 /* Write packet context */
1358 memcpy(&packet_context_pos, &stream->pos,
dc3fffef 1359 sizeof(packet_context_pos));
19abc2c6 1360 BT_LOGV_STR("Serializing packet context field.");
10cb7b41 1361 ret = bt_ctf_field_serialize(stream->packet_context,
dc3fffef 1362 &stream->pos, native_byte_order);
98edd02c 1363 if (ret) {
19abc2c6
PP
1364 BT_LOGE("Cannot serialize stream's packet context field: "
1365 "field-addr=%p", stream->packet_context);
98edd02c
JG
1366 goto end;
1367 }
12c8a1a3
JG
1368 }
1369
19abc2c6
PP
1370 BT_LOGV("Serializing events: count=%u", stream->events->len);
1371
273b65be
JG
1372 for (i = 0; i < stream->events->len; i++) {
1373 struct bt_ctf_event *event = g_ptr_array_index(
1374 stream->events, i);
19abc2c6
PP
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);
273b65be 1384
273b65be 1385 /* Write event header */
19abc2c6 1386 BT_LOGV_STR("Serializing event's header field.");
662e778c 1387 ret = bt_ctf_field_serialize(event->event_header,
dc3fffef 1388 &stream->pos, native_byte_order);
273b65be 1389 if (ret) {
19abc2c6
PP
1390 BT_LOGE("Cannot serialize event's header field: "
1391 "field-addr=%p", event->event_header);
273b65be
JG
1392 goto end;
1393 }
1394
8bfa3f9c 1395 /* Write stream event context */
5fd2e9fd 1396 if (event->stream_event_context) {
19abc2c6 1397 BT_LOGV_STR("Serializing event's stream event context field.");
8bfa3f9c 1398 ret = bt_ctf_field_serialize(
dc3fffef
PP
1399 event->stream_event_context, &stream->pos,
1400 native_byte_order);
8bfa3f9c 1401 if (ret) {
19abc2c6
PP
1402 BT_LOGE("Cannot serialize event's stream event context field: "
1403 "field-addr=%p", event->stream_event_context);
8bfa3f9c
JG
1404 goto end;
1405 }
1406 }
1407
273b65be 1408 /* Write event content */
dc3fffef
PP
1409 ret = bt_ctf_event_serialize(event, &stream->pos,
1410 native_byte_order);
273b65be 1411 if (ret) {
19abc2c6 1412 /* bt_ctf_event_serialize() logs errors */
273b65be
JG
1413 goto end;
1414 }
1415 }
1416
0686ef94
JG
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
98edd02c
JG
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;
c9af50d1
JG
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) {
19abc2c6
PP
1435 BT_LOGW("Cannot set `content_size` field in packet context: "
1436 "ret=%d, packet-context-field-addr=%p",
1437 ret, stream->packet_context);
c9af50d1
JG
1438 goto end;
1439 }
98edd02c 1440 }
273b65be 1441
c9af50d1
JG
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) {
19abc2c6
PP
1446 BT_LOGW("Cannot set `packet_size` field in packet context: "
1447 "ret=%d, packet-context-field-addr=%p",
1448 ret, stream->packet_context);
c9af50d1
JG
1449 goto end;
1450 }
98edd02c 1451 }
273b65be 1452
19abc2c6 1453 BT_LOGV("Rewriting (serializing) packet context field.");
98edd02c 1454 ret = bt_ctf_field_serialize(stream->packet_context,
dc3fffef 1455 &packet_context_pos, native_byte_order);
98edd02c 1456 if (ret) {
19abc2c6
PP
1457 BT_LOGE("Cannot serialize stream's packet context field: "
1458 "field-addr=%p", stream->packet_context);
98edd02c
JG
1459 goto end;
1460 }
273b65be
JG
1461 }
1462
1463 g_ptr_array_set_size(stream->events, 0);
1464 stream->flushed_packet_count++;
0686ef94 1465 stream->size += packet_size_bits / CHAR_BIT;
273b65be 1466end:
c9af50d1
JG
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 }
83509119 1484 bt_put(integer);
cd7d8fb7
JG
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;
19abc2c6
PP
1494 } else {
1495 BT_LOGV("Flushed stream's current packet: packet-size=%" PRIu64,
1496 packet_size_bits);
cd7d8fb7 1497 }
273b65be
JG
1498 return ret;
1499}
1500
19abc2c6 1501/* Pre-2.0 CTF writer backward compatibility */
273b65be
JG
1502void bt_ctf_stream_get(struct bt_ctf_stream *stream)
1503{
83509119 1504 bt_get(stream);
273b65be
JG
1505}
1506
19abc2c6 1507/* Pre-2.0 CTF writer backward compatibility */
273b65be
JG
1508void bt_ctf_stream_put(struct bt_ctf_stream *stream)
1509{
83509119 1510 bt_put(stream);
273b65be
JG
1511}
1512
1513static
83509119 1514void bt_ctf_stream_destroy(struct bt_object *obj)
273b65be
JG
1515{
1516 struct bt_ctf_stream *stream;
3230ee6b 1517 int i;
273b65be 1518
83509119 1519 stream = container_of(obj, struct bt_ctf_stream, base);
19abc2c6
PP
1520 BT_LOGD("Destroying stream object: addr=%p, name=\"%s\"",
1521 stream, bt_ctf_stream_get_name(stream));
3230ee6b
PP
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
19abc2c6
PP
1529 BT_LOGD("Calling destroy listener: func=%p, data=%p, index=%d",
1530 listener->func, listener->data, i);
3230ee6b
PP
1531 listener->func(stream, listener->data);
1532 }
1533
dc3fffef 1534 (void) bt_ctf_stream_pos_fini(&stream->pos);
0686ef94
JG
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) {
19abc2c6
PP
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);
0686ef94
JG
1551 }
1552
1553 if (close(stream->pos.fd)) {
19abc2c6
PP
1554 BT_LOGE("Failed to close stream file: %s: "
1555 "ret=%d, errno=%d", strerror(errno),
1556 ret, errno);
0686ef94 1557 }
9f56e450 1558 }
12c8a1a3 1559
12c8a1a3 1560 if (stream->events) {
19abc2c6 1561 BT_LOGD_STR("Putting events.");
12c8a1a3
JG
1562 g_ptr_array_free(stream->events, TRUE);
1563 }
b71d7298
PP
1564
1565 if (stream->name) {
1566 g_string_free(stream->name, TRUE);
1567 }
41ac640a 1568
3230ee6b
PP
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
19abc2c6 1595 BT_LOGD_STR("Putting packet header field.");
83509119 1596 bt_put(stream->packet_header);
19abc2c6 1597 BT_LOGD_STR("Putting packet context field.");
83509119 1598 bt_put(stream->packet_context);
273b65be
JG
1599 g_free(stream);
1600}
1601
273b65be 1602static
af9296f3 1603int _set_structure_field_integer(struct bt_ctf_field *structure, char *name,
c55a9f58 1604 uint64_t value, bt_bool force)
273b65be
JG
1605{
1606 int ret = 0;
d7b1ea66 1607 struct bt_ctf_field_type *field_type = NULL;
19abc2c6 1608 struct bt_ctf_field *integer;
12c8a1a3 1609
19abc2c6
PP
1610 assert(structure);
1611 assert(name);
273b65be 1612
19abc2c6 1613 integer = bt_ctf_field_structure_get_field(structure, name);
12c8a1a3
JG
1614 if (!integer) {
1615 /* Field not found, not an error. */
19abc2c6
PP
1616 BT_LOGV("Field not found: struct-field-addr=%p, "
1617 "name=\"%s\", force=%d", structure, name, force);
12c8a1a3
JG
1618 goto end;
1619 }
1620
1621 /* Make sure the payload has not already been set. */
af9296f3 1622 if (!force && bt_ctf_field_is_set(integer)) {
12c8a1a3 1623 /* Payload already set, not an error */
19abc2c6
PP
1624 BT_LOGV("Field's payload is already set: struct-field-addr=%p, "
1625 "name=\"%s\", force=%d", structure, name, force);
12c8a1a3
JG
1626 goto end;
1627 }
1628
d7b1ea66 1629 field_type = bt_ctf_field_get_type(integer);
d7b1ea66 1630 assert(field_type);
1487a16a 1631 if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) {
d7b1ea66
JG
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 */
19abc2c6
PP
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));
d7b1ea66
JG
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 }
af9296f3 1651 ret = !ret ? 1 : ret;
273b65be 1652end:
83509119
JG
1653 bt_put(integer);
1654 bt_put(field_type);
273b65be
JG
1655 return ret;
1656}
b71d7298 1657
af9296f3
JG
1658static
1659int set_structure_field_integer(struct bt_ctf_field *structure, char *name,
1660 uint64_t value)
1661{
c55a9f58 1662 return _set_structure_field_integer(structure, name, value, BT_TRUE);
af9296f3
JG
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 */
1671static
1672int try_set_structure_field_integer(struct bt_ctf_field *structure, char *name,
1673 uint64_t value)
1674{
c55a9f58 1675 return _set_structure_field_integer(structure, name, value, BT_FALSE);
af9296f3
JG
1676}
1677
b71d7298
PP
1678const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream)
1679{
1680 const char *name = NULL;
1681
1682 if (!stream) {
19abc2c6 1683 BT_LOGW_STR("Invalid parameter: stream is NULL.");
b71d7298
PP
1684 goto end;
1685 }
1686
1687 name = stream->name ? stream->name->str : NULL;
1688
1689end:
1690 return name;
1691}
98a4cbef
PP
1692
1693int bt_ctf_stream_is_writer(struct bt_ctf_stream *stream)
1694{
1695 int ret = -1;
1696
1697 if (!stream) {
19abc2c6 1698 BT_LOGW_STR("Invalid parameter: stream is NULL.");
98a4cbef
PP
1699 goto end;
1700 }
1701
1702 ret = (stream->pos.fd >= 0);
1703
1704end:
1705 return ret;
1706}
3230ee6b
PP
1707
1708BT_HIDDEN
1709void 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);
19abc2c6
PP
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));
3230ee6b
PP
1734}
1735
1736BT_HIDDEN
1737struct 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
1746BT_HIDDEN
1747void 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);
19abc2c6
PP
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);
3230ee6b
PP
1760}
1761
1762BT_HIDDEN
1763void 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--;
19abc2c6
PP
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);
3230ee6b
PP
1783 }
1784 }
1785}
This page took 0.125084 seconds and 4 git commands to generate.