ir: bt_ctf_stream_append_event(): do not always reset parent
[babeltrace.git] / formats / ctf / ir / stream.c
index 69e2fe18bb3356f2169ab48ff857f06296ed4a25..56abfcea5f89fe1f78f47241428fcc20d3688361 100644 (file)
@@ -35,6 +35,8 @@
 #include <babeltrace/ctf-ir/stream.h>
 #include <babeltrace/ctf-ir/stream-internal.h>
 #include <babeltrace/ctf-ir/stream-class-internal.h>
+#include <babeltrace/ctf-ir/trace-internal.h>
+#include <babeltrace/ctf-writer/writer-internal.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/ctf-writer/functor-internal.h>
 #include <babeltrace/compiler.h>
@@ -252,21 +254,71 @@ void release_event(struct bt_ctf_event *event)
        }
 }
 
-BT_HIDDEN
+static
+int create_stream_file(struct bt_ctf_writer *writer,
+               struct bt_ctf_stream *stream)
+{
+       int fd;
+       GString *filename = g_string_new(stream->stream_class->name->str);
+
+       if (stream->stream_class->name->len == 0) {
+               int64_t ret;
+
+               ret = bt_ctf_stream_class_get_id(stream->stream_class);
+               if (ret < 0) {
+                       fd = -1;
+                       goto error;
+               }
+
+               g_string_printf(filename, "stream_%" PRId64, ret);
+       }
+
+       g_string_append_printf(filename, "_%" PRIu32, stream->id);
+       fd = openat(writer->trace_dir_fd, filename->str,
+               O_RDWR | O_CREAT | O_TRUNC,
+               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+error:
+       g_string_free(filename, TRUE);
+       return fd;
+}
+
+static
+int set_stream_fd(struct bt_ctf_stream *stream, int fd)
+{
+       int ret = 0;
+
+       if (stream->pos.fd != -1) {
+               ret = -1;
+               goto end;
+       }
+
+       ctf_init_pos(&stream->pos, NULL, fd, O_RDWR);
+       stream->pos.fd = fd;
+end:
+       return ret;
+}
+
 struct bt_ctf_stream *bt_ctf_stream_create(
-       struct bt_ctf_stream_class *stream_class,
-       struct bt_ctf_trace *trace)
+               struct bt_ctf_stream_class *stream_class,
+               const char *name)
 {
        int ret;
        struct bt_ctf_stream *stream = NULL;
+       struct bt_ctf_trace *trace = NULL;
+       struct bt_ctf_writer *writer = NULL;
 
-       if (!stream_class || !trace) {
-               goto end;
+       if (!stream_class) {
+               goto error;
+       }
+
+       trace = bt_ctf_stream_class_get_trace(stream_class);
+       if (!trace) {
+               goto error;
        }
 
        stream = g_new0(struct bt_ctf_stream, 1);
        if (!stream) {
-               goto end;
+               goto error;
        }
 
        bt_object_init(stream, bt_ctf_stream_destroy);
@@ -275,70 +327,100 @@ struct bt_ctf_stream *bt_ctf_stream_create(
         * reachable; it needs its parent to remain valid.
         */
        bt_object_set_parent(stream, trace);
-       stream->packet_context = bt_ctf_field_create(
-               stream_class->packet_context_type);
-       if (!stream->packet_context) {
-               goto error;
-       }
-
-       /* Initialize events_discarded */
-       ret = set_structure_field_integer(stream->packet_context,
-               "events_discarded", 0);
-       if (ret) {
-               goto error;
-       }
-
-       stream->pos.fd = -1;
        stream->id = stream_class->next_stream_id++;
        stream->stream_class = stream_class;
-       stream->events = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) release_event);
-       if (!stream->events) {
-               goto error;
-       }
+       stream->pos.fd = -1;
 
-       /* A trace is not allowed to have a NULL packet header */
-       assert(trace->packet_header_type);
-       stream->packet_header = bt_ctf_field_create(trace->packet_header_type);
-       if (!stream->packet_header) {
-               goto error;
+       if (name) {
+               stream->name = g_string_new(name);
+               if (!stream->name) {
+                       goto error;
+               }
        }
-       /*
-        * Attempt to populate the default trace packet header fields
-        * (magic, uuid and stream_id). This will _not_ fail shall the
-        * fields not be found or be of an incompatible type; they will
-        * simply not be populated automatically. The user will have to
-        * make sure to set the trace packet header fields himself before
-        * flushing.
-        */
-       ret = set_packet_header(stream);
-       if (ret) {
-               goto error;
+
+       if (trace->is_created_by_writer) {
+               int fd;
+               writer = (struct bt_ctf_writer *)
+                       bt_object_get_parent(trace);
+
+               assert(writer);
+               stream->packet_context = bt_ctf_field_create(
+                       stream_class->packet_context_type);
+               if (!stream->packet_context) {
+                       goto error;
+               }
+
+               /* Initialize events_discarded */
+               ret = set_structure_field_integer(stream->packet_context,
+                       "events_discarded", 0);
+               if (ret) {
+                       goto error;
+               }
+
+               stream->events = g_ptr_array_new_with_free_func(
+                       (GDestroyNotify) release_event);
+               if (!stream->events) {
+                       goto error;
+               }
+
+               /* A trace is not allowed to have a NULL packet header */
+               assert(trace->packet_header_type);
+               stream->packet_header =
+                       bt_ctf_field_create(trace->packet_header_type);
+               if (!stream->packet_header) {
+                       goto error;
+               }
+
+               /*
+                * Attempt to populate the default trace packet header fields
+                * (magic, uuid and stream_id). This will _not_ fail shall the
+                * fields not be found or be of an incompatible type; they will
+                * simply not be populated automatically. The user will have to
+                * make sure to set the trace packet header fields himself
+                * before flushing.
+                */
+               ret = set_packet_header(stream);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Create file associated with this stream */
+               fd = create_stream_file(writer, stream);
+               if (fd < 0) {
+                       goto error;
+               }
+
+               ret = set_stream_fd(stream, fd);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Freeze the writer */
+               bt_ctf_writer_freeze(writer);
+       } else {
+               /* Non-writer stream indicated by a negative FD */
+               ret = set_stream_fd(stream, -1);
+               if (ret) {
+                       goto error;
+               }
+
+               stream->clock_values = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, NULL, g_free);
        }
-end:
+
+       /* Add this stream to the trace's streams */
+       g_ptr_array_add(trace->streams, stream);
+
+       BT_PUT(trace);
+       BT_PUT(writer);
        return stream;
 error:
        BT_PUT(stream);
-       bt_put(trace);
+       BT_PUT(trace);
+       BT_PUT(writer);
        return stream;
 }
 
-BT_HIDDEN
-int bt_ctf_stream_set_fd(struct bt_ctf_stream *stream, int fd)
-{
-       int ret = 0;
-
-       if (stream->pos.fd != -1) {
-               ret = -1;
-               goto end;
-       }
-
-       ctf_init_pos(&stream->pos, NULL, fd, O_RDWR);
-       stream->pos.fd = fd;
-end:
-       return ret;
-}
-
 struct bt_ctf_stream_class *bt_ctf_stream_get_class(
                struct bt_ctf_stream *stream)
 {
@@ -362,7 +444,8 @@ int bt_ctf_stream_get_discarded_events_count(
        struct bt_ctf_field *events_discarded_field = NULL;
        struct bt_ctf_field_type *events_discarded_field_type = NULL;
 
-       if (!stream || !count || !stream->packet_context) {
+       if (!stream || !count || !stream->packet_context ||
+                       stream->pos.fd < 0) {
                ret = -1;
                goto end;
        }
@@ -425,7 +508,7 @@ void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
        struct bt_ctf_field *events_discarded_field = NULL;
        struct bt_ctf_field_type *events_discarded_field_type = NULL;
 
-       if (!stream || !stream->packet_context) {
+       if (!stream || !stream->packet_context || stream->pos.fd < 0) {
                goto end;
        }
 
@@ -478,7 +561,20 @@ int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
 {
        int ret = 0;
 
-       if (!stream || !event) {
+       if (!stream || !event || stream->pos.fd < 0) {
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * The event is not supposed to have a parent stream at this
+        * point. The only other way an event can have a parent stream
+        * is if it was assigned when setting a packet to the event,
+        * in which case the packet's stream is not a writer stream,
+        * and thus the user is trying to append an event which belongs
+        * to another stream.
+        */
+       if (event->base.parent) {
                ret = -1;
                goto end;
        }
@@ -486,13 +582,13 @@ int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
        bt_object_set_parent(event, stream);
        ret = bt_ctf_event_populate_event_header(event);
        if (ret) {
-               goto end;
+               goto error;
        }
 
        /* Make sure the various scopes of the event are set */
        ret = bt_ctf_event_validate(event);
        if (ret) {
-               goto end;
+               goto error;
        }
 
        /* Save the new event and freeze it */
@@ -506,14 +602,17 @@ int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
         * longer needed.
         */
        bt_put(event->event_class);
+
 end:
-       if (ret) {
-               /*
-                * Orphan the event; we were not succesful in associating it to
-                * a stream.
-                */
-               bt_object_set_parent(event, NULL);
-       }
+       return ret;
+
+error:
+       /*
+        * Orphan the event; we were not successful in associating it to
+        * a stream.
+        */
+       bt_object_set_parent(event, NULL);
+
        return ret;
 }
 
@@ -522,7 +621,7 @@ struct bt_ctf_field *bt_ctf_stream_get_packet_context(
 {
        struct bt_ctf_field *packet_context = NULL;
 
-       if (!stream) {
+       if (!stream || stream->pos.fd < 0) {
                goto end;
        }
 
@@ -540,7 +639,7 @@ int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream,
        int ret = 0;
        struct bt_ctf_field_type *field_type;
 
-       if (!stream || !field) {
+       if (!stream || !field || stream->pos.fd < 0) {
                ret = -1;
                goto end;
        }
@@ -565,7 +664,7 @@ struct bt_ctf_field *bt_ctf_stream_get_packet_header(
 {
        struct bt_ctf_field *packet_header = NULL;
 
-       if (!stream) {
+       if (!stream || stream->pos.fd < 0) {
                goto end;
        }
 
@@ -584,7 +683,7 @@ int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream,
        struct bt_ctf_trace *trace = NULL;
        struct bt_ctf_field_type *field_type = NULL;
 
-       if (!stream || !field) {
+       if (!stream || !field || stream->pos.fd < 0) {
                ret = -1;
                goto end;
        }
@@ -833,9 +932,17 @@ void bt_ctf_stream_destroy(struct bt_object *obj)
        if (stream->events) {
                g_ptr_array_free(stream->events, TRUE);
        }
+
+       if (stream->name) {
+               g_string_free(stream->name, TRUE);
+       }
+
+       if (stream->clock_values) {
+               g_hash_table_destroy(stream->clock_values);
+       }
+
        bt_put(stream->packet_header);
        bt_put(stream->packet_context);
-       bt_put(stream->event_context);
        g_free(stream);
 }
 
@@ -888,3 +995,92 @@ end:
        bt_put(field_type);
        return ret;
 }
+
+const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream)
+{
+       const char *name = NULL;
+
+       if (!stream) {
+               goto end;
+       }
+
+       name = stream->name ? stream->name->str : NULL;
+
+end:
+       return name;
+}
+
+BT_HIDDEN
+void bt_ctf_stream_update_clock_value(struct bt_ctf_stream *stream,
+               struct bt_ctf_field *value_field)
+{
+       struct bt_ctf_field_type *value_type = NULL;
+       struct bt_ctf_clock *clock = NULL;
+       uint64_t requested_new_value;
+       uint64_t requested_new_value_mask;
+       uint64_t *cur_value;
+       uint64_t cur_value_masked;
+       int requested_new_value_size;
+       int ret;
+
+       assert(stream);
+       assert(clock);
+       assert(value_field);
+       value_type = bt_ctf_field_get_type(value_field);
+       assert(value_type);
+       clock = bt_ctf_field_type_integer_get_mapped_clock(value_type);
+       assert(clock);
+       requested_new_value_size =
+               bt_ctf_field_type_integer_get_size(value_type);
+       assert(requested_new_value_size > 0);
+       ret = bt_ctf_field_unsigned_integer_get_value(value_field,
+               &requested_new_value);
+       assert(!ret);
+       cur_value = g_hash_table_lookup(stream->clock_values, clock);
+
+       if (!cur_value) {
+               /*
+                * Updating the value of a clock which is not registered
+                * yet, so register it with the new value as its initial
+                * value.
+                */
+               uint64_t *requested_new_value_ptr = g_new0(uint64_t, 1);
+
+               *requested_new_value_ptr = requested_new_value;
+               g_hash_table_insert(stream->clock_values, clock,
+                       requested_new_value_ptr);
+               goto end;
+       }
+
+       /*
+        * Special case for a 64-bit new value, which is the limit
+        * of a clock value as of this version: overwrite the
+        * current value directly.
+        */
+       if (requested_new_value_size == 64) {
+               *cur_value = requested_new_value;
+               goto end;
+       }
+
+       requested_new_value_mask = (1ULL << requested_new_value_size) - 1;
+       cur_value_masked = *cur_value & requested_new_value_mask;
+
+       if (requested_new_value < cur_value_masked) {
+               /*
+                * It looks like a wrap happened on the number of bits
+                * of the requested new value. Assume that the clock
+                * value wrapped only one time.
+                */
+               *cur_value += requested_new_value_mask + 1;
+       }
+
+       /* Clear the low bits of the current clock value */
+       *cur_value &= ~requested_new_value_mask;
+
+       /* Set the low bits of the current clock value */
+       *cur_value |= requested_new_value;
+
+end:
+       bt_put(clock);
+       bt_put(value_type);
+}
This page took 0.037038 seconds and 4 git commands to generate.