Commit | Line | Data |
---|---|---|
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 | ||
3f043b05 | 29 | #include <babeltrace/ctf-ir/clock.h> |
adc315b8 | 30 | #include <babeltrace/ctf-ir/clock-internal.h> |
273b65be | 31 | #include <babeltrace/ctf-writer/event.h> |
adc315b8 JG |
32 | #include <babeltrace/ctf-ir/event-internal.h> |
33 | #include <babeltrace/ctf-ir/event-types-internal.h> | |
34 | #include <babeltrace/ctf-ir/event-fields-internal.h> | |
3f043b05 JG |
35 | #include <babeltrace/ctf-ir/stream.h> |
36 | #include <babeltrace/ctf-ir/stream-internal.h> | |
adc315b8 | 37 | #include <babeltrace/ctf-ir/stream-class-internal.h> |
83509119 | 38 | #include <babeltrace/ref.h> |
273b65be JG |
39 | #include <babeltrace/ctf-writer/functor-internal.h> |
40 | #include <babeltrace/compiler.h> | |
41 | #include <babeltrace/align.h> | |
d246b111 | 42 | #include <babeltrace/ctf/ctf-index.h> |
273b65be JG |
43 | |
44 | static | |
83509119 | 45 | void bt_ctf_stream_destroy(struct bt_object *obj); |
273b65be | 46 | static |
273b65be JG |
47 | int set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t); |
48 | ||
d246b111 JG |
49 | static |
50 | int set_packet_header_magic(struct bt_ctf_stream *stream) | |
51 | { | |
52 | int ret = 0; | |
53 | struct bt_ctf_field_type *magic_field_type = NULL; | |
54 | struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field( | |
55 | stream->packet_header, "magic"); | |
56 | ||
57 | if (!magic_field) { | |
58 | /* No magic field found. Not an error, skip. */ | |
59 | goto end; | |
60 | } | |
61 | ||
62 | if (!bt_ctf_field_validate(magic_field)) { | |
63 | /* Value already set. Not an error, skip. */ | |
64 | goto end; | |
65 | } | |
66 | ||
67 | magic_field_type = bt_ctf_field_get_type(magic_field); | |
68 | assert(magic_field_type); | |
69 | ||
70 | if (bt_ctf_field_type_get_type_id(magic_field_type) != | |
71 | CTF_TYPE_INTEGER) { | |
72 | /* Magic field is not an integer. Not an error, skip. */ | |
73 | goto end; | |
74 | } | |
75 | ||
76 | if (bt_ctf_field_type_integer_get_size(magic_field_type) != 32) { | |
77 | /* | |
78 | * Magic field is not of the expected size. | |
79 | * Not an error, skip. | |
80 | */ | |
81 | goto end; | |
82 | } | |
83 | ||
84 | ret = bt_ctf_field_type_integer_get_signed(magic_field_type); | |
85 | assert(ret >= 0); | |
86 | if (ret) { | |
87 | ret = bt_ctf_field_signed_integer_set_value(magic_field, | |
88 | (int64_t) 0xC1FC1FC1); | |
89 | } else { | |
90 | ret = bt_ctf_field_unsigned_integer_set_value(magic_field, | |
91 | (uint64_t) 0xC1FC1FC1); | |
92 | } | |
93 | end: | |
83509119 JG |
94 | bt_put(magic_field); |
95 | bt_put(magic_field_type); | |
d246b111 JG |
96 | return ret; |
97 | } | |
98 | ||
99 | static | |
100 | int set_packet_header_uuid(struct bt_ctf_stream *stream) | |
101 | { | |
102 | int i, ret = 0; | |
103 | struct bt_ctf_field_type *uuid_field_type = NULL; | |
104 | struct bt_ctf_field_type *element_field_type = NULL; | |
105 | struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field( | |
106 | stream->packet_header, "uuid"); | |
107 | ||
108 | if (!uuid_field) { | |
109 | /* No uuid field found. Not an error, skip. */ | |
110 | goto end; | |
111 | } | |
112 | ||
113 | if (!bt_ctf_field_validate(uuid_field)) { | |
114 | /* Value already set. Not an error, skip. */ | |
115 | goto end; | |
116 | } | |
117 | ||
118 | uuid_field_type = bt_ctf_field_get_type(uuid_field); | |
119 | assert(uuid_field_type); | |
120 | if (bt_ctf_field_type_get_type_id(uuid_field_type) != | |
121 | CTF_TYPE_ARRAY) { | |
122 | /* UUID field is not an array. Not an error, skip. */ | |
123 | goto end; | |
124 | } | |
125 | ||
126 | if (bt_ctf_field_type_array_get_length(uuid_field_type) != 16) { | |
127 | /* | |
128 | * UUID field is not of the expected size. | |
129 | * Not an error, skip. | |
130 | */ | |
131 | goto end; | |
132 | } | |
133 | ||
134 | element_field_type = bt_ctf_field_type_array_get_element_type( | |
135 | uuid_field_type); | |
136 | assert(element_field_type); | |
137 | if (bt_ctf_field_type_get_type_id(element_field_type) != | |
138 | CTF_TYPE_INTEGER) { | |
139 | /* UUID array elements are not integers. Not an error, skip */ | |
140 | goto end; | |
141 | } | |
142 | ||
143 | for (i = 0; i < 16; i++) { | |
144 | struct bt_ctf_field *uuid_element = | |
145 | bt_ctf_field_array_get_field(uuid_field, i); | |
146 | ||
147 | ret = bt_ctf_field_type_integer_get_signed(element_field_type); | |
148 | assert(ret >= 0); | |
149 | ||
150 | if (ret) { | |
151 | ret = bt_ctf_field_signed_integer_set_value( | |
152 | uuid_element, (int64_t) stream->trace->uuid[i]); | |
153 | } else { | |
154 | ret = bt_ctf_field_unsigned_integer_set_value( | |
155 | uuid_element, | |
156 | (uint64_t) stream->trace->uuid[i]); | |
157 | } | |
83509119 | 158 | bt_put(uuid_element); |
d246b111 JG |
159 | if (ret) { |
160 | goto end; | |
161 | } | |
162 | } | |
163 | ||
164 | end: | |
83509119 JG |
165 | bt_put(uuid_field); |
166 | bt_put(uuid_field_type); | |
167 | bt_put(element_field_type); | |
d246b111 JG |
168 | return ret; |
169 | } | |
170 | static | |
171 | int set_packet_header_stream_id(struct bt_ctf_stream *stream) | |
172 | { | |
173 | int ret = 0; | |
174 | uint32_t stream_id; | |
175 | struct bt_ctf_field_type *stream_id_field_type = NULL; | |
176 | struct bt_ctf_field *stream_id_field = bt_ctf_field_structure_get_field( | |
177 | stream->packet_header, "stream_id"); | |
178 | ||
179 | if (!stream_id_field) { | |
180 | /* No stream_id field found. Not an error, skip. */ | |
181 | goto end; | |
182 | } | |
183 | ||
184 | if (!bt_ctf_field_validate(stream_id_field)) { | |
185 | /* Value already set. Not an error, skip. */ | |
186 | goto end; | |
187 | } | |
188 | ||
189 | stream_id_field_type = bt_ctf_field_get_type(stream_id_field); | |
190 | assert(stream_id_field_type); | |
191 | if (bt_ctf_field_type_get_type_id(stream_id_field_type) != | |
192 | CTF_TYPE_INTEGER) { | |
193 | /* stream_id field is not an integer. Not an error, skip. */ | |
194 | goto end; | |
195 | } | |
196 | ||
197 | stream_id = stream->stream_class->id; | |
198 | ret = bt_ctf_field_type_integer_get_signed(stream_id_field_type); | |
199 | assert(ret >= 0); | |
200 | if (ret) { | |
201 | ret = bt_ctf_field_signed_integer_set_value(stream_id_field, | |
202 | (int64_t) stream_id); | |
203 | } else { | |
204 | ret = bt_ctf_field_unsigned_integer_set_value(stream_id_field, | |
205 | (uint64_t) stream_id); | |
206 | } | |
207 | end: | |
83509119 JG |
208 | bt_put(stream_id_field); |
209 | bt_put(stream_id_field_type); | |
d246b111 JG |
210 | return ret; |
211 | } | |
212 | ||
213 | static | |
214 | int set_packet_header(struct bt_ctf_stream *stream) | |
215 | { | |
216 | int ret; | |
217 | ||
218 | ret = set_packet_header_magic(stream); | |
219 | if (ret) { | |
220 | goto end; | |
221 | } | |
222 | ||
223 | ret = set_packet_header_uuid(stream); | |
224 | if (ret) { | |
225 | goto end; | |
226 | } | |
227 | ||
228 | ret = set_packet_header_stream_id(stream); | |
229 | if (ret) { | |
230 | goto end; | |
231 | } | |
232 | end: | |
233 | return ret; | |
234 | } | |
235 | ||
123fbdec JG |
236 | static |
237 | void put_event(struct bt_ctf_event *event) | |
238 | { | |
239 | bt_ctf_event_set_stream(event, NULL); | |
83509119 | 240 | bt_put(event); |
123fbdec JG |
241 | } |
242 | ||
273b65be JG |
243 | BT_HIDDEN |
244 | struct bt_ctf_stream *bt_ctf_stream_create( | |
d246b111 JG |
245 | struct bt_ctf_stream_class *stream_class, |
246 | struct bt_ctf_trace *trace) | |
273b65be | 247 | { |
12c8a1a3 | 248 | int ret; |
273b65be JG |
249 | struct bt_ctf_stream *stream = NULL; |
250 | ||
d246b111 | 251 | if (!stream_class || !trace) { |
273b65be JG |
252 | goto end; |
253 | } | |
254 | ||
255 | stream = g_new0(struct bt_ctf_stream, 1); | |
256 | if (!stream) { | |
257 | goto end; | |
258 | } | |
259 | ||
a4031f67 | 260 | /* A stream has no ownership of its trace (weak ptr) */ |
d246b111 | 261 | stream->trace = trace; |
83509119 | 262 | bt_object_init(stream, bt_ctf_stream_destroy); |
12c8a1a3 JG |
263 | stream->packet_context = bt_ctf_field_create( |
264 | stream_class->packet_context_type); | |
265 | if (!stream->packet_context) { | |
83509119 | 266 | goto error; |
12c8a1a3 JG |
267 | } |
268 | ||
af181248 JG |
269 | /* |
270 | * A stream class may not have a stream event context defined | |
271 | * in which case this stream will never have a stream_event_context | |
272 | * member since, after a stream's creation, the parent stream class | |
273 | * is "frozen" (immutable). | |
274 | */ | |
275 | if (stream_class->event_context_type) { | |
276 | stream->event_context = bt_ctf_field_create( | |
277 | stream_class->event_context_type); | |
278 | if (!stream->packet_context) { | |
83509119 | 279 | goto error; |
af181248 JG |
280 | } |
281 | } | |
282 | ||
e19cc57d | 283 | /* Initialize events_discarded */ |
12c8a1a3 JG |
284 | ret = set_structure_field_integer(stream->packet_context, |
285 | "events_discarded", 0); | |
286 | if (ret) { | |
83509119 | 287 | goto error; |
12c8a1a3 JG |
288 | } |
289 | ||
273b65be JG |
290 | stream->pos.fd = -1; |
291 | stream->id = stream_class->next_stream_id++; | |
292 | stream->stream_class = stream_class; | |
83509119 | 293 | bt_get(stream_class); |
273b65be | 294 | stream->events = g_ptr_array_new_with_free_func( |
123fbdec | 295 | (GDestroyNotify) put_event); |
8bfa3f9c | 296 | if (!stream->events) { |
83509119 | 297 | goto error; |
8bfa3f9c JG |
298 | } |
299 | if (stream_class->event_context_type) { | |
300 | stream->event_contexts = g_ptr_array_new_with_free_func( | |
9aac8f72 | 301 | (GDestroyNotify) bt_put); |
8bfa3f9c | 302 | if (!stream->event_contexts) { |
83509119 | 303 | goto error; |
8bfa3f9c JG |
304 | } |
305 | } | |
d246b111 JG |
306 | |
307 | /* A trace is not allowed to have a NULL packet header */ | |
308 | assert(trace->packet_header_type); | |
309 | stream->packet_header = bt_ctf_field_create(trace->packet_header_type); | |
92351460 | 310 | if (!stream->packet_header) { |
83509119 | 311 | goto error; |
92351460 | 312 | } |
d246b111 JG |
313 | /* |
314 | * Attempt to populate the default trace packet header fields | |
315 | * (magic, uuid and stream_id). This will _not_ fail shall the | |
316 | * fields not be found or be of an incompatible type; they will | |
317 | * simply not be populated automatically. The user will have to | |
318 | * make sure to set the trace packet header fields himself before | |
319 | * flushing. | |
320 | */ | |
321 | ret = set_packet_header(stream); | |
322 | if (ret) { | |
83509119 | 323 | goto error; |
d246b111 | 324 | } |
273b65be JG |
325 | end: |
326 | return stream; | |
83509119 JG |
327 | error: |
328 | BT_PUT(stream); | |
329 | return stream; | |
273b65be JG |
330 | } |
331 | ||
273b65be JG |
332 | BT_HIDDEN |
333 | int bt_ctf_stream_set_fd(struct bt_ctf_stream *stream, int fd) | |
334 | { | |
335 | int ret = 0; | |
336 | ||
337 | if (stream->pos.fd != -1) { | |
338 | ret = -1; | |
339 | goto end; | |
340 | } | |
341 | ||
342 | ctf_init_pos(&stream->pos, NULL, fd, O_RDWR); | |
343 | stream->pos.fd = fd; | |
344 | end: | |
345 | return ret; | |
346 | } | |
347 | ||
3baf0856 JG |
348 | struct bt_ctf_stream_class *bt_ctf_stream_get_class( |
349 | struct bt_ctf_stream *stream) | |
350 | { | |
351 | struct bt_ctf_stream_class *stream_class = NULL; | |
352 | ||
353 | if (!stream) { | |
354 | goto end; | |
355 | } | |
356 | ||
357 | stream_class = stream->stream_class; | |
83509119 | 358 | bt_get(stream_class); |
3baf0856 JG |
359 | end: |
360 | return stream_class; | |
361 | } | |
362 | ||
a78a2e25 JG |
363 | int bt_ctf_stream_get_discarded_events_count( |
364 | struct bt_ctf_stream *stream, uint64_t *count) | |
365 | { | |
366 | int64_t ret = 0; | |
12c8a1a3 JG |
367 | int field_signed; |
368 | struct bt_ctf_field *events_discarded_field = NULL; | |
369 | struct bt_ctf_field_type *events_discarded_field_type = NULL; | |
a78a2e25 | 370 | |
12c8a1a3 | 371 | if (!stream || !count || !stream->packet_context) { |
a78a2e25 JG |
372 | ret = -1; |
373 | goto end; | |
374 | } | |
375 | ||
12c8a1a3 JG |
376 | events_discarded_field = bt_ctf_field_structure_get_field( |
377 | stream->packet_context, "events_discarded"); | |
378 | if (!events_discarded_field) { | |
379 | ret = -1; | |
380 | goto end; | |
381 | } | |
382 | ||
383 | events_discarded_field_type = bt_ctf_field_get_type( | |
384 | events_discarded_field); | |
385 | if (!events_discarded_field_type) { | |
386 | ret = -1; | |
387 | goto end; | |
388 | } | |
389 | ||
390 | field_signed = bt_ctf_field_type_integer_get_signed( | |
391 | events_discarded_field_type); | |
392 | if (field_signed < 0) { | |
393 | ret = field_signed; | |
394 | goto end; | |
395 | } | |
396 | ||
397 | if (field_signed) { | |
398 | int64_t signed_count; | |
399 | ||
400 | ret = bt_ctf_field_signed_integer_get_value( | |
401 | events_discarded_field, &signed_count); | |
402 | if (ret) { | |
403 | goto end; | |
404 | } | |
405 | if (signed_count < 0) { | |
406 | /* Invalid value */ | |
407 | ret = -1; | |
408 | goto end; | |
409 | } | |
410 | *count = (uint64_t) signed_count; | |
411 | } else { | |
412 | ret = bt_ctf_field_unsigned_integer_get_value( | |
413 | events_discarded_field, count); | |
414 | if (ret) { | |
415 | goto end; | |
416 | } | |
417 | } | |
a78a2e25 | 418 | end: |
83509119 JG |
419 | bt_put(events_discarded_field); |
420 | bt_put(events_discarded_field_type); | |
a78a2e25 JG |
421 | return ret; |
422 | } | |
423 | ||
273b65be JG |
424 | void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream, |
425 | uint64_t event_count) | |
426 | { | |
12c8a1a3 JG |
427 | int ret; |
428 | int field_signed; | |
429 | uint64_t previous_count; | |
430 | uint64_t new_count; | |
431 | struct bt_ctf_field *events_discarded_field = NULL; | |
432 | struct bt_ctf_field_type *events_discarded_field_type = NULL; | |
433 | ||
434 | if (!stream || !stream->packet_context) { | |
435 | goto end; | |
436 | } | |
437 | ||
438 | ret = bt_ctf_stream_get_discarded_events_count(stream, | |
439 | &previous_count); | |
440 | if (ret) { | |
441 | goto end; | |
442 | } | |
443 | ||
444 | events_discarded_field = bt_ctf_field_structure_get_field( | |
445 | stream->packet_context, "events_discarded"); | |
446 | if (!events_discarded_field) { | |
447 | goto end; | |
448 | } | |
449 | ||
450 | events_discarded_field_type = bt_ctf_field_get_type( | |
451 | events_discarded_field); | |
452 | if (!events_discarded_field_type) { | |
453 | goto end; | |
454 | } | |
455 | ||
456 | field_signed = bt_ctf_field_type_integer_get_signed( | |
457 | events_discarded_field_type); | |
458 | if (field_signed < 0) { | |
459 | goto end; | |
273b65be JG |
460 | } |
461 | ||
12c8a1a3 JG |
462 | new_count = previous_count + event_count; |
463 | if (field_signed) { | |
464 | ret = bt_ctf_field_signed_integer_set_value( | |
465 | events_discarded_field, (int64_t) new_count); | |
466 | if (ret) { | |
467 | goto end; | |
468 | } | |
469 | } else { | |
470 | ret = bt_ctf_field_unsigned_integer_set_value( | |
471 | events_discarded_field, new_count); | |
472 | if (ret) { | |
473 | goto end; | |
474 | } | |
475 | } | |
476 | ||
477 | end: | |
83509119 JG |
478 | bt_put(events_discarded_field); |
479 | bt_put(events_discarded_field_type); | |
273b65be JG |
480 | } |
481 | ||
482 | int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, | |
483 | struct bt_ctf_event *event) | |
484 | { | |
485 | int ret = 0; | |
af181248 | 486 | struct bt_ctf_field *event_context_copy = NULL; |
273b65be JG |
487 | |
488 | if (!stream || !event) { | |
489 | ret = -1; | |
490 | goto end; | |
491 | } | |
492 | ||
123fbdec JG |
493 | ret = bt_ctf_event_set_stream(event, stream); |
494 | if (ret) { | |
495 | /* Event was already associated to a stream */ | |
496 | ret = -1; | |
497 | goto end; | |
498 | } | |
499 | ||
662e778c JG |
500 | ret = bt_ctf_event_populate_event_header(event); |
501 | if (ret) { | |
502 | goto end; | |
503 | } | |
504 | ||
785b5390 | 505 | /* Make sure the event's payload is set */ |
273b65be JG |
506 | ret = bt_ctf_event_validate(event); |
507 | if (ret) { | |
508 | goto end; | |
509 | } | |
510 | ||
8bfa3f9c JG |
511 | /* Sample the current stream event context by copying it */ |
512 | if (stream->event_context) { | |
513 | /* Make sure the event context's payload is set */ | |
514 | ret = bt_ctf_field_validate(stream->event_context); | |
515 | if (ret) { | |
516 | goto end; | |
517 | } | |
518 | ||
519 | event_context_copy = bt_ctf_field_copy(stream->event_context); | |
520 | if (!event_context_copy) { | |
521 | ret = -1; | |
522 | goto end; | |
523 | } | |
524 | } | |
525 | ||
83509119 | 526 | bt_get(event); |
8bfa3f9c | 527 | /* Save the new event along with its associated stream event context */ |
273b65be | 528 | g_ptr_array_add(stream->events, event); |
8bfa3f9c JG |
529 | if (event_context_copy) { |
530 | g_ptr_array_add(stream->event_contexts, event_context_copy); | |
531 | } | |
273b65be | 532 | end: |
123fbdec JG |
533 | if (ret) { |
534 | (void) bt_ctf_event_set_stream(event, NULL); | |
535 | } | |
273b65be JG |
536 | return ret; |
537 | } | |
538 | ||
12c8a1a3 JG |
539 | struct bt_ctf_field *bt_ctf_stream_get_packet_context( |
540 | struct bt_ctf_stream *stream) | |
541 | { | |
542 | struct bt_ctf_field *packet_context = NULL; | |
543 | ||
544 | if (!stream) { | |
545 | goto end; | |
546 | } | |
547 | ||
548 | packet_context = stream->packet_context; | |
12c8a1a3 | 549 | if (packet_context) { |
83509119 | 550 | bt_get(packet_context); |
12c8a1a3 | 551 | } |
34629a55 | 552 | end: |
12c8a1a3 JG |
553 | return packet_context; |
554 | } | |
555 | ||
556 | int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream, | |
557 | struct bt_ctf_field *field) | |
558 | { | |
559 | int ret = 0; | |
560 | struct bt_ctf_field_type *field_type; | |
561 | ||
562 | if (!stream || !field) { | |
563 | ret = -1; | |
564 | goto end; | |
565 | } | |
566 | ||
567 | field_type = bt_ctf_field_get_type(field); | |
568 | if (field_type != stream->stream_class->packet_context_type) { | |
569 | ret = -1; | |
570 | goto end; | |
571 | } | |
572 | ||
83509119 JG |
573 | bt_put(field_type); |
574 | bt_get(field); | |
575 | bt_put(stream->packet_context); | |
12c8a1a3 JG |
576 | stream->packet_context = field; |
577 | end: | |
578 | return ret; | |
579 | } | |
580 | ||
8bfa3f9c JG |
581 | struct bt_ctf_field *bt_ctf_stream_get_event_context( |
582 | struct bt_ctf_stream *stream) | |
583 | { | |
584 | struct bt_ctf_field *event_context = NULL; | |
585 | ||
586 | if (!stream) { | |
587 | goto end; | |
588 | } | |
589 | ||
590 | event_context = stream->event_context; | |
591 | if (event_context) { | |
83509119 | 592 | bt_get(event_context); |
8bfa3f9c JG |
593 | } |
594 | end: | |
595 | return event_context; | |
596 | } | |
597 | ||
598 | int bt_ctf_stream_set_event_context(struct bt_ctf_stream *stream, | |
599 | struct bt_ctf_field *field) | |
600 | { | |
601 | int ret = 0; | |
602 | struct bt_ctf_field_type *field_type = NULL; | |
603 | ||
604 | if (!stream || !field) { | |
605 | ret = -1; | |
606 | goto end; | |
607 | } | |
608 | ||
609 | field_type = bt_ctf_field_get_type(field); | |
610 | if (field_type != stream->stream_class->event_context_type) { | |
611 | ret = -1; | |
612 | goto end; | |
613 | } | |
614 | ||
83509119 JG |
615 | bt_get(field); |
616 | bt_put(stream->event_context); | |
8bfa3f9c JG |
617 | stream->event_context = field; |
618 | end: | |
83509119 | 619 | bt_put(field_type); |
8bfa3f9c JG |
620 | return ret; |
621 | } | |
622 | ||
263a7df5 JG |
623 | struct bt_ctf_field *bt_ctf_stream_get_packet_header( |
624 | struct bt_ctf_stream *stream) | |
625 | { | |
626 | struct bt_ctf_field *packet_header = NULL; | |
627 | ||
628 | if (!stream) { | |
629 | goto end; | |
630 | } | |
631 | ||
632 | packet_header = stream->packet_header; | |
633 | if (packet_header) { | |
83509119 | 634 | bt_get(packet_header); |
263a7df5 JG |
635 | } |
636 | end: | |
637 | return packet_header; | |
638 | } | |
639 | ||
640 | int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream, | |
641 | struct bt_ctf_field *field) | |
642 | { | |
643 | int ret = 0; | |
644 | struct bt_ctf_field_type *field_type = NULL; | |
645 | ||
646 | if (!stream || !field) { | |
647 | ret = -1; | |
648 | goto end; | |
649 | } | |
650 | ||
651 | field_type = bt_ctf_field_get_type(field); | |
652 | if (field_type != stream->trace->packet_header_type) { | |
653 | ret = -1; | |
654 | goto end; | |
655 | } | |
656 | ||
83509119 JG |
657 | bt_get(field); |
658 | bt_put(stream->packet_header); | |
263a7df5 JG |
659 | stream->packet_header = field; |
660 | end: | |
83509119 | 661 | bt_put(field_type); |
263a7df5 JG |
662 | return ret; |
663 | } | |
664 | ||
9a220c32 JG |
665 | static |
666 | int get_event_header_timestamp(struct bt_ctf_field *event_header, uint64_t *timestamp) | |
667 | { | |
668 | int ret = 0; | |
669 | struct bt_ctf_field *timestamp_field = NULL; | |
670 | struct bt_ctf_field_type *timestamp_field_type = NULL; | |
671 | ||
672 | timestamp_field = bt_ctf_field_structure_get_field(event_header, | |
673 | "timestamp"); | |
674 | if (!timestamp_field) { | |
675 | ret = -1; | |
676 | goto end; | |
677 | } | |
678 | ||
679 | timestamp_field_type = bt_ctf_field_get_type(timestamp_field); | |
680 | assert(timestamp_field_type); | |
681 | if (bt_ctf_field_type_get_type_id(timestamp_field_type) != | |
682 | CTF_TYPE_INTEGER) { | |
683 | ret = -1; | |
684 | goto end; | |
685 | } | |
686 | ||
687 | if (bt_ctf_field_type_integer_get_signed(timestamp_field_type)) { | |
688 | int64_t val; | |
689 | ||
690 | ret = bt_ctf_field_signed_integer_get_value(timestamp_field, | |
691 | &val); | |
692 | if (ret) { | |
693 | goto end; | |
694 | } | |
695 | *timestamp = (uint64_t) val; | |
696 | } else { | |
697 | ret = bt_ctf_field_unsigned_integer_get_value(timestamp_field, | |
698 | timestamp); | |
699 | if (ret) { | |
700 | goto end; | |
701 | } | |
702 | } | |
703 | end: | |
83509119 JG |
704 | bt_put(timestamp_field); |
705 | bt_put(timestamp_field_type); | |
9a220c32 JG |
706 | return ret; |
707 | } | |
708 | ||
273b65be JG |
709 | int bt_ctf_stream_flush(struct bt_ctf_stream *stream) |
710 | { | |
711 | int ret = 0; | |
712 | size_t i; | |
12c8a1a3 | 713 | uint64_t timestamp_begin, timestamp_end, events_discarded; |
273b65be JG |
714 | struct bt_ctf_field *integer = NULL; |
715 | struct ctf_stream_pos packet_context_pos; | |
716 | ||
bc37ae52 JG |
717 | if (!stream || stream->pos.fd < 0) { |
718 | /* | |
719 | * Stream does not have an associated fd. It is, | |
720 | * therefore, not a stream being used to write events. | |
721 | */ | |
273b65be JG |
722 | ret = -1; |
723 | goto end; | |
724 | } | |
725 | ||
726 | if (!stream->events->len) { | |
727 | goto end; | |
728 | } | |
729 | ||
d246b111 JG |
730 | ret = bt_ctf_field_validate(stream->packet_header); |
731 | if (ret) { | |
732 | goto end; | |
733 | } | |
734 | ||
28362f2b JG |
735 | /* mmap the next packet */ |
736 | ctf_packet_seek(&stream->pos.parent, 0, SEEK_CUR); | |
d246b111 JG |
737 | |
738 | ret = bt_ctf_field_serialize(stream->packet_header, &stream->pos); | |
739 | if (ret) { | |
740 | goto end; | |
273b65be JG |
741 | } |
742 | ||
12c8a1a3 | 743 | /* Set the default context attributes if present and unset. */ |
9a220c32 JG |
744 | if (!get_event_header_timestamp( |
745 | ((struct bt_ctf_event *) g_ptr_array_index( | |
746 | stream->events, 0))->event_header, ×tamp_begin)) { | |
747 | ret = set_structure_field_integer(stream->packet_context, | |
748 | "timestamp_begin", timestamp_begin); | |
749 | if (ret) { | |
750 | goto end; | |
751 | } | |
273b65be JG |
752 | } |
753 | ||
9a220c32 JG |
754 | if (!get_event_header_timestamp( |
755 | ((struct bt_ctf_event *) g_ptr_array_index( | |
756 | stream->events, stream->events->len - 1))->event_header, | |
757 | ×tamp_end)) { | |
273b65be | 758 | |
9a220c32 JG |
759 | ret = set_structure_field_integer(stream->packet_context, |
760 | "timestamp_end", timestamp_end); | |
761 | if (ret) { | |
762 | goto end; | |
763 | } | |
764 | } | |
12c8a1a3 | 765 | ret = set_structure_field_integer(stream->packet_context, |
273b65be JG |
766 | "content_size", UINT64_MAX); |
767 | if (ret) { | |
768 | goto end; | |
769 | } | |
770 | ||
12c8a1a3 | 771 | ret = set_structure_field_integer(stream->packet_context, |
273b65be JG |
772 | "packet_size", UINT64_MAX); |
773 | if (ret) { | |
774 | goto end; | |
775 | } | |
776 | ||
777 | /* Write packet context */ | |
778 | memcpy(&packet_context_pos, &stream->pos, | |
779 | sizeof(struct ctf_stream_pos)); | |
12c8a1a3 | 780 | ret = bt_ctf_field_serialize(stream->packet_context, |
273b65be JG |
781 | &stream->pos); |
782 | if (ret) { | |
783 | goto end; | |
784 | } | |
785 | ||
12c8a1a3 JG |
786 | ret = bt_ctf_stream_get_discarded_events_count(stream, |
787 | &events_discarded); | |
788 | if (ret) { | |
789 | goto end; | |
790 | } | |
791 | ||
792 | /* Unset the packet context's fields. */ | |
793 | ret = bt_ctf_field_reset(stream->packet_context); | |
794 | if (ret) { | |
795 | goto end; | |
796 | } | |
797 | ||
798 | /* Set the previous number of discarded events. */ | |
799 | ret = set_structure_field_integer(stream->packet_context, | |
800 | "events_discarded", events_discarded); | |
801 | if (ret) { | |
802 | goto end; | |
803 | } | |
804 | ||
273b65be JG |
805 | for (i = 0; i < stream->events->len; i++) { |
806 | struct bt_ctf_event *event = g_ptr_array_index( | |
807 | stream->events, i); | |
273b65be | 808 | |
662e778c | 809 | ret = bt_ctf_field_reset(event->event_header); |
12c8a1a3 JG |
810 | if (ret) { |
811 | goto end; | |
812 | } | |
813 | ||
273b65be | 814 | /* Write event header */ |
662e778c | 815 | ret = bt_ctf_field_serialize(event->event_header, |
273b65be JG |
816 | &stream->pos); |
817 | if (ret) { | |
818 | goto end; | |
819 | } | |
820 | ||
8bfa3f9c JG |
821 | /* Write stream event context */ |
822 | if (stream->event_contexts) { | |
823 | ret = bt_ctf_field_serialize( | |
824 | g_ptr_array_index(stream->event_contexts, i), | |
825 | &stream->pos); | |
826 | if (ret) { | |
827 | goto end; | |
828 | } | |
829 | } | |
830 | ||
273b65be JG |
831 | /* Write event content */ |
832 | ret = bt_ctf_event_serialize(event, &stream->pos); | |
833 | if (ret) { | |
834 | goto end; | |
835 | } | |
836 | } | |
837 | ||
838 | /* | |
839 | * Update the packet total size and content size and overwrite the | |
840 | * packet context. | |
3a092c05 JG |
841 | * Copy base_mma as the packet may have been remapped (e.g. when a |
842 | * packet is resized). | |
273b65be | 843 | */ |
3a092c05 | 844 | packet_context_pos.base_mma = stream->pos.base_mma; |
12c8a1a3 | 845 | ret = set_structure_field_integer(stream->packet_context, |
273b65be JG |
846 | "content_size", stream->pos.offset); |
847 | if (ret) { | |
848 | goto end; | |
849 | } | |
850 | ||
12c8a1a3 | 851 | ret = set_structure_field_integer(stream->packet_context, |
273b65be JG |
852 | "packet_size", stream->pos.packet_size); |
853 | if (ret) { | |
854 | goto end; | |
855 | } | |
856 | ||
12c8a1a3 | 857 | ret = bt_ctf_field_serialize(stream->packet_context, |
273b65be JG |
858 | &packet_context_pos); |
859 | if (ret) { | |
860 | goto end; | |
861 | } | |
862 | ||
863 | g_ptr_array_set_size(stream->events, 0); | |
8bfa3f9c JG |
864 | if (stream->event_contexts) { |
865 | g_ptr_array_set_size(stream->event_contexts, 0); | |
866 | } | |
273b65be JG |
867 | stream->flushed_packet_count++; |
868 | end: | |
83509119 | 869 | bt_put(integer); |
273b65be JG |
870 | return ret; |
871 | } | |
872 | ||
873 | void bt_ctf_stream_get(struct bt_ctf_stream *stream) | |
874 | { | |
83509119 | 875 | bt_get(stream); |
273b65be JG |
876 | } |
877 | ||
878 | void bt_ctf_stream_put(struct bt_ctf_stream *stream) | |
879 | { | |
83509119 | 880 | bt_put(stream); |
273b65be JG |
881 | } |
882 | ||
883 | static | |
83509119 | 884 | void bt_ctf_stream_destroy(struct bt_object *obj) |
273b65be JG |
885 | { |
886 | struct bt_ctf_stream *stream; | |
273b65be | 887 | |
83509119 | 888 | stream = container_of(obj, struct bt_ctf_stream, base); |
273b65be | 889 | ctf_fini_pos(&stream->pos); |
0e45d308 | 890 | if (stream->pos.fd >= 0 && close(stream->pos.fd)) { |
9f56e450 JG |
891 | perror("close"); |
892 | } | |
12c8a1a3 | 893 | |
83509119 | 894 | bt_put(stream->stream_class); |
12c8a1a3 JG |
895 | if (stream->events) { |
896 | g_ptr_array_free(stream->events, TRUE); | |
897 | } | |
8bfa3f9c JG |
898 | if (stream->event_contexts) { |
899 | g_ptr_array_free(stream->event_contexts, TRUE); | |
900 | } | |
83509119 JG |
901 | bt_put(stream->packet_header); |
902 | bt_put(stream->packet_context); | |
903 | bt_put(stream->event_context); | |
273b65be JG |
904 | g_free(stream); |
905 | } | |
906 | ||
273b65be JG |
907 | static |
908 | int set_structure_field_integer(struct bt_ctf_field *structure, char *name, | |
909 | uint64_t value) | |
910 | { | |
911 | int ret = 0; | |
d7b1ea66 | 912 | struct bt_ctf_field_type *field_type = NULL; |
273b65be JG |
913 | struct bt_ctf_field *integer = |
914 | bt_ctf_field_structure_get_field(structure, name); | |
12c8a1a3 JG |
915 | |
916 | if (!structure || !name) { | |
273b65be JG |
917 | ret = -1; |
918 | goto end; | |
919 | } | |
920 | ||
12c8a1a3 JG |
921 | if (!integer) { |
922 | /* Field not found, not an error. */ | |
923 | goto end; | |
924 | } | |
925 | ||
926 | /* Make sure the payload has not already been set. */ | |
927 | if (!bt_ctf_field_validate(integer)) { | |
928 | /* Payload already set, not an error */ | |
929 | goto end; | |
930 | } | |
931 | ||
d7b1ea66 JG |
932 | field_type = bt_ctf_field_get_type(integer); |
933 | /* Something is serioulsly wrong */ | |
934 | assert(field_type); | |
935 | if (bt_ctf_field_type_get_type_id(field_type) != CTF_TYPE_INTEGER) { | |
936 | /* | |
937 | * The user most likely meant for us to populate this field | |
938 | * automatically. However, we can only do this if the field | |
939 | * is an integer. Return an error. | |
940 | */ | |
941 | ret = -1; | |
942 | goto end; | |
943 | } | |
944 | ||
945 | if (bt_ctf_field_type_integer_get_signed(field_type)) { | |
946 | ret = bt_ctf_field_signed_integer_set_value(integer, | |
947 | (int64_t) value); | |
948 | } else { | |
949 | ret = bt_ctf_field_unsigned_integer_set_value(integer, value); | |
950 | } | |
273b65be | 951 | end: |
83509119 JG |
952 | bt_put(integer); |
953 | bt_put(field_type); | |
273b65be JG |
954 | return ret; |
955 | } |