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