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 <babeltrace/compat/mman-internal.h>
35 #include <sys/types.h>
38 #include <babeltrace/align-internal.h>
39 #include <babeltrace/endian-internal.h>
40 #include <babeltrace/common-internal.h>
41 #include <babeltrace/mmap-align-internal.h>
42 #include <babeltrace/types.h>
43 #include <babeltrace/assert-internal.h>
44 #include <babeltrace/bitfield-internal.h>
48 /* Stream file's descriptor */
51 /* Offset (bytes) of memory map (current packet) in the stream file */
54 /* Offset (bytes) of packet's first byte in the memory map */
55 off_t mmap_base_offset
;
57 /* Current offset (bits) within current packet */
58 uint64_t offset_in_cur_packet_bits
;
60 /* Current packet size (bytes) */
61 uint64_t cur_packet_size_bytes
;
63 /* Previous packet size (bytes) */
64 uint64_t prev_packet_size_bytes
;
66 /* Current stream size (bytes) */
67 uint64_t stream_size_bytes
;
69 /* Memory map base address */
70 struct mmap_align
*base_mma
;
72 /* Stream file's path (for debugging) */
76 union bt_ctfser_int_val
{
82 * Initializes a CTF serializer.
84 * This function opens the file `path` for writing.
87 int bt_ctfser_init(struct bt_ctfser
*ctfser
, const char *path
);
90 * Finalizes a CTF serializer.
92 * This function truncates the stream file so that there's no extra
93 * padding after the last packet, and then closes the file.
96 int bt_ctfser_fini(struct bt_ctfser
*ctfser
);
101 * All the next writing functions are performed within this new packet.
104 int bt_ctfser_open_packet(struct bt_ctfser
*ctfser
);
107 * Closes the current packet, making its size `packet_size_bytes`.
110 void bt_ctfser_close_current_packet(struct bt_ctfser
*ctfser
,
111 uint64_t packet_size_bytes
);
114 int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser
*ctfser
);
117 uint64_t _bt_ctfser_cur_packet_size_bits(struct bt_ctfser
*ctfser
)
119 return ctfser
->cur_packet_size_bytes
* 8;
123 uint64_t _bt_ctfser_prev_packet_size_bits(struct bt_ctfser
*ctfser
)
125 return ctfser
->prev_packet_size_bytes
* 8;
129 uint64_t _bt_ctfser_offset_bytes(struct bt_ctfser
*ctfser
)
131 return ctfser
->offset_in_cur_packet_bits
/ 8;
135 uint8_t *_bt_ctfser_get_addr(struct bt_ctfser
*ctfser
)
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
);
144 bool _bt_ctfser_has_space_left(struct bt_ctfser
*ctfser
, uint64_t size_bits
)
146 bool has_space_left
= true;
148 if (unlikely((ctfser
->offset_in_cur_packet_bits
+ size_bits
>
149 _bt_ctfser_cur_packet_size_bits(ctfser
)))) {
150 has_space_left
= false;
154 if (unlikely(ctfser
->offset_in_cur_packet_bits
< 0 || size_bits
>
155 UINT64_MAX
- ctfser
->offset_in_cur_packet_bits
)) {
156 has_space_left
= false;
161 return has_space_left
;
165 void _bt_ctfser_incr_offset(struct bt_ctfser
*ctfser
, uint64_t size_bits
)
167 BT_ASSERT(_bt_ctfser_has_space_left(ctfser
, size_bits
));
168 ctfser
->offset_in_cur_packet_bits
+= size_bits
;
172 * Aligns the current offset within the current packet to
173 * `alignment_bits` bits (power of two, > 0).
176 int bt_ctfser_align_offset_in_current_packet(struct bt_ctfser
*ctfser
,
177 uint64_t alignment_bits
)
180 uint64_t align_size_bits
;
182 BT_ASSERT(alignment_bits
> 0);
183 align_size_bits
= ALIGN(ctfser
->offset_in_cur_packet_bits
,
184 alignment_bits
) - ctfser
->offset_in_cur_packet_bits
;
186 if (unlikely(!_bt_ctfser_has_space_left(ctfser
, align_size_bits
))) {
187 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
193 _bt_ctfser_incr_offset(ctfser
, align_size_bits
);
200 int _bt_ctfser_write_byte_aligned_int_no_align(struct bt_ctfser
*ctfser
,
201 union bt_ctfser_int_val value
,
202 unsigned int size_bits
, bool is_signed
, int byte_order
)
206 /* Reverse byte order? */
207 bool rbo
= byte_order
!= BYTE_ORDER
;
209 BT_ASSERT(size_bits
% 8 == 0);
210 BT_ASSERT(_bt_ctfser_has_space_left(ctfser
, size_bits
));
216 uint8_t v
= (uint8_t) value
.u
;
218 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
223 uint16_t v
= (uint16_t) value
.u
;
226 v
= GUINT16_SWAP_LE_BE(v
);
229 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
234 uint32_t v
= (uint32_t) value
.u
;
237 v
= GUINT32_SWAP_LE_BE(v
);
240 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
245 uint64_t v
= (uint64_t) value
.u
;
248 v
= GUINT64_SWAP_LE_BE(v
);
251 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
261 int8_t v
= (int8_t) value
.i
;
263 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
268 int16_t v
= (int16_t) value
.i
;
271 v
= GUINT16_SWAP_LE_BE(v
);
274 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
279 int32_t v
= (int32_t) value
.i
;
282 v
= GUINT32_SWAP_LE_BE(v
);
285 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
290 int64_t v
= (int64_t) value
.i
;
293 v
= GUINT64_SWAP_LE_BE(v
);
296 memcpy(_bt_ctfser_get_addr(ctfser
), &v
, sizeof(v
));
304 _bt_ctfser_incr_offset(ctfser
, size_bits
);
309 * Writes an integer known to have an alignment that is >= 8 at the
310 * current offset within the current packet.
313 int bt_ctfser_write_byte_aligned_int(struct bt_ctfser
*ctfser
,
314 union bt_ctfser_int_val value
, unsigned int alignment_bits
,
315 unsigned int size_bits
, bool is_signed
, int byte_order
)
319 BT_ASSERT(alignment_bits
% 8 == 0);
320 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
325 if (unlikely(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
326 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
332 ret
= _bt_ctfser_write_byte_aligned_int_no_align(ctfser
, value
,
333 size_bits
, is_signed
, byte_order
);
343 * Writes an integer at the current offset within the current packet.
346 int bt_ctfser_write_int(struct bt_ctfser
*ctfser
, union bt_ctfser_int_val value
,
347 unsigned int alignment_bits
, unsigned int size_bits
, bool is_signed
,
352 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, alignment_bits
);
357 if (unlikely(!_bt_ctfser_has_space_left(ctfser
, size_bits
))) {
358 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
364 if (alignment_bits
% 8 == 0 && size_bits
% 8 == 0) {
365 ret
= _bt_ctfser_write_byte_aligned_int_no_align(ctfser
, value
,
366 size_bits
, is_signed
, byte_order
);
371 if (byte_order
== LITTLE_ENDIAN
) {
372 bt_bitfield_write_le(mmap_align_addr(ctfser
->base_mma
) +
373 ctfser
->mmap_base_offset
, uint8_t,
374 ctfser
->offset_in_cur_packet_bits
, size_bits
,
377 bt_bitfield_write_be(mmap_align_addr(ctfser
->base_mma
) +
378 ctfser
->mmap_base_offset
, uint8_t,
379 ctfser
->offset_in_cur_packet_bits
, size_bits
,
383 if (byte_order
== LITTLE_ENDIAN
) {
384 bt_bitfield_write_le(mmap_align_addr(ctfser
->base_mma
) +
385 ctfser
->mmap_base_offset
, uint8_t,
386 ctfser
->offset_in_cur_packet_bits
, size_bits
,
389 bt_bitfield_write_be(mmap_align_addr(ctfser
->base_mma
) +
390 ctfser
->mmap_base_offset
, uint8_t,
391 ctfser
->offset_in_cur_packet_bits
, size_bits
,
396 _bt_ctfser_incr_offset(ctfser
, size_bits
);
403 * Writes a 32-bit floating point number at the current offset within
404 * the current packet.
407 int bt_ctfser_write_float32(struct bt_ctfser
*ctfser
, double value
,
408 unsigned int alignment_bits
, int byte_order
)
410 union bt_ctfser_int_val int_value
;
416 u32f
.f
= (float) value
;
417 int_value
.u
= u32f
.u
;
418 return bt_ctfser_write_int(ctfser
, int_value
, alignment_bits
,
419 32, false, byte_order
);
423 * Writes a 64-bit floating point number at the current offset within
424 * the current packet.
427 int bt_ctfser_write_float64(struct bt_ctfser
*ctfser
, double value
,
428 unsigned int alignment_bits
, int byte_order
)
430 union bt_ctfser_int_val int_value
;
437 int_value
.u
= u64f
.u
;
438 return bt_ctfser_write_int(ctfser
, int_value
, alignment_bits
,
439 64, false, byte_order
);
443 * Writes a C string, including the terminating null character, at the
444 * current offset within the current packet.
447 int bt_ctfser_write_string(struct bt_ctfser
*ctfser
, const char *value
)
450 const char *at
= value
;
452 ret
= bt_ctfser_align_offset_in_current_packet(ctfser
, 8);
458 if (unlikely(!_bt_ctfser_has_space_left(ctfser
, 8))) {
459 ret
= _bt_ctfser_increase_cur_packet_size(ctfser
);
465 memcpy(_bt_ctfser_get_addr(ctfser
), at
, sizeof(*at
));
466 _bt_ctfser_incr_offset(ctfser
, 8);
468 if (unlikely(*at
== '\0')) {
480 * Returns the current offset within the current packet (bits).
483 uint64_t bt_ctfser_get_offset_in_current_packet_bits(struct bt_ctfser
*ctfser
)
485 return ctfser
->offset_in_cur_packet_bits
;
489 * Sets the current offset within the current packet (bits).
492 void bt_ctfser_set_offset_in_current_packet_bits(struct bt_ctfser
*ctfser
,
493 uint64_t offset_bits
)
495 BT_ASSERT(offset_bits
<= _bt_ctfser_cur_packet_size_bits(ctfser
));
496 ctfser
->offset_in_cur_packet_bits
= offset_bits
;
499 #endif /* BABELTRACE_CTFSER_INTERNAL_H */