1 #ifndef BABELTRACE_CTFSER_INTERNAL_H
2 #define BABELTRACE_CTFSER_INTERNAL_H
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>
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:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
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
27 * The Common Trace Format (CTF) Specification is available at
28 * http://www.efficios.com/ctf
34 #include "compat/mman.h"
35 #include <sys/types.h>
38 #include "common/align.h"
39 #include "compat/endian.h"
40 #include "common/common.h"
41 #include "common/mmap-align.h"
42 #include <babeltrace2/types.h>
43 #include "common/assert.h"
44 #include "common/macros.h"
45 #include "compat/bitfield.h"
49 /* Stream file's descriptor */
52 /* Offset (bytes) of memory map (current packet) in the stream file */
55 /* Offset (bytes) of packet's first byte in the memory map */
56 off_t mmap_base_offset
;
58 /* Current offset (bits) within current packet */
59 uint64_t offset_in_cur_packet_bits
;
61 /* Current packet size (bytes) */
62 uint64_t cur_packet_size_bytes
;
64 /* Previous packet size (bytes) */
65 uint64_t prev_packet_size_bytes
;
67 /* Current stream size (bytes) */
68 uint64_t stream_size_bytes
;
70 /* Memory map base address */
71 struct mmap_align
*base_mma
;
73 /* Stream file's path (for debugging) */
78 * Initializes a CTF serializer.
80 * This function opens the file `path` for writing.
83 int bt_ctfser_init(struct bt_ctfser
*ctfser
, const char *path
);
86 * Finalizes a CTF serializer.
88 * This function truncates the stream file so that there's no extra
89 * padding after the last packet, and then closes the file.
92 int bt_ctfser_fini(struct bt_ctfser
*ctfser
);
97 * All the next writing functions are performed within this new packet.
100 int bt_ctfser_open_packet(struct bt_ctfser
*ctfser
);
103 * Closes the current packet, making its size `packet_size_bytes`.
106 void bt_ctfser_close_current_packet(struct bt_ctfser
*ctfser
,
107 uint64_t packet_size_bytes
);
110 int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser
*ctfser
);
113 uint64_t _bt_ctfser_cur_packet_size_bits(struct bt_ctfser
*ctfser
)
115 return ctfser
->cur_packet_size_bytes
* 8;
119 uint64_t _bt_ctfser_prev_packet_size_bits(struct bt_ctfser
*ctfser
)
121 return ctfser
->prev_packet_size_bytes
* 8;
125 uint64_t _bt_ctfser_offset_bytes(struct bt_ctfser
*ctfser
)
127 return ctfser
->offset_in_cur_packet_bits
/ 8;
131 uint8_t *_bt_ctfser_get_addr(struct bt_ctfser
*ctfser
)
133 /* Only makes sense to get the address after aligning on byte */
134 BT_ASSERT(ctfser
->offset_in_cur_packet_bits
% 8 == 0);
135 return ((uint8_t *) mmap_align_addr(ctfser
->base_mma
)) +
136 ctfser
->mmap_base_offset
+ _bt_ctfser_offset_bytes(ctfser
);
140 bool _bt_ctfser_has_space_left(struct bt_ctfser
*ctfser
, uint64_t size_bits
)
142 bool has_space_left
= true;
144 if (G_UNLIKELY((ctfser
->offset_in_cur_packet_bits
+ size_bits
>
145 _bt_ctfser_cur_packet_size_bits(ctfser
)))) {
146 has_space_left
= false;
150 if (G_UNLIKELY(size_bits
> UINT64_MAX
- ctfser
->offset_in_cur_packet_bits
)) {
151 has_space_left
= false;
156 return has_space_left
;
160 void _bt_ctfser_incr_offset(struct bt_ctfser
*ctfser
, uint64_t size_bits
)
162 BT_ASSERT(_bt_ctfser_has_space_left(ctfser
, size_bits
));
163 ctfser
->offset_in_cur_packet_bits
+= size_bits
;
167 * Aligns the current offset within the current packet to
168 * `alignment_bits` bits (power of two, > 0).
171 int bt_ctfser_align_offset_in_current_packet(struct bt_ctfser
*ctfser
,
172 uint64_t alignment_bits
)
175 uint64_t align_size_bits
;
177 BT_ASSERT(alignment_bits
> 0);
178 align_size_bits
= ALIGN(ctfser
->offset_in_cur_packet_bits
,
179 alignment_bits
) - ctfser
->offset_in_cur_packet_bits
;
181 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, align_size_bits
))) {
182 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
183 if (G_UNLIKELY(ret
)) {
188 _bt_ctfser_incr_offset(ctfser
, align_size_bits
);
195 int _bt_ctfser_write_byte_aligned_unsigned_int_no_align(
196 struct bt_ctfser
*ctfser
, uint64_t value
,
197 unsigned int size_bits
, int byte_order
)
201 /* Reverse byte order? */
202 bool rbo
= byte_order
!= BYTE_ORDER
;
204 BT_ASSERT(size_bits
% 8 == 0);
205 BT_ASSERT(_bt_ctfser_has_space_left(ctfser
, size_bits
));
210 uint8_t v
= (uint8_t) value
;
212 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
217 uint16_t v
= (uint16_t) value
;
220 v
= GUINT16_SWAP_LE_BE(v
);
223 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
228 uint32_t v
= (uint32_t) value
;
231 v
= GUINT32_SWAP_LE_BE(v
);
234 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
239 uint64_t v
= (uint64_t) value
;
242 v
= GUINT64_SWAP_LE_BE(v
);
245 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
252 _bt_ctfser_incr_offset(ctfser
, size_bits
);
257 int _bt_ctfser_write_byte_aligned_signed_int_no_align(
258 struct bt_ctfser
*ctfser
, int64_t value
,
259 unsigned int size_bits
, int byte_order
)
263 /* Reverse byte order? */
264 bool rbo
= byte_order
!= BYTE_ORDER
;
266 BT_ASSERT(size_bits
% 8 == 0);
267 BT_ASSERT(_bt_ctfser_has_space_left(ctfser
, size_bits
));
272 int8_t v
= (int8_t) value
;
274 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
279 int16_t v
= (int16_t) value
;
282 v
= GUINT16_SWAP_LE_BE(v
);
285 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
290 int32_t v
= (int32_t) value
;
293 v
= GUINT32_SWAP_LE_BE(v
);
296 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
301 int64_t v
= (int64_t) value
;
304 v
= GUINT64_SWAP_LE_BE(v
);
307 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
314 _bt_ctfser_incr_offset(ctfser
, size_bits
);
319 * Writes an unsigned integer known to have a size that is a multiple of
320 * 8 and an alignment that is >= 8 at the current offset within the
324 int bt_ctfser_write_byte_aligned_unsigned_int(struct bt_ctfser
*ctfser
,
325 uint64_t value
, unsigned int alignment_bits
,
326 unsigned int size_bits
, int byte_order
)
330 BT_ASSERT(alignment_bits
% 8 == 0);
331 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
332 if (G_UNLIKELY(ret
)) {
336 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
337 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
338 if (G_UNLIKELY(ret
)) {
343 ret
= _bt_ctfser_write_byte_aligned_unsigned_int_no_align(ctfser
, value
,
344 size_bits
, byte_order
);
345 if (G_UNLIKELY(ret
)) {
354 * Writes a signed integer known to have a size that is a multiple of 8
355 * and an alignment that is >= 8 at the current offset within the
359 int bt_ctfser_write_byte_aligned_signed_int(struct bt_ctfser
*ctfser
,
360 int64_t value
, unsigned int alignment_bits
,
361 unsigned int size_bits
, int byte_order
)
365 BT_ASSERT(alignment_bits
% 8 == 0);
366 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
367 if (G_UNLIKELY(ret
)) {
371 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
372 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
373 if (G_UNLIKELY(ret
)) {
378 ret
= _bt_ctfser_write_byte_aligned_signed_int_no_align(ctfser
, value
,
379 size_bits
, byte_order
);
380 if (G_UNLIKELY(ret
)) {
389 * Writes an unsigned integer at the current offset within the current
393 int bt_ctfser_write_unsigned_int(struct bt_ctfser
*ctfser
, uint64_t value
,
394 unsigned int alignment_bits
, unsigned int size_bits
,
399 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
400 if (G_UNLIKELY(ret
)) {
404 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
405 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
406 if (G_UNLIKELY(ret
)) {
411 if (alignment_bits
% 8 == 0 && size_bits
% 8 == 0) {
412 ret
= _bt_ctfser_write_byte_aligned_unsigned_int_no_align(
413 ctfser
, value
, size_bits
, byte_order
);
417 if (byte_order
== LITTLE_ENDIAN
) {
418 bt_bitfield_write_le(mmap_align_addr(ctfser
->base_mma
) +
419 ctfser
->mmap_base_offset
, uint8_t,
420 ctfser
->offset_in_cur_packet_bits
, size_bits
, value
);
422 bt_bitfield_write_be(mmap_align_addr(ctfser
->base_mma
) +
423 ctfser
->mmap_base_offset
, uint8_t,
424 ctfser
->offset_in_cur_packet_bits
, size_bits
, value
);
427 _bt_ctfser_incr_offset(ctfser
, size_bits
);
434 * Writes a signed integer at the current offset within the current
438 int bt_ctfser_write_signed_int(struct bt_ctfser
*ctfser
, int64_t value
,
439 unsigned int alignment_bits
, unsigned int size_bits
,
444 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
445 if (G_UNLIKELY(ret
)) {
449 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
450 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
451 if (G_UNLIKELY(ret
)) {
456 if (alignment_bits
% 8 == 0 && size_bits
% 8 == 0) {
457 ret
= _bt_ctfser_write_byte_aligned_signed_int_no_align(
458 ctfser
, value
, size_bits
, byte_order
);
462 if (byte_order
== LITTLE_ENDIAN
) {
463 bt_bitfield_write_le(mmap_align_addr(ctfser
->base_mma
) +
464 ctfser
->mmap_base_offset
, uint8_t,
465 ctfser
->offset_in_cur_packet_bits
, size_bits
, value
);
467 bt_bitfield_write_be(mmap_align_addr(ctfser
->base_mma
) +
468 ctfser
->mmap_base_offset
, uint8_t,
469 ctfser
->offset_in_cur_packet_bits
, size_bits
, value
);
472 _bt_ctfser_incr_offset(ctfser
, size_bits
);
479 * Writes a 32-bit floating point number at the current offset within
480 * the current packet.
483 int bt_ctfser_write_float32(struct bt_ctfser
*ctfser
, double value
,
484 unsigned int alignment_bits
, int byte_order
)
491 u32f
.f
= (float) value
;
492 return bt_ctfser_write_unsigned_int(ctfser
, (uint64_t) u32f
.u
,
493 alignment_bits
, 32, byte_order
);
497 * Writes a 64-bit floating point number at the current offset within
498 * the current packet.
501 int bt_ctfser_write_float64(struct bt_ctfser
*ctfser
, double value
,
502 unsigned int alignment_bits
, int byte_order
)
510 return bt_ctfser_write_unsigned_int(ctfser
, u64f
.u
, alignment_bits
,
515 * Writes a C string, including the terminating null character, at the
516 * current offset within the current packet.
519 int bt_ctfser_write_string(struct bt_ctfser
*ctfser
, const char *value
)
522 const char *at
= value
;
524 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, 8);
525 if (G_UNLIKELY(ret
)) {
530 if (G_UNLIKELY(!_bt_ctfser_has_space_left(ctfser
, 8))) {
531 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
532 if (G_UNLIKELY(ret
)) {
537 memcpy(_bt_ctfser_get_addr(ctfser
), at
, sizeof(*at
));
538 _bt_ctfser_incr_offset(ctfser
, 8);
540 if (G_UNLIKELY(*at
== '\0')) {
552 * Returns the current offset within the current packet (bits).
555 uint64_t bt_ctfser_get_offset_in_current_packet_bits(struct bt_ctfser
*ctfser
)
557 return ctfser
->offset_in_cur_packet_bits
;
561 * Sets the current offset within the current packet (bits).
564 void bt_ctfser_set_offset_in_current_packet_bits(struct bt_ctfser
*ctfser
,
565 uint64_t offset_bits
)
567 BT_ASSERT(offset_bits
<= _bt_ctfser_cur_packet_size_bits(ctfser
));
568 ctfser
->offset_in_cur_packet_bits
= offset_bits
;
572 const char *bt_ctfser_get_file_path(struct bt_ctfser
*ctfser
)
574 return ctfser
->path
->str
;
577 #endif /* BABELTRACE_CTFSER_INTERNAL_H */