Fix: Check integer signedness in packet header when auto-populating
[babeltrace.git] / formats / ctf / ir / stream.c
index e618251e577a3d6e5614b475faa8b1d30c926385..45f875ff641ff7a2b0efaedbb1591b9ad4e59432 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * stream.c
  *
- * Babeltrace CTF Writer
+ * Babeltrace CTF IR - Stream
  *
  * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
  *
@@ -48,6 +48,7 @@ BT_HIDDEN
 struct bt_ctf_stream *bt_ctf_stream_create(
                struct bt_ctf_stream_class *stream_class)
 {
+       int ret;
        struct bt_ctf_stream *stream = NULL;
 
        if (!stream_class) {
@@ -60,15 +61,55 @@ struct bt_ctf_stream *bt_ctf_stream_create(
        }
 
        bt_ctf_ref_init(&stream->ref_count);
+       stream->packet_context = bt_ctf_field_create(
+               stream_class->packet_context_type);
+       if (!stream->packet_context) {
+               goto error_destroy;
+       }
+
+       /*
+        * A stream class may not have a stream event context defined
+        * in which case this stream will never have a stream_event_context
+        * member since, after a stream's creation, the parent stream class
+        * is "frozen" (immutable).
+        */
+       if (stream_class->event_context_type) {
+               stream->event_context = bt_ctf_field_create(
+                       stream_class->event_context_type);
+               if (!stream->packet_context) {
+                       goto error_destroy;
+               }
+       }
+
+       /* Initialize events_discarded */
+       ret = set_structure_field_integer(stream->packet_context,
+               "events_discarded", 0);
+       if (ret) {
+               goto error_destroy;
+       }
+
        stream->pos.fd = -1;
        stream->id = stream_class->next_stream_id++;
        stream->stream_class = stream_class;
        bt_ctf_stream_class_get(stream_class);
        bt_ctf_stream_class_freeze(stream_class);
        stream->events = g_ptr_array_new_with_free_func(
-               (GDestroyNotify)bt_ctf_event_put);
+               (GDestroyNotify) bt_ctf_event_put);
+       if (!stream->events) {
+               goto error_destroy;
+       }
+       if (stream_class->event_context_type) {
+               stream->event_contexts = g_ptr_array_new_with_free_func(
+                       (GDestroyNotify) bt_ctf_field_put);
+               if (!stream->event_contexts) {
+                       goto error_destroy;
+               }
+       }
 end:
        return stream;
+error_destroy:
+       bt_ctf_stream_destroy(&stream->ref_count);
+       return NULL;
 }
 
 BT_HIDDEN
