Move to kernel style SPDX license identifiers
[babeltrace.git] / src / ctfser / ctfser.h
... / ...
CommitLineData
1/*
2 * SPDX-License-Identifier: MIT
3 *
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 *
8 * The Common Trace Format (CTF) Specification is available at
9 * http://www.efficios.com/ctf
10 */
11
12#ifndef BABELTRACE_CTFSER_INTERNAL_H
13#define BABELTRACE_CTFSER_INTERNAL_H
14
15#include <stdbool.h>
16#include <stdlib.h>
17#include <stdint.h>
18#include <limits.h>
19#include "compat/mman.h"
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <fcntl.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"
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;
60
61 /* Serializer's log level */
62 int log_level;
63};
64
65/*
66 * Initializes a CTF serializer.
67 *
68 * This function opens the file `path` for writing.
69 */
70BT_HIDDEN
71int bt_ctfser_init(struct bt_ctfser *ctfser, const char *path,
72 int log_level);
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 */
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);
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
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;
136 goto end;
137 }
138
139 if (G_UNLIKELY(size_bits > UINT64_MAX - ctfser->offset_in_cur_packet_bits)) {
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{
151 BT_ASSERT_DBG(_bt_ctfser_has_space_left(ctfser, size_bits));
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
166 BT_ASSERT_DBG(alignment_bits > 0);
167 align_size_bits = ALIGN(ctfser->offset_in_cur_packet_bits,
168 alignment_bits) - ctfser->offset_in_cur_packet_bits;
169
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)) {
173 goto end;
174 }
175 }
176
177 _bt_ctfser_incr_offset(ctfser, align_size_bits);
178
179end:
180 return ret;
181}
182
183static inline
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)
187{
188 int ret = 0;
189
190 /* Reverse byte order? */
191 bool rbo = byte_order != BYTE_ORDER;
192
193 BT_ASSERT_DBG(size_bits % 8 == 0);
194 BT_ASSERT_DBG(_bt_ctfser_has_space_left(ctfser, size_bits));
195
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;
207
208 if (rbo) {
209 v = GUINT16_SWAP_LE_BE(v);
210 }
211
212 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
213 break;
214 }
215 case 32:
216 {
217 uint32_t v = (uint32_t) value;
218
219 if (rbo) {
220 v = GUINT32_SWAP_LE_BE(v);
221 }
222
223 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
224 break;
225 }
226 case 64:
227 {
228 uint64_t v = (uint64_t) value;
229
230 if (rbo) {
231 v = GUINT64_SWAP_LE_BE(v);
232 }
233
234 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
235 break;
236 }
237 default:
238 bt_common_abort();
239 }
240
241 _bt_ctfser_incr_offset(ctfser, size_bits);
242 return ret;
243}
244
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;
251
252 /* Reverse byte order? */
253 bool rbo = byte_order != BYTE_ORDER;
254
255 BT_ASSERT_DBG(size_bits % 8 == 0);
256 BT_ASSERT_DBG(_bt_ctfser_has_space_left(ctfser, size_bits));
257
258 switch (size_bits) {
259 case 8:
260 {
261 int8_t v = (int8_t) value;
262
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);
272 }
273
274 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
275 break;
276 }
277 case 32:
278 {
279 int32_t v = (int32_t) value;
280
281 if (rbo) {
282 v = GUINT32_SWAP_LE_BE(v);
283 }
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);
294 }
295
296 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
297 break;
298 }
299 default:
300 bt_common_abort();
301 }
302
303 _bt_ctfser_incr_offset(ctfser, size_bits);
304 return ret;
305}
306
307/*
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.
311 */
312static inline
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)
316{
317 int ret;
318
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)) {
322 goto end;
323 }
324
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)) {
328 goto end;
329 }
330 }
331
332 ret = _bt_ctfser_write_byte_aligned_unsigned_int_no_align(ctfser, value,
333 size_bits, byte_order);
334 if (G_UNLIKELY(ret)) {
335 goto end;
336 }
337
338end:
339 return ret;
340}
341
342/*
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.
346 */
347static inline
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
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)) {
357 goto end;
358 }
359
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)) {
363 goto end;
364 }
365 }
366
367 ret = _bt_ctfser_write_byte_aligned_signed_int_no_align(ctfser, value,
368 size_bits, byte_order);
369 if (G_UNLIKELY(ret)) {
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,
384 int byte_order)
385{
386 int ret = 0;
387
388 ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
389 if (G_UNLIKELY(ret)) {
390 goto end;
391 }
392
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)) {
396 goto end;
397 }
398 }
399
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);
403 goto end;
404 }
405
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);
410 } else {
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);
434 if (G_UNLIKELY(ret)) {
435 goto end;
436 }
437
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)) {
441 goto end;
442 }
443 }
444
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
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{
475 union u32f {
476 uint32_t u;
477 float f;
478 } u32f;
479
480 u32f.f = (float) value;
481 return bt_ctfser_write_unsigned_int(ctfser, (uint64_t) u32f.u,
482 alignment_bits, 32, byte_order);
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{
493 union u64f {
494 uint64_t u;
495 double d;
496 } u64f;
497
498 u64f.d = value;
499 return bt_ctfser_write_unsigned_int(ctfser, u64f.u, alignment_bits,
500 64, byte_order);
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);
514 if (G_UNLIKELY(ret)) {
515 goto end;
516 }
517
518 while (true) {
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)) {
522 goto end;
523 }
524 }
525
526 memcpy(_bt_ctfser_get_addr(ctfser), at, sizeof(*at));
527 _bt_ctfser_incr_offset(ctfser, 8);
528
529 if (G_UNLIKELY(*at == '\0')) {
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{
556 BT_ASSERT_DBG(offset_bits <= _bt_ctfser_cur_packet_size_bits(ctfser));
557 ctfser->offset_in_cur_packet_bits = offset_bits;
558}
559
560static inline
561const char *bt_ctfser_get_file_path(struct bt_ctfser *ctfser)
562{
563 return ctfser->path->str;
564}
565
566#endif /* BABELTRACE_CTFSER_INTERNAL_H */
This page took 0.02421 seconds and 4 git commands to generate.