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