src.ctf.fs: keep empty structures
[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
76union bt_ctfser_int_val {
77 int64_t i;
78 uint64_t u;
79};
80
81/*
82 * Initializes a CTF serializer.
83 *
84 * This function opens the file `path` for writing.
85 */
86BT_HIDDEN
87int bt_ctfser_init(struct bt_ctfser *ctfser, const char *path);
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 */
95BT_HIDDEN
96int 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 */
103BT_HIDDEN
104int bt_ctfser_open_packet(struct bt_ctfser *ctfser);
105
106/*
107 * Closes the current packet, making its size `packet_size_bytes`.
108 */
109BT_HIDDEN
110void bt_ctfser_close_current_packet(struct bt_ctfser *ctfser,
111 uint64_t packet_size_bytes);
112
113BT_HIDDEN
114int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser *ctfser);
115
116static inline
117uint64_t _bt_ctfser_cur_packet_size_bits(struct bt_ctfser *ctfser)
118{
119 return ctfser->cur_packet_size_bytes * 8;
120}
121
122static inline
123uint64_t _bt_ctfser_prev_packet_size_bits(struct bt_ctfser *ctfser)
124{
125 return ctfser->prev_packet_size_bytes * 8;
126}
127
128static inline
129uint64_t _bt_ctfser_offset_bytes(struct bt_ctfser *ctfser)
130{
131 return ctfser->offset_in_cur_packet_bits / 8;
132}
133
134static inline
135uint8_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
143static inline
144bool _bt_ctfser_has_space_left(struct bt_ctfser *ctfser, uint64_t size_bits)
145{
146 bool has_space_left = true;
147
148 if (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 (unlikely(ctfser->offset_in_cur_packet_bits < 0 || size_bits >
155 UINT64_MAX - ctfser->offset_in_cur_packet_bits)) {
156 has_space_left = false;
157 goto end;
158 }
159
160end:
161 return has_space_left;
162}
163
164static inline
165void _bt_ctfser_incr_offset(struct bt_ctfser *ctfser, uint64_t size_bits)
166{
167 BT_ASSERT(_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 */
175static inline
176int 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(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 (unlikely(!_bt_ctfser_has_space_left(ctfser, align_size_bits))) {
187 ret = _bt_ctfser_increase_cur_packet_size(ctfser);
188 if (unlikely(ret)) {
189 goto end;
190 }
191 }
192
193 _bt_ctfser_incr_offset(ctfser, align_size_bits);
194
195end:
196 return ret;
197}
198
199static inline
200int _bt_ctfser_write_byte_aligned_int_no_align(struct bt_ctfser *ctfser,
201 union bt_ctfser_int_val value,
202 unsigned int size_bits, bool is_signed, int byte_order)
203{
204 int ret = 0;
205
206 /* Reverse byte order? */
207 bool rbo = byte_order != BYTE_ORDER;
208
209 BT_ASSERT(size_bits % 8 == 0);
210 BT_ASSERT(_bt_ctfser_has_space_left(ctfser, size_bits));
211
212 if (!is_signed) {
213 switch (size_bits) {
214 case 8:
215 {
216 uint8_t v = (uint8_t) value.u;
217
218 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
219 break;
220 }
221 case 16:
222 {
223 uint16_t v = (uint16_t) value.u;
224
225 if (rbo) {
226 v = GUINT16_SWAP_LE_BE(v);
227 }
228
229 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
230 break;
231 }
232 case 32:
233 {
234 uint32_t v = (uint32_t) value.u;
235
236 if (rbo) {
237 v = GUINT32_SWAP_LE_BE(v);
238 }
239
240 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
241 break;
242 }
243 case 64:
244 {
245 uint64_t v = (uint64_t) value.u;
246
247 if (rbo) {
248 v = GUINT64_SWAP_LE_BE(v);
249 }
250
251 memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
252 break;
253 }
254 default:
255 abort();
256 }
257 } else {
258 switch (size_bits) {
259 case 8:
260 {
261 int8_t v = (int8_t) value.i;
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.i;
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.i;
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.i;
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 abort();
301 }
302 }
303
304 _bt_ctfser_incr_offset(ctfser, size_bits);
305 return ret;
306}
307
308/*
309 * Writes an integer known to have an alignment that is >= 8 at the
310 * current offset within the current packet.
311 */
312static inline
313int bt_ctfser_write_byte_aligned_int(struct bt_ctfser *ctfser,
314 union bt_ctfser_int_val value, unsigned int alignment_bits,
315 unsigned int size_bits, bool is_signed, int byte_order)
316{
317 int ret;
318
319 BT_ASSERT(alignment_bits % 8 == 0);
320 ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
321 if (unlikely(ret)) {
322 goto end;
323 }
324
325 if (unlikely(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
326 ret = _bt_ctfser_increase_cur_packet_size(ctfser);
327 if (unlikely(ret)) {
328 goto end;
329 }
330 }
331
332 ret = _bt_ctfser_write_byte_aligned_int_no_align(ctfser, value,
333 size_bits, is_signed, byte_order);
334 if (unlikely(ret)) {
335 goto end;
336 }
337
338end:
339 return ret;
340}
341
342/*
343 * Writes an integer at the current offset within the current packet.
344 */
345static inline
346int bt_ctfser_write_int(struct bt_ctfser *ctfser, union bt_ctfser_int_val value,
347 unsigned int alignment_bits, unsigned int size_bits, bool is_signed,
348 int byte_order)
349{
350 int ret = 0;
351
352 ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
353 if (unlikely(ret)) {
354 goto end;
355 }
356
357 if (unlikely(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
358 ret = _bt_ctfser_increase_cur_packet_size(ctfser);
359 if (unlikely(ret)) {
360 goto end;
361 }
362 }
363
364 if (alignment_bits % 8 == 0 && size_bits % 8 == 0) {
365 ret = _bt_ctfser_write_byte_aligned_int_no_align(ctfser, value,
366 size_bits, is_signed, byte_order);
367 goto end;
368 }
369
370 if (!is_signed) {
371 if (byte_order == LITTLE_ENDIAN) {
372 bt_bitfield_write_le(mmap_align_addr(ctfser->base_mma) +
373 ctfser->mmap_base_offset, uint8_t,
374 ctfser->offset_in_cur_packet_bits, size_bits,
375 value.u);
376 } else {
377 bt_bitfield_write_be(mmap_align_addr(ctfser->base_mma) +
378 ctfser->mmap_base_offset, uint8_t,
379 ctfser->offset_in_cur_packet_bits, size_bits,
380 value.u);
381 }
382 } else {
383 if (byte_order == LITTLE_ENDIAN) {
384 bt_bitfield_write_le(mmap_align_addr(ctfser->base_mma) +
385 ctfser->mmap_base_offset, uint8_t,
386 ctfser->offset_in_cur_packet_bits, size_bits,
387 value.i);
388 } else {
389 bt_bitfield_write_be(mmap_align_addr(ctfser->base_mma) +
390 ctfser->mmap_base_offset, uint8_t,
391 ctfser->offset_in_cur_packet_bits, size_bits,
392 value.i);
393 }
394 }
395
396 _bt_ctfser_incr_offset(ctfser, size_bits);
397
398end:
399 return ret;
400}
401
402/*
403 * Writes a 32-bit floating point number at the current offset within
404 * the current packet.
405 */
406static inline
407int bt_ctfser_write_float32(struct bt_ctfser *ctfser, double value,
408 unsigned int alignment_bits, int byte_order)
409{
410 union bt_ctfser_int_val int_value;
411 union u32f {
412 uint32_t u;
413 float f;
414 } u32f;
415
416 u32f.f = (float) value;
417 int_value.u = u32f.u;
418 return bt_ctfser_write_int(ctfser, int_value, alignment_bits,
419 32, false, byte_order);
420}
421
422/*
423 * Writes a 64-bit floating point number at the current offset within
424 * the current packet.
425 */
426static inline
427int bt_ctfser_write_float64(struct bt_ctfser *ctfser, double value,
428 unsigned int alignment_bits, int byte_order)
429{
430 union bt_ctfser_int_val int_value;
431 union u64f {
432 uint64_t u;
433 float f;
434 } u64f;
435
436 u64f.f = value;
437 int_value.u = u64f.u;
438 return bt_ctfser_write_int(ctfser, int_value, alignment_bits,
439 64, false, byte_order);
440}
441
442/*
443 * Writes a C string, including the terminating null character, at the
444 * current offset within the current packet.
445 */
446static inline
447int bt_ctfser_write_string(struct bt_ctfser *ctfser, const char *value)
448{
449 int ret = 0;
450 const char *at = value;
451
452 ret = bt_ctfser_align_offset_in_current_packet(ctfser, 8);
453 if (unlikely(ret)) {
454 goto end;
455 }
456
457 while (true) {
458 if (unlikely(!_bt_ctfser_has_space_left(ctfser, 8))) {
459 ret = _bt_ctfser_increase_cur_packet_size(ctfser);
460 if (unlikely(ret)) {
461 goto end;
462 }
463 }
464
465 memcpy(_bt_ctfser_get_addr(ctfser), at, sizeof(*at));
466 _bt_ctfser_incr_offset(ctfser, 8);
467
468 if (unlikely(*at == '\0')) {
469 break;
470 }
471
472 at++;
473 }
474
475end:
476 return ret;
477}
478
479/*
480 * Returns the current offset within the current packet (bits).
481 */
482static inline
483uint64_t bt_ctfser_get_offset_in_current_packet_bits(struct bt_ctfser *ctfser)
484{
485 return ctfser->offset_in_cur_packet_bits;
486}
487
488/*
489 * Sets the current offset within the current packet (bits).
490 */
491static inline
492void bt_ctfser_set_offset_in_current_packet_bits(struct bt_ctfser *ctfser,
493 uint64_t offset_bits)
494{
495 BT_ASSERT(offset_bits <= _bt_ctfser_cur_packet_size_bits(ctfser));
496 ctfser->offset_in_cur_packet_bits = offset_bits;
497}
498
499#endif /* BABELTRACE_CTFSER_INTERNAL_H */
This page took 0.040243 seconds and 4 git commands to generate.