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