@@ -107,25 +148,127 @@ int bt_ctf_stream_get_discarded_events_count(
                struct bt_ctf_stream *stream, uint64_t *count)
 {
        int64_t ret = 0;
+       int field_signed;
+       struct bt_ctf_field *events_discarded_field = NULL;
+       struct bt_ctf_field_type *events_discarded_field_type = NULL;
+
+       if (!stream || !count || !stream->packet_context) {
+               ret = -1;
+               goto end;
+       }
 
-       if (!stream || !count) {
+       events_discarded_field = bt_ctf_field_structure_get_field(
+               stream->packet_context, "events_discarded");
+       if (!events_discarded_field) {
                ret = -1;
                goto end;
        }
 
-       *count = stream->events_discarded;
+       events_discarded_field_type = bt_ctf_field_get_type(
+               events_discarded_field);
+       if (!events_discarded_field_type) {
+               ret = -1;
+               goto end;
+       }
+
+       field_signed = bt_ctf_field_type_integer_get_signed(
+               events_discarded_field_type);
+       if (field_signed < 0) {
+               ret = field_signed;
+               goto end;
+       }
+
+       if (field_signed) {
+               int64_t signed_count;
+
+               ret = bt_ctf_field_signed_integer_get_value(
+                       events_discarded_field, &signed_count);
+               if (ret) {
+                       goto end;
+               }
+               if (signed_count < 0) {
+                       /* Invalid value */
+                       ret = -1;
+                       goto end;
+               }
+               *count = (uint64_t) signed_count;
+       } else {
+               ret = bt_ctf_field_unsigned_integer_get_value(
+                       events_discarded_field, count);
+               if (ret) {
+                       goto end;
+               }
+       }
 end:
+       if (events_discarded_field) {
+               bt_ctf_field_put(events_discarded_field);
+       }
+       if (events_discarded_field_type) {
+               bt_ctf_field_type_put(events_discarded_field_type);
+       }
        return ret;
 }
 
 void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
                uint64_t event_count)
 {
-       if (!stream) {
-               return;
+       int ret;
+       int field_signed;
+       uint64_t previous_count;
+       uint64_t new_count;
+       struct bt_ctf_field *events_discarded_field = NULL;
+       struct bt_ctf_field_type *events_discarded_field_type = NULL;
+
+       if (!stream || !stream->packet_context) {
+               goto end;
+       }
+
+       ret = bt_ctf_stream_get_discarded_events_count(stream,
+               &previous_count);
+       if (ret) {
+               goto end;
        }
 
-       stream->events_discarded += event_count;
+       events_discarded_field = bt_ctf_field_structure_get_field(
+               stream->packet_context, "events_discarded");
+       if (!events_discarded_field) {
+               goto end;
+       }
+
+       events_discarded_field_type = bt_ctf_field_get_type(
+               events_discarded_field);
+       if (!events_discarded_field_type) {
+               goto end;
+       }
+
+       field_signed = bt_ctf_field_type_integer_get_signed(
+               events_discarded_field_type);
+       if (field_signed < 0) {
+               goto end;
+       }
+
+       new_count = previous_count + event_count;
+       if (field_signed) {
+               ret = bt_ctf_field_signed_integer_set_value(
+                       events_discarded_field, (int64_t) new_count);
+               if (ret) {
+                       goto end;
+               }
+       } else {
+               ret = bt_ctf_field_unsigned_integer_set_value(
+                       events_discarded_field, new_count);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       if (events_discarded_field) {
+               bt_ctf_field_put(events_discarded_field);
+       }
+       if (events_discarded_field_type) {
+               bt_ctf_field_type_put(events_discarded_field_type);
+       }
 }
 
 int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
@@ -133,17 +276,34 @@ int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
 {
        int ret = 0;
        uint64_t timestamp;
+       struct bt_ctf_field *event_context_copy = NULL;
 
        if (!stream || !event) {
                ret = -1;
                goto end;
        }
 
+       /* Make sure the event's payload is set */
        ret = bt_ctf_event_validate(event);
        if (ret) {
                goto end;
        }
 
+       /* Sample the current stream event context by copying it */
+       if (stream->event_context) {
+               /* Make sure the event context's payload is set */
+               ret = bt_ctf_field_validate(stream->event_context);
+               if (ret) {
+                       goto end;
+               }
+
+               event_context_copy = bt_ctf_field_copy(stream->event_context);
+               if (!event_context_copy) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
        timestamp = bt_ctf_clock_get_time(stream->stream_class->clock);
        ret = bt_ctf_event_set_timestamp(event, timestamp);
        if (ret) {
@@ -151,21 +311,115 @@ int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
        }
 
        bt_ctf_event_get(event);
+       /* Save the new event along with its associated stream event context */
        g_ptr_array_add(stream->events, event);
+       if (event_context_copy) {
+               g_ptr_array_add(stream->event_contexts, event_context_copy);
+       }
+end:
+       return ret;
+}
+
+struct bt_ctf_field *bt_ctf_stream_get_packet_context(
+               struct bt_ctf_stream *stream)
+{
+       struct bt_ctf_field *packet_context = NULL;
+
+       if (!stream) {
+               goto end;
+       }
+
+       packet_context = stream->packet_context;
+       if (packet_context) {
+               bt_ctf_field_get(packet_context);
+       }
+end:
+       return packet_context;
+}
+
+int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream,
+               struct bt_ctf_field *field)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *field_type;
+
+       if (!stream || !field) {
+               ret = -1;
+               goto end;
+       }
+
+       field_type = bt_ctf_field_get_type(field);
+       if (field_type != stream->stream_class->packet_context_type) {
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_field_type_put(field_type);
+       bt_ctf_field_get(field);
+       bt_ctf_field_put(stream->packet_context);
+       stream->packet_context = field;
 end:
        return ret;
 }
 
+struct bt_ctf_field *bt_ctf_stream_get_event_context(
+               struct bt_ctf_stream *stream)
+{
+       struct bt_ctf_field *event_context = NULL;
+
+       if (!stream) {
+               goto end;
+       }
+
+       event_context = stream->event_context;
+       if (event_context) {
+               bt_ctf_field_get(event_context);
+       }
+end:
+       return event_context;
+}
+
+int bt_ctf_stream_set_event_context(struct bt_ctf_stream *stream,
+               struct bt_ctf_field *field)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *field_type = NULL;
+
+       if (!stream || !field) {
+               ret = -1;
+               goto end;
+       }
+
+       field_type = bt_ctf_field_get_type(field);
+       if (field_type != stream->stream_class->event_context_type) {
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_field_get(field);
+       bt_ctf_field_put(stream->event_context);
+       stream->event_context = field;
+end:
+       if (field_type) {
+               bt_ctf_field_type_put(field_type);
+       }
+       return ret;
+}
+
 int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
 {
        int ret = 0;
        size_t i;
-       uint64_t timestamp_begin, timestamp_end;
+       uint64_t timestamp_begin, timestamp_end, events_discarded;
        struct bt_ctf_stream_class *stream_class;
        struct bt_ctf_field *integer = NULL;
        struct ctf_stream_pos packet_context_pos;
 
-       if (!stream) {
+       if (!stream || stream->pos.fd < 0) {
+               /*
+                * Stream does not have an associated fd. It is,
+                * therefore, not a stream being used to write events.
+                */
                ret = -1;
                goto end;
        }
@@ -183,31 +437,27 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
                stream->events, 0))->timestamp;
        timestamp_end = ((struct bt_ctf_event *) g_ptr_array_index(
                stream->events, stream->events->len - 1))->timestamp;
-       ret = set_structure_field_integer(stream_class->packet_context,
+
+       /* Set the default context attributes if present and unset. */
+       ret = set_structure_field_integer(stream->packet_context,
                "timestamp_begin", timestamp_begin);
        if (ret) {
                goto end;
        }
 
-       ret = set_structure_field_integer(stream_class->packet_context,
+       ret = set_structure_field_integer(stream->packet_context,
                "timestamp_end", timestamp_end);
        if (ret) {
                goto end;
        }
 
-       ret = set_structure_field_integer(stream_class->packet_context,
-               "events_discarded", stream->events_discarded);
-       if (ret) {
-               goto end;
-       }
-
-       ret = set_structure_field_integer(stream_class->packet_context,
+       ret = set_structure_field_integer(stream->packet_context,
                "content_size", UINT64_MAX);
        if (ret) {
                goto end;
        }
 
-       ret = set_structure_field_integer(stream_class->packet_context,
+       ret = set_structure_field_integer(stream->packet_context,
                "packet_size", UINT64_MAX);
        if (ret) {
                goto end;
@@ -216,12 +466,31 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
        /* Write packet context */
        memcpy(&packet_context_pos, &stream->pos,
               sizeof(struct ctf_stream_pos));
-       ret = bt_ctf_field_serialize(stream_class->packet_context,
+       ret = bt_ctf_field_serialize(stream->packet_context,
                &stream->pos);
        if (ret) {
                goto end;
        }
 
+       ret = bt_ctf_stream_get_discarded_events_count(stream,
+               &events_discarded);
+       if (ret) {
+               goto end;
+       }
+
+       /* Unset the packet context's fields. */
+       ret = bt_ctf_field_reset(stream->packet_context);
+       if (ret) {
+               goto end;
+       }
+
+       /* Set the previous number of discarded events. */
+       ret = set_structure_field_integer(stream->packet_context,
+               "events_discarded", events_discarded);
+       if (ret) {
+               goto end;
+       }
+
        for (i = 0; i < stream->events->len; i++) {
                struct bt_ctf_event *event = g_ptr_array_index(
                        stream->events, i);
@@ -229,6 +498,11 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
                        event->event_class);
                uint64_t timestamp = bt_ctf_event_get_timestamp(event);
 
+               ret = bt_ctf_field_reset(stream_class->event_header);
+               if (ret) {
+                       goto end;
+               }
+
                ret = set_structure_field_integer(stream_class->event_header,
                        "id", event_id);
                if (ret) {
@@ -247,6 +521,16 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
                        goto end;
                }
 
+               /* Write stream event context */
+               if (stream->event_contexts) {
+                       ret = bt_ctf_field_serialize(
+                               g_ptr_array_index(stream->event_contexts, i),
+                               &stream->pos);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
                /* Write event content */
                ret = bt_ctf_event_serialize(event, &stream->pos);
                if (ret) {
@@ -261,25 +545,28 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
         * packet is resized).
         */
        packet_context_pos.base_mma = stream->pos.base_mma;
-       ret = set_structure_field_integer(stream_class->packet_context,
+       ret = set_structure_field_integer(stream->packet_context,
                "content_size", stream->pos.offset);
        if (ret) {
                goto end;
        }
 
-       ret = set_structure_field_integer(stream_class->packet_context,
+       ret = set_structure_field_integer(stream->packet_context,
                "packet_size", stream->pos.packet_size);
        if (ret) {
                goto end;
        }
 
-       ret = bt_ctf_field_serialize(stream_class->packet_context,
+       ret = bt_ctf_field_serialize(stream->packet_context,
                &packet_context_pos);
        if (ret) {
                goto end;
        }
 
        g_ptr_array_set_size(stream->events, 0);
+       if (stream->event_contexts) {
+               g_ptr_array_set_size(stream->event_contexts, 0);
+       }
        stream->flushed_packet_count++;
 end:
        bt_ctf_field_put(integer);
@@ -318,8 +605,22 @@ void bt_ctf_stream_destroy(struct bt_ctf_ref *ref)
        if (close(stream->pos.fd)) {
                perror("close");
        }
-       bt_ctf_stream_class_put(stream->stream_class);
-       g_ptr_array_free(stream->events, TRUE);
+
+       if (stream->stream_class) {
+               bt_ctf_stream_class_put(stream->stream_class);
+       }
+       if (stream->events) {
+               g_ptr_array_free(stream->events, TRUE);
+       }
+       if (stream->event_contexts) {
+               g_ptr_array_free(stream->event_contexts, TRUE);
+       }
+       if (stream->packet_context) {
+               bt_ctf_field_put(stream->packet_context);
+       }
+       if (stream->event_context) {
+               bt_ctf_field_put(stream->event_context);
+       }
        g_free(stream);
 }
 
@@ -328,16 +629,51 @@ int set_structure_field_integer(struct bt_ctf_field *structure, char *name,
                uint64_t value)
 {
        int ret = 0;
-
+       struct bt_ctf_field_type *field_type = NULL;
        struct bt_ctf_field *integer =
                bt_ctf_field_structure_get_field(structure, name);
+
+       if (!structure || !name) {
+               ret = -1;
+               goto end;
+       }
+
        if (!integer) {
+               /* Field not found, not an error. */
+               goto end;
+       }
+
+       /* Make sure the payload has not already been set. */
+       if (!bt_ctf_field_validate(integer)) {
+               /* Payload already set, not an error */
+               goto end;
+       }
+
+       field_type = bt_ctf_field_get_type(integer);
+       /* Something is serioulsly wrong */
+       assert(field_type);
+       if (bt_ctf_field_type_get_type_id(field_type) != CTF_TYPE_INTEGER) {
+               /*
+                * The user most likely meant for us to populate this field
+                * automatically. However, we can only do this if the field
+                * is an integer. Return an error.
+                */
                ret = -1;
                goto end;
        }
 
-       ret = bt_ctf_field_unsigned_integer_set_value(integer, value);
+       if (bt_ctf_field_type_integer_get_signed(field_type)) {
+               ret = bt_ctf_field_signed_integer_set_value(integer,
+                       (int64_t) value);
+       } else {
+               ret = bt_ctf_field_unsigned_integer_set_value(integer, value);
+       }
 end:
-       bt_ctf_field_put(integer);
+       if (integer) {
+               bt_ctf_field_put(integer);
+       }
+       if (field_type) {
+               bt_ctf_field_type_put(field_type);
+       }
        return ret;
 }
This page took 0.029005 seconds and 4 git commands to generate.