Fix: bt_ctfser_write_float64(): use `double` in union, not `float`
[babeltrace.git] / src / ctfser / ctfser.h
CommitLineData
013f35c6
PP
1#ifndef BABELTRACE_CTFSER_INTERNAL_H
2#define BABELTRACE_CTFSER_INTERNAL_H
3
4/*
5 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
6 * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 * Copyright 2017-2019 Philippe Proulx <pproulx@efficios.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * The Common Trace Format (CTF) Specification is available at
28 * http://www.efficios.com/ctf
29 */
30
31#include <stdlib.h>
32#include <stdint.h>
33#include <limits.h>
578e048b 34#include "compat/mman.h"
013f35c6
PP
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
578e048b
MJ
38#include "common/align.h"
39#include "compat/endian.h"
40#include "common/common.h"
41#include "common/mmap-align.h"
3fadfbc0 42#include <babeltrace2/types.h>
578e048b 43#include "common/assert.h"
91d81473 44#include "common/macros.h"
578e048b 45#include "compat/bitfield.h"
013f35c6
PP
46#include <glib.h>
47
48struct bt_ctfser {
49 /* Stream file's descriptor */
50 int fd;
51
52 /* Offset (bytes) of memory map (current packet) in the stream file */
53 off_t mmap_offset;
54
55 /* Offset (bytes) of packet's first byte in the memory map */
56 off_t mmap_base_offset;
57
58 /* Current offset (bits) within current packet */
59 uint64_t offset_in_cur_packet_bits;
60
61 /* Current packet size (bytes) */
62 uint64_t cur_packet_size_bytes;
63
64 /* Previous packet size (bytes) */
65 uint64_t prev_packet_size_bytes;
66
67 /* Current stream size (bytes) */
68 uint64_t stream_size_bytes;
69
70 /* Memory map base address */
71 struct mmap_align *base_mma;
72
73 /* Stream file's path (for debugging) */
74 GString *path;
86d8b7b8
PP
75
76 /* Serializer's log level */
77 int log_level;
013f35c6
PP
78};
79
013f35c6
PP
80/*
81 * Initializes a CTF serializer.
82 *
83 * This function opens the file `path` for writing.
84 */
85BT_HIDDEN
86d8b7b8
PP
86int bt_ctfser_init(struct bt_ctfser *ctfser, const char *path,
87 int log_level);
013f35c6
PP
88
89/*
90 * Finalizes a CTF serializer.
91 *
92 * This function truncates the stream file so that there's no extra
93 * padding after the last packet, and then closes the file.
94 */
95BT_HIDDEN
96int bt_ctfser_fini(struct bt_ctfser *ctfser);
97
98/*
99 * Opens a new packet.
100 *
101 * All the next writing functions are performed within this new packet.
102 */
103BT_HIDDEN
104int bt_ctfser_open_packet(struct bt_ctfser *ctfser);
105
106/*
107 * Closes the current packet, making its size `packet_size_bytes`.
108 */
109BT_HIDDEN
110void bt_ctfser_close_current_packet(struct bt_ctfser *ctfser,
111 uint64_t packet_size_bytes);
112
113BT_HIDDEN
114int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser *ctfser);
115
116static inline
117uint64_t _bt_ctfser_cur_packet_size_bits(struct bt_ctfser *ctfser)
118{
119 return ctfser->cur_packet_size_bytes * 8;
120}
121
122static inline
123uint64_t _bt_ctfser_prev_packet_size_bits(struct bt_ctfser *ctfser)
124{
125 return ctfser->prev_packet_size_bytes * 8;
126}
127
128static inline
129uint64_t _bt_ctfser_offset_bytes(struct bt_ctfser *ctfser)
130{
131 return ctfser->offset_in_cur_packet_bits / 8;
132}
133
134static inline
135uint8_t *_bt_ctfser_get_addr(struct bt_ctfser *ctfser)
136{
137 /* Only makes sense to get the address after aligning on byte */
138 BT_ASSERT(ctfser->offset_in_cur_packet_bits % 8 == 0);
139 return ((uint8_t *) mmap_align_addr(ctfser->base_mma)) +
140 ctfser->mmap_base_offset + _bt_ctfser_offset_bytes(ctfser);
141}
142
143static inline
144bool _bt_ctfser_has_space_left(struct bt_ctfser *ctfser, uint64_t size_bits)
145{
146 bool has_space_left = true;
147
91d81473 148 if (G_UNLIKELY((ctfser->offset_in_cur_packet_bits + size_bits >
013f35c6
PP
149 _bt_ctfser_cur_packet_size_bits(ctfser)))) {
150 has_space_left = false;
151 goto end;
152 }
153
91d81473 154 if (G_UNLIKELY(size_bits > UINT64_MAX - ctfser->offset_in_cur_packet_bits)) {
013f35c6
PP
155 has_space_left = false;
156 goto end;
157 }
158
159end:
160 return has_space_left;
161}
162
163static inline
164void _bt_ctfser_incr_offset(struct bt_ctfser *ctfser, uint64_t size_bits)
165{
166 BT_ASSERT(_bt_ctfser_has_space_left(ctfser, size_bits));
167 ctfser->offset_in_cur_packet_bits += size_bits;
168}
169
170/*
171 * Aligns the current offset within the current packet to
172 * `alignment_bits` bits (power of two, > 0).
173 */
174static inline
175int bt_ctfser_align_offset_in_current_packet(struct bt_ctfser *ctfser,
176 uint64_t alignment_bits)
177{
178 int ret = 0;
179 uint64_t align_size_bits;
180
181 BT_ASSERT(alignment_bits > 0);
182 align_size_bits = ALIGN(ctfser->offset_in_cur_packet_bits,
183 alignment_bits) - ctfser->offset_in_cur_packet_bits;
184
91d81473 185 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser, align_size_bits))) {
013f35c6 186 ret = _bt_ctfser_increase_cur_packet_size(ctfser);
91d81473 187 if (G_UNLIKELY(ret)) {
013f35c6
PP
188 goto end;
189 }
190 }
191
192 _bt_ctfser_incr_offset(ctfser, align_size_bits);
193
194end:
195 return ret;
196}
197
198static inline
d6981059
PP
199int _bt_ctfser_write_byte_aligned_unsigned_int_no_align(
200 struct bt_ctfser *ctfser, uint64_t value,
201 unsigned int size_bits, int byte_order)
013f35c6
PP
202{
203 int ret = 0;
204
205 /* Reverse byte order? */
206 bool rbo = byte_order != BYTE_ORDER;
207
208 BT_ASSERT(size_bits % 8 == 0);
209 BT_ASSERT(_bt_ctfser_has_space_left(ctfser, size_bits));
210
d6981059
PP
211 switch (size_bits) {
212 case 8:
213 {
214 uint8_t v = (uint8_t) value;
215
216 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
217 break;
218 }
219 case 16:
220 {
221 uint16_t v = (uint16_t) value;
013f35c6 222
d6981059
PP
223 if (rbo) {
224 v = GUINT16_SWAP_LE_BE(v);
013f35c6 225 }
013f35c6 226
d6981059
PP
227 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
228 break;
229 }
230 case 32:
231 {
232 uint32_t v = (uint32_t) value;
013f35c6 233
d6981059
PP
234 if (rbo) {
235 v = GUINT32_SWAP_LE_BE(v);
013f35c6 236 }
013f35c6 237
d6981059
PP
238 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
239 break;
240 }
241 case 64:
242 {
243 uint64_t v = (uint64_t) value;
013f35c6 244
d6981059
PP
245 if (rbo) {
246 v = GUINT64_SWAP_LE_BE(v);
013f35c6 247 }
013f35c6 248
d6981059
PP
249 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
250 break;
251 }
252 default:
253 abort();
254 }
013f35c6 255
d6981059
PP
256 _bt_ctfser_incr_offset(ctfser, size_bits);
257 return ret;
258}
013f35c6 259
d6981059
PP
260static inline
261int _bt_ctfser_write_byte_aligned_signed_int_no_align(
262 struct bt_ctfser *ctfser, int64_t value,
263 unsigned int size_bits, int byte_order)
264{
265 int ret = 0;
013f35c6 266
d6981059
PP
267 /* Reverse byte order? */
268 bool rbo = byte_order != BYTE_ORDER;
013f35c6 269
d6981059
PP
270 BT_ASSERT(size_bits % 8 == 0);
271 BT_ASSERT(_bt_ctfser_has_space_left(ctfser, size_bits));
013f35c6 272
d6981059
PP
273 switch (size_bits) {
274 case 8:
275 {
276 int8_t v = (int8_t) value;
013f35c6 277
d6981059
PP
278 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
279 break;
280 }
281 case 16:
282 {
283 int16_t v = (int16_t) value;
284
285 if (rbo) {
286 v = GUINT16_SWAP_LE_BE(v);
013f35c6 287 }
013f35c6 288
d6981059
PP
289 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
290 break;
291 }
292 case 32:
293 {
294 int32_t v = (int32_t) value;
013f35c6 295
d6981059
PP
296 if (rbo) {
297 v = GUINT32_SWAP_LE_BE(v);
013f35c6 298 }
d6981059
PP
299
300 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
301 break;
302 }
303 case 64:
304 {
305 int64_t v = (int64_t) value;
306
307 if (rbo) {
308 v = GUINT64_SWAP_LE_BE(v);
013f35c6 309 }
d6981059
PP
310
311 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
312 break;
313 }
314 default:
315 abort();
013f35c6
PP
316 }
317
318 _bt_ctfser_incr_offset(ctfser, size_bits);
319 return ret;
320}
321
322/*
d6981059
PP
323 * Writes an unsigned integer known to have a size that is a multiple of
324 * 8 and an alignment that is >= 8 at the current offset within the
325 * current packet.
013f35c6
PP
326 */
327static inline
d6981059
PP
328int bt_ctfser_write_byte_aligned_unsigned_int(struct bt_ctfser *ctfser,
329 uint64_t value, unsigned int alignment_bits,
330 unsigned int size_bits, int byte_order)
013f35c6
PP
331{
332 int ret;
333
334 BT_ASSERT(alignment_bits % 8 == 0);
335 ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
91d81473 336 if (G_UNLIKELY(ret)) {
013f35c6
PP
337 goto end;
338 }
339
91d81473 340 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
013f35c6 341 ret = _bt_ctfser_increase_cur_packet_size(ctfser);
91d81473 342 if (G_UNLIKELY(ret)) {
013f35c6
PP
343 goto end;
344 }
345 }
346
d6981059
PP
347 ret = _bt_ctfser_write_byte_aligned_unsigned_int_no_align(ctfser, value,
348 size_bits, byte_order);
91d81473 349 if (G_UNLIKELY(ret)) {
013f35c6
PP
350 goto end;
351 }
352
353end:
354 return ret;
355}
356
357/*
d6981059
PP
358 * Writes a signed integer known to have a size that is a multiple of 8
359 * and an alignment that is >= 8 at the current offset within the
360 * current packet.
013f35c6
PP
361 */
362static inline
d6981059
PP
363int bt_ctfser_write_byte_aligned_signed_int(struct bt_ctfser *ctfser,
364 int64_t value, unsigned int alignment_bits,
365 unsigned int size_bits, int byte_order)
366{
367 int ret;
368
369 BT_ASSERT(alignment_bits % 8 == 0);
370 ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
91d81473 371 if (G_UNLIKELY(ret)) {
d6981059
PP
372 goto end;
373 }
374
91d81473 375 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
d6981059 376 ret = _bt_ctfser_increase_cur_packet_size(ctfser);
91d81473 377 if (G_UNLIKELY(ret)) {
d6981059
PP
378 goto end;
379 }
380 }
381
382 ret = _bt_ctfser_write_byte_aligned_signed_int_no_align(ctfser, value,
383 size_bits, byte_order);
91d81473 384 if (G_UNLIKELY(ret)) {
d6981059
PP
385 goto end;
386 }
387
388end:
389 return ret;
390}
391
392/*
393 * Writes an unsigned integer at the current offset within the current
394 * packet.
395 */
396static inline
397int bt_ctfser_write_unsigned_int(struct bt_ctfser *ctfser, uint64_t value,
398 unsigned int alignment_bits, unsigned int size_bits,
013f35c6
PP
399 int byte_order)
400{
401 int ret = 0;
402
403 ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
91d81473 404 if (G_UNLIKELY(ret)) {
013f35c6
PP
405 goto end;
406 }
407
91d81473 408 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
013f35c6 409 ret = _bt_ctfser_increase_cur_packet_size(ctfser);
91d81473 410 if (G_UNLIKELY(ret)) {
013f35c6
PP
411 goto end;
412 }
413 }
414
415 if (alignment_bits % 8 == 0 && size_bits % 8 == 0) {
d6981059
PP
416 ret = _bt_ctfser_write_byte_aligned_unsigned_int_no_align(
417 ctfser, value, size_bits, byte_order);
013f35c6
PP
418 goto end;
419 }
420
d6981059
PP
421 if (byte_order == LITTLE_ENDIAN) {
422 bt_bitfield_write_le(mmap_align_addr(ctfser->base_mma) +
423 ctfser->mmap_base_offset, uint8_t,
424 ctfser->offset_in_cur_packet_bits, size_bits, value);
013f35c6 425 } else {
d6981059
PP
426 bt_bitfield_write_be(mmap_align_addr(ctfser->base_mma) +
427 ctfser->mmap_base_offset, uint8_t,
428 ctfser->offset_in_cur_packet_bits, size_bits, value);
429 }
430
431 _bt_ctfser_incr_offset(ctfser, size_bits);
432
433end:
434 return ret;
435}
436
437/*
438 * Writes a signed integer at the current offset within the current
439 * packet.
440 */
441static inline
442int bt_ctfser_write_signed_int(struct bt_ctfser *ctfser, int64_t value,
443 unsigned int alignment_bits, unsigned int size_bits,
444 int byte_order)
445{
446 int ret = 0;
447
448 ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
91d81473 449 if (G_UNLIKELY(ret)) {
d6981059
PP
450 goto end;
451 }
452
91d81473 453 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
d6981059 454 ret = _bt_ctfser_increase_cur_packet_size(ctfser);
91d81473 455 if (G_UNLIKELY(ret)) {
d6981059 456 goto end;
013f35c6
PP
457 }
458 }
459
d6981059
PP
460 if (alignment_bits % 8 == 0 && size_bits % 8 == 0) {
461 ret = _bt_ctfser_write_byte_aligned_signed_int_no_align(
462 ctfser, value, size_bits, byte_order);
463 goto end;
464 }
465
466 if (byte_order == LITTLE_ENDIAN) {
467 bt_bitfield_write_le(mmap_align_addr(ctfser->base_mma) +
468 ctfser->mmap_base_offset, uint8_t,
469 ctfser->offset_in_cur_packet_bits, size_bits, value);
470 } else {
471 bt_bitfield_write_be(mmap_align_addr(ctfser->base_mma) +
472 ctfser->mmap_base_offset, uint8_t,
473 ctfser->offset_in_cur_packet_bits, size_bits, value);
474 }
475
013f35c6
PP
476 _bt_ctfser_incr_offset(ctfser, size_bits);
477
478end:
479 return ret;
480}
481
482/*
483 * Writes a 32-bit floating point number at the current offset within
484 * the current packet.
485 */
486static inline
487int bt_ctfser_write_float32(struct bt_ctfser *ctfser, double value,
488 unsigned int alignment_bits, int byte_order)
489{
013f35c6
PP
490 union u32f {
491 uint32_t u;
492 float f;
493 } u32f;
494
495 u32f.f = (float) value;
d6981059
PP
496 return bt_ctfser_write_unsigned_int(ctfser, (uint64_t) u32f.u,
497 alignment_bits, 32, byte_order);
013f35c6
PP
498}
499
500/*
501 * Writes a 64-bit floating point number at the current offset within
502 * the current packet.
503 */
504static inline
505int bt_ctfser_write_float64(struct bt_ctfser *ctfser, double value,
506 unsigned int alignment_bits, int byte_order)
507{
013f35c6
PP
508 union u64f {
509 uint64_t u;
1fba7c7b 510 double d;
013f35c6
PP
511 } u64f;
512
1fba7c7b 513 u64f.d = value;
d6981059
PP
514 return bt_ctfser_write_unsigned_int(ctfser, u64f.u, alignment_bits,
515 64, byte_order);
013f35c6
PP
516}
517
518/*
519 * Writes a C string, including the terminating null character, at the
520 * current offset within the current packet.
521 */
522static inline
523int bt_ctfser_write_string(struct bt_ctfser *ctfser, const char *value)
524{
525 int ret = 0;
526 const char *at = value;
527
528 ret = bt_ctfser_align_offset_in_current_packet(ctfser, 8);
91d81473 529 if (G_UNLIKELY(ret)) {
013f35c6
PP
530 goto end;
531 }
532
533 while (true) {
91d81473 534 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser, 8))) {
013f35c6 535 ret = _bt_ctfser_increase_cur_packet_size(ctfser);
91d81473 536 if (G_UNLIKELY(ret)) {
013f35c6
PP
537 goto end;
538 }
539 }
540
541 memcpy(_bt_ctfser_get_addr(ctfser), at, sizeof(*at));
542 _bt_ctfser_incr_offset(ctfser, 8);
543
91d81473 544 if (G_UNLIKELY(*at == '\0')) {
013f35c6
PP
545 break;
546 }
547
548 at++;
549 }
550
551end:
552 return ret;
553}
554
555/*
556 * Returns the current offset within the current packet (bits).
557 */
558static inline
559uint64_t bt_ctfser_get_offset_in_current_packet_bits(struct bt_ctfser *ctfser)
560{
561 return ctfser->offset_in_cur_packet_bits;
562}
563
564/*
565 * Sets the current offset within the current packet (bits).
566 */
567static inline
568void bt_ctfser_set_offset_in_current_packet_bits(struct bt_ctfser *ctfser,
569 uint64_t offset_bits)
570{
571 BT_ASSERT(offset_bits <= _bt_ctfser_cur_packet_size_bits(ctfser));
572 ctfser->offset_in_cur_packet_bits = offset_bits;
573}
574
15fe47e0
PP
575static inline
576const char *bt_ctfser_get_file_path(struct bt_ctfser *ctfser)
577{
578 return ctfser->path->str;
579}
580
013f35c6 581#endif /* BABELTRACE_CTFSER_INTERNAL_H */
This page took 0.063723 seconds and 4 git commands to generate.