Start packet mmap work
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 5 May 2011 04:21:35 +0000 (00:21 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 5 May 2011 04:21:35 +0000 (00:21 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
16 files changed:
converter/babeltrace.c
formats/ctf/ctf.c
formats/ctf/metadata/ctf-test/succeed/ctf-embedded-1.txt
formats/ctf/metadata/ctf-visitor-generate-io-struct.c
formats/ctf/types/float.c
include/babeltrace/ctf/metadata.h
include/babeltrace/ctf/types.h
include/babeltrace/types.h
types/array.c
types/enum.c
types/float.c
types/integer.c
types/sequence.c
types/string.c
types/struct.c
types/variant.c

index b603dee53e22a555b0f7b94c9dda7e3651c71ddf..dd6b9a2c40c3f3079a8c920e336eaa16a112058f 100644 (file)
@@ -69,7 +69,8 @@ static void list_formats(FILE *fp)
 
 static void usage(FILE *fp)
 {
-       fprintf(fp, "Babeltrace %u.%u\n\n", BABELTRACE_VERSION_MAJOR,
+       fprintf(fp, "BabelTrace Trace Converter %u.%u\n\n",
+               BABELTRACE_VERSION_MAJOR,
                BABELTRACE_VERSION_MINOR);
        fprintf(fp, "usage : babeltrace [OPTIONS] INPUT OUTPUT\n");
        fprintf(fp, "\n");
@@ -96,6 +97,11 @@ static int parse_options(int argc, char **argv)
        poptContext pc;
        int opt, ret = 0;
 
+       if (argc == 1) {
+               usage(stdout);
+               return 1;       /* exit cleanly */
+       }
+
        pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 0);
        poptReadDefaultConfig(pc, 0);
 
index 9b2f0fbf65dc195b426433de7596f6c18850aba2..0c635d5701a987542409c8c1fcb8346e4e210832 100644 (file)
@@ -20,6 +20,9 @@
 #include <babeltrace/ctf/types.h>
 #include <babeltrace/ctf/metadata.h>
 #include <babeltrace/babeltrace.h>
+#include <inttypes.h>
+#include <uuid/uuid.h>
+#include <sys/mman.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <stdlib.h>
 
-
 #include "metadata/ctf-scanner.h"
 #include "metadata/ctf-parser.h"
 #include "metadata/ctf-ast.h"
 
+/*
+ * We currently simply map a page to read the packet header and packet
+ * context to get the packet length and content length.
+ */
+#define MAX_PACKET_HEADER_LEN  getpagesize()
+#define UUID_LEN 16    /* uuid by value len */
+
 extern int yydebug;
 
 struct trace_descriptor {
@@ -69,6 +78,35 @@ static struct format ctf_format = {
        .close_trace = ctf_close_trace,
 };
 
+void move_pos_slow(struct stream_pos *pos, size_t offset)
+{
+       int ret;
+
+       /*
+        * The caller should never ask for move_pos across packets,
+        * except to get exactly at the beginning of the next packet.
+        */
+       assert(pos->offset + offset == pos->content_size);
+
+       if (pos->base) {
+               /* unmap old base */
+               ret = munmap(pos->base, pos->packet_size);
+               if (ret) {
+                       fprintf(stdout, "Unable to unmap old base: %s.\n",
+                               strerror(errno));
+                       assert(0);
+               }
+       }
+
+       pos->mmap_offset += pos->packet_size / CHAR_BIT;
+       /* map new base. Need mapping length from header. */
+       pos->base = mmap(NULL, MAX_PACKET_HEADER_LEN, PROT_READ,
+                        MAP_PRIVATE, pos->fd, pos->mmap_offset);
+       pos->content_size = 0;  /* Unknown at this point */
+       pos->packet_size = 0;   /* Unknown at this point */
+
+}
+
 /*
  * TODO: for now, we treat the metadata file as a simple text file
  * (without any header nor packets nor padding).
@@ -80,17 +118,17 @@ int ctf_open_trace_metadata_read(struct trace_descriptor *td)
        FILE *fp;
        int ret = 0;
 
-       td->ctf_trace.metadata.fd = openat(td->ctf_trace.dirfd,
+       td->ctf_trace.metadata.pos.fd = openat(td->ctf_trace.dirfd,
                        "metadata", O_RDONLY);
-       if (td->ctf_trace.metadata.fd < 0) {
+       if (td->ctf_trace.metadata.pos.fd < 0) {
                fprintf(stdout, "Unable to open metadata.\n");
-               return td->ctf_trace.metadata.fd;
+               return td->ctf_trace.metadata.pos.fd;
        }
 
        if (babeltrace_debug)
                yydebug = 1;
 
-       fp = fdopen(td->ctf_trace.metadata.fd, "r");
+       fp = fdopen(td->ctf_trace.metadata.pos.fd, "r");
        if (!fp) {
                fprintf(stdout, "Unable to open metadata stream.\n");
                ret = -errno;
@@ -133,7 +171,211 @@ end:
 end_scanner_alloc:
        fclose(fp);
 end_stream:
-       close(td->ctf_trace.metadata.fd);
+       close(td->ctf_trace.metadata.pos.fd);
+       return ret;
+}
+
+
+static
+int create_stream_packet_index(struct trace_descriptor *td,
+                              struct ctf_file_stream *file_stream)
+{
+       struct ctf_stream *stream;
+       int len_index;
+       struct stream_pos *pos;
+       struct stat filestats;
+       struct packet_index packet_index;
+       int first_packet = 1;
+       int ret;
+
+       pos = &file_stream->pos;
+
+       ret = fstat(pos->fd, &filestats);
+       if (ret < 0)
+               return ret;
+
+       for (pos->mmap_offset = 0; pos->mmap_offset < filestats.st_size; ) {
+               uint64_t stream_id = 0;
+
+               if (pos->base) {
+                       /* unmap old base */
+                       ret = munmap(pos->base, pos->packet_size);
+                       if (ret) {
+                               fprintf(stdout, "Unable to unmap old base: %s.\n",
+                                       strerror(errno));
+                               return ret;
+                       }
+               }
+               /* map new base. Need mapping length from header. */
+               pos->base = mmap(NULL, MAX_PACKET_HEADER_LEN, PROT_READ,
+                                MAP_PRIVATE, pos->fd, pos->mmap_offset);
+               pos->content_size = 0;  /* Unknown at this point */
+               pos->packet_size = 0;   /* Unknown at this point */
+               pos->offset = 0;        /* Position of the packet header */
+
+               /* read and check header, set stream id (and check) */
+               if (td->ctf_trace.packet_header) {
+                       /* Read packet header */
+                       td->ctf_trace.packet_header->p.declaration->copy(NULL, NULL,
+                               pos, &ctf_format, &td->ctf_trace.packet_header->p);
+
+                       len_index = struct_declaration_lookup_field_index(td->ctf_trace.packet_header->declaration, g_quark_from_static_string("magic"));
+                       if (len_index >= 0) {
+                               struct definition_integer *defint;
+                               struct field *field;
+
+                               field = struct_definition_get_field_from_index(td->ctf_trace.packet_header, len_index);
+                               assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
+                               defint = container_of(field->definition, struct definition_integer, p);
+                               assert(defint->declaration->signedness == FALSE);
+                               if (defint->value._unsigned != CTF_MAGIC) {
+                                       fprintf(stdout, "[error] Invalid magic number %" PRIX64 ".\n",
+                                                       defint->value._unsigned);
+                                       return -EINVAL;
+                               }
+                       }
+
+                       /* check uuid */
+                       len_index = struct_declaration_lookup_field_index(td->ctf_trace.packet_header->declaration, g_quark_from_static_string("trace_uuid"));
+                       if (len_index >= 0) {
+                               struct definition_array *defarray;
+                               struct field *field;
+                               uint64_t i;
+                               uint8_t uuidval[UUID_LEN];
+
+
+                               field = struct_definition_get_field_from_index(td->ctf_trace.packet_header, len_index);
+                               assert(field->definition->declaration->id == CTF_TYPE_ARRAY);
+                               defarray = container_of(field->definition, struct definition_array, p);
+                               assert(defarray->declaration->len == UUID_LEN);
+                               assert(defarray->declaration->elem->id == CTF_TYPE_INTEGER);
+
+                               for (i = 0; i < UUID_LEN; i++) {
+                                       struct definition *elem;
+                                       struct definition_integer *defint;
+
+                                       elem = array_index(defarray, i);
+                                       assert(elem);
+                                       defint = container_of(elem, struct definition_integer, p);
+                                       uuidval[i] = defint->value._unsigned;
+                               }
+                               ret = uuid_compare(td->ctf_trace.uuid, uuidval);
+                               if (ret) {
+                                       fprintf(stdout, "[error] Unique Universal Identifiers do not match.\n");
+                                       return -EINVAL;
+                               }
+                       }
+
+
+                       len_index = struct_declaration_lookup_field_index(td->ctf_trace.packet_header->declaration, g_quark_from_static_string("stream_id"));
+                       if (len_index >= 0) {
+                               struct definition_integer *defint;
+                               struct field *field;
+
+                               field = struct_definition_get_field_from_index(td->ctf_trace.packet_header, len_index);
+                               assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
+                               defint = container_of(field->definition, struct definition_integer, p);
+                               assert(defint->declaration->signedness == FALSE);
+                               stream_id = defint->value._unsigned;
+                       }
+               }
+
+               if (!first_packet && file_stream->stream_id != stream_id) {
+                       fprintf(stdout, "[error] Stream ID is changing within a stream.\n");
+                       return -EINVAL;
+               }
+               if (first_packet) {
+                       file_stream->stream_id = stream_id;
+                       if (stream_id >= td->ctf_trace.streams->len) {
+                               fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
+                               return -EINVAL;
+                       }
+                       stream = g_ptr_array_index(td->ctf_trace.streams, stream_id);
+                       if (!stream) {
+                               fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
+                               return -EINVAL;
+                       }
+                       file_stream->stream = stream;
+               }
+               first_packet = 0;
+
+               /* Read packet context */
+               stream->packet_context->p.declaration->copy(NULL, NULL,
+                               pos, &ctf_format, &stream->packet_context->p);
+
+               /* read content size from header */
+               len_index = struct_declaration_lookup_field_index(stream->packet_context->declaration, g_quark_from_static_string("content_size"));
+               if (len_index >= 0) {
+                       struct definition_integer *defint;
+                       struct field *field;
+
+                       field = struct_definition_get_field_from_index(stream->packet_context, len_index);
+                       assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
+                       defint = container_of(field->definition, struct definition_integer, p);
+                       assert(defint->declaration->signedness == FALSE);
+                       pos->content_size = defint->value._unsigned;
+               } else {
+                       /* Use file size for packet size */
+                       pos->content_size = filestats.st_size * CHAR_BIT;
+               }
+
+               /* read packet size from header */
+               len_index = struct_declaration_lookup_field_index(stream->packet_context->declaration, g_quark_from_static_string("packet_size"));
+               if (len_index >= 0) {
+                       struct definition_integer *defint;
+                       struct field *field;
+
+                       field = struct_definition_get_field_from_index(stream->packet_context, len_index);
+                       assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
+                       defint = container_of(field->definition, struct definition_integer, p);
+                       assert(defint->declaration->signedness == FALSE);
+                       pos->packet_size = defint->value._unsigned;
+               } else {
+                       /* Use content size if non-zero, else file size */
+                       pos->packet_size = pos->content_size ? : filestats.st_size * CHAR_BIT;
+               }
+
+               packet_index.offset = pos->mmap_offset;
+               packet_index.content_size = pos->content_size;
+               packet_index.packet_size = pos->packet_size;
+               /* add index to packet array */
+               g_array_append_val(file_stream->pos.packet_index, packet_index);
+
+               pos->mmap_offset += pos->packet_size / CHAR_BIT;
+       }
+
+       return 0;
+}
+
+/*
+ * Note: many file streams can inherit from the same stream class
+ * description (metadata).
+ */
+static
+int ctf_open_file_stream_read(struct trace_descriptor *td, const char *path, int flags)
+{
+       int ret;
+       struct ctf_file_stream *file_stream;
+
+       ret = openat(td->ctf_trace.dirfd, path, flags);
+       if (ret < 0)
+               goto error;
+       file_stream = g_new0(struct ctf_file_stream, 1);
+       file_stream->pos.fd = ret;
+       file_stream->pos.packet_index = g_array_new(FALSE, TRUE,
+                                               sizeof(struct packet_index));
+       ret = create_stream_packet_index(td, file_stream);
+       if (ret)
+               goto error_index;
+       /* Add stream file to stream class */
+       g_ptr_array_add(file_stream->stream->files, file_stream);
+       return 0;
+
+error_index:
+       (void) g_array_free(file_stream->pos.packet_index, TRUE);
+       close(file_stream->pos.fd);
+       g_free(file_stream);
+error:
        return ret;
 }
 
@@ -161,6 +403,9 @@ int ctf_open_trace_read(struct trace_descriptor *td, const char *path, int flags
                ret = -ENOENT;
                goto error_dirfd;
        }
+
+       td->ctf_trace.streams = g_ptr_array_new();
+
        /*
         * Keep the metadata file separate.
         */
@@ -186,7 +431,6 @@ int ctf_open_trace_read(struct trace_descriptor *td, const char *path, int flags
                if (ret) {
                        fprintf(stdout, "Readdir error.\n");
                        goto readdir_error;
-                       
                }
                if (!diriter)
                        break;
@@ -194,6 +438,7 @@ int ctf_open_trace_read(struct trace_descriptor *td, const char *path, int flags
                                || !strcmp(diriter->d_name, "..")
                                || !strcmp(diriter->d_name, "metadata"))
                        continue;
+               /* TODO: open file stream */
        }
 
        free(dirent);
@@ -202,6 +447,7 @@ int ctf_open_trace_read(struct trace_descriptor *td, const char *path, int flags
 readdir_error:
        free(dirent);
 error_metadata:
+       g_ptr_array_free(td->ctf_trace.streams, TRUE);
        close(td->ctf_trace.dirfd);
 error_dirfd:
        closedir(td->ctf_trace.dir);
@@ -262,8 +508,32 @@ error:
        return NULL;
 }
 
+static
+void ctf_close_file_stream(struct ctf_file_stream *file_stream)
+{
+       (void) g_array_free(file_stream->pos.packet_index, TRUE);
+       close(file_stream->pos.fd);
+}
+
 void ctf_close_trace(struct trace_descriptor *td)
 {
+       int i;
+
+       if (td->ctf_trace.streams) {
+               for (i = 0; i < td->ctf_trace.streams->len; i++) {
+                       struct ctf_stream *stream;
+                       int j;
+
+                       stream = g_ptr_array_index(td->ctf_trace.streams, i);
+                       for (j = 0; j < stream->files->len; j++) {
+                               struct ctf_file_stream *file_stream;
+                               file_stream = g_ptr_array_index(td->ctf_trace.streams, j);
+                               ctf_close_file_stream(file_stream);
+                       }
+
+               }
+               g_ptr_array_free(td->ctf_trace.streams, TRUE);
+       }
        closedir(td->ctf_trace.dir);
        g_free(td);
 }
index 05b1c98a46a0635e71cf882fa517b705d1bca014..4a97cdf7a9f6dfaf82697cdbc8197dd523b74cb5 100644 (file)
@@ -2,7 +2,7 @@ trace {
        major = 0;
        minor = 1;
        uuid = "f816d884-6cea-11e0-ac7a-8f5f4e9f7724";
-       endian = big;   /* Assuming big endian streams */
+       byte_order = be;        /* Assuming big endian streams */
 };
 
 /* Architecture with 32-bit pointers, 32-bit integers, 32-bit longs */
index f4776a0a0dc70577cbfe85ffbd787f38b53239ed..1981832e4bb6a7372a32cc5073912ae9787a9f52 100644 (file)
@@ -993,6 +993,28 @@ int get_boolean(FILE *fd, int depth, struct ctf_node *unary_expression)
 
 }
 
