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