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 "common/assert.h"
28 #include "common/macros.h"
29 #include "compat/bitfield.h"
33 /* Stream file's descriptor */
36 /* Offset (bytes) of memory map (current packet) in the stream file */
39 /* Offset (bytes) of packet's first byte in the memory map */
40 off_t mmap_base_offset
;
42 /* Current offset (bits) within current packet */
43 uint64_t offset_in_cur_packet_bits
;
45 /* Current packet size (bytes) */
46 uint64_t cur_packet_size_bytes
;
48 /* Previous packet size (bytes) */
49 uint64_t prev_packet_size_bytes
;
51 /* Current stream size (bytes) */
52 uint64_t stream_size_bytes
;
54 /* Memory map base address */
55 struct mmap_align_data
*base_mma
;
57 /* Stream file's path (for debugging) */
60 /* Serializer's log level */
65 * Initializes a CTF serializer.
67 * This function opens the file `path` for writing.
70 int bt_ctfser_init(struct bt_ctfser
*ctfser
, const char *path
,
74 * Finalizes a CTF serializer.
76 * This function truncates the stream file so that there's no extra
77 * padding after the last packet, and then closes the file.
80 int bt_ctfser_fini(struct bt_ctfser
*ctfser
);
85 * All the next writing functions are performed within this new packet.
88 int bt_ctfser_open_packet(struct bt_ctfser
*ctfser
);
91 * Closes the current packet, making its size `packet_size_bytes`.
94 void bt_ctfser_close_current_packet(struct bt_ctfser
*ctfser
,
95 uint64_t packet_size_bytes
);
98 int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser
*ctfser
);
101 uint64_t _bt_ctfser_cur_packet_size_bits(struct bt_ctfser
*ctfser
)
103 return ctfser
->cur_packet_size_bytes
* 8;
107 uint64_t _bt_ctfser_prev_packet_size_bits(struct bt_ctfser
*ctfser
)
109 return ctfser
->prev_packet_size_bytes
* 8;
113 uint64_t _bt_ctfser_offset_bytes(struct bt_ctfser
*ctfser
)
115 return ctfser
->offset_in_cur_packet_bits
/ 8;
119 uint8_t *_bt_ctfser_get_addr(struct bt_ctfser
*ctfser
)
121 /* Only makes sense to get the address after aligning on byte */
122 BT_ASSERT_DBG(ctfser
->offset_in_cur_packet_bits
% 8 == 0);
123 return ((uint8_t *) mmap_align_addr(ctfser
->base_mma
)) +
124 ctfser
->mmap_base_offset
+ _bt_ctfser_offset_bytes(ctfser
);
128 bool _bt_ctfser_has_space_left(struct bt_ctfser
*ctfser
, uint64_t size_bits
)
130 bool has_space_left
= true;
132 if (G_UNLIKELY((ctfser
->offset_in_cur_packet_bits
+ size_bits
>
133 _bt_ctfser_cur_packet_size_bits(ctfser
)))) {
134 has_space_left
= false;
138 if (G_UNLIKELY(size_bits
> UINT64_MAX
- ctfser
->offset_in_cur_packet_bits
)) {
139 has_space_left
= false;
144 return has_space_left
;
148 void _bt_ctfser_incr_offset(struct bt_ctfser
*ctfser
, uint64_t size_bits
)
150 BT_ASSERT_DBG(_bt_ctfser_has_space_left(ctfser
, size_bits
));
151 ctfser
->offset_in_cur_packet_bits
+= size_bits
;
155 * Aligns the current offset within the current packet to
156 * `alignment_bits` bits (power of two, > 0).
159 int bt_ctfser_align_offset_in_current_packet(struct bt_ctfser
*ctfser
,
160 uint64_t alignment_bits
)
163 uint64_t align_size_bits
;
165 BT_ASSERT_DBG(alignment_bits
> 0);
166 align_size_bits
= BT_ALIGN(ctfser
->offset_in_cur_packet_bits
,
167 alignment_bits
) - ctfser
->offset_in_cur_packet_bits
;
169 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, align_size_bits
))) {
170 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
171 if (G_UNLIKELY(ret
)) {
176 _bt_ctfser_incr_offset(ctfser
, align_size_bits
);
183 int _bt_ctfser_write_byte_aligned_unsigned_int_no_align(
184 struct bt_ctfser
*ctfser
, uint64_t value
,
185 unsigned int size_bits
, int byte_order
)
189 /* Reverse byte order? */
190 bool rbo
= byte_order
!= BYTE_ORDER
;
192 BT_ASSERT_DBG(size_bits
% 8 == 0);
193 BT_ASSERT_DBG(_bt_ctfser_has_space_left(ctfser
, size_bits
));
198 uint8_t v
= (uint8_t) value
;
200 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
205 uint16_t v
= (uint16_t) value
;
208 v
= GUINT16_SWAP_LE_BE(v
);
211 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
216 uint32_t v
= (uint32_t) value
;
219 v
= GUINT32_SWAP_LE_BE(v
);
222 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
227 uint64_t v
= (uint64_t) value
;
230 v
= GUINT64_SWAP_LE_BE(v
);
233 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
240 _bt_ctfser_incr_offset(ctfser
, size_bits
);
245 int _bt_ctfser_write_byte_aligned_signed_int_no_align(
246 struct bt_ctfser
*ctfser
, int64_t value
,
247 unsigned int size_bits
, int byte_order
)
251 /* Reverse byte order? */
252 bool rbo
= byte_order
!= BYTE_ORDER
;
254 BT_ASSERT_DBG(size_bits
% 8 == 0);
255 BT_ASSERT_DBG(_bt_ctfser_has_space_left(ctfser
, size_bits
));
260 int8_t v
= (int8_t) value
;
262 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
267 int16_t v
= (int16_t) value
;
270 v
= GUINT16_SWAP_LE_BE(v
);
273 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
278 int32_t v
= (int32_t) value
;
281 v
= GUINT32_SWAP_LE_BE(v
);
284 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
289 int64_t v
= (int64_t) value
;
292 v
= GUINT64_SWAP_LE_BE(v
);
295 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
302 _bt_ctfser_incr_offset(ctfser
, size_bits
);
307 * Writes an unsigned integer known to have a size that is a multiple of
308 * 8 and an alignment that is >= 8 at the current offset within the
312 int bt_ctfser_write_byte_aligned_unsigned_int(struct bt_ctfser
*ctfser
,
313 uint64_t value
, unsigned int alignment_bits
,
314 unsigned int size_bits
, int byte_order
)
318 BT_ASSERT_DBG(alignment_bits
% 8 == 0);
319 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
320 if (G_UNLIKELY(ret
)) {
324 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
325 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
326 if (G_UNLIKELY(ret
)) {
331 ret
= _bt_ctfser_write_byte_aligned_unsigned_int_no_align(ctfser
, value
,
332 size_bits
, byte_order
);
333 if (G_UNLIKELY(ret
)) {
342 * Writes a signed integer known to have a size that is a multiple of 8
343 * and an alignment that is >= 8 at the current offset within the
347 int bt_ctfser_write_byte_aligned_signed_int(struct bt_ctfser
*ctfser
,
348 int64_t value
, unsigned int alignment_bits
,
349 unsigned int size_bits
, int byte_order
)
353 BT_ASSERT_DBG(alignment_bits
% 8 == 0);
354 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
355 if (G_UNLIKELY(ret
)) {
359 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
360 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
361 if (G_UNLIKELY(ret
)) {
366 ret
= _bt_ctfser_write_byte_aligned_signed_int_no_align(ctfser
, value
,
367 size_bits
, byte_order
);
368 if (G_UNLIKELY(ret
)) {
377 * Writes an unsigned integer at the current offset within the current
381 int bt_ctfser_write_unsigned_int(struct bt_ctfser
*ctfser
, uint64_t value
,
382 unsigned int alignment_bits
, unsigned int size_bits
,
387 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
388 if (G_UNLIKELY(ret
)) {
392 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
393 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
394 if (G_UNLIKELY(ret
)) {
399 if (alignment_bits
% 8 == 0 && size_bits
% 8 == 0) {
400 ret
= _bt_ctfser_write_byte_aligned_unsigned_int_no_align(
401 ctfser
, value
, size_bits
, byte_order
);
405 if (byte_order
== LITTLE_ENDIAN
) {
406 bt_bitfield_write_le((uint8_t *) mmap_align_addr(ctfser
->base_mma
) +
407 ctfser
->mmap_base_offset
, uint8_t,
408 ctfser
->offset_in_cur_packet_bits
, size_bits
, value
);
410 bt_bitfield_write_be((uint8_t *) mmap_align_addr(ctfser
->base_mma
) +
411 ctfser
->mmap_base_offset
, uint8_t,
412 ctfser
->offset_in_cur_packet_bits
, size_bits
, value
);
415 _bt_ctfser_incr_offset(ctfser
, size_bits
);
422 * Writes a signed integer at the current offset within the current
426 int bt_ctfser_write_signed_int(struct bt_ctfser
*ctfser
, int64_t value
,
427 unsigned int alignment_bits
, unsigned int size_bits
,
432 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
433 if (G_UNLIKELY(ret
)) {
437 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
438 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
439 if (G_UNLIKELY(ret
)) {
444 if (alignment_bits
% 8 == 0 && size_bits
% 8 == 0) {
445 ret
= _bt_ctfser_write_byte_aligned_signed_int_no_align(
446 ctfser
, value
, size_bits
, byte_order
);
450 if (byte_order
== LITTLE_ENDIAN
) {
451 bt_bitfield_write_le((uint8_t *) mmap_align_addr(ctfser
->base_mma
) +
452 ctfser
->mmap_base_offset
, uint8_t,
453 ctfser
->offset_in_cur_packet_bits
, size_bits
, value
);
455 bt_bitfield_write_be((uint8_t *) mmap_align_addr(ctfser
->base_mma
) +
456 ctfser
->mmap_base_offset
, uint8_t,
457 ctfser
->offset_in_cur_packet_bits
, size_bits
, value
);
460 _bt_ctfser_incr_offset(ctfser
, size_bits
);
467 * Writes a 32-bit floating point number at the current offset within
468 * the current packet.
471 int bt_ctfser_write_float32(struct bt_ctfser
*ctfser
, double value
,
472 unsigned int alignment_bits
, int byte_order
)
479 u32f
.f
= (float) value
;
480 return bt_ctfser_write_unsigned_int(ctfser
, (uint64_t) u32f
.u
,
481 alignment_bits
, 32, byte_order
);
485 * Writes a 64-bit floating point number at the current offset within
486 * the current packet.
489 int bt_ctfser_write_float64(struct bt_ctfser
*ctfser
, double value
,
490 unsigned int alignment_bits
, int byte_order
)
498 return bt_ctfser_write_unsigned_int(ctfser
, u64f
.u
, alignment_bits
,
503 * Writes a C string, including the terminating null character, at the
504 * current offset within the current packet.
507 int bt_ctfser_write_string(struct bt_ctfser
*ctfser
, const char *value
)
510 const char *at
= value
;
512 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, 8);
513 if (G_UNLIKELY(ret
)) {
518 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, 8))) {
519 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
520 if (G_UNLIKELY(ret
)) {
525 memcpy(_bt_ctfser_get_addr(ctfser
), at
, sizeof(*at
));
526 _bt_ctfser_incr_offset(ctfser
, 8);
528 if (G_UNLIKELY(*at
== '\0')) {
540 * Returns the current offset within the current packet (bits).
543 uint64_t bt_ctfser_get_offset_in_current_packet_bits(struct bt_ctfser
*ctfser
)
545 return ctfser
->offset_in_cur_packet_bits
;
549 * Sets the current offset within the current packet (bits).
552 void bt_ctfser_set_offset_in_current_packet_bits(struct bt_ctfser
*ctfser
,
553 uint64_t offset_bits
)
555 BT_ASSERT_DBG(offset_bits
<= _bt_ctfser_cur_packet_size_bits(ctfser
));
556 ctfser
->offset_in_cur_packet_bits
= offset_bits
;
560 const char *bt_ctfser_get_file_path(struct bt_ctfser
*ctfser
)
562 return ctfser
->path
->str
;
565 #endif /* BABELTRACE_CTFSER_INTERNAL_H */