+static
+int get_trace_byte_order(FILE *fd, int depth, struct ctf_node *unary_expression)
+{
+       int byte_order;
+
+       if (unary_expression->u.unary_expression.type != UNARY_STRING) {
+               fprintf(fd, "[error] %s: byte_order: expecting string\n",
+                       __func__);
+               return -EINVAL;
+       }
+       if (!strcmp(unary_expression->u.unary_expression.u.string, "be"))
+               byte_order = BIG_ENDIAN;
+       else if (!strcmp(unary_expression->u.unary_expression.u.string, "le"))
+               byte_order = LITTLE_ENDIAN;
+       else {
+               fprintf(fd, "[error] %s: unexpected string \"%s\". Should be \"native\", \"network\", \"be\" or \"le\".\n",
+                       __func__, unary_expression->u.unary_expression.u.string);
+               return -EINVAL;
+       }
+       return byte_order;
+}
+
 static
 int get_byte_order(FILE *fd, int depth, struct ctf_node *unary_expression,
                struct ctf_trace *trace)
@@ -1300,12 +1322,14 @@ int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
 
                        if (CTF_EVENT_FIELD_IS_SET(event, name)) {
                                fprintf(fd, "[error] %s: name already declared in event declaration\n", __func__);
-                               return -EPERM;
+                               ret = -EPERM;
+                               goto error;
                        }
                        right = concatenate_unary_strings(&node->u.ctf_expression.right);
                        if (!right) {
                                fprintf(fd, "[error] %s: unexpected unary expression for event name\n", __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        event->name = g_quark_from_string(right);
                        g_free(right);
@@ -1313,28 +1337,33 @@ int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
                } else if (!strcmp(left, "id")) {
                        if (CTF_EVENT_FIELD_IS_SET(event, id)) {
                                fprintf(fd, "[error] %s: id already declared in event declaration\n", __func__);
-                               return -EPERM;
+                               ret = -EPERM;
+                               goto error;
                        }
                        ret = get_unary_unsigned(&node->u.ctf_expression.right, &event->id);
                        if (ret) {
                                fprintf(fd, "[error] %s: unexpected unary expression for event id\n", __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        CTF_EVENT_SET_FIELD(event, id);
                } else if (!strcmp(left, "stream_id")) {
                        if (CTF_EVENT_FIELD_IS_SET(event, stream_id)) {
                                fprintf(fd, "[error] %s: stream_id already declared in event declaration\n", __func__);
-                               return -EPERM;
+                               ret = -EPERM;
+                               goto error;
                        }
                        ret = get_unary_unsigned(&node->u.ctf_expression.right, &event->stream_id);
                        if (ret) {
                                fprintf(fd, "[error] %s: unexpected unary expression for event stream_id\n", __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        event->stream = trace_stream_lookup(trace, event->stream_id);
                        if (!event->stream) {
                                fprintf(fd, "[error] %s: stream id %" PRIu64 " cannot be found\n", __func__, event->stream_id);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        CTF_EVENT_SET_FIELD(event, stream_id);
                } else if (!strcmp(left, "context")) {
@@ -1342,34 +1371,45 @@ int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
 
                        if (event->context_decl) {
                                fprintf(fd, "[error] %s: context already declared in event declaration\n", __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        declaration = ctf_type_specifier_list_visit(fd, depth,
                                        _cds_list_first_entry(&node->u.ctf_expression.right,
                                                struct ctf_node, siblings),
                                        event->declaration_scope, trace);
-                       if (!declaration)
-                               return -EPERM;
-                       if (declaration->id != CTF_TYPE_STRUCT)
-                               return -EPERM;
+                       if (!declaration) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       if (declaration->id != CTF_TYPE_STRUCT) {
+                               ret = -EPERM;
+                               goto error;
+                       }
                        event->context_decl = container_of(declaration, struct declaration_struct, p);
                } else if (!strcmp(left, "fields")) {
                        struct declaration *declaration;
 
                        if (event->fields_decl) {
                                fprintf(fd, "[error] %s: fields already declared in event declaration\n", __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        declaration = ctf_type_specifier_list_visit(fd, depth,
                                        _cds_list_first_entry(&node->u.ctf_expression.right,
                                                struct ctf_node, siblings),
                                        event->declaration_scope, trace);
-                       if (!declaration)
-                               return -EPERM;
-                       if (declaration->id != CTF_TYPE_STRUCT)
-                               return -EPERM;
+                       if (!declaration) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       if (declaration->id != CTF_TYPE_STRUCT) {
+                               ret = -EPERM;
+                               goto error;
+                       }
                        event->fields_decl = container_of(declaration, struct declaration_struct, p);
                }
+error:
                g_free(left);
                break;
        }
@@ -1378,7 +1418,7 @@ int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
        /* TODO: declaration specifier should be added. */
        }
 
-       return 0;
+       return ret;
 }
 
 static
@@ -1402,15 +1442,23 @@ int ctf_event_visit(FILE *fd, int depth, struct ctf_node *node,
                fprintf(fd, "[error] %s: missing name field in event declaration\n", __func__);
                goto error;
        }
-       if (!CTF_EVENT_FIELD_IS_SET(event, id)) {
+       /* Allow only one event without id per stream */
+       if (!CTF_EVENT_FIELD_IS_SET(event, id)
+           && event->stream->events_by_id->len != 0) {
                ret = -EPERM;
                fprintf(fd, "[error] %s: missing id field in event declaration\n", __func__);
                goto error;
        }
        if (!CTF_EVENT_FIELD_IS_SET(event, stream_id)) {
-               ret = -EPERM;
-               fprintf(fd, "[error] %s: missing stream_id field in event declaration\n", __func__);
-               goto error;
+               /* Allow missing stream_id if there is only a single stream */
+               if (trace->streams->len == 1) {
+                       event->stream_id = 0;
+                       event->stream = trace_stream_lookup(trace, event->stream_id);
+               } else {
+                       ret = -EPERM;
+                       fprintf(fd, "[error] %s: missing stream_id field in event declaration\n", __func__);
+                       goto error;
+               }
        }
        if (event->stream->events_by_id->len <= event->id)
                g_ptr_array_set_size(event->stream->events_by_id, event->id + 1);
@@ -1485,12 +1533,14 @@ int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, str
                if (!strcmp(left, "id")) {
                        if (CTF_STREAM_FIELD_IS_SET(stream, stream_id)) {
                                fprintf(fd, "[error] %s: id already declared in stream declaration\n", __func__);
-                               return -EPERM;
+                               ret = -EPERM;
+                               goto error;
                        }
                        ret = get_unary_unsigned(&node->u.ctf_expression.right, &stream->stream_id);
                        if (ret) {
                                fprintf(fd, "[error] %s: unexpected unary expression for stream id\n", __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        CTF_STREAM_SET_FIELD(stream, stream_id);
                } else if (!strcmp(left, "event.header")) {
@@ -1498,50 +1548,66 @@ int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, str
 
                        if (stream->event_header_decl) {
                                fprintf(fd, "[error] %s: event.header already declared in stream declaration\n", __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        declaration = ctf_type_specifier_list_visit(fd, depth,
                                        _cds_list_first_entry(&node->u.ctf_expression.right,
                                                struct ctf_node, siblings),
                                        stream->declaration_scope, trace);
-                       if (!declaration)
-                               return -EPERM;
-                       if (declaration->id != CTF_TYPE_STRUCT)
-                               return -EPERM;
+                       if (!declaration) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       if (declaration->id != CTF_TYPE_STRUCT) {
+                               ret = -EPERM;
+                               goto error;
+                       }
                        stream->event_header_decl = container_of(declaration, struct declaration_struct, p);
                } else if (!strcmp(left, "event.context")) {
                        struct declaration *declaration;
 
                        if (stream->event_context_decl) {
                                fprintf(fd, "[error] %s: event.context already declared in stream declaration\n", __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        declaration = ctf_type_specifier_list_visit(fd, depth,
                                        _cds_list_first_entry(&node->u.ctf_expression.right,
                                                struct ctf_node, siblings),
                                        stream->declaration_scope, trace);
-                       if (!declaration)
-                               return -EPERM;
-                       if (declaration->id != CTF_TYPE_STRUCT)
-                               return -EPERM;
+                       if (!declaration) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       if (declaration->id != CTF_TYPE_STRUCT) {
+                               ret = -EPERM;
+                               goto error;
+                       }
                        stream->event_context_decl = container_of(declaration, struct declaration_struct, p);
                } else if (!strcmp(left, "packet.context")) {
                        struct declaration *declaration;
 
                        if (stream->packet_context_decl) {
                                fprintf(fd, "[error] %s: packet.context already declared in stream declaration\n", __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        declaration = ctf_type_specifier_list_visit(fd, depth,
                                        _cds_list_first_entry(&node->u.ctf_expression.right,
                                                struct ctf_node, siblings),
                                        stream->declaration_scope, trace);
-                       if (!declaration)
-                               return -EPERM;
-                       if (declaration->id != CTF_TYPE_STRUCT)
-                               return -EPERM;
+                       if (!declaration) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       if (declaration->id != CTF_TYPE_STRUCT) {
+                               ret = -EPERM;
+                               goto error;
+                       }
                        stream->packet_context_decl = container_of(declaration, struct declaration_struct, p);
                }
+error:
                g_free(left);
                break;
        }
@@ -1550,7 +1616,7 @@ int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, str
        /* TODO: declaration specifier should be added. */
        }
 
-       return 0;
+       return ret;
 }
 
 static
@@ -1566,12 +1632,25 @@ int ctf_stream_visit(FILE *fd, int depth, struct ctf_node *node,
        stream->declaration_scope = new_declaration_scope(parent_declaration_scope);
        stream->events_by_id = g_ptr_array_new();
        stream->event_quark_to_id = g_hash_table_new(g_direct_hash, g_direct_equal);
+       stream->files = g_ptr_array_new();
        cds_list_for_each_entry(iter, &node->u.stream.declaration_list, siblings) {
                ret = ctf_stream_declaration_visit(fd, depth + 1, iter, stream, trace);
                if (ret)
                        goto error;
        }
-       if (!CTF_STREAM_FIELD_IS_SET(stream, stream_id)) {
+       if (CTF_STREAM_FIELD_IS_SET(stream, stream_id)) {
+               /* check that packet header has stream_id field. */
+               if (!trace->packet_header_decl
+                   || struct_declaration_lookup_field_index(trace->packet_header_decl, g_quark_from_static_string("stream_id")) < 0) {
+                       ret = -EPERM;
+                       fprintf(fd, "[error] %s: missing stream_id field in packet header declaration, but stream_id attribute is declared for stream.\n", __func__);
+                       goto error;
+               }
+       }
+
+       /* Allow only one id-less stream */
+       if (!CTF_STREAM_FIELD_IS_SET(stream, stream_id)
+           && trace->streams->len != 0) {
                ret = -EPERM;
                fprintf(fd, "[error] %s: missing id field in stream declaration\n", __func__);
                goto error;
@@ -1580,7 +1659,7 @@ int ctf_stream_visit(FILE *fd, int depth, struct ctf_node *node,
                g_ptr_array_set_size(trace->streams, stream->stream_id + 1);
        g_ptr_array_index(trace->streams, stream->stream_id) = stream;
 
-       parent_def_scope = NULL;
+       parent_def_scope = trace->definition_scope;
        if (stream->packet_context_decl) {
                stream->packet_context =
                        container_of(
@@ -1625,6 +1704,7 @@ error:
        declaration_unref(&stream->event_header_decl->p);
        declaration_unref(&stream->event_context_decl->p);
        declaration_unref(&stream->packet_context_decl->p);
+       g_ptr_array_free(stream->files, TRUE);
        g_ptr_array_free(stream->events_by_id, TRUE);
        g_hash_table_destroy(stream->event_quark_to_id);
        free_declaration_scope(stream->declaration_scope);
@@ -1663,37 +1743,80 @@ int ctf_trace_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
                if (!strcmp(left, "major")) {
                        if (CTF_TRACE_FIELD_IS_SET(trace, major)) {
                                fprintf(fd, "[error] %s: major already declared in trace declaration\n", __func__);
-                               return -EPERM;
+                               ret = -EPERM;
+                               goto error;
                        }
                        ret = get_unary_unsigned(&node->u.ctf_expression.right, &trace->major);
                        if (ret) {
                                fprintf(fd, "[error] %s: unexpected unary expression for trace major number\n", __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        CTF_TRACE_SET_FIELD(trace, major);
                } else if (!strcmp(left, "minor")) {
                        if (CTF_TRACE_FIELD_IS_SET(trace, minor)) {
                                fprintf(fd, "[error] %s: minor already declared in trace declaration\n", __func__);
-                               return -EPERM;
+                               ret = -EPERM;
+                               goto error;
                        }
                        ret = get_unary_unsigned(&node->u.ctf_expression.right, &trace->minor);
                        if (ret) {
                                fprintf(fd, "[error] %s: unexpected unary expression for trace minor number\n", __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        CTF_TRACE_SET_FIELD(trace, minor);
                } else if (!strcmp(left, "uuid")) {
                        if (CTF_TRACE_FIELD_IS_SET(trace, uuid)) {
                                fprintf(fd, "[error] %s: uuid already declared in trace declaration\n", __func__);
-                               return -EPERM;
+                               ret = -EPERM;
+                               goto error;
                        }
                        ret = get_unary_uuid(&node->u.ctf_expression.right, &trace->uuid);
                        if (ret) {
                                fprintf(fd, "[error] %s: unexpected unary expression for trace uuid\n", __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        CTF_TRACE_SET_FIELD(trace, uuid);
+               } else if (!strcmp(left, "byte_order")) {
+                       struct ctf_node *right;
+                       int byte_order;
+
+                       if (CTF_TRACE_FIELD_IS_SET(trace, byte_order)) {
+                               fprintf(fd, "[error] %s: endianness already declared in trace declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       right = _cds_list_first_entry(&node->u.ctf_expression.right, struct ctf_node, siblings);
+                       byte_order = get_trace_byte_order(fd, depth, right);
+                       if (byte_order < 0)
+                               return -EINVAL;
+                       trace->byte_order = byte_order;
+                       CTF_TRACE_SET_FIELD(trace, byte_order);
+               } else if (!strcmp(left, "packet.header")) {
+                       struct declaration *declaration;
+
+                       if (trace->packet_header_decl) {
+                               fprintf(fd, "[error] %s: packet.header already declared in trace declaration\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       declaration = ctf_type_specifier_list_visit(fd, depth,
+                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                               struct ctf_node, siblings),
+                                       trace->declaration_scope, trace);
+                       if (!declaration) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       if (declaration->id != CTF_TYPE_STRUCT) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       trace->packet_header_decl = container_of(declaration, struct declaration_struct, p);
                }
+error:
                g_free(left);
                break;
        }
@@ -1702,12 +1825,13 @@ int ctf_trace_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
        /* TODO: declaration specifier should be added. */
        }
 
-       return 0;
+       return ret;
 }
 
 static
 int ctf_trace_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace *trace)
 {
+       struct definition_scope *parent_def_scope;
        int ret = 0;
        struct ctf_node *iter;
 
@@ -1735,8 +1859,35 @@ int ctf_trace_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace
                fprintf(fd, "[error] %s: missing uuid field in trace declaration\n", __func__);
                goto error;
        }
+
+       parent_def_scope = NULL;
+       if (trace->packet_header_decl) {
+               trace->packet_header =
+                       container_of(
+                       trace->packet_header_decl->p.definition_new(&trace->packet_header_decl->p,
+                               parent_def_scope, 0, 0),
+                       struct definition_struct, p);
+               set_dynamic_definition_scope(&trace->packet_header->p,
+                                            trace->packet_header->scope,
+                                            "trace.packet.header");
+               parent_def_scope = trace->packet_header->scope;
+               declaration_unref(&trace->packet_header_decl->p);
+       }
+       trace->definition_scope = parent_def_scope;
+
+       if (!CTF_TRACE_FIELD_IS_SET(trace, byte_order)) {
+               /* check that the packet header contains a "magic" field */
+               if (!trace->packet_header
+                   || struct_declaration_lookup_field_index(trace->packet_header_decl, g_quark_from_static_string("magic")) < 0) {
+                       ret = -EPERM;
+                       fprintf(fd, "[error] %s: missing both byte_order and packet header magic number in trace declaration\n", __func__);
+                       goto error_free_def;
+               }
+       }
        return 0;
 
+error_free_def:
+       definition_unref(&trace->packet_header->p);
 error:
        g_ptr_array_free(trace->streams, TRUE);
        free_declaration_scope(trace->declaration_scope);
index 72c779123bbd74e628e4a31b8eb0c847882c47cf..3d84952bbb547480f97bbd77768d55113b42f820 100644 (file)
@@ -119,7 +119,8 @@ double ctf_double_read(struct stream_pos *srcp,
        struct stream_pos destp;
 
        align_pos(srcp, float_declaration->p.alignment);
-       init_pos(&destp, (char *) u.bits);
+       init_pos(&destp, -1);
+       destp.base = (char *) u.bits;
        _ctf_float_copy(&destp, dest_declaration, srcp, float_declaration);
        declaration_unref(&dest_declaration->p);
        return u.v;
@@ -139,7 +140,8 @@ void ctf_double_write(struct stream_pos *destp,
 
        u.v = v;
        align_pos(destp, float_declaration->p.alignment);
-       init_pos(&srcp, (char *) u.bits);
+       init_pos(&srcp, -1);
+       srcp.base = (char *) u.bits;
        _ctf_float_copy(destp, float_declaration, &srcp, src_declaration);
        declaration_unref(&src_declaration->p);
 }
@@ -156,7 +158,8 @@ long double ctf_ldouble_read(struct stream_pos *srcp,
        struct stream_pos destp;
 
        align_pos(srcp, float_declaration->p.alignment);
-       init_pos(&destp, (char *) u.bits);
+       init_pos(&destp, -1);
+       destp.base = (char *) u.bits;
        _ctf_float_copy(&destp, dest_declaration, srcp, float_declaration);
        declaration_unref(&dest_declaration->p);
        return u.v;
@@ -176,7 +179,8 @@ void ctf_ldouble_write(struct stream_pos *destp,
 
        u.v = v;
        align_pos(destp, float_declaration->p.alignment);
-       init_pos(&srcp, (char *) u.bits);
+       init_pos(&srcp, -1);
+       srcp.base = (char *) u.bits;
        _ctf_float_copy(destp, float_declaration, &srcp, src_declaration);
        declaration_unref(&src_declaration->p);
 }
index d833a56d771dad990d5bf566160254f86f7107f8..330238ba0dc5f0a2e63c5d381c4aeda693fcdb9c 100644 (file)
 #include <assert.h>
 #include <glib.h>
 
+#define CTF_MAGIC      0xC1FC1FC1
+
 struct ctf_trace;
 struct ctf_stream;
 struct ctf_event;
 
-struct ctf_stream_file {
-       /* Information about stream backing file */
-       int fd;
-       char *mmap;                             /* current stream mmap */
+struct ctf_file_stream {
+       uint64_t stream_id;
+       struct ctf_stream *stream;
        struct stream_pos pos;                  /* current stream position */
 };
 
@@ -58,18 +59,28 @@ struct ctf_trace {
        struct declaration_scope *root_declaration_scope;
 
        struct declaration_scope *declaration_scope;
-       GPtrArray *streams;                     /* Array of struct ctf_stream pointers*/
-       struct ctf_stream_file metadata;
+       /* innermost definition scope. to be used as parent of stream. */
+       struct definition_scope *definition_scope;
+       GPtrArray *streams;                     /* Array of struct ctf_stream pointers */
+       struct ctf_file_stream metadata;
+
+       /* Declarations only used when parsing */
+       struct declaration_struct *packet_header_decl;
+
+       /* Definitions used afterward */
+       struct definition_struct *packet_header;
 
        uint64_t major;
        uint64_t minor;
        uuid_t uuid;
-       int byte_order;
+       int byte_order;         /* trace BYTE_ORDER. 0 if unset. */
 
        enum {                                  /* Fields populated mask */
-               CTF_TRACE_major =       (1U << 0),
-               CTF_TRACE_minor =       (1U << 1),
-               CTF_TRACE_uuid  =       (1U << 2),
+               CTF_TRACE_major         =       (1U << 0),
+               CTF_TRACE_minor         =       (1U << 1),
+               CTF_TRACE_uuid          =       (1U << 2),
+               CTF_TRACE_byte_order    =       (1U << 3),
+               CTF_TRACE_packet_header =       (1U << 4),
        } field_mask;
 
        /* Information about trace backing directory and files */
@@ -117,7 +128,7 @@ struct ctf_stream {
                CTF_STREAM_stream_id =  (1 << 0),
        } field_mask;
 
-       struct ctf_stream_file file;            /* Backing file */
+       GPtrArray *files;                       /* Array of struct ctf_file_stream pointers */
 };
 
 #define CTF_EVENT_SET_FIELD(ctf_event, field)                          \
index c311b532738612fb2feeb31da1655755f610101a..91c3303c2835b92529d773966b9a8cd0adbc52b7 100644 (file)
 
 #include <babeltrace/types.h>
 #include <stdint.h>
+#include <unistd.h>
 #include <glib.h>
 
-/*
- * Always update stream_pos with move_pos and init_pos.
- */
-struct stream_pos {
-       char *base;             /* Base address */
-       size_t offset;          /* Offset from base, in bits */
-       int dummy;              /* Dummy position, for length calculation */
+struct packet_index {
+       off_t offset;           /* offset of the packet in the file, in bytes */
+       size_t packet_size;     /* packet size, in bits */
+       size_t content_size;    /* content size, in bits */
 };
 
-static inline
-void init_pos(struct stream_pos *pos, char *base)
-{
-       pos->base = base;       /* initial base, page-aligned */
-       pos->offset = 0;
-       pos->dummy = false;
-}
-
-/*
- * move_pos - move position of a relative bit offset
- *
- * TODO: allow larger files by updating base too.
- */
-static inline
-void move_pos(struct stream_pos *pos, size_t offset)
-{
-       pos->offset = pos->offset + offset;
-}
-
 /*
- * align_pos - align position on a bit offset (> 0)
- *
- * TODO: allow larger files by updating base too.
+ * Always update stream_pos with move_pos and init_pos.
  */
-static inline
-void align_pos(struct stream_pos *pos, size_t offset)
-{
-       pos->offset += offset_align(pos->offset, offset);
-}
+struct stream_pos {
+       int fd;                 /* backing file fd. -1 if unset. */
+       GArray *packet_index;   /* contains struct packet_index */
 
-static inline
-void copy_pos(struct stream_pos *dest, struct stream_pos *src)
-{
-       memcpy(dest, src, sizeof(struct stream_pos));
-}
+       /* Current position */
+       off_t mmap_offset;      /* mmap offset in the file, in bytes */
+       size_t packet_size;     /* current packet size, in bits */
+       size_t content_size;    /* current content size, in bits */
+       char *base;             /* mmap base address */
+       size_t offset;          /* offset from base, in bits */
 
-static inline
-char *get_pos_addr(struct stream_pos *pos)
-{
-       /* Only makes sense to get the address after aligning on CHAR_BIT */
-       assert(!(pos->offset % CHAR_BIT));
-       return pos->base + (pos->offset / CHAR_BIT);
-}
+       int dummy;              /* dummy position, for length calculation */
+};
 
 /*
  * IMPORTANT: All lengths (len) and offsets (start, end) are expressed in bits,
@@ -140,4 +111,57 @@ void ctf_sequence_begin(struct stream_pos *pos,
 void ctf_sequence_end(struct stream_pos *pos,
                const struct declaration_sequence *sequence_declaration);
 
+void move_pos_slow(struct stream_pos *pos, size_t offset);
+
+static inline
+void init_pos(struct stream_pos *pos, int fd)
+{
+       pos->fd = fd;
+       pos->mmap_offset = 0;
+       pos->packet_size = 0;
+       pos->content_size = 0;
+       pos->base = NULL;
+       pos->offset = 0;
+       pos->dummy = false;
+}
+
+/*
+ * move_pos - move position of a relative bit offset
+ *
+ * TODO: allow larger files by updating base too.
+ */
+static inline
+void move_pos(struct stream_pos *pos, size_t offset)
+{
+       if (pos->fd >= 0 && pos->offset + offset >= pos->content_size)
+               move_pos_slow(pos, offset);
+       else
+               pos->offset += offset;
+}
+
+/*
+ * align_pos - align position on a bit offset (> 0)
+ *
+ * TODO: allow larger files by updating base too.
+ */
+static inline
+void align_pos(struct stream_pos *pos, size_t offset)
+{
+       pos->offset += offset_align(pos->offset, offset);
+}
+
+static inline
+void copy_pos(struct stream_pos *dest, struct stream_pos *src)
+{
+       memcpy(dest, src, sizeof(struct stream_pos));
+}
+
+static inline
+char *get_pos_addr(struct stream_pos *pos)
+{
+       /* Only makes sense to get the address after aligning on CHAR_BIT */
+       assert(!(pos->offset % CHAR_BIT));
+       return pos->base + (pos->offset / CHAR_BIT);
+}
+
 #endif /* _BABELTRACE_CTF_TYPES_H */
index 3d2b70a4ed92d878588ff5547d7fc85537ac43b8..d01b672437c5512017c09fa017b55c97dfd51ec3 100644 (file)
@@ -275,7 +275,7 @@ struct definition_array {
        struct definition p;
        struct declaration_array *declaration;
        struct definition_scope *scope;
-       struct field current_element;           /* struct field */
+       GArray *elems;                  /* struct field */
 };
 
 struct declaration_sequence {
@@ -290,7 +290,7 @@ struct definition_sequence {
        struct declaration_sequence *declaration;
        struct definition_scope *scope;
        struct definition_integer *len;
-       struct field current_element;           /* struct field */
+       GArray *elems;                  /* struct field */
 };
 
 int register_declaration(GQuark declaration_name,
@@ -409,17 +409,17 @@ void struct_declaration_add_field(struct declaration_struct *struct_declaration,
 /*
  * Returns the index of a field within a structure.
  */
-unsigned long struct_declaration_lookup_field_index(struct declaration_struct *struct_declaration,
+int struct_declaration_lookup_field_index(struct declaration_struct *struct_declaration,
                                                    GQuark field_name);
 /*
  * field returned only valid as long as the field structure is not appended to.
  */
 struct declaration_field *
 struct_declaration_get_field_from_index(struct declaration_struct *struct_declaration,
-                                       unsigned long index);
+                                       int index);
 struct field *
-struct_get_field_from_index(struct definition_struct *struct_definition,
-                           unsigned long index);
+struct_definition_get_field_from_index(struct definition_struct *struct_definition,
+                                      int index);
 
 /*
  * The tag enumeration is validated to ensure that it contains only mappings
@@ -457,6 +457,7 @@ struct field *variant_get_current_field(struct definition_variant *variant);
 struct declaration_array *
        array_declaration_new(size_t len, struct declaration *elem_declaration,
                struct declaration_scope *parent_scope);
+struct definition *array_index(struct definition_array *array, uint64_t i);
 
 /*
  * int_declaration and elem_declaration passed as parameter now belong
@@ -466,6 +467,7 @@ struct declaration_sequence *
        sequence_declaration_new(struct declaration_integer *len_declaration, 
                struct declaration *elem_declaration,
                struct declaration_scope *parent_scope);
+struct definition *sequence_index(struct definition_sequence *sequence, uint64_t i);
 
 /*
  * in: path (dot separated), out: q (GArray of GQuark)
index c218a11a8bb1a2c66fbf7d0c06d81ba322084ef5..d8ddd637c69bb804e5401e8276da9ba22a69969d 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <babeltrace/compiler.h>
 #include <babeltrace/format.h>
+#include <inttypes.h>
 
 static
 struct definition *_array_definition_new(struct declaration *declaration,
@@ -36,14 +37,17 @@ void array_copy(struct stream_pos *dest, const struct format *fdest,
        uint64_t i;
 
        fsrc->array_begin(src, array_declaration);
-       fdest->array_begin(dest, array_declaration);
+       if (fdest)
+               fdest->array_begin(dest, array_declaration);
 
        for (i = 0; i < array_declaration->len; i++) {
-               struct definition *elem = array->current_element.definition;
+               struct definition *elem =
+                       g_array_index(array->elems, struct field, i).definition;
                elem->declaration->copy(dest, fdest, src, fsrc, elem);
        }
        fsrc->array_end(src, array_declaration);
-       fdest->array_end(dest, array_declaration);
+       if (fdest)
+               fdest->array_end(dest, array_declaration);
 }
 
 static
@@ -91,6 +95,7 @@ struct definition *
        struct declaration_array *array_declaration =
                container_of(declaration, struct declaration_array, p);
        struct definition_array *array;
+       uint64_t i;
 
        array = g_new(struct definition_array, 1);
        declaration_ref(&array_declaration->p);
@@ -99,11 +104,25 @@ struct definition *
        array->p.ref = 1;
        array->p.index = index;
        array->scope = new_definition_scope(parent_scope, field_name);
-       array->current_element.definition =
-               array_declaration->elem->definition_new(array_declaration->elem,
-                                         parent_scope,
-                                         g_quark_from_static_string("[]"),
-                                         0);
+       array->elems = g_array_sized_new(FALSE, TRUE, sizeof(struct field),
+                                        array_declaration->len);
+       g_array_set_size(array->elems, array_declaration->len);
+       for (i = 0; i < array_declaration->len; i++) {
+               struct field *field;
+               GString *str;
+               GQuark name;
+
+               str = g_string_new("");
+               g_string_printf(str, "[%" PRIu64 "]", i);
+               name = g_quark_from_string(str->str);
+               (void) g_string_free(str, TRUE);
+
+               field = &g_array_index(array->elems, struct field, i);
+               field->name = name;
+               field->definition = array_declaration->elem->definition_new(array_declaration->elem,
+                                         array->scope,
+                                         name, i);
+       }
        return &array->p;
 }
 
@@ -112,11 +131,23 @@ void _array_definition_free(struct definition *definition)
 {
        struct definition_array *array =
                container_of(definition, struct definition_array, p);
-       struct definition *elem_definition =
-               array->current_element.definition;
+       uint64_t i;
 
-       elem_definition->declaration->definition_free(elem_definition);
+       for (i = 0; i < array->elems->len; i++) {
+               struct field *field;
+
+               field = &g_array_index(array->elems, struct field, i);
+               field->definition->declaration->definition_free(field->definition);
+       }
+       (void) g_array_free(array->elems, TRUE);
        free_definition_scope(array->scope);
        declaration_unref(array->p.declaration);
        g_free(array);
 }
+
+struct definition *array_index(struct definition_array *array, uint64_t i)
+{
+       if (i >= array->elems->len)
+               return NULL;
+       return g_array_index(array->elems, struct field, i).definition;
+}
index 4c2d2b7795013237a633c3333a176d553f2f93f6..368c21a6910187dc8d6e9ce45dd80fc547b2757a 100644 (file)
@@ -371,7 +371,8 @@ void enum_copy(struct stream_pos *dest, const struct format *fdest,
         * now to test enum read and write code.
         */
        v = g_array_index(array, GQuark, 0);
-       return fdest->enum_write(dest, enum_declaration, v);
+       if (fdest)
+               fdest->enum_write(dest, enum_declaration, v);
 }
 
 static
index 576f8622567c75af82bf3acfd91d8c9f321fe438..3b2523e24f5c6fee571c367852b04667a9f8d88a 100644 (file)
@@ -42,7 +42,8 @@ void float_copy(struct stream_pos *destp,
                double v;
 
                v = fsrc->double_read(srcp, float_declaration);
-               fdest->double_write(destp, float_declaration, v);
+               if (fdest)
+                       fdest->double_write(destp, float_declaration, v);
        }
 }
 
index 7b7d22c8d4b1b48ebe12ed6c80550c1c8fd222dd..16cd903dc8aa8b7740859b0e7e30aae9bd4109a4 100644 (file)
@@ -40,12 +40,14 @@ void integer_copy(struct stream_pos *dest, const struct format *fdest,
                uint64_t v;
 
                v = fsrc->uint_read(src, integer_declaration);
-               fdest->uint_write(dest, integer_declaration, v);
+               if (fdest)
+                       fdest->uint_write(dest, integer_declaration, v);
        } else {
                int64_t v;
 
                v = fsrc->int_read(src, integer_declaration);
-               fdest->int_write(dest, integer_declaration, v);
+               if (fdest)
+                       fdest->int_write(dest, integer_declaration, v);
        }
 }
 
index a719ee99b2dce596bad6bfe3ce600cc8c209c5fc..50763d7ad7ec7b7ed85ec2b70b523873791dd30a 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <babeltrace/compiler.h>
 #include <babeltrace/format.h>
+#include <inttypes.h>
 
 #ifndef max
 #define max(a, b)      ((a) < (b) ? (b) : (a))
@@ -37,21 +38,48 @@ void sequence_copy(struct stream_pos *dest, const struct format *fdest,
        struct definition_sequence *sequence =
                container_of(definition, struct definition_sequence, p);
        struct declaration_sequence *sequence_declaration = sequence->declaration;
-       uint64_t i;
+       uint64_t len, oldlen, i;
 
        fsrc->sequence_begin(src, sequence_declaration);
-       fdest->sequence_begin(dest, sequence_declaration);
+       if (fdest)
+               fdest->sequence_begin(dest, sequence_declaration);
 
        sequence->len->p.declaration->copy(dest, fdest, src, fsrc,
                                    &sequence->len->p);
+       len = sequence->len->value._unsigned;
+       g_array_set_size(sequence->elems, len);
+       /*
+        * Yes, large sequences could be _painfully slow_ to parse due
+        * to memory allocation for each event read. At least, never
+        * shrink the sequence. Note: the sequence GArray len should
+        * never be used as indicator of the current sequence length.
+        * One should always look at the sequence->len->value._unsigned
+        * value for that.
+        */
+       oldlen = sequence->elems->len;
+       if (oldlen < len)
+               g_array_set_size(sequence->elems, len);
+
+       for (i = oldlen; i < len; i++) {
+               struct field *field;
+               GString *str;
+               GQuark name;
+
+               str = g_string_new("");
+               g_string_printf(str, "[%" PRIu64 "]", i);
+               (void) g_string_free(str, TRUE);
+               name = g_quark_from_string(str->str);
 
-       for (i = 0; i < sequence->len->value._unsigned; i++) {
-               struct definition *elem =
-                       sequence->current_element.definition;
-               elem->declaration->copy(dest, fdest, src, fsrc, elem);
+               field = &g_array_index(sequence->elems, struct field, i);
+               field->name = name;
+               field->definition = sequence_declaration->elem->definition_new(sequence_declaration->elem,
+                                         sequence->scope,
+                                         name, i);
+               field->definition->declaration->copy(dest, fdest, src, fsrc, field->definition);
        }
        fsrc->sequence_end(src, sequence_declaration);
-       fdest->sequence_end(dest, sequence_declaration);
+       if (fdest)
+               fdest->sequence_end(dest, sequence_declaration);
 }
 
 static
@@ -110,14 +138,11 @@ struct definition *_sequence_definition_new(struct declaration *declaration,
        sequence->p.index = index;
        sequence->scope = new_definition_scope(parent_scope, field_name);
        len_parent = sequence_declaration->len_declaration->p.definition_new(&sequence_declaration->len_declaration->p,
-                               parent_scope,
+                               sequence->scope,
                                g_quark_from_static_string("length"), 0);
        sequence->len =
                container_of(len_parent, struct definition_integer, p);
-       sequence->current_element.definition =
-               sequence_declaration->elem->definition_new(sequence_declaration->elem,
-                               parent_scope,
-                               g_quark_from_static_string("[]"), 1);
+       sequence->elems = g_array_new(FALSE, TRUE, sizeof(struct field));
        return &sequence->p;
 }
 
@@ -127,12 +152,25 @@ void _sequence_definition_free(struct definition *definition)
        struct definition_sequence *sequence =
                container_of(definition, struct definition_sequence, p);
        struct definition *len_definition = &sequence->len->p;
-       struct definition *elem_definition =
-               sequence->current_element.definition;
+       uint64_t i;
+
+       for (i = 0; i < sequence->elems->len; i++) {
+               struct field *field;
 
+               field = &g_array_index(sequence->elems, struct field, i);
+               field->definition->declaration->definition_free(field->definition);
+       }
+       (void) g_array_free(sequence->elems, TRUE);
        len_definition->declaration->definition_free(len_definition);
-       elem_definition->declaration->definition_free(elem_definition);
        free_definition_scope(sequence->scope);
        declaration_unref(sequence->p.declaration);
        g_free(sequence);
 }
+
+struct definition *sequence_index(struct definition_sequence *sequence, uint64_t i)
+{
+       if (i >= sequence->len->value._unsigned)
+               return NULL;
+       assert(i < sequence->elems->len);
+       return g_array_index(sequence->elems, struct field, i).definition;
+}
index f8778c845052709464f110cba1099ab662ce2e59..796f05cd6a47f555c2584993d89956b9479adf02 100644 (file)
@@ -35,13 +35,14 @@ void string_copy(struct stream_pos *dest, const struct format *fdest,
                container_of(definition, struct definition_string, p);
        struct declaration_string *string_declaration = string->declaration;
 
-       if (fsrc->string_copy == fdest->string_copy) {
+       if (fdest && (fsrc->string_copy == fdest->string_copy)) {
                fsrc->string_copy(dest, src, string_declaration);
        } else {
                char *tmp = NULL;
 
                fsrc->string_read(&tmp, src, string_declaration);
-               fdest->string_write(dest, tmp, string_declaration);
+               if (fdest)
+                       fdest->string_write(dest, tmp, string_declaration);
                fsrc->string_free_temp(tmp);
        }
 }
index 69e3a553a2d64202344d8ca411af21daa07f7d8d..ea2e28c14c29884e5b1faf8551504913d15bbb06 100644 (file)
@@ -40,7 +40,8 @@ void struct_copy(struct stream_pos *dest, const struct format *fdest,
        unsigned long i;
 
        fsrc->struct_begin(src, struct_declaration);
-       fdest->struct_begin(dest, struct_declaration);
+       if (fdest)
+               fdest->struct_begin(dest, struct_declaration);
 
        for (i = 0; i < _struct->fields->len; i++) {
                struct field *field = &g_array_index(_struct->fields,
@@ -51,7 +52,8 @@ void struct_copy(struct stream_pos *dest, const struct format *fdest,
 
        }
        fsrc->struct_end(src, struct_declaration);
-       fdest->struct_end(dest, struct_declaration);
+       if (fdest)
+               fdest->struct_end(dest, struct_declaration);
 }
 
 static
@@ -184,15 +186,24 @@ void struct_declaration_add_field(struct declaration_struct *struct_declaration,
                                       field_declaration->alignment);
 }
 
-unsigned long
-       struct_declaration_lookup_field_index(struct declaration_struct *struct_declaration,
+/*
+ * struct_declaration_lookup_field_index - returns field index
+ *
+ * Returns the index of a field in a structure, or -1 if it does not
+ * exist.
+ */
+int struct_declaration_lookup_field_index(struct declaration_struct *struct_declaration,
                                       GQuark field_name)
 {
-       unsigned long index;
-
-       index = (unsigned long) g_hash_table_lookup(struct_declaration->fields_by_name,
-                                                   (gconstpointer) (unsigned long) field_name);
-       return index;
+       gpointer index;
+       gboolean found;
+
+       found = g_hash_table_lookup_extended(struct_declaration->fields_by_name,
+                                   (gconstpointer) (unsigned long) field_name,
+                                   NULL, &index);
+       if (!found)
+               return -1;
+       return (int) (unsigned long) index;
 }
 
 /*
@@ -200,8 +211,10 @@ unsigned long
  */
 struct declaration_field *
        struct_declaration_get_field_from_index(struct declaration_struct *struct_declaration,
-                                        unsigned long index)
+                                        int index)
 {
+       if (index < 0)
+               return NULL;
        return &g_array_index(struct_declaration->fields, struct declaration_field, index);
 }
 
@@ -210,7 +223,9 @@ struct declaration_field *
  */
 struct field *
 struct_definition_get_field_from_index(struct definition_struct *_struct,
-                                       unsigned long index)
+                                       int index)
 {
+       if (index < 0)
+               return NULL;
        return &g_array_index(_struct->fields, struct field, index);
 }
index a61d895c274c5041e339e6c9e09eddb5f8ae40de..1af0c790dc6fd5f56b5a1845f04a565c81add211 100644 (file)
@@ -38,14 +38,16 @@ void variant_copy(struct stream_pos *dest, const struct format *fdest,
        struct declaration *field_declaration;
 
        fsrc->variant_begin(src, variant_declaration);
-       fdest->variant_begin(dest, variant_declaration);
+       if (fdest)
+               fdest->variant_begin(dest, variant_declaration);
 
        field = variant_get_current_field(variant);
        field_declaration = field->definition->declaration;
        field_declaration->copy(dest, fdest, src, fsrc, field->definition);
 
        fsrc->variant_end(src, variant_declaration);
-       fdest->variant_end(dest, variant_declaration);
+       if (fdest)
+               fdest->variant_end(dest, variant_declaration);
 }
 
 static
This page took 0.075421 seconds and 4 git commands to generate.