2 * SPDX-License-Identifier: MIT
4 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
5 * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 * Copyright 2017-2019 Philippe Proulx <pproulx@efficios.com>
8 * The Common Trace Format (CTF) Specification is available at
9 * http://www.efficios.com/ctf
12 #ifndef BABELTRACE_CTFSER_INTERNAL_H
13 #define BABELTRACE_CTFSER_INTERNAL_H
19 #include "compat/mman.h"
20 #include <sys/types.h>
23 #include "common/align.h"
24 #include "compat/endian.h"
25 #include "common/common.h"
26 #include "common/mmap-align.h"
27 #include <babeltrace2/types.h>
28 #include "common/assert.h"
29 #include "common/macros.h"
30 #include "compat/bitfield.h"
34 /* Stream file's descriptor */
37 /* Offset (bytes) of memory map (current packet) in the stream file */
40 /* Offset (bytes) of packet's first byte in the memory map */
41 off_t mmap_base_offset
;
43 /* Current offset (bits) within current packet */
44 uint64_t offset_in_cur_packet_bits
;
46 /* Current packet size (bytes) */
47 uint64_t cur_packet_size_bytes
;
49 /* Previous packet size (bytes) */
50 uint64_t prev_packet_size_bytes
;
52 /* Current stream size (bytes) */
53 uint64_t stream_size_bytes
;
55 /* Memory map base address */
56 struct mmap_align_data
*base_mma
;
58 /* Stream file's path (for debugging) */
61 /* Serializer's log level */
66 * Initializes a CTF serializer.
68 * This function opens the file `path` for writing.
71 int bt_ctfser_init(struct bt_ctfser
*ctfser
, const char *path
,
75 * Finalizes a CTF serializer.
77 * This function truncates the stream file so that there's no extra
78 * padding after the last packet, and then closes the file.
81 int bt_ctfser_fini(struct bt_ctfser
*ctfser
);
86 * All the next writing functions are performed within this new packet.
89 int bt_ctfser_open_packet(struct bt_ctfser
*ctfser
);
92 * Closes the current packet, making its size `packet_size_bytes`.
95 void bt_ctfser_close_current_packet(struct bt_ctfser
*ctfser
,
96 uint64_t packet_size_bytes
);
99 int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser
*ctfser
);
102 uint64_t _bt_ctfser_cur_packet_size_bits(struct bt_ctfser
*ctfser
)
104 return ctfser
->cur_packet_size_bytes
* 8;
108 uint64_t _bt_ctfser_prev_packet_size_bits(struct bt_ctfser
*ctfser
)
110 return ctfser
->prev_packet_size_bytes
* 8;
114 uint64_t _bt_ctfser_offset_bytes(struct bt_ctfser
*ctfser
)
116 return ctfser
->offset_in_cur_packet_bits
/ 8;
120 uint8_t *_bt_ctfser_get_addr(struct bt_ctfser
*ctfser
)
122 /* Only makes sense to get the address after aligning on byte */
123 BT_ASSERT_DBG(ctfser
->offset_in_cur_packet_bits
% 8 == 0);
124 return ((uint8_t *) mmap_align_addr(ctfser
->base_mma
)) +
125 ctfser
->mmap_base_offset
+ _bt_ctfser_offset_bytes(ctfser
);
129 bool _bt_ctfser_has_space_left(struct bt_ctfser
*ctfser
, uint64_t size_bits
)
131 bool has_space_left
= true;
133 if (G_UNLIKELY((ctfser
->offset_in_cur_packet_bits
+ size_bits
>
134 _bt_ctfser_cur_packet_size_bits(ctfser
)))) {
135 has_space_left
= false;
139 if (G_UNLIKELY(size_bits
> UINT64_MAX
- ctfser
->offset_in_cur_packet_bits
)) {
140 has_space_left
= false;
145 return has_space_left
;
149 void _bt_ctfser_incr_offset(struct bt_ctfser
*ctfser
, uint64_t size_bits
)
151 BT_ASSERT_DBG(_bt_ctfser_has_space_left(ctfser
, size_bits
));
152 ctfser
->offset_in_cur_packet_bits
+= size_bits
;
156 * Aligns the current offset within the current packet to
157 * `alignment_bits` bits (power of two, > 0).
160 int bt_ctfser_align_offset_in_current_packet(struct bt_ctfser
*ctfser
,
161 uint64_t alignment_bits
)
164 uint64_t align_size_bits
;
166 BT_ASSERT_DBG(alignment_bits
> 0);
167 align_size_bits
= BT_ALIGN(ctfser
->offset_in_cur_packet_bits
,
168 alignment_bits
) - ctfser
->offset_in_cur_packet_bits
;
170 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, align_size_bits
))) {
171 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
172 if (G_UNLIKELY(ret
)) {
177 _bt_ctfser_incr_offset(ctfser
, align_size_bits
);
184 int _bt_ctfser_write_byte_aligned_unsigned_int_no_align(
185 struct bt_ctfser
*ctfser
, uint64_t value
,
186 unsigned int size_bits
, int byte_order
)
190 /* Reverse byte order? */
191 bool rbo
= byte_order
!= BYTE_ORDER
;
193 BT_ASSERT_DBG(size_bits
% 8 == 0);
194 BT_ASSERT_DBG(_bt_ctfser_has_space_left(ctfser
, size_bits
));
199 uint8_t v
= (uint8_t) value
;
201 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
206 uint16_t v
= (uint16_t) value
;
209 v
= GUINT16_SWAP_LE_BE(v
);
212 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
217 uint32_t v
= (uint32_t) value
;
220 v
= GUINT32_SWAP_LE_BE(v
);
223 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
228 uint64_t v
= (uint64_t) value
;
231 v
= GUINT64_SWAP_LE_BE(v
);
234 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
241 _bt_ctfser_incr_offset(ctfser
, size_bits
);
246 int _bt_ctfser_write_byte_aligned_signed_int_no_align(
247 struct bt_ctfser
*ctfser
, int64_t value
,
248 unsigned int size_bits
, int byte_order
)
252 /* Reverse byte order? */
253 bool rbo
= byte_order
!= BYTE_ORDER
;
255 BT_ASSERT_DBG(size_bits
% 8 == 0);
256 BT_ASSERT_DBG(_bt_ctfser_has_space_left(ctfser
, size_bits
));
261 int8_t v
= (int8_t) value
;
263 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
268 int16_t v
= (int16_t) value
;
271 v
= GUINT16_SWAP_LE_BE(v
);
274 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
279 int32_t v
= (int32_t) value
;
282 v
= GUINT32_SWAP_LE_BE(v
);
285 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
290 int64_t v
= (int64_t) value
;
293 v
= GUINT64_SWAP_LE_BE(v
);
296 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
303 _bt_ctfser_incr_offset(ctfser
, size_bits
);
308 * Writes an unsigned integer known to have a size that is a multiple of
309 * 8 and an alignment that is >= 8 at the current offset within the
313 int bt_ctfser_write_byte_aligned_unsigned_int(struct bt_ctfser
*ctfser
,
314 uint64_t value
, unsigned int alignment_bits
,
315 unsigned int size_bits
, int byte_order
)
319 BT_ASSERT_DBG(alignment_bits
% 8 == 0);
320 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
321 if (G_UNLIKELY(ret
)) {
325 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
326 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
327 if (G_UNLIKELY(ret
)) {
332 ret
= _bt_ctfser_write_byte_aligned_unsigned_int_no_align(ctfser
, value
,
333 size_bits
, byte_order
);
334 if (G_UNLIKELY(ret
)) {
343 * Writes a signed integer known to have a size that is a multiple of 8
344 * and an alignment that is >= 8 at the current offset within the
348 int bt_ctfser_write_byte_aligned_signed_int(struct bt_ctfser
*ctfser
,
349 int64_t value
, unsigned int alignment_bits
,
350 unsigned int size_bits
, int byte_order
)
354 BT_ASSERT_DBG(alignment_bits
% 8 == 0);
355 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
356 if (G_UNLIKELY(ret
)) {
360 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
361 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
362 if (G_UNLIKELY(ret
)) {
367 ret
= _bt_ctfser_write_byte_aligned_signed_int_no_align(ctfser
, value
,
368 size_bits
, byte_order
);
369 if (G_UNLIKELY(ret
)) {
378 * Writes an unsigned integer at the current offset within the current
382 int bt_ctfser_write_unsigned_int(struct bt_ctfser
*ctfser
, uint64_t value
,
383 unsigned int alignment_bits
, unsigned int size_bits
,
388 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
389 if (G_UNLIKELY(ret
)) {
393 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
394 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
395 if (G_UNLIKELY(ret
)) {
400 if (alignment_bits
% 8 == 0 && size_bits
% 8 == 0) {
401 ret
= _bt_ctfser_write_byte_aligned_unsigned_int_no_align(
402 ctfser
, value
, size_bits
, byte_order
);
406 if (byte_order
== LITTLE_ENDIAN
) {
407 bt_bitfield_write_le((uint8_t *) mmap_align_addr(ctfser
->base_mma
) +
408 ctfser
->mmap_base_offset
, uint8_t,
409 ctfser
->offset_in_cur_packet_bits
, size_bits
, value
);
411 bt_bitfield_write_be((uint8_t *) mmap_align_addr(ctfser
->base_mma
) +
412 ctfser
->mmap_base_offset
, uint8_t,
413 ctfser
->offset_in_cur_packet_bits
, size_bits
, value
);
416 _bt_ctfser_incr_offset(ctfser
, size_bits
);
423 * Writes a signed integer at the current offset within the current
427 int bt_ctfser_write_signed_int(struct bt_ctfser
*ctfser
, int64_t value
,
428 unsigned int alignment_bits
, unsigned int size_bits
,
433 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
434 if (G_UNLIKELY(ret
)) {
438 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
439 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
440 if (G_UNLIKELY(ret
)) {
445 if (alignment_bits
% 8 == 0 && size_bits
% 8 == 0) {
446 ret
= _bt_ctfser_write_byte_aligned_signed_int_no_align(
447 ctfser
, value
, size_bits
, byte_order
);
451 if (byte_order
== LITTLE_ENDIAN
) {
452 bt_bitfield_write_le((uint8_t *) mmap_align_addr(ctfser
->base_mma
) +
453 ctfser
->mmap_base_offset
, uint8_t,
454 ctfser
->offset_in_cur_packet_bits
, size_bits
, value
);
456 bt_bitfield_write_be((uint8_t *) mmap_align_addr(ctfser
->base_mma
) +
457 ctfser
->mmap_base_offset
, uint8_t,
458 ctfser
->offset_in_cur_packet_bits
, size_bits
, value
);
461 _bt_ctfser_incr_offset(ctfser
, size_bits
);
468 * Writes a 32-bit floating point number at the current offset within
469 * the current packet.
472 int bt_ctfser_write_float32(struct bt_ctfser
*ctfser
, double value
,
473 unsigned int alignment_bits
, int byte_order
)
480 u32f
.f
= (float) value
;
481 return bt_ctfser_write_unsigned_int(ctfser
, (uint64_t) u32f
.u
,
482 alignment_bits
, 32, byte_order
);
486 * Writes a 64-bit floating point number at the current offset within
487 * the current packet.
490 int bt_ctfser_write_float64(struct bt_ctfser
*ctfser
, double value
,
491 unsigned int alignment_bits
, int byte_order
)
499 return bt_ctfser_write_unsigned_int(ctfser
, u64f
.u
, alignment_bits
,
504 * Writes a C string, including the terminating null character, at the
505 * current offset within the current packet.
508 int bt_ctfser_write_string(struct bt_ctfser
*ctfser
, const char *value
)
511 const char *at
= value
;
513 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, 8);
514 if (G_UNLIKELY(ret
)) {
519 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, 8))) {
520 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
521 if (G_UNLIKELY(ret
)) {
526 memcpy(_bt_ctfser_get_addr(ctfser
), at
, sizeof(*at
));
527 _bt_ctfser_incr_offset(ctfser
, 8);
529 if (G_UNLIKELY(*at
== '\0')) {
541 * Returns the current offset within the current packet (bits).
544 uint64_t bt_ctfser_get_offset_in_current_packet_bits(struct bt_ctfser
*ctfser
)
546 return ctfser
->offset_in_cur_packet_bits
;
550 * Sets the current offset within the current packet (bits).
553 void bt_ctfser_set_offset_in_current_packet_bits(struct bt_ctfser
*ctfser
,
554 uint64_t offset_bits
)
556 BT_ASSERT_DBG(offset_bits
<= _bt_ctfser_cur_packet_size_bits(ctfser
));
557 ctfser
->offset_in_cur_packet_bits
= offset_bits
;
561 const char *bt_ctfser_get_file_path(struct bt_ctfser
*ctfser
)
563 return ctfser
->path
->str
;
566 #endif /* BABELTRACE_CTFSER_INTERNAL_H */