SUBDIRS = include \
common \
+ ctfser \
compat \
logging \
lib
bindings/python/bt2/setup.py
bindings/python/bt2/bt2/__init__.py
common/Makefile
+ ctfser/Makefile
compat/Makefile
cli/Makefile
doc/Makefile
--- /dev/null
+AM_CPPFLAGS += -DINSTALL_LIBDIR=\"$(libdir)\"
+
+noinst_LTLIBRARIES = libbabeltrace-ctfser.la
+
+libbabeltrace_ctfser_la_SOURCES = ctfser.c logging.c logging.h
--- /dev/null
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTFSER"
+#include "logging.h"
+
+#include <unistd.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <babeltrace/assert-internal.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdbool.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/common-internal.h>
+#include <babeltrace/ctfser-internal.h>
+#include <babeltrace/compat/unistd-internal.h>
+#include <babeltrace/compat/fcntl-internal.h>
+
+static inline
+uint64_t get_packet_size_increment_bytes(void)
+{
+ return bt_common_get_page_size() * 8;
+}
+
+static inline
+void mmap_align_ctfser(struct bt_ctfser *ctfser)
+{
+ ctfser->base_mma = mmap_align(ctfser->cur_packet_size_bytes, PROT_WRITE,
+ MAP_SHARED, ctfser->fd, ctfser->mmap_offset);
+}
+
+BT_HIDDEN
+int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser *ctfser)
+{
+ int ret;
+
+ BT_ASSERT(ctfser);
+ BT_LOGV("Increasing stream file's current packet size: "
+ "path=\"%s\", fd=%d, "
+ "offset-in-cur-packet-bits=%" PRIu64 ", "
+ "cur-packet-size-bytes=%" PRIu64,
+ ctfser->path->str, ctfser->fd,
+ ctfser->offset_in_cur_packet_bits,
+ ctfser->cur_packet_size_bytes);
+ ret = munmap_align(ctfser->base_mma);
+ if (ret) {
+ BT_LOGE_ERRNO("Failed to perform an aligned memory unmapping",
+ ": ret=%d", ret);
+ goto end;
+ }
+
+ ctfser->cur_packet_size_bytes += get_packet_size_increment_bytes();
+
+ do {
+ ret = bt_posix_fallocate(ctfser->fd, ctfser->mmap_offset,
+ ctfser->cur_packet_size_bytes);
+ } while (ret == EINTR);
+
+ if (ret) {
+ BT_LOGE("Failed to preallocate memory space: ret=%d", ret);
+ goto end;
+ }
+
+ mmap_align_ctfser(ctfser);
+ if (ctfser->base_mma == MAP_FAILED) {
+ BT_LOGE_ERRNO("Failed to perform an aligned memory mapping",
+ ": ret=%d", ret);
+ ret = -1;
+ goto end;
+ }
+
+ BT_LOGV("Increased packet size: "
+ "path=\"%s\", fd=%d, "
+ "offset-in-cur-packet-bits=%" PRIu64 ", "
+ "new-packet-size-bytes=%" PRIu64,
+ ctfser->path->str, ctfser->fd,
+ ctfser->offset_in_cur_packet_bits,
+ ctfser->cur_packet_size_bytes);
+
+end:
+ return ret;
+}
+
+BT_HIDDEN
+int bt_ctfser_init(struct bt_ctfser *ctfser, const char *path)
+{
+ int ret = 0;
+
+ BT_ASSERT(ctfser);
+ memset(ctfser, 0, sizeof(*ctfser));
+ ctfser->fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ if (ctfser->fd < 0) {
+ BT_LOGW_ERRNO("Failed to open stream file for writing",
+ ": path=\"%s\", ret=%d",
+ path, ctfser->fd);
+ ret = -1;
+ goto end;
+ }
+
+ ctfser->path = g_string_new(path);
+
+end:
+ return ret;
+}
+
+BT_HIDDEN
+int bt_ctfser_fini(struct bt_ctfser *ctfser)
+{
+ int ret = 0;
+
+ if (ctfser->fd == -1) {
+ goto free_path;
+ }
+
+ /*
+ * Truncate the stream file's size to the minimum required to
+ * fit the last packet as we might have grown it too much during
+ * the last memory map.
+ */
+ do {
+ ret = ftruncate(ctfser->fd, ctfser->stream_size_bytes);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret) {
+ BT_LOGE_ERRNO("Failed to truncate stream file",
+ ": ret=%d, size-bytes=%" PRIu64,
+ ret, ctfser->stream_size_bytes);
+ goto end;
+ }
+
+ if (ctfser->base_mma) {
+ /* Unmap old base */
+ ret = munmap_align(ctfser->base_mma);
+ if (ret) {
+ BT_LOGE_ERRNO("Failed to unmap stream file",
+ ": ret=%d, size-bytes=%" PRIu64,
+ ret, ctfser->stream_size_bytes);
+ goto end;
+ }
+
+ ctfser->base_mma = NULL;
+ }
+
+ ret = close(ctfser->fd);
+ if (ret) {
+ BT_LOGE_ERRNO("Failed to close stream file",
+ ": ret=%d", ret);
+ goto end;
+ }
+
+ ctfser->fd = -1;
+
+free_path:
+ if (ctfser->path) {
+ g_string_free(ctfser->path, TRUE);
+ ctfser->path = NULL;
+ }
+
+end:
+ return ret;
+}
+
+BT_HIDDEN
+int bt_ctfser_open_packet(struct bt_ctfser *ctfser)
+{
+ int ret = 0;
+
+ BT_LOGV("Opening packet: path=\"%s\", fd=%d, "
+ "prev-packet-size-bytes=%" PRIu64,
+ ctfser->path->str, ctfser->fd,
+ ctfser->prev_packet_size_bytes);
+
+ if (ctfser->base_mma) {
+ /* Unmap old base (previous packet) */
+ ret = munmap_align(ctfser->base_mma);
+ if (ret) {
+ BT_LOGE_ERRNO("Failed to unmap stream file",
+ ": ret=%d, size-bytes=%" PRIu64,
+ ret, ctfser->stream_size_bytes);
+ goto end;
+ }
+
+ ctfser->base_mma = NULL;
+ }
+
+ /*
+ * Add the previous packet's size to the memory map address
+ * offset to start writing immediately after it.
+ */
+ ctfser->mmap_offset += ctfser->prev_packet_size_bytes;
+ ctfser->prev_packet_size_bytes = 0;
+
+ /* Make initial space for the current packet */
+ ctfser->cur_packet_size_bytes = get_packet_size_increment_bytes();
+
+ do {
+ ret = bt_posix_fallocate(ctfser->fd, ctfser->mmap_offset,
+ ctfser->cur_packet_size_bytes);
+ } while (ret == EINTR);
+
+ if (ret) {
+ BT_LOGE("Failed to preallocate memory space: ret=%d", ret);
+ goto end;
+ }
+
+ /* Start writing at the beginning of the current packet */
+ ctfser->offset_in_cur_packet_bits = 0;
+
+ /* Get new base address */
+ mmap_align_ctfser(ctfser);
+ if (ctfser->base_mma == MAP_FAILED) {
+ BT_LOGE_ERRNO("Failed to perform an aligned memory mapping",
+ ": ret=%d", ret);
+ ret = -1;
+ goto end;
+ }
+
+ BT_LOGV("Opened packet: path=\"%s\", fd=%d, "
+ "cur-packet-size-bytes=%" PRIu64,
+ ctfser->path->str, ctfser->fd,
+ ctfser->cur_packet_size_bytes);
+
+end:
+ return ret;
+}
+
+BT_HIDDEN
+void bt_ctfser_close_current_packet(struct bt_ctfser *ctfser,
+ uint64_t packet_size_bytes)
+{
+ BT_LOGV("Closing packet: path=\"%s\", fd=%d, "
+ "offset-in-cur-packet-bits=%" PRIu64
+ "cur-packet-size-bytes=%" PRIu64,
+ ctfser->path->str, ctfser->fd,
+ ctfser->offset_in_cur_packet_bits,
+ ctfser->cur_packet_size_bytes);
+
+ /*
+ * This will be used during the next call to
+ * bt_ctfser_open_packet(): we add
+ * `ctfser->prev_packet_size_bytes` to the current memory map
+ * address offset (first byte of _this_ packet), effectively
+ * making _this_ packet the required size.
+ */
+ ctfser->prev_packet_size_bytes = packet_size_bytes;
+ ctfser->stream_size_bytes += packet_size_bytes;
+ BT_LOGV("Closed packet: path=\"%s\", fd=%d, "
+ "stream-file-size-bytes=%" PRIu64,
+ ctfser->path->str, ctfser->fd,
+ ctfser->stream_size_bytes);
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_ctfser_log_level
+#include <babeltrace/logging-internal.h>
+
+BT_LOG_INIT_LOG_LEVEL(bt_ctfser_log_level, "BABELTRACE_CTFSER_LOG_LEVEL");
--- /dev/null
+#ifndef COMMON_LOGGING_H
+#define COMMON_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_ctfser_log_level
+#include <babeltrace/logging-internal.h>
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_ctfser_log_level);
+
+#endif /* COMMON_LOGGING_H */
babeltrace/compat/mman-internal.h \
babeltrace/compat/socket-internal.h \
babeltrace/common-internal.h \
+ babeltrace/ctfser-internal.h \
babeltrace/bitfield-internal.h \
babeltrace/object-internal.h \
babeltrace/object-pool-internal.h \
babeltrace/ctf-writer/field-wrapper-internal.h \
babeltrace/ctf-writer/functor-internal.h \
babeltrace/ctf-writer/resolve-internal.h \
- babeltrace/ctf-writer/serialize-internal.h \
babeltrace/ctf-writer/stream-class-internal.h \
babeltrace/ctf-writer/stream-internal.h \
babeltrace/ctf-writer/trace-internal.h \
#include <babeltrace/ctf-writer/validation-internal.h>
#include <babeltrace/ctf-writer/object-internal.h>
#include <babeltrace/ctf-writer/values-internal.h>
+#include <babeltrace/ctfser-internal.h>
struct bt_ctf_stream_class;
struct bt_ctf_stream_pos;
BT_HIDDEN
int bt_ctf_event_serialize(struct bt_ctf_event *event,
- struct bt_ctf_stream_pos *pos,
+ struct bt_ctfser *pos,
enum bt_ctf_byte_order native_byte_order);
static inline
#include <babeltrace/common-internal.h>
#include <babeltrace/ctf-writer/field-types-internal.h>
#include <babeltrace/ctf-writer/fields.h>
-#include <babeltrace/ctf-writer/serialize-internal.h>
#include <babeltrace/ctf-writer/utils-internal.h>
#include <babeltrace/ctf-writer/object-internal.h>
+#include <babeltrace/ctfser-internal.h>
#include <babeltrace/types.h>
#include <glib.h>
#include <inttypes.h>
BT_HIDDEN
int bt_ctf_field_serialize_recursive(struct bt_ctf_field *field,
- struct bt_ctf_stream_pos *pos,
+ struct bt_ctfser *ctfser,
enum bt_ctf_byte_order native_byte_order);
BT_HIDDEN
+++ /dev/null
-#ifndef BABELTRACE_CTF_WRITER_SERIALIZE_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_SERIALIZE_INTERNAL_H
-
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <limits.h>
-#include <babeltrace/compat/mman-internal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <babeltrace/align-internal.h>
-#include <babeltrace/endian-internal.h>
-#include <babeltrace/common-internal.h>
-#include <babeltrace/mmap-align-internal.h>
-#include <babeltrace/types.h>
-#include <babeltrace/ctf-writer/field-types.h>
-#include <babeltrace/ctf-writer/fields-internal.h>
-#include <babeltrace/ctf-writer/fields.h>
-#include <babeltrace/assert-internal.h>
-
-#define PACKET_LEN_INCREMENT (bt_common_get_page_size() * 8 * CHAR_BIT)
-
-#if (BYTE_ORDER == BIG_ENDIAN)
-# define BT_CTF_MY_BYTE_ORDER BT_CTF_BYTE_ORDER_BIG_ENDIAN
-#else
-# define BT_CTF_MY_BYTE_ORDER BT_CTF_BYTE_ORDER_LITTLE_ENDIAN
-#endif
-
-struct bt_ctf_stream_pos {
- int fd;
- int prot; /* mmap protection */
- int flags; /* mmap flags */
-
- /* Current position */
- off_t mmap_offset; /* mmap offset in the file, in bytes */
- off_t mmap_base_offset; /* offset of start of packet in mmap, in bytes */
- uint64_t packet_size; /* current packet size, in bits */
- int64_t offset; /* offset from base, in bits. EOF for end of file. */
- struct mmap_align *base_mma;/* mmap base address */
-};
-
-BT_HIDDEN
-int bt_ctf_field_integer_write(struct bt_ctf_field_common *field,
- struct bt_ctf_stream_pos *pos,
- enum bt_ctf_byte_order native_byte_order);
-
-BT_HIDDEN
-int bt_ctf_field_floating_point_write(struct bt_ctf_field_common *field,
- struct bt_ctf_stream_pos *pos,
- enum bt_ctf_byte_order native_byte_order);
-
-static inline
-int bt_ctf_stream_pos_access_ok(struct bt_ctf_stream_pos *pos, uint64_t bit_len)
-{
- uint64_t max_len;
-
- if (unlikely(pos->offset == EOF))
- return 0;
-
- if (pos->prot == PROT_READ) {
- /*
- * Reads may only reach up to the "content_size",
- * regardless of the packet_size.
- */
- max_len = pos->offset;
- } else {
- /* Writes may take place up to the end of the packet. */
- max_len = pos->packet_size;
- }
- if (unlikely(pos->offset < 0 || bit_len > INT64_MAX - pos->offset)) {
- return 0;
- }
- if (unlikely(pos->offset + bit_len > max_len))
- return 0;
- return 1;
-}
-
-static inline
-int bt_ctf_stream_pos_move(struct bt_ctf_stream_pos *pos, uint64_t bit_offset)
-{
- int ret = 0;
-
- ret = bt_ctf_stream_pos_access_ok(pos, bit_offset);
- if (!ret) {
- goto end;
- }
- pos->offset += bit_offset;
-end:
- return ret;
-}
-
-static inline
-int bt_ctf_stream_pos_align(struct bt_ctf_stream_pos *pos, uint64_t bit_offset)
-{
- return bt_ctf_stream_pos_move(pos,
- offset_align(pos->offset, bit_offset));
-}
-
-static inline
-char *bt_ctf_stream_pos_get_addr(struct bt_ctf_stream_pos *pos)
-{
- /* Only makes sense to get the address after aligning on CHAR_BIT */
- BT_ASSERT(!(pos->offset % CHAR_BIT));
- return ((char *) mmap_align_addr(pos->base_mma)) +
- pos->mmap_base_offset + (pos->offset / CHAR_BIT);
-}
-
-static inline
-int bt_ctf_stream_pos_init(struct bt_ctf_stream_pos *pos,
- int fd, int open_flags)
-{
- pos->fd = fd;
-
- switch (open_flags & O_ACCMODE) {
- case O_RDONLY:
- pos->prot = PROT_READ;
- pos->flags = MAP_PRIVATE;
- break;
- case O_RDWR:
- pos->prot = PROT_READ | PROT_WRITE;
- pos->flags = MAP_SHARED;
- break;
- default:
- abort();
- }
-
- return 0;
-}
-
-static inline
-int bt_ctf_stream_pos_fini(struct bt_ctf_stream_pos *pos)
-{
- if (pos->base_mma) {
- int ret;
-
- /* unmap old base */
- ret = munmap_align(pos->base_mma);
- if (ret) {
- return -1;
- }
- }
-
- return 0;
-}
-
-BT_HIDDEN
-void bt_ctf_stream_pos_packet_seek(struct bt_ctf_stream_pos *pos, size_t index,
- int whence);
-
-#endif /* BABELTRACE_CTF_WRITER_SERIALIZE_INTERNAL_H */
#include <babeltrace/assert-internal.h>
#include <babeltrace/assert-pre-internal.h>
#include <babeltrace/babeltrace-internal.h>
-#include <babeltrace/ctf-writer/serialize-internal.h>
#include <babeltrace/ctf-writer/stream-internal.h>
#include <babeltrace/ctf-writer/stream.h>
#include <babeltrace/ctf-writer/utils-internal.h>
#include <babeltrace/ctf-writer/object-internal.h>
+#include <babeltrace/ctfser-internal.h>
#include <stdint.h>
struct bt_ctf_stream_common;
/* Array of pointers to bt_ctf_event for the current packet */
GPtrArray *events;
- struct bt_ctf_stream_pos pos;
+ struct bt_ctfser ctfser;
unsigned int flushed_packet_count;
uint64_t discarded_events;
- uint64_t size;
uint64_t last_ts_end;
};
-BT_HIDDEN
-int bt_ctf_stream_set_fd(struct bt_ctf_stream *stream, int fd);
-
BT_HIDDEN
struct bt_ctf_stream *bt_ctf_stream_create_with_id(
struct bt_ctf_stream_class *stream_class,
--- /dev/null
+#ifndef BABELTRACE_CTFSER_INTERNAL_H
+#define BABELTRACE_CTFSER_INTERNAL_H
+
+/*
+ * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017-2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include <babeltrace/compat/mman-internal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <babeltrace/align-internal.h>
+#include <babeltrace/endian-internal.h>
+#include <babeltrace/common-internal.h>
+#include <babeltrace/mmap-align-internal.h>
+#include <babeltrace/types.h>
+#include <babeltrace/assert-internal.h>
+#include <babeltrace/bitfield-internal.h>
+#include <glib.h>
+
+struct bt_ctfser {
+ /* Stream file's descriptor */
+ int fd;
+
+ /* Offset (bytes) of memory map (current packet) in the stream file */
+ off_t mmap_offset;
+
+ /* Offset (bytes) of packet's first byte in the memory map */
+ off_t mmap_base_offset;
+
+ /* Current offset (bits) within current packet */
+ uint64_t offset_in_cur_packet_bits;
+
+ /* Current packet size (bytes) */
+ uint64_t cur_packet_size_bytes;
+
+ /* Previous packet size (bytes) */
+ uint64_t prev_packet_size_bytes;
+
+ /* Current stream size (bytes) */
+ uint64_t stream_size_bytes;
+
+ /* Memory map base address */
+ struct mmap_align *base_mma;
+
+ /* Stream file's path (for debugging) */
+ GString *path;
+};
+
+union bt_ctfser_int_val {
+ int64_t i;
+ uint64_t u;
+};
+
+/*
+ * Initializes a CTF serializer.
+ *
+ * This function opens the file `path` for writing.
+ */
+BT_HIDDEN
+int bt_ctfser_init(struct bt_ctfser *ctfser, const char *path);
+
+/*
+ * Finalizes a CTF serializer.
+ *
+ * This function truncates the stream file so that there's no extra
+ * padding after the last packet, and then closes the file.
+ */
+BT_HIDDEN
+int bt_ctfser_fini(struct bt_ctfser *ctfser);
+
+/*
+ * Opens a new packet.
+ *
+ * All the next writing functions are performed within this new packet.
+ */
+BT_HIDDEN
+int bt_ctfser_open_packet(struct bt_ctfser *ctfser);
+
+/*
+ * Closes the current packet, making its size `packet_size_bytes`.
+ */
+BT_HIDDEN
+void bt_ctfser_close_current_packet(struct bt_ctfser *ctfser,
+ uint64_t packet_size_bytes);
+
+BT_HIDDEN
+int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser *ctfser);
+
+static inline
+uint64_t _bt_ctfser_cur_packet_size_bits(struct bt_ctfser *ctfser)
+{
+ return ctfser->cur_packet_size_bytes * 8;
+}
+
+static inline
+uint64_t _bt_ctfser_prev_packet_size_bits(struct bt_ctfser *ctfser)
+{
+ return ctfser->prev_packet_size_bytes * 8;
+}
+
+static inline
+uint64_t _bt_ctfser_offset_bytes(struct bt_ctfser *ctfser)
+{
+ return ctfser->offset_in_cur_packet_bits / 8;
+}
+
+static inline
+uint8_t *_bt_ctfser_get_addr(struct bt_ctfser *ctfser)
+{
+ /* Only makes sense to get the address after aligning on byte */
+ BT_ASSERT(ctfser->offset_in_cur_packet_bits % 8 == 0);
+ return ((uint8_t *) mmap_align_addr(ctfser->base_mma)) +
+ ctfser->mmap_base_offset + _bt_ctfser_offset_bytes(ctfser);
+}
+
+static inline
+bool _bt_ctfser_has_space_left(struct bt_ctfser *ctfser, uint64_t size_bits)
+{
+ bool has_space_left = true;
+
+ if (unlikely((ctfser->offset_in_cur_packet_bits + size_bits >
+ _bt_ctfser_cur_packet_size_bits(ctfser)))) {
+ has_space_left = false;
+ goto end;
+ }
+
+ if (unlikely(ctfser->offset_in_cur_packet_bits < 0 || size_bits >
+ UINT64_MAX - ctfser->offset_in_cur_packet_bits)) {
+ has_space_left = false;
+ goto end;
+ }
+
+end:
+ return has_space_left;
+}
+
+static inline
+void _bt_ctfser_incr_offset(struct bt_ctfser *ctfser, uint64_t size_bits)
+{
+ BT_ASSERT(_bt_ctfser_has_space_left(ctfser, size_bits));
+ ctfser->offset_in_cur_packet_bits += size_bits;
+}
+
+/*
+ * Aligns the current offset within the current packet to
+ * `alignment_bits` bits (power of two, > 0).
+ */
+static inline
+int bt_ctfser_align_offset_in_current_packet(struct bt_ctfser *ctfser,
+ uint64_t alignment_bits)
+{
+ int ret = 0;
+ uint64_t align_size_bits;
+
+ BT_ASSERT(alignment_bits > 0);
+ align_size_bits = ALIGN(ctfser->offset_in_cur_packet_bits,
+ alignment_bits) - ctfser->offset_in_cur_packet_bits;
+
+ if (unlikely(!_bt_ctfser_has_space_left(ctfser, align_size_bits))) {
+ ret = _bt_ctfser_increase_cur_packet_size(ctfser);
+ if (unlikely(ret)) {
+ goto end;
+ }
+ }
+
+ _bt_ctfser_incr_offset(ctfser, align_size_bits);
+
+end:
+ return ret;
+}
+
+static inline
+int _bt_ctfser_write_byte_aligned_int_no_align(struct bt_ctfser *ctfser,
+ union bt_ctfser_int_val value,
+ unsigned int size_bits, bool is_signed, int byte_order)
+{
+ int ret = 0;
+
+ /* Reverse byte order? */
+ bool rbo = byte_order != BYTE_ORDER;
+
+ BT_ASSERT(size_bits % 8 == 0);
+ BT_ASSERT(_bt_ctfser_has_space_left(ctfser, size_bits));
+
+ if (!is_signed) {
+ switch (size_bits) {
+ case 8:
+ {
+ uint8_t v = (uint8_t) value.u;
+
+ memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+ break;
+ }
+ case 16:
+ {
+ uint16_t v = (uint16_t) value.u;
+
+ if (rbo) {
+ v = GUINT16_SWAP_LE_BE(v);
+ }
+
+ memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+ break;
+ }
+ case 32:
+ {
+ uint32_t v = (uint32_t) value.u;
+
+ if (rbo) {
+ v = GUINT32_SWAP_LE_BE(v);
+ }
+
+ memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+ break;
+ }
+ case 64:
+ {
+ uint64_t v = (uint64_t) value.u;
+
+ if (rbo) {
+ v = GUINT64_SWAP_LE_BE(v);
+ }
+
+ memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+ break;
+ }
+ default:
+ abort();
+ }
+ } else {
+ switch (size_bits) {
+ case 8:
+ {
+ int8_t v = (int8_t) value.i;
+
+ memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+ break;
+ }
+ case 16:
+ {
+ int16_t v = (int16_t) value.i;
+
+ if (rbo) {
+ v = GUINT16_SWAP_LE_BE(v);
+ }
+
+ memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+ break;
+ }
+ case 32:
+ {
+ int32_t v = (int32_t) value.i;
+
+ if (rbo) {
+ v = GUINT32_SWAP_LE_BE(v);
+ }
+
+ memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+ break;
+ }
+ case 64:
+ {
+ int64_t v = (int64_t) value.i;
+
+ if (rbo) {
+ v = GUINT64_SWAP_LE_BE(v);
+ }
+
+ memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+ break;
+ }
+ default:
+ abort();
+ }
+ }
+
+ _bt_ctfser_incr_offset(ctfser, size_bits);
+ return ret;
+}
+
+/*
+ * Writes an integer known to have an alignment that is >= 8 at the
+ * current offset within the current packet.
+ */
+static inline
+int bt_ctfser_write_byte_aligned_int(struct bt_ctfser *ctfser,
+ union bt_ctfser_int_val value, unsigned int alignment_bits,
+ unsigned int size_bits, bool is_signed, int byte_order)
+{
+ int ret;
+
+ BT_ASSERT(alignment_bits % 8 == 0);
+ ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
+ if (unlikely(ret)) {
+ goto end;
+ }
+
+ if (unlikely(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
+ ret = _bt_ctfser_increase_cur_packet_size(ctfser);
+ if (unlikely(ret)) {
+ goto end;
+ }
+ }
+
+ ret = _bt_ctfser_write_byte_aligned_int_no_align(ctfser, value,
+ size_bits, is_signed, byte_order);
+ if (unlikely(ret)) {
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+/*
+ * Writes an integer at the current offset within the current packet.
+ */
+static inline
+int bt_ctfser_write_int(struct bt_ctfser *ctfser, union bt_ctfser_int_val value,
+ unsigned int alignment_bits, unsigned int size_bits, bool is_signed,
+ int byte_order)
+{
+ int ret = 0;
+
+ ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
+ if (unlikely(ret)) {
+ goto end;
+ }
+
+ if (unlikely(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
+ ret = _bt_ctfser_increase_cur_packet_size(ctfser);
+ if (unlikely(ret)) {
+ goto end;
+ }
+ }
+
+ if (alignment_bits % 8 == 0 && size_bits % 8 == 0) {
+ ret = _bt_ctfser_write_byte_aligned_int_no_align(ctfser, value,
+ size_bits, is_signed, byte_order);
+ goto end;
+ }
+
+ if (!is_signed) {
+ if (byte_order == LITTLE_ENDIAN) {
+ bt_bitfield_write_le(mmap_align_addr(ctfser->base_mma) +
+ ctfser->mmap_base_offset, uint8_t,
+ ctfser->offset_in_cur_packet_bits, size_bits,
+ value.u);
+ } else {
+ bt_bitfield_write_be(mmap_align_addr(ctfser->base_mma) +
+ ctfser->mmap_base_offset, uint8_t,
+ ctfser->offset_in_cur_packet_bits, size_bits,
+ value.u);
+ }
+ } else {
+ if (byte_order == LITTLE_ENDIAN) {
+ bt_bitfield_write_le(mmap_align_addr(ctfser->base_mma) +
+ ctfser->mmap_base_offset, uint8_t,
+ ctfser->offset_in_cur_packet_bits, size_bits,
+ value.i);
+ } else {
+ bt_bitfield_write_be(mmap_align_addr(ctfser->base_mma) +
+ ctfser->mmap_base_offset, uint8_t,
+ ctfser->offset_in_cur_packet_bits, size_bits,
+ value.i);
+ }
+ }
+
+ _bt_ctfser_incr_offset(ctfser, size_bits);
+
+end:
+ return ret;
+}
+
+/*
+ * Writes a 32-bit floating point number at the current offset within
+ * the current packet.
+ */
+static inline
+int bt_ctfser_write_float32(struct bt_ctfser *ctfser, double value,
+ unsigned int alignment_bits, int byte_order)
+{
+ union bt_ctfser_int_val int_value;
+ union u32f {
+ uint32_t u;
+ float f;
+ } u32f;
+
+ u32f.f = (float) value;
+ int_value.u = u32f.u;
+ return bt_ctfser_write_int(ctfser, int_value, alignment_bits,
+ 32, false, byte_order);
+}
+
+/*
+ * Writes a 64-bit floating point number at the current offset within
+ * the current packet.
+ */
+static inline
+int bt_ctfser_write_float64(struct bt_ctfser *ctfser, double value,
+ unsigned int alignment_bits, int byte_order)
+{
+ union bt_ctfser_int_val int_value;
+ union u64f {
+ uint64_t u;
+ float f;
+ } u64f;
+
+ u64f.f = value;
+ int_value.u = u64f.u;
+ return bt_ctfser_write_int(ctfser, int_value, alignment_bits,
+ 64, false, byte_order);
+}
+
+/*
+ * Writes a C string, including the terminating null character, at the
+ * current offset within the current packet.
+ */
+static inline
+int bt_ctfser_write_string(struct bt_ctfser *ctfser, const char *value)
+{
+ int ret = 0;
+ const char *at = value;
+
+ ret = bt_ctfser_align_offset_in_current_packet(ctfser, 8);
+ if (unlikely(ret)) {
+ goto end;
+ }
+
+ while (true) {
+ if (unlikely(!_bt_ctfser_has_space_left(ctfser, 8))) {
+ ret = _bt_ctfser_increase_cur_packet_size(ctfser);
+ if (unlikely(ret)) {
+ goto end;
+ }
+ }
+
+ memcpy(_bt_ctfser_get_addr(ctfser), at, sizeof(*at));
+ _bt_ctfser_incr_offset(ctfser, 8);
+
+ if (unlikely(*at == '\0')) {
+ break;
+ }
+
+ at++;
+ }
+
+end:
+ return ret;
+}
+
+/*
+ * Returns the current offset within the current packet (bits).
+ */
+static inline
+uint64_t bt_ctfser_get_offset_in_current_packet_bits(struct bt_ctfser *ctfser)
+{
+ return ctfser->offset_in_cur_packet_bits;
+}
+
+/*
+ * Sets the current offset within the current packet (bits).
+ */
+static inline
+void bt_ctfser_set_offset_in_current_packet_bits(struct bt_ctfser *ctfser,
+ uint64_t offset_bits)
+{
+ BT_ASSERT(offset_bits <= _bt_ctfser_cur_packet_size_bits(ctfser));
+ ctfser->offset_in_cur_packet_bits = offset_bits;
+}
+
+#endif /* BABELTRACE_CTFSER_INTERNAL_H */
ctf-writer/libctf-writer.la \
$(top_builddir)/logging/libbabeltrace-logging.la \
$(top_builddir)/common/libbabeltrace-common.la \
+ $(top_builddir)/ctfser/libbabeltrace-ctfser.la \
$(top_builddir)/compat/libcompat.la
if ENABLE_BUILT_IN_PYTHON_PLUGIN_SUPPORT
ctf-writer/libctf-writer.la \
$(top_builddir)/logging/libbabeltrace-logging.la \
$(top_builddir)/common/libbabeltrace-common.la \
+ $(top_builddir)/ctfser/libbabeltrace-ctfser.la \
$(top_builddir)/compat/libcompat.la
object.c \
object-pool.c \
resolve.c \
- serialize.c \
stream.c \
stream-class.c \
trace.c \
BT_HIDDEN
int bt_ctf_event_serialize(struct bt_ctf_event *event,
- struct bt_ctf_stream_pos *pos,
+ struct bt_ctfser *ctfser,
enum bt_ctf_byte_order native_byte_order)
{
int ret = 0;
BT_ASSERT(event);
- BT_ASSERT(pos);
+ BT_ASSERT(ctfser);
BT_LOGV_STR("Serializing event's context field.");
if (event->common.context_field) {
ret = bt_ctf_field_serialize_recursive(
- (void *) event->common.context_field, pos,
+ (void *) event->common.context_field, ctfser,
native_byte_order);
if (ret) {
BT_LOGW("Cannot serialize event's context field: "
BT_LOGV_STR("Serializing event's payload field.");
if (event->common.payload_field) {
ret = bt_ctf_field_serialize_recursive(
- (void *) event->common.payload_field, pos,
+ (void *) event->common.payload_field, ctfser,
native_byte_order);
if (ret) {
BT_LOGW("Cannot serialize event's payload field: "
#include <babeltrace/compiler-internal.h>
#include <babeltrace/ctf-writer/field-types-internal.h>
#include <babeltrace/ctf-writer/fields-internal.h>
-#include <babeltrace/ctf-writer/serialize-internal.h>
#include <babeltrace/endian-internal.h>
#include <babeltrace/ctf-writer/object-internal.h>
#include <babeltrace/ctf-writer/object.h>
+#include <babeltrace/ctfser-internal.h>
#include <float.h>
#include <inttypes.h>
#include <inttypes.h>
};
typedef int (*bt_ctf_field_serialize_recursive_func)(
- struct bt_ctf_field_common *, struct bt_ctf_stream_pos *,
+ struct bt_ctf_field_common *, struct bt_ctfser *,
enum bt_ctf_byte_order);
static
BT_HIDDEN
int bt_ctf_field_serialize_recursive(struct bt_ctf_field *field,
- struct bt_ctf_stream_pos *pos,
+ struct bt_ctfser *ctfser,
enum bt_ctf_byte_order native_byte_order)
{
struct bt_ctf_field_common *field_common = (void *) field;
bt_ctf_field_serialize_recursive_func serialize_func;
- BT_ASSERT(pos);
+ BT_ASSERT(ctfser);
BT_ASSERT_PRE_NON_NULL(field, "Field");
BT_ASSERT(field_common->spec.writer.serialize_func);
serialize_func = field_common->spec.writer.serialize_func;
- return serialize_func(field_common, pos,
+ return serialize_func(field_common, ctfser,
native_byte_order);
}
static
-int increase_packet_size(struct bt_ctf_stream_pos *pos)
+int bt_ctf_field_integer_serialize(struct bt_ctf_field_common *field,
+ struct bt_ctfser *ctfser,
+ enum bt_ctf_byte_order native_byte_order)
{
int ret;
+ struct bt_ctf_field_type_common_integer *int_type =
+ BT_CTF_FROM_COMMON(field->type);
+ struct bt_ctf_field_common_integer *int_field =
+ BT_CTF_FROM_COMMON(field);
+ enum bt_ctf_byte_order byte_order;
+ union bt_ctfser_int_val value;
- BT_ASSERT(pos);
- BT_LOGV("Increasing packet size: pos-offset=%" PRId64 ", "
- "cur-packet-size=%" PRIu64,
- pos->offset, pos->packet_size);
- ret = munmap_align(pos->base_mma);
- if (ret) {
- BT_LOGE_ERRNO("Failed to perform an aligned memory unmapping",
- ": ret=%d", ret);
- goto end;
+ BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Integer field");
+ BT_LOGV("Serializing CTF writer integer field: addr=%p, native-bo=%s",
+ field,
+ bt_ctf_byte_order_string(native_byte_order));
+ byte_order = int_type->user_byte_order;
+ if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
+ byte_order = native_byte_order;
}
- pos->packet_size += PACKET_LEN_INCREMENT;
- do {
- ret = bt_posix_fallocate(pos->fd, pos->mmap_offset,
- pos->packet_size / CHAR_BIT);
- } while (ret == EINTR);
- if (ret) {
- BT_LOGE_ERRNO("Failed to preallocate memory space",
- ": ret=%d", ret);
- errno = EINTR;
- ret = -1;
+ value.i = int_field->payload.signd;
+ value.u = int_field->payload.unsignd;
+ ret = bt_ctfser_write_int(ctfser, value, int_type->common.alignment,
+ int_type->size, int_type->is_signed,
+ byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
+ LITTLE_ENDIAN : BIG_ENDIAN);
+ if (unlikely(ret)) {
+ BT_LOGE("Cannot serialize integer field: ret=%d", ret);
goto end;
}
- pos->base_mma = mmap_align(pos->packet_size / CHAR_BIT, pos->prot,
- pos->flags, pos->fd, pos->mmap_offset);
- if (pos->base_mma == MAP_FAILED) {
- BT_LOGE_ERRNO("Failed to perform an aligned memory mapping",
- ": ret=%d", ret);
- ret = -1;
- }
-
- BT_LOGV("Increased packet size: pos-offset=%" PRId64 ", "
- "new-packet-size=%" PRIu64,
- pos->offset, pos->packet_size);
- BT_ASSERT(pos->packet_size % 8 == 0);
-
-end:
- return ret;
-}
-
-static
-int bt_ctf_field_integer_serialize(struct bt_ctf_field_common *field,
- struct bt_ctf_stream_pos *pos,
- enum bt_ctf_byte_order native_byte_order)
-{
- int ret = 0;
-
- BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Integer field");
- BT_LOGV("Serializing CTF writer integer field: addr=%p, pos-offset=%" PRId64 ", "
- "native-bo=%s", field, pos->offset,
- bt_ctf_byte_order_string((int) native_byte_order));
-
-retry:
- ret = bt_ctf_field_integer_write(field, pos, native_byte_order);
- if (ret == -EFAULT) {
- /*
- * The field is too large to fit in the current packet's
- * remaining space. Bump the packet size and retry.
- */
- ret = increase_packet_size(pos);
- if (ret) {
- BT_LOGE("Cannot increase packet size: ret=%d", ret);
- goto end;
- }
- goto retry;
- }
-
end:
return ret;
}
static
-int bt_ctf_field_enumeration_serialize_recursive(struct bt_ctf_field_common *field,
- struct bt_ctf_stream_pos *pos,
+int bt_ctf_field_enumeration_serialize_recursive(
+ struct bt_ctf_field_common *field, struct bt_ctfser *ctfser,
enum bt_ctf_byte_order native_byte_order)
{
struct bt_ctf_field_enumeration *enumeration = (void *) field;
- BT_LOGV("Serializing enumeration field: addr=%p, pos-offset=%" PRId64 ", "
- "native-bo=%s", field, pos->offset,
- bt_ctf_byte_order_string((int) native_byte_order));
+ BT_LOGV("Serializing enumeration field: addr=%p, native-bo=%s",
+ field, bt_ctf_byte_order_string(native_byte_order));
BT_LOGV_STR("Serializing enumeration field's payload field.");
return bt_ctf_field_serialize_recursive(
- (void *) enumeration->container, pos, native_byte_order);
+ (void *) enumeration->container, ctfser, native_byte_order);
}
static
int bt_ctf_field_floating_point_serialize(struct bt_ctf_field_common *field,
- struct bt_ctf_stream_pos *pos,
+ struct bt_ctfser *ctfser,
enum bt_ctf_byte_order native_byte_order)
{
- int ret = 0;
+ int ret = -1;
+ struct bt_ctf_field_type_common_floating_point *flt_type =
+ BT_CTF_FROM_COMMON(field->type);
+ struct bt_ctf_field_common_floating_point *flt_field = BT_CTF_FROM_COMMON(field);
+ enum bt_ctf_byte_order byte_order;
BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field");
- BT_LOGV("Serializing floating point number field: addr=%p, pos-offset=%" PRId64 ", "
- "native-bo=%s", field, pos->offset,
- bt_ctf_byte_order_string((int) native_byte_order));
+ BT_LOGV("Serializing floating point number field: "
+ "addr=%p, native-bo=%s", field,
+ bt_ctf_byte_order_string(native_byte_order));
-retry:
- ret = bt_ctf_field_floating_point_write(field, pos,
- native_byte_order);
- if (ret == -EFAULT) {
- /*
- * The field is too large to fit in the current packet's
- * remaining space. Bump the packet size and retry.
- */
- ret = increase_packet_size(pos);
- if (ret) {
- BT_LOGE("Cannot increase packet size: ret=%d", ret);
- goto end;
- }
- goto retry;
+ byte_order = flt_type->user_byte_order;
+ if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
+ byte_order = native_byte_order;
+ }
+
+ if (flt_type->mant_dig == FLT_MANT_DIG) {
+ ret = bt_ctfser_write_float32(ctfser, flt_field->payload,
+ flt_type->common.alignment,
+ byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
+ LITTLE_ENDIAN : BIG_ENDIAN);
+ } else if (flt_type->mant_dig == DBL_MANT_DIG) {
+ ret = bt_ctfser_write_float64(ctfser, flt_field->payload,
+ flt_type->common.alignment,
+ byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
+ LITTLE_ENDIAN : BIG_ENDIAN);
+ } else {
+ abort();
+ }
+
+ if (unlikely(ret)) {
+ BT_LOGE("Cannot serialize floating point number field: "
+ "ret=%d", ret);
+ goto end;
}
end:
static
int bt_ctf_field_structure_serialize_recursive(struct bt_ctf_field_common *field,
- struct bt_ctf_stream_pos *pos,
+ struct bt_ctfser *ctfser,
enum bt_ctf_byte_order native_byte_order)
{
int64_t i;
- int ret = 0;
+ int ret;
struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
- BT_LOGV("Serializing structure field: addr=%p, pos-offset=%" PRId64 ", "
- "native-bo=%s", field, pos->offset,
- bt_ctf_byte_order_string((int) native_byte_order));
-
- while (!bt_ctf_stream_pos_access_ok(pos,
- offset_align(pos->offset, field->type->alignment))) {
- ret = increase_packet_size(pos);
- if (ret) {
- BT_LOGE("Cannot increase packet size: ret=%d", ret);
- goto end;
- }
- }
-
- if (!bt_ctf_stream_pos_align(pos, field->type->alignment)) {
- BT_LOGE("Cannot align packet's position: pos-offset=%" PRId64 ", "
- "align=%u", pos->offset, field->type->alignment);
- ret = -1;
+ BT_LOGV("Serializing structure field: addr=%p, native-bo=%s",
+ field, bt_ctf_byte_order_string(native_byte_order));
+ ret = bt_ctfser_align_offset_in_current_packet(ctfser,
+ field->type->alignment);
+ if (unlikely(ret)) {
+ BT_LOGE("Cannot align offset before serializing structure field: "
+ "ret=%d", ret);
goto end;
}
structure->fields, i);
const char *field_name = NULL;
- BT_LOGV("Serializing structure field's field: pos-offset=%" PRId64 ", "
- "field-addr=%p, index=%" PRId64,
- pos->offset, member, i);
+ BT_LOGV("Serializing structure field's field: ser-offset=%" PRIu64 ", "
+ "field-addr=%p, index=%" PRIu64,
+ bt_ctfser_get_offset_in_current_packet_bits(ctfser),
+ member, i);
- if (!member) {
+ if (unlikely(!member)) {
ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
field->type, &field_name, NULL, i);
BT_ASSERT(ret == 0);
goto end;
}
- ret = bt_ctf_field_serialize_recursive((void *) member, pos,
+ ret = bt_ctf_field_serialize_recursive((void *) member, ctfser,
native_byte_order);
- if (ret) {
+ if (unlikely(ret)) {
ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
field->type, &field_name, NULL, i);
BT_ASSERT(ret == 0);
static
int bt_ctf_field_variant_serialize_recursive(struct bt_ctf_field_common *field,
- struct bt_ctf_stream_pos *pos,
+ struct bt_ctfser *ctfser,
enum bt_ctf_byte_order native_byte_order)
{
struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
- BT_LOGV("Serializing variant field: addr=%p, pos-offset=%" PRId64 ", "
- "native-bo=%s", field, pos->offset,
- bt_ctf_byte_order_string((int) native_byte_order));
+ BT_LOGV("Serializing variant field: addr=%p, native-bo=%s",
+ field, bt_ctf_byte_order_string(native_byte_order));
BT_LOGV_STR("Serializing variant field's payload field.");
return bt_ctf_field_serialize_recursive(
- (void *) variant->current_field, pos, native_byte_order);
+ (void *) variant->current_field, ctfser, native_byte_order);
}
static
int bt_ctf_field_array_serialize_recursive(struct bt_ctf_field_common *field,
- struct bt_ctf_stream_pos *pos,
+ struct bt_ctfser *ctfser,
enum bt_ctf_byte_order native_byte_order)
{
int64_t i;
int ret = 0;
struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
- BT_LOGV("Serializing array field: addr=%p, pos-offset=%" PRId64 ", "
- "native-bo=%s", field, pos->offset,
- bt_ctf_byte_order_string((int) native_byte_order));
+ BT_LOGV("Serializing array field: addr=%p, native-bo=%s",
+ field, bt_ctf_byte_order_string(native_byte_order));
for (i = 0; i < array->elements->len; i++) {
struct bt_ctf_field_common *elem_field =
g_ptr_array_index(array->elements, i);
BT_LOGV("Serializing array field's element field: "
- "pos-offset=%" PRId64 ", field-addr=%p, index=%" PRId64,
- pos->offset, elem_field, i);
+ "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64,
+ bt_ctfser_get_offset_in_current_packet_bits(ctfser),
+ elem_field, i);
ret = bt_ctf_field_serialize_recursive(
- (void *) elem_field, pos, native_byte_order);
- if (ret) {
+ (void *) elem_field, ctfser, native_byte_order);
+ if (unlikely(ret)) {
BT_LOGW("Cannot serialize array field's element field: "
"array-field-addr=%p, field-addr=%p, "
"index=%" PRId64, field, elem_field, i);
static
int bt_ctf_field_sequence_serialize_recursive(struct bt_ctf_field_common *field,
- struct bt_ctf_stream_pos *pos,
+ struct bt_ctfser *ctfser,
enum bt_ctf_byte_order native_byte_order)
{
int64_t i;
int ret = 0;
struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
- BT_LOGV("Serializing sequence field: addr=%p, pos-offset=%" PRId64 ", "
- "native-bo=%s", field, pos->offset,
- bt_ctf_byte_order_string((int) native_byte_order));
+ BT_LOGV("Serializing sequence field: addr=%p, native-bo=%s",
+ field, bt_ctf_byte_order_string(native_byte_order));
for (i = 0; i < sequence->elements->len; i++) {
struct bt_ctf_field_common *elem_field =
g_ptr_array_index(sequence->elements, i);
BT_LOGV("Serializing sequence field's element field: "
- "pos-offset=%" PRId64 ", field-addr=%p, index=%" PRId64,
- pos->offset, elem_field, i);
+ "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64,
+ bt_ctfser_get_offset_in_current_packet_bits(ctfser),
+ elem_field, i);
ret = bt_ctf_field_serialize_recursive(
- (void *) elem_field, pos, native_byte_order);
- if (ret) {
+ (void *) elem_field, ctfser, native_byte_order);
+ if (unlikely(ret)) {
BT_LOGW("Cannot serialize sequence field's element field: "
"sequence-field-addr=%p, field-addr=%p, "
"index=%" PRId64, field, elem_field, i);
static
int bt_ctf_field_string_serialize(struct bt_ctf_field_common *field,
- struct bt_ctf_stream_pos *pos,
+ struct bt_ctfser *ctfser,
enum bt_ctf_byte_order native_byte_order)
{
- int64_t i;
- int ret = 0;
+ int ret;
struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
- struct bt_ctf_field_type *character_type =
- get_field_type(FIELD_TYPE_ALIAS_UINT8_T);
- struct bt_ctf_field *character;
BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field");
- BT_LOGV("Serializing string field: addr=%p, pos-offset=%" PRId64 ", "
- "native-bo=%s", field, pos->offset,
- bt_ctf_byte_order_string((int) native_byte_order));
-
- BT_LOGV_STR("Creating character field from string field's character field type.");
- character = bt_ctf_field_create(character_type);
-
- for (i = 0; i < string->size + 1; i++) {
- const uint64_t chr = (uint64_t) ((char *) string->buf->data)[i];
-
- ret = bt_ctf_field_integer_unsigned_set_value(character, chr);
- BT_ASSERT(ret == 0);
- BT_LOGV("Serializing string field's character field: "
- "pos-offset=%" PRId64 ", field-addr=%p, "
- "index=%" PRId64 ", char-int=%" PRIu64,
- pos->offset, character, i, chr);
- ret = bt_ctf_field_integer_serialize(
- (void *) character, pos, native_byte_order);
- if (ret) {
- BT_LOGW_STR("Cannot serialize character field.");
- goto end;
- }
+ BT_LOGV("Serializing string field: addr=%p, native-bo=%s",
+ field, bt_ctf_byte_order_string((int) native_byte_order));
+ ret = bt_ctfser_write_string(ctfser, (const char *) string->buf->data);
+ if (unlikely(ret)) {
+ BT_LOGE("Cannot serialize string field: ret=%d", ret);
+ goto end;
}
end:
- bt_ctf_object_put_ref(character);
- bt_ctf_object_put_ref(character_type);
return ret;
}
+++ /dev/null
-/*
- * serialize.c
- *
- * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * The original author of the serialization functions for Babeltrace 1
- * is Mathieu Desnoyers. Philippe Proulx modified the functions in 2017
- * to use Babeltrace 2 objects.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-SERIALIZE"
-#include <babeltrace/lib-logging-internal.h>
-
-#include <babeltrace/align-internal.h>
-#include <babeltrace/bitfield-internal.h>
-#include <babeltrace/common-internal.h>
-#include <babeltrace/compat/fcntl-internal.h>
-#include <babeltrace/ctf-writer/field-types-internal.h>
-#include <babeltrace/ctf-writer/field-types.h>
-#include <babeltrace/ctf-writer/fields-internal.h>
-#include <babeltrace/ctf-writer/fields.h>
-#include <babeltrace/ctf-writer/serialize-internal.h>
-#include <babeltrace/ctf-writer/utils-internal.h>
-#include <babeltrace/endian-internal.h>
-#include <babeltrace/mmap-align-internal.h>
-#include <babeltrace/types.h>
-#include <glib.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#if (FLT_RADIX != 2)
-# error "Unsupported floating point radix"
-#endif
-
-union intval {
- int64_t signd;
- uint64_t unsignd;
-};
-
-/*
- * The aligned read/write functions are expected to be faster than the
- * bitfield variants. They will be enabled eventually as an
- * optimisation.
- */
-static
-int aligned_integer_write(struct bt_ctf_stream_pos *pos, union intval value,
- unsigned int alignment, unsigned int size, bt_bool is_signed,
- enum bt_ctf_byte_order byte_order)
-{
- /* reverse byte order */
- bt_bool rbo = (byte_order != BT_CTF_MY_BYTE_ORDER);
-
- if (!bt_ctf_stream_pos_align(pos, alignment))
- return -EFAULT;
-
- if (!bt_ctf_stream_pos_access_ok(pos, size))
- return -EFAULT;
-
- BT_ASSERT(!(pos->offset % CHAR_BIT));
- if (!is_signed) {
- switch (size) {
- case 8:
- {
- uint8_t v = value.unsignd;
-
- memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v));
- break;
- }
- case 16:
- {
- uint16_t v = value.unsignd;
-
- if (rbo)
- v = GUINT16_SWAP_LE_BE(v);
- memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v));
- break;
- }
- case 32:
- {
- uint32_t v = value.unsignd;
-
- if (rbo)
- v = GUINT32_SWAP_LE_BE(v);
- memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v));
- break;
- }
- case 64:
- {
- uint64_t v = value.unsignd;
-
- if (rbo)
- v = GUINT64_SWAP_LE_BE(v);
- memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v));
- break;
- }
- default:
- abort();
- }
- } else {
- switch (size) {
- case 8:
- {
- uint8_t v = value.signd;
-
- memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v));
- break;
- }
- case 16:
- {
- int16_t v = value.signd;
-
- if (rbo)
- v = GUINT16_SWAP_LE_BE(v);
- memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v));
- break;
- }
- case 32:
- {
- int32_t v = value.signd;
-
- if (rbo)
- v = GUINT32_SWAP_LE_BE(v);
- memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v));
- break;
- }
- case 64:
- {
- int64_t v = value.signd;
-
- if (rbo)
- v = GUINT64_SWAP_LE_BE(v);
- memcpy(bt_ctf_stream_pos_get_addr(pos), &v, sizeof(v));
- break;
- }
- default:
- abort();
- }
- }
-
- if (!bt_ctf_stream_pos_move(pos, size))
- return -EFAULT;
- return 0;
-}
-
-static
-int integer_write(struct bt_ctf_stream_pos *pos, union intval value,
- unsigned int alignment, unsigned int size, bt_bool is_signed,
- enum bt_ctf_byte_order byte_order)
-{
- if (!(alignment % CHAR_BIT)
- && !(size % CHAR_BIT)) {
- return aligned_integer_write(pos, value, alignment,
- size, is_signed, byte_order);
- }
-
- if (!bt_ctf_stream_pos_align(pos, alignment))
- return -EFAULT;
-
- if (!bt_ctf_stream_pos_access_ok(pos, size))
- return -EFAULT;
-
- if (!is_signed) {
- if (byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN)
- bt_bitfield_write_le(mmap_align_addr(pos->base_mma) +
- pos->mmap_base_offset, unsigned char,
- pos->offset, size, value.unsignd);
- else
- bt_bitfield_write_be(mmap_align_addr(pos->base_mma) +
- pos->mmap_base_offset, unsigned char,
- pos->offset, size, value.unsignd);
- } else {
- if (byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN)
- bt_bitfield_write_le(mmap_align_addr(pos->base_mma) +
- pos->mmap_base_offset, unsigned char,
- pos->offset, size, value.signd);
- else
- bt_bitfield_write_be(mmap_align_addr(pos->base_mma) +
- pos->mmap_base_offset, unsigned char,
- pos->offset, size, value.signd);
- }
-
- if (!bt_ctf_stream_pos_move(pos, size))
- return -EFAULT;
- return 0;
-}
-
-BT_HIDDEN
-int bt_ctf_field_integer_write(struct bt_ctf_field_common *field,
- struct bt_ctf_stream_pos *pos,
- enum bt_ctf_byte_order native_byte_order)
-{
- struct bt_ctf_field_type_common_integer *int_type =
- BT_CTF_FROM_COMMON(field->type);
- struct bt_ctf_field_common_integer *int_field = BT_CTF_FROM_COMMON(field);
- enum bt_ctf_byte_order byte_order;
- union intval value;
-
- byte_order = (int) int_type->user_byte_order;
- if ((int) byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
- byte_order = native_byte_order;
- }
-
- value.signd = int_field->payload.signd;
- value.unsignd = int_field->payload.unsignd;
- return integer_write(pos, value, int_type->common.alignment,
- int_type->size, int_type->is_signed,
- byte_order);
-}
-
-BT_HIDDEN
-int bt_ctf_field_floating_point_write(
- struct bt_ctf_field_common *field,
- struct bt_ctf_stream_pos *pos,
- enum bt_ctf_byte_order native_byte_order)
-{
- struct bt_ctf_field_type_common_floating_point *flt_type =
- BT_CTF_FROM_COMMON(field->type);
- struct bt_ctf_field_common_floating_point *flt_field = BT_CTF_FROM_COMMON(field);
- enum bt_ctf_byte_order byte_order;
- union intval value;
- unsigned int size;
-
- byte_order = (int) flt_type->user_byte_order;
- if ((int) byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
- byte_order = native_byte_order;
- }
-
- if (flt_type->mant_dig == FLT_MANT_DIG) {
- union u32f {
- uint32_t u;
- float f;
- } u32f;
-
- u32f.f = (float) flt_field->payload;
- value.unsignd = u32f.u;
- size = 32;
- } else if (flt_type->mant_dig == DBL_MANT_DIG) {
- union u64d {
- uint64_t u;
- double d;
- } u64d;
-
- u64d.d = flt_field->payload;
- value.unsignd = u64d.u;
- size = 64;
- } else {
- return -EINVAL;
- }
-
- return integer_write(pos, value, flt_type->common.alignment,
- size, BT_FALSE, byte_order);
-}
-
-BT_HIDDEN
-void bt_ctf_stream_pos_packet_seek(struct bt_ctf_stream_pos *pos, size_t index,
- int whence)
-{
- int ret;
-
- BT_ASSERT(whence == SEEK_CUR && index == 0);
-
- if (pos->base_mma) {
- /* unmap old base */
- ret = munmap_align(pos->base_mma);
- if (ret) {
- // FIXME: this can legitimately fail?
- abort();
- }
- pos->base_mma = NULL;
- }
-
- /* The writer will add padding */
- pos->mmap_offset += pos->packet_size / CHAR_BIT;
- pos->packet_size = PACKET_LEN_INCREMENT;
- do {
- ret = bt_posix_fallocate(pos->fd, pos->mmap_offset,
- pos->packet_size / CHAR_BIT);
- } while (ret == EINTR);
- BT_ASSERT(ret == 0);
- pos->offset = 0;
-
- /* map new base. Need mapping length from header. */
- pos->base_mma = mmap_align(pos->packet_size / CHAR_BIT, pos->prot,
- pos->flags, pos->fd, pos->mmap_offset);
- if (pos->base_mma == MAP_FAILED) {
- // FIXME: this can legitimately fail?
- abort();
- }
-}
#include <babeltrace/ctf-writer/trace.h>
#include <babeltrace/ctf-writer/writer-internal.h>
#include <babeltrace/ctf-writer/object.h>
+#include <babeltrace/ctfser-internal.h>
#include <inttypes.h>
#include <stdint.h>
#include <unistd.h>
}
static
-int set_packet_context_packet_size(struct bt_ctf_stream *stream)
+int set_packet_context_packet_size(struct bt_ctf_stream *stream,
+ uint64_t packet_size_bits)
{
int ret = 0;
struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
stream->packet_context, "packet_size");
- BT_ASSERT(stream);
-
- if (!field) {
- /* No packet size field found. Not an error, skip. */
- BT_LOGV("No field named `packet_size` in packet context: skipping: "
- "stream-addr=%p, stream-name=\"%s\"",
- stream, bt_ctf_stream_get_name(stream));
- goto end;
- }
-
- ret = bt_ctf_field_integer_unsigned_set_value(field,
- stream->pos.packet_size);
+ ret = bt_ctf_field_integer_unsigned_set_value(field, packet_size_bits);
if (ret) {
BT_LOGW("Cannot set packet context field's `packet_size` integer field's value: "
"stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
stream, bt_ctf_stream_get_name(stream),
- field, stream->pos.packet_size);
+ field, packet_size_bits);
} else {
BT_LOGV("Set packet context field's `packet_size` field's value: "
"stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
stream, bt_ctf_stream_get_name(stream),
- field, stream->pos.packet_size);
+ field, packet_size_bits);
}
-end:
bt_ctf_object_put_ref(field);
return ret;
}
static
-int set_packet_context_content_size(struct bt_ctf_stream *stream)
+int set_packet_context_content_size(struct bt_ctf_stream *stream,
+ uint64_t content_size_bits)
{
int ret = 0;
struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
goto end;
}
- ret = bt_ctf_field_integer_unsigned_set_value(field,
- stream->pos.offset);
+ ret = bt_ctf_field_integer_unsigned_set_value(field, content_size_bits);
if (ret) {
BT_LOGW("Cannot set packet context field's `content_size` integer field's value: "
- "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRId64,
+ "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
stream, bt_ctf_stream_get_name(stream),
- field, stream->pos.offset);
+ field, content_size_bits);
} else {
BT_LOGV("Set packet context field's `content_size` field's value: "
- "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRId64,
+ "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
stream, bt_ctf_stream_get_name(stream),
- field, stream->pos.offset);
+ field, content_size_bits);
}
end:
}
static
-int auto_populate_packet_context(struct bt_ctf_stream *stream, bool set_ts)
+int auto_populate_packet_context(struct bt_ctf_stream *stream, bool set_ts,
+ uint64_t packet_size_bits, uint64_t content_size_bits)
{
int ret = 0;
goto end;
}
- ret = set_packet_context_packet_size(stream);
+ ret = set_packet_context_packet_size(stream, packet_size_bits);
if (ret) {
BT_LOGW("Cannot set packet context's packet size field: "
"stream-addr=%p, stream-name=\"%s\"",
goto end;
}
- ret = set_packet_context_content_size(stream);
+ ret = set_packet_context_content_size(stream, content_size_bits);
if (ret) {
BT_LOGW("Cannot set packet context's content size field: "
"stream-addr=%p, stream-name=\"%s\"",
int create_stream_file(struct bt_ctf_writer *writer,
struct bt_ctf_stream *stream)
{
- int fd;
+ int ret = 0;
GString *filename = g_string_new(NULL);
int64_t stream_class_id;
char *file_path = NULL;
file_path = g_build_filename(writer->path->str, filename->str, NULL);
if (file_path == NULL) {
- fd = -1;
+ ret = -1;
goto end;
}
- fd = open(file_path,
- O_RDWR | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ ret = bt_ctfser_init(&stream->ctfser, file_path);
g_free(file_path);
- if (fd < 0) {
- BT_LOGW_ERRNO("Failed to open stream file for writing",
- ": file_path=\"%s\", filename=\"%s\", ret=%d",
- file_path, filename->str, fd);
+ if (ret) {
+ /* bt_ctfser_init() logs errors */
goto end;
}
BT_LOGD("Created stream file for writing: "
"stream-addr=%p, stream-name=\"%s\", "
- "filename=\"%s\", fd=%d", stream, bt_ctf_stream_get_name(stream),
- filename->str, fd);
+ "filename=\"%s\"", stream, bt_ctf_stream_get_name(stream),
+ filename->str);
end:
g_string_free(filename, TRUE);
- return fd;
-}
-
-static
-void set_stream_fd(struct bt_ctf_stream *stream, int fd)
-{
- (void) bt_ctf_stream_pos_init(&stream->pos, fd, O_RDWR);
- stream->pos.fd = fd;
+ return ret;
}
BT_HIDDEN
goto error;
}
- stream->pos.fd = -1;
writer = (struct bt_ctf_writer *)
bt_ctf_object_get_parent(&trace->common.base);
stream->last_ts_end = -1ULL;
goto error;
}
- set_stream_fd(stream, fd);
-
/* Freeze the writer */
BT_LOGD_STR("Freezing stream's CTF writer.");
bt_ctf_writer_freeze(writer);
goto end;
}
- if (stream->pos.fd < 0) {
- BT_LOGW("Invalid parameter: stream is not a CTF writer stream: "
- "stream-addr=%p, stream-name=\"%s\"",
- stream, bt_ctf_stream_get_name(stream));
- ret = -1;
- goto end;
- }
-
*count = (uint64_t) stream->discarded_events;
end:
goto end;
}
- if (stream->pos.fd < 0) {
- BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
- goto end;
- }
-
events_discarded_field = bt_ctf_field_structure_get_field_by_name(
stream->packet_context, "events_discarded");
if (!events_discarded_field) {
goto end;
}
- if (stream->pos.fd < 0) {
- BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
- ret = -1;
- goto end;
- }
-
BT_LOGV("Appending event to stream: "
"stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
"event-class-name=\"%s\", event-class-id=%" PRId64,
goto end;
}
- if (stream->pos.fd < 0) {
- BT_LOGW("Invalid parameter: stream is not a CTF writer stream: "
- "stream-addr=%p, stream-name=\"%s\"", stream,
- bt_ctf_stream_get_name(stream));
- goto end;
- }
-
packet_context = stream->packet_context;
if (packet_context) {
bt_ctf_object_get_ref(packet_context);
goto end;
}
- if (stream->pos.fd < 0) {
- BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
- ret = -1;
- goto end;
- }
-
field_type = bt_ctf_field_get_type(field);
if (bt_ctf_field_type_common_compare((void *) field_type,
stream->common.stream_class->packet_context_field_type)) {
goto end;
}
- if (stream->pos.fd < 0) {
- BT_LOGW("Invalid parameter: stream is not a CTF writer stream: "
- "stream-addr=%p, stream-name=\"%s\"", stream,
- bt_ctf_stream_get_name(stream));
- goto end;
- }
-
packet_header = stream->packet_header;
if (packet_header) {
bt_ctf_object_get_ref(packet_header);
goto end;
}
- if (stream->pos.fd < 0) {
- BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
- ret = -1;
- goto end;
- }
-
trace = (struct bt_ctf_trace *)
bt_ctf_object_get_parent(&stream->common.base);
{
int ret = 0;
size_t i;
- struct bt_ctf_stream_pos packet_context_pos;
+ uint64_t packet_context_offset_bits;
struct bt_ctf_trace *trace;
enum bt_ctf_byte_order native_byte_order;
bool has_packet_size = false;
+ uint64_t packet_size_bits = 0;
+ uint64_t content_size_bits = 0;
if (!stream) {
BT_LOGW_STR("Invalid parameter: stream is NULL.");
goto end_no_stream;
}
- if (stream->pos.fd < 0) {
- BT_LOGW_STR("Invalid parameter: stream is not a CTF writer stream.");
- ret = -1;
- goto end;
- }
-
if (stream->packet_context) {
struct bt_ctf_field *packet_size_field;
goto end;
}
- ret = auto_populate_packet_context(stream, true);
+ /* Initialize packet/content sizes to `0`; we will overwrite later */
+ ret = auto_populate_packet_context(stream, true, 0, 0);
if (ret) {
BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
ret = -1;
goto end;
}
- /* mmap the next packet */
- BT_LOGV("Seeking to the next packet: pos-offset=%" PRId64,
- stream->pos.offset);
- bt_ctf_stream_pos_packet_seek(&stream->pos, 0, SEEK_CUR);
- BT_ASSERT(stream->pos.packet_size % 8 == 0);
+ ret = bt_ctfser_open_packet(&stream->ctfser);
+ if (ret) {
+ /* bt_ctfser_open_packet() logs errors */
+ ret = -1;
+ goto end;
+ }
if (stream->packet_header) {
- BT_LOGV_STR("Serializing packet header field.");
+ BT_LOGV_STR("Serializing packet header field (initial).");
ret = bt_ctf_field_serialize_recursive(stream->packet_header,
- &stream->pos, native_byte_order);
+ &stream->ctfser, native_byte_order);
if (ret) {
BT_LOGW("Cannot serialize stream's packet header field: "
"field-addr=%p", stream->packet_header);
}
if (stream->packet_context) {
+ /* Save packet context's position to overwrite it later */
+ packet_context_offset_bits =
+ bt_ctfser_get_offset_in_current_packet_bits(
+ &stream->ctfser);
+
/* Write packet context */
- memcpy(&packet_context_pos, &stream->pos,
- sizeof(packet_context_pos));
- BT_LOGV_STR("Serializing packet context field.");
+ BT_LOGV_STR("Serializing packet context field (initial).");
ret = bt_ctf_field_serialize_recursive(stream->packet_context,
- &stream->pos, native_byte_order);
+ &stream->ctfser, native_byte_order);
if (ret) {
BT_LOGW("Cannot serialize stream's packet context field: "
"field-addr=%p", stream->packet_context);
BT_LOGV("Serializing event: index=%zu, event-addr=%p, "
"event-class-name=\"%s\", event-class-id=%" PRId64 ", "
- "pos-offset=%" PRId64 ", packet-size=%" PRIu64,
+ "ser-offset=%" PRIu64,
i, event, bt_ctf_event_class_get_name(event_class),
bt_ctf_event_class_get_id(event_class),
- stream->pos.offset, stream->pos.packet_size);
+ bt_ctfser_get_offset_in_current_packet_bits(
+ &stream->ctfser));
/* Write event header */
if (event->common.header_field) {
BT_LOGV_STR("Serializing event's header field.");
ret = bt_ctf_field_serialize_recursive(
(void *) event->common.header_field->field,
- &stream->pos, native_byte_order);
+ &stream->ctfser, native_byte_order);
if (ret) {
BT_LOGW("Cannot serialize event's header field: "
"field-addr=%p",
BT_LOGV_STR("Serializing event's stream event context field.");
ret = bt_ctf_field_serialize_recursive(
(void *) event->common.stream_event_context_field,
- &stream->pos, native_byte_order);
+ &stream->ctfser, native_byte_order);
if (ret) {
BT_LOGW("Cannot serialize event's stream event context field: "
"field-addr=%p",
}
/* Write event content */
- ret = bt_ctf_event_serialize(event,
- &stream->pos, native_byte_order);
+ ret = bt_ctf_event_serialize(event, &stream->ctfser,
+ native_byte_order);
if (ret) {
/* bt_ctf_event_serialize() logs errors */
goto end;
}
}
- if (!has_packet_size && stream->pos.offset % 8 != 0) {
+ content_size_bits = bt_ctfser_get_offset_in_current_packet_bits(
+ &stream->ctfser);
+
+ if (!has_packet_size && content_size_bits % 8 != 0) {
BT_LOGW("Stream's packet context field type has no `packet_size` field, "
"but current content size is not a multiple of 8 bits: "
- "content-size=%" PRId64 ", "
+ "content-size=%" PRIu64 ", "
"packet-size=%" PRIu64,
- stream->pos.offset,
- stream->pos.packet_size);
+ content_size_bits,
+ packet_size_bits);
ret = -1;
goto end;
}
- BT_ASSERT(stream->pos.packet_size % 8 == 0);
-
- /*
- * Remove extra padding bytes.
- */
- stream->pos.packet_size = (stream->pos.offset + 7) & ~7;
+ /* Set packet size; make it a multiple of 8 */
+ packet_size_bits = (content_size_bits + 7) & ~UINT64_C(7);
if (stream->packet_context) {
/*
- * The whole packet is serialized at this point. Make sure that,
- * if `packet_size` is missing, the current content size is
- * equal to the current packet size.
+ * The whole packet is serialized at this point. Make
+ * sure that, if `packet_size` is missing, the current
+ * content size is equal to the current packet size.
*/
- struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
- stream->packet_context, "content_size");
+ struct bt_ctf_field *field =
+ bt_ctf_field_structure_get_field_by_name(
+ stream->packet_context, "content_size");
bt_ctf_object_put_ref(field);
if (!field) {
- if (stream->pos.offset != stream->pos.packet_size) {
+ if (content_size_bits != packet_size_bits) {
BT_LOGW("Stream's packet context's `content_size` field is missing, "
"but current packet's content size is not equal to its packet size: "
- "content-size=%" PRId64 ", "
+ "content-size=%" PRIu64 ", "
"packet-size=%" PRIu64,
- stream->pos.offset,
- stream->pos.packet_size);
+ bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser),
+ packet_size_bits);
ret = -1;
goto end;
}
* Overwrite the packet context now that the stream
* position's packet and content sizes have the correct
* values.
- *
- * Copy base_mma as the packet may have been remapped
- * (e.g. when a packet is resized).
*/
- packet_context_pos.base_mma = stream->pos.base_mma;
- ret = auto_populate_packet_context(stream, false);
+ bt_ctfser_set_offset_in_current_packet_bits(&stream->ctfser,
+ packet_context_offset_bits);
+ ret = auto_populate_packet_context(stream, false,
+ packet_size_bits, content_size_bits);
if (ret) {
BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
ret = -1;
BT_LOGV("Rewriting (serializing) packet context field.");
ret = bt_ctf_field_serialize_recursive(stream->packet_context,
- &packet_context_pos, native_byte_order);
+ &stream->ctfser, native_byte_order);
if (ret) {
BT_LOGW("Cannot serialize stream's packet context field: "
"field-addr=%p", stream->packet_context);
g_ptr_array_set_size(stream->events, 0);
stream->flushed_packet_count++;
- stream->size += stream->pos.packet_size / CHAR_BIT;
+ bt_ctfser_close_current_packet(&stream->ctfser, packet_size_bits / 8);
end:
/* Reset automatically-set fields. */
reset_structure_field(stream->packet_context, "events_discarded");
}
- if (ret < 0) {
- /*
- * We failed to write the packet. Its size is therefore set to 0
- * to ensure the next mapping is done in the same place rather
- * than advancing by "stream->pos.packet_size", which would
- * leave a corrupted packet in the trace.
- */
- stream->pos.packet_size = 0;
- } else {
- BT_LOGV("Flushed stream's current packet: content-size=%" PRId64 ", "
- "packet-size=%" PRIu64,
- stream->pos.offset, stream->pos.packet_size);
+ if (ret == 0) {
+ BT_LOGV("Flushed stream's current packet: "
+ "content-size=%" PRIu64 ", packet-size=%" PRIu64,
+ content_size_bits, packet_size_bits);
}
end_no_stream:
stream, bt_ctf_stream_get_name(stream));
bt_ctf_stream_common_finalize(BT_CTF_TO_COMMON(stream));
- (void) bt_ctf_stream_pos_fini(&stream->pos);
-
- if (stream->pos.fd >= 0) {
- int ret;
-
- /*
- * Truncate the file's size to the minimum required to fit the
- * last packet as we might have grown it too much on the last
- * mmap.
- */
- do {
- ret = ftruncate(stream->pos.fd, stream->size);
- } while (ret == -1 && errno == EINTR);
- if (ret) {
- BT_LOGE_ERRNO("Failed to truncate stream file",
- ": ret=%d, size=%" PRIu64,
- ret, (uint64_t) stream->size);
- }
-
- if (close(stream->pos.fd)) {
- BT_LOGE_ERRNO("Failed to close stream file",
- ": ret=%d", ret);
- }
- }
+ bt_ctfser_fini(&stream->ctfser);
if (stream->events) {
BT_LOGD_STR("Putting events.");
}
if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
- byte_order = BT_CTF_MY_BYTE_ORDER;
+ if (BYTE_ORDER == LITTLE_ENDIAN) {
+ byte_order = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN;
+ } else {
+ byte_order = BT_CTF_BYTE_ORDER_BIG_ENDIAN;
+ }
}
ret = bt_ctf_trace_set_native_byte_order(writer->trace,