port: namespace align.h with BT_ prefix
[babeltrace.git] / src / ctfser / ctfser.h
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
33 struct 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 */
70 BT_HIDDEN
71 int 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 */
80 BT_HIDDEN
81 int 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 */
88 BT_HIDDEN
89 int bt_ctfser_open_packet(struct bt_ctfser *ctfser);
90
91 /*
92 * Closes the current packet, making its size `packet_size_bytes`.
93 */
94 BT_HIDDEN
95 void bt_ctfser_close_current_packet(struct bt_ctfser *ctfser,
96 uint64_t packet_size_bytes);
97
98 BT_HIDDEN
99 int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser *ctfser);
100
101 static inline
102 uint64_t _bt_ctfser_cur_packet_size_bits(struct bt_ctfser *ctfser)
103 {
104 return ctfser->cur_packet_size_bytes * 8;
105 }
106
107 static inline
108 uint64_t _bt_ctfser_prev_packet_size_bits(struct bt_ctfser *ctfser)
109 {
110 return ctfser->prev_packet_size_bytes * 8;
111 }
112
113 static inline
114 uint64_t _bt_ctfser_offset_bytes(struct bt_ctfser *ctfser)
115 {
116 return ctfser->offset_in_cur_packet_bits / 8;
117 }
118
119 static inline
120 uint8_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
128 static inline
129 bool _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
144 end:
145 return has_space_left;
146 }
147
148 static inline
149 void _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 */
159 static inline
160 int 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 = BT_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
179 end:
180 return ret;
181 }
182
183 static inline
184 int _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
245 static inline
246 int _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 */
312 static inline
313 int 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
338 end:
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 */
347 static inline
348 int 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
373 end:
374 return ret;
375 }
376
377 /*
378 * Writes an unsigned integer at the current offset within the current
379 * packet.
380 */
381 static inline
382 int 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
418 end:
419 return ret;
420 }
421
422 /*
423 * Writes a signed integer at the current offset within the current
424 * packet.
425 */
426 static inline
427 int 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
463 end:
464 return ret;
465 }
466
467 /*
468 * Writes a 32-bit floating point number at the current offset within
469 * the current packet.
470 */
471 static inline
472 int 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 */
489 static inline
490 int 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 */
507 static inline
508 int 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
536 end:
537 return ret;
538 }
539
540 /*
541 * Returns the current offset within the current packet (bits).
542 */
543 static inline
544 uint64_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 */
552 static inline
553 void 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
560 static inline
561 const 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.039859 seconds and 4 git commands to generate.