Allow NULL (unset) packet, stream and event headers, contexts
[babeltrace.git] / plugins / ctf / common / notif-iter / notif-iter.c
index 56bf9fff49b04e9bbc829d6f2c791840d9bd5f86..6411dd1f20c6626132ee007061ca530c069e35f1 100644 (file)
@@ -173,6 +173,9 @@ struct bt_ctf_notif_iter {
 
        /* Current content size (bits) (-1 if unknown) */
        int64_t cur_content_size;
+
+       /* bt_ctf_clock to uint64_t. */
+       GHashTable *clock_states;
 };
 
 static
@@ -496,8 +499,7 @@ enum bt_ctf_notif_iter_status read_packet_header_begin_state(
        packet_header_type = bt_ctf_trace_get_packet_header_type(
                        notit->meta.trace);
        if (!packet_header_type) {
-               PERR("Failed to retrieve trace's packet header type\n");
-               ret = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+               notit->state = STATE_AFTER_TRACE_PACKET_HEADER;
                goto end;
        }
 
@@ -533,7 +535,8 @@ bool is_variant_type(struct bt_ctf_field_type *field_type)
 }
 
 static inline
-enum bt_ctf_notif_iter_status set_current_stream_class(struct bt_ctf_notif_iter *notit)
+enum bt_ctf_notif_iter_status set_current_stream_class(
+               struct bt_ctf_notif_iter *notit)
 {
        enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
        struct bt_ctf_field_type *packet_header_type;
@@ -578,7 +581,6 @@ enum bt_ctf_notif_iter_status set_current_stream_class(struct bt_ctf_notif_iter
        }
 
        BT_PUT(notit->meta.stream_class);
-
        notit->meta.stream_class = bt_ctf_trace_get_stream_class_by_id(
                        notit->meta.trace, stream_id);
        if (!notit->meta.stream_class) {
@@ -620,8 +622,7 @@ enum bt_ctf_notif_iter_status read_packet_context_begin_state(
        packet_context_type = bt_ctf_stream_class_get_packet_context_type(
                        notit->meta.stream_class);
        if (!packet_context_type) {
-               PERR("Failed to retrieve stream class's packet context\n");
-               status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+               notit->state = STATE_AFTER_STREAM_PACKET_CONTEXT;
                goto end;
        }
 
@@ -732,8 +733,7 @@ enum bt_ctf_notif_iter_status read_event_header_begin_state(
        event_header_type = bt_ctf_stream_class_get_event_header_type(
                notit->meta.stream_class);
        if (!event_header_type) {
-               PERR("Failed to retrieve stream class's event header type\n");
-               status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+               notit->state = STATE_AFTER_STREAM_EVENT_HEADER;
                goto end;
        }
 
@@ -889,12 +889,6 @@ enum bt_ctf_notif_iter_status after_event_header_state(
 {
        enum bt_ctf_notif_iter_status status;
 
-       status = set_current_packet_content_sizes(notit);
-       if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
-               PERR("Failed to set current packet and content sizes\n");
-               goto end;
-       }
-
        status = set_current_event_class(notit);
        if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
                PERR("Failed to set current event class\n");
@@ -917,8 +911,7 @@ enum bt_ctf_notif_iter_status read_stream_event_context_begin_state(
        stream_event_context_type = bt_ctf_stream_class_get_event_context_type(
                notit->meta.stream_class);
        if (!stream_event_context_type) {
-               PERR("Failed to retrieve stream class's event context type\n");
-               status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+               notit->state = STATE_DSCOPE_EVENT_CONTEXT_BEGIN;
                goto end;
        }
 
@@ -951,11 +944,9 @@ enum bt_ctf_notif_iter_status read_event_context_begin_state(
        event_context_type = bt_ctf_event_class_get_context_type(
                notit->meta.event_class);
        if (!event_context_type) {
-               PERR("Failed to retrieve event class's context type\n");
-               status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+               notit->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN;
                goto end;
        }
-
        status = read_dscope_begin_state(notit, event_context_type,
                STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
                STATE_DSCOPE_EVENT_CONTEXT_CONTINUE,
@@ -985,8 +976,7 @@ enum bt_ctf_notif_iter_status read_event_payload_begin_state(
        event_payload_type = bt_ctf_event_class_get_payload_type(
                notit->meta.event_class);
        if (!event_payload_type) {
-               PERR("Failed to retrieve event class's payload type\n");
-               status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+               notit->state = STATE_EMIT_NOTIF_EVENT;
                goto end;
        }
 
@@ -1227,6 +1217,103 @@ end:
        return next_field;
 }
 
+static
+void update_clock_state(uint64_t *state,
+               struct bt_ctf_field *value_field)
+{
+       struct bt_ctf_field_type *value_type = NULL;
+       uint64_t requested_new_value;
+       uint64_t requested_new_value_mask;
+       uint64_t cur_value_masked;
+       int requested_new_value_size;
+       int ret;
+
+       value_type = bt_ctf_field_get_type(value_field);
+       assert(value_type);
+
+       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);
+
+       /*
+        * 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) {
+               *state = requested_new_value;
+               goto end;
+       }
+
+       requested_new_value_mask = (1ULL << requested_new_value_size) - 1;
+       cur_value_masked = *state & 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.
+                */
+               *state += requested_new_value_mask + 1;
+       }
+
+       /* Clear the low bits of the current clock value. */
+       *state &= ~requested_new_value_mask;
+
+       /* Set the low bits of the current clock value. */
+       *state |= requested_new_value;
+end:
+       bt_put(value_type);
+}
+
+static
+enum bt_ctf_btr_status update_clock(struct bt_ctf_notif_iter *notit,
+               struct bt_ctf_field_type *int_field_type,
+               struct bt_ctf_field *int_field)
+{
+       gboolean clock_found;
+       uint64_t *clock_state;
+       enum bt_ctf_btr_status ret = BT_CTF_BTR_STATUS_OK;
+       struct bt_ctf_clock *clock = bt_ctf_field_type_integer_get_mapped_clock(
+                       int_field_type);
+
+       if (likely(!clock)) {
+               goto end_no_clock;
+       }
+
+       clock_found = g_hash_table_lookup_extended(notit->clock_states,
+                       clock, NULL, (gpointer) &clock_state);
+       if (unlikely(!clock_found)) {
+               const char *clock_name = bt_ctf_clock_get_name(clock);
+
+               PERR("Unknown clock %s mapped to integer encountered in stream\n",
+                               clock_name ? : "NULL");
+               ret = BT_CTF_BTR_STATUS_ERROR;
+               goto end;
+       }
+
+       if (unlikely(!clock_state)) {
+               clock_state = g_new0(uint64_t, 1);
+               if (!clock_state) {
+                       ret = BT_CTF_BTR_STATUS_ENOMEM;
+                       goto end;
+               }
+               g_hash_table_insert(notit->clock_states, bt_get(clock),
+                               clock_state);
+       }
+
+       /* Update the clock's state. */
+       update_clock_state(clock_state, int_field);
+end:
+       bt_put(clock);
+end_no_clock:
+       return ret;
+}
+
 static
 enum bt_ctf_btr_status btr_signed_int_cb(int64_t value,
                struct bt_ctf_field_type *type, void *data)
@@ -1242,18 +1329,22 @@ enum bt_ctf_btr_status btr_signed_int_cb(int64_t value,
        if (!field) {
                PERR("Failed to get next field (signed int)\n");
                status = BT_CTF_BTR_STATUS_ERROR;
-               goto end;
+               goto end_no_put;
        }
 
        switch(bt_ctf_field_type_get_type_id(type)) {
        case BT_CTF_TYPE_ID_INTEGER:
                /* Integer field is created field */
                BT_MOVE(int_field, field);
+               bt_get(type);
                break;
        case BT_CTF_TYPE_ID_ENUM:
                int_field = bt_ctf_field_enumeration_get_container(field);
+               type = bt_ctf_field_get_type(int_field);
                break;
        default:
+               assert(0);
+               type = NULL;
                break;
        }
 
@@ -1266,11 +1357,12 @@ enum bt_ctf_btr_status btr_signed_int_cb(int64_t value,
        ret = bt_ctf_field_signed_integer_set_value(int_field, value);
        assert(!ret);
        stack_top(notit->stack)->index++;
-
+       status = update_clock(notit, type, int_field);
 end:
        BT_PUT(field);
        BT_PUT(int_field);
-
+       BT_PUT(type);
+end_no_put:
        return status;
 }
 
@@ -1289,18 +1381,22 @@ enum bt_ctf_btr_status btr_unsigned_int_cb(uint64_t value,
        if (!field) {
                PERR("Failed to get next field (unsigned int)\n");
                status = BT_CTF_BTR_STATUS_ERROR;
-               goto end;
+               goto end_no_put;
        }
 
        switch(bt_ctf_field_type_get_type_id(type)) {
        case BT_CTF_TYPE_ID_INTEGER:
                /* Integer field is created field */
                BT_MOVE(int_field, field);
+               bt_get(type);
                break;
        case BT_CTF_TYPE_ID_ENUM:
                int_field = bt_ctf_field_enumeration_get_container(field);
+               type = bt_ctf_field_get_type(int_field);
                break;
        default:
+               assert(0);
+               type = NULL;
                break;
        }
 
@@ -1313,11 +1409,12 @@ enum bt_ctf_btr_status btr_unsigned_int_cb(uint64_t value,
        ret = bt_ctf_field_unsigned_integer_set_value(int_field, value);
        assert(!ret);
        stack_top(notit->stack)->index++;
-
+       status = update_clock(notit, type, int_field);
 end:
        BT_PUT(field);
        BT_PUT(int_field);
-
+       BT_PUT(type);
+end_no_put:
        return status;
 }
 
@@ -1377,6 +1474,18 @@ enum bt_ctf_btr_status btr_string_begin_cb(
                goto end;
        }
 
+       /*
+        * Initialize string field payload to an empty string since in the
+        * case of a length 0 string the btr_string_cb won't be called and
+        * we will end up with an unset string payload.
+        */
+       ret = bt_ctf_field_string_set_value(field, "");
+       if (ret) {
+               PERR("Failed to initialize string field\n");
+               status = BT_CTF_BTR_STATUS_ERROR;
+               goto end;
+       }
+
 end:
        BT_PUT(field);
 
@@ -1638,10 +1747,42 @@ struct bt_ctf_field_type *btr_get_variant_type_cb(
 end:
        BT_PUT(tag_field);
        BT_PUT(selected_field);
+       BT_PUT(path);
 
        return selected_field_type;
 }
 
+static
+int set_event_clocks(struct bt_ctf_event *event,
+               struct bt_ctf_notif_iter *notit)
+{
+       int ret;
+       GHashTableIter iter;
+       struct bt_ctf_clock *clock;
+       uint64_t *clock_state;
+
+       g_hash_table_iter_init(&iter, notit->clock_states);
+
+       while (g_hash_table_iter_next(&iter, (gpointer) &clock,
+                       (gpointer) &clock_state)) {
+               struct bt_ctf_clock_value *clock_value;
+
+               clock_value = bt_ctf_clock_value_create(clock, *clock_state);
+               if (!clock_value) {
+                       ret = -1;
+                       goto end;
+               }
+               ret = bt_ctf_event_set_clock_value(event, clock, clock_value);
+               bt_put(clock_value);
+               if (ret) {
+                       goto end;
+               }
+       }
+       ret = 0;
+end:
+       return ret;
+}
+
 static
 struct bt_ctf_event *create_event(struct bt_ctf_notif_iter *notit)
 {
@@ -1679,6 +1820,11 @@ struct bt_ctf_event *create_event(struct bt_ctf_notif_iter *notit)
                goto error;
        }
 
+       ret = set_event_clocks(event, notit);
+       if (ret) {
+               goto error;
+       }
+
        /* Associate with current packet. */
        assert(notit->packet);
        ret = bt_ctf_event_set_packet(event, notit->packet);
@@ -1818,11 +1964,40 @@ end:
        BT_PUT(event);
 }
 
+static
+int init_clock_states(GHashTable *clock_states, struct bt_ctf_trace *trace)
+{
+       int clock_count, i, ret = 0;
+
+       clock_count = bt_ctf_trace_get_clock_count(trace);
+       if (clock_count <= 0) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < clock_count; i++) {
+               struct bt_ctf_clock *clock;
+
+               clock = bt_ctf_trace_get_clock(trace, i);
+               if (!clock) {
+                       ret = -1;
+                       goto end;
+               }
+
+               g_hash_table_insert(clock_states, bt_get(clock), NULL);
+               bt_put(clock);
+       }
+end:
+       return ret;
+}
+
+BT_HIDDEN
 struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace,
                size_t max_request_sz,
                struct bt_ctf_notif_iter_medium_ops medops,
                void *data, FILE *err_stream)
 {
+       int ret;
        struct bt_ctf_notif_iter *notit = NULL;
        struct bt_ctf_btr_cbs cbs = {
                .types = {
@@ -1848,9 +2023,18 @@ struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace,
                PERR("Failed to allocate memory for CTF notification iterator\n");
                goto end;
        }
-
-       notit->meta.trace = trace;
-       bt_get(notit->meta.trace);
+       notit->clock_states = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, bt_put, g_free);
+       if (!notit->clock_states) {
+               PERR("Failed to create hash table\n");
+               goto error;
+       }
+       ret = init_clock_states(notit->clock_states, trace);
+       if (ret) {
+               PERR("Failed to initialize stream clock states\n");
+               goto error;
+       }
+       notit->meta.trace = bt_get(trace);
        notit->medium.medops = medops;
        notit->medium.max_request_sz = max_request_sz;
        notit->medium.data = data;
@@ -1858,23 +2042,23 @@ struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace,
        notit->stack = stack_new(notit);
        if (!notit->stack) {
                PERR("Failed to create stack\n");
-               bt_ctf_notif_iter_destroy(notit);
-               notit = NULL;
-               goto end;
+               goto error;
        }
 
        notit->btr = bt_ctf_btr_create(cbs, notit, err_stream);
        if (!notit->btr) {
                PERR("Failed to create binary type reader\n");
-               bt_ctf_notif_iter_destroy(notit);
-               notit = NULL;
-               goto end;
+               goto error;
        }
 
        bt_ctf_notif_iter_reset(notit);
 
 end:
        return notit;
+error:
+       bt_ctf_notif_iter_destroy(notit);
+       notit = NULL;
+       goto end;
 }
 
 void bt_ctf_notif_iter_destroy(struct bt_ctf_notif_iter *notit)
@@ -1893,6 +2077,9 @@ void bt_ctf_notif_iter_destroy(struct bt_ctf_notif_iter *notit)
                bt_ctf_btr_destroy(notit->btr);
        }
 
+       if (notit->clock_states) {
+               g_hash_table_destroy(notit->clock_states);
+       }
        g_free(notit);
 }
 
This page took 0.028719 seconds and 4 git commands to generate.