X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Fplugins%2Fctf%2Fcommon%2Fmsg-iter%2Fmsg-iter.c;h=de7e594ff74382a9973a8ef6e6a76b1338135154;hb=98b15851a941e7342b8bb19e265cdc3a40fabfb8;hp=87ff39af87a22a6bac395fea033dad0a4ececd5a;hpb=44269abb1a3769a1f76eab0de5b23cd7cb0cb58d;p=babeltrace.git diff --git a/src/plugins/ctf/common/msg-iter/msg-iter.c b/src/plugins/ctf/common/msg-iter/msg-iter.c index 87ff39af..de7e594f 100644 --- a/src/plugins/ctf/common/msg-iter/msg-iter.c +++ b/src/plugins/ctf/common/msg-iter/msg-iter.c @@ -104,10 +104,12 @@ enum state { STATE_DSCOPE_EVENT_PAYLOAD_BEGIN, STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE, STATE_EMIT_MSG_EVENT, + STATE_EMIT_QUEUED_MSG_EVENT, STATE_SKIP_PACKET_PADDING, STATE_EMIT_MSG_PACKET_END_MULTI, STATE_EMIT_MSG_PACKET_END_SINGLE, STATE_CHECK_EMIT_MSG_STREAM_END, + STATE_EMIT_QUEUED_MSG_PACKET_END, STATE_EMIT_MSG_STREAM_END, STATE_DONE, }; @@ -133,6 +135,12 @@ struct bt_msg_iter { /* True to emit a stream end message. */ bool emit_stream_end_msg; + /* + * True if library objects are unavailable during the decoding and + * should not be created/used. + */ + bool dry_run; + /* True to set the stream */ bool set_stream; @@ -175,6 +183,12 @@ struct bt_msg_iter { /* Current event message (NULL if not created yet) */ bt_message *event_msg; + /* + * True if we need to emit a packet beginning message before we emit + * the next event message or the packet end message. + */ + bool emit_delayed_packet_beginning_msg; + /* Database of current dynamic scopes */ struct { bt_field *stream_packet_context; @@ -302,12 +316,16 @@ const char *state_string(enum state state) return "DSCOPE_EVENT_PAYLOAD_CONTINUE"; case STATE_EMIT_MSG_EVENT: return "EMIT_MSG_EVENT"; + case STATE_EMIT_QUEUED_MSG_EVENT: + return "EMIT_QUEUED_MSG_EVENT"; case STATE_SKIP_PACKET_PADDING: return "SKIP_PACKET_PADDING"; case STATE_EMIT_MSG_PACKET_END_MULTI: return "EMIT_MSG_PACKET_END_MULTI"; case STATE_EMIT_MSG_PACKET_END_SINGLE: return "EMIT_MSG_PACKET_END_SINGLE"; + case STATE_EMIT_QUEUED_MSG_PACKET_END: + return "EMIT_QUEUED_MSG_PACKET_END"; case STATE_EMIT_MSG_STREAM_END: return "EMIT_MSG_STREAM_END"; case STATE_DONE: @@ -351,7 +369,7 @@ void stack_destroy(struct stack *stack) { struct bt_msg_iter *notit; - BT_ASSERT(stack); + BT_ASSERT_DBG(stack); notit = stack->notit; BT_COMP_LOGD("Destroying stack: addr=%p", stack); @@ -368,9 +386,9 @@ void stack_push(struct stack *stack, bt_field *base) struct stack_entry *entry; struct bt_msg_iter *notit; - BT_ASSERT(stack); + BT_ASSERT_DBG(stack); notit = stack->notit; - BT_ASSERT(base); + BT_ASSERT_DBG(base); BT_COMP_LOGT("Pushing base field on stack: stack-addr=%p, " "stack-size-before=%zu, stack-size-after=%zu", stack, stack->size, stack->size + 1); @@ -388,7 +406,7 @@ void stack_push(struct stack *stack, bt_field *base) static inline unsigned int stack_size(struct stack *stack) { - BT_ASSERT(stack); + BT_ASSERT_DBG(stack); return stack->size; } @@ -397,8 +415,8 @@ void stack_pop(struct stack *stack) { struct bt_msg_iter *notit; - BT_ASSERT(stack); - BT_ASSERT(stack_size(stack)); + BT_ASSERT_DBG(stack); + BT_ASSERT_DBG(stack_size(stack)); notit = stack->notit; BT_COMP_LOGT("Popping from stack: " "stack-addr=%p, stack-size-before=%zu, stack-size-after=%zu", @@ -409,8 +427,8 @@ void stack_pop(struct stack *stack) static inline struct stack_entry *stack_top(struct stack *stack) { - BT_ASSERT(stack); - BT_ASSERT(stack_size(stack)); + BT_ASSERT_DBG(stack); + BT_ASSERT_DBG(stack_size(stack)); return &g_array_index(stack->entries, struct stack_entry, stack->size - 1); } @@ -424,7 +442,7 @@ bool stack_empty(struct stack *stack) static void stack_clear(struct stack *stack) { - BT_ASSERT(stack); + BT_ASSERT_DBG(stack); stack->size = 0; } @@ -977,7 +995,7 @@ enum bt_msg_iter_status read_packet_context_begin_state( BT_ASSERT(!notit->packet_context_field); - if (packet_context_fc->in_ir) { + if (packet_context_fc->in_ir && !notit->dry_run) { /* * Create free packet context field from stream class. * This field is going to be moved to the packet once we @@ -1245,15 +1263,15 @@ enum bt_msg_iter_status set_current_event_message( enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK; bt_message *msg = NULL; - BT_ASSERT(notit->meta.ec); - BT_ASSERT(notit->packet); + BT_ASSERT_DBG(notit->meta.ec); + BT_ASSERT_DBG(notit->packet); BT_COMP_LOGD("Creating event message from event class and packet: " "notit-addr=%p, ec-addr=%p, ec-name=\"%s\", packet-addr=%p", notit, notit->meta.ec, notit->meta.ec->name->str, notit->packet); - BT_ASSERT(notit->msg_iter); - BT_ASSERT(notit->meta.sc); + BT_ASSERT_DBG(notit->msg_iter); + BT_ASSERT_DBG(notit->meta.sc); if (bt_stream_class_borrow_default_clock_class(notit->meta.sc->ir_sc)) { msg = bt_message_event_create_with_packet_and_default_clock_snapshot( @@ -1296,6 +1314,10 @@ enum bt_msg_iter_status after_event_header_state( goto end; } + if (G_UNLIKELY(notit->dry_run)) { + goto next_state; + } + status = set_current_event_message(notit); if (status != BT_MSG_ITER_STATUS_OK) { goto end; @@ -1303,7 +1325,9 @@ enum bt_msg_iter_status after_event_header_state( notit->event = bt_message_event_borrow_event( notit->event_msg); - BT_ASSERT(notit->event); + BT_ASSERT_DBG(notit->event); + +next_state: notit->state = STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN; end: @@ -1323,12 +1347,12 @@ enum bt_msg_iter_status read_event_common_context_begin_state( goto end; } - if (event_common_context_fc->in_ir) { - BT_ASSERT(!notit->dscopes.event_common_context); + if (event_common_context_fc->in_ir && !notit->dry_run) { + BT_ASSERT_DBG(!notit->dscopes.event_common_context); notit->dscopes.event_common_context = bt_event_borrow_common_context_field( notit->event); - BT_ASSERT(notit->dscopes.event_common_context); + BT_ASSERT_DBG(notit->dscopes.event_common_context); } BT_COMP_LOGT("Decoding event common context field: " @@ -1376,12 +1400,12 @@ enum bt_msg_iter_status read_event_spec_context_begin_state( goto end; } - if (event_spec_context_fc->in_ir) { - BT_ASSERT(!notit->dscopes.event_spec_context); + if (event_spec_context_fc->in_ir && !notit->dry_run) { + BT_ASSERT_DBG(!notit->dscopes.event_spec_context); notit->dscopes.event_spec_context = bt_event_borrow_specific_context_field( notit->event); - BT_ASSERT(notit->dscopes.event_spec_context); + BT_ASSERT_DBG(notit->dscopes.event_spec_context); } BT_COMP_LOGT("Decoding event specific context field: " @@ -1432,12 +1456,12 @@ enum bt_msg_iter_status read_event_payload_begin_state( goto end; } - if (event_payload_fc->in_ir) { - BT_ASSERT(!notit->dscopes.event_payload); + if (event_payload_fc->in_ir && !notit->dry_run) { + BT_ASSERT_DBG(!notit->dscopes.event_payload); notit->dscopes.event_payload = bt_event_borrow_payload_field( notit->event); - BT_ASSERT(notit->dscopes.event_payload); + BT_ASSERT_DBG(notit->dscopes.event_payload); } BT_COMP_LOGT("Decoding event payload field: " @@ -1719,6 +1743,9 @@ enum bt_msg_iter_status handle_state(struct bt_msg_iter *notit) case STATE_EMIT_MSG_EVENT: notit->state = STATE_DSCOPE_EVENT_HEADER_BEGIN; break; + case STATE_EMIT_QUEUED_MSG_EVENT: + notit->state = STATE_EMIT_MSG_EVENT; + break; case STATE_SKIP_PACKET_PADDING: status = skip_packet_padding_state(notit); break; @@ -1731,6 +1758,9 @@ enum bt_msg_iter_status handle_state(struct bt_msg_iter *notit) case STATE_CHECK_EMIT_MSG_STREAM_END: status = check_emit_msg_stream_end(notit); break; + case STATE_EMIT_QUEUED_MSG_PACKET_END: + notit->state = STATE_EMIT_MSG_PACKET_END_SINGLE; + break; case STATE_EMIT_MSG_STREAM_END: notit->state = STATE_DONE; break; @@ -1791,8 +1821,6 @@ void bt_msg_iter_reset(struct bt_msg_iter *notit) bt_msg_iter_reset_for_next_stream_file(notit); notit->cur_stream_class_id = -1; notit->cur_data_stream_id = -1; - notit->emit_stream_begin_msg = true; - notit->emit_stream_end_msg = true; notit->snapshots.discarded_events = UINT64_C(-1); notit->snapshots.packets = UINT64_C(-1); notit->prev_packet_snapshots.discarded_events = UINT64_C(-1); @@ -1807,45 +1835,40 @@ bt_field *borrow_next_field(struct bt_msg_iter *notit) bt_field *next_field = NULL; bt_field *base_field; const bt_field_class *base_fc; + bt_field_class_type base_fc_type; size_t index; - BT_ASSERT(!stack_empty(notit->stack)); + BT_ASSERT_DBG(!stack_empty(notit->stack)); index = stack_top(notit->stack)->index; base_field = stack_top(notit->stack)->base; - BT_ASSERT(base_field); + BT_ASSERT_DBG(base_field); base_fc = bt_field_borrow_class_const(base_field); - BT_ASSERT(base_fc); + BT_ASSERT_DBG(base_fc); + base_fc_type = bt_field_class_get_type(base_fc); - switch (bt_field_class_get_type(base_fc)) { - case BT_FIELD_CLASS_TYPE_STRUCTURE: - { - BT_ASSERT(index < + if (base_fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) { + BT_ASSERT_DBG(index < bt_field_class_structure_get_member_count( bt_field_borrow_class_const( base_field))); next_field = bt_field_structure_borrow_member_field_by_index( base_field, index); - break; - } - case BT_FIELD_CLASS_TYPE_STATIC_ARRAY: - case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: - BT_ASSERT(index < bt_field_array_get_length(base_field)); + } else if (bt_field_class_type_is(base_fc_type, + BT_FIELD_CLASS_TYPE_ARRAY)) { + BT_ASSERT_DBG(index < bt_field_array_get_length(base_field)); next_field = bt_field_array_borrow_element_field_by_index( base_field, index); - break; - case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: - case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: - case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: - BT_ASSERT(index == 0); + } else if (bt_field_class_type_is(base_fc_type, + BT_FIELD_CLASS_TYPE_VARIANT)) { + BT_ASSERT_DBG(index == 0); next_field = bt_field_variant_borrow_selected_option_field( base_field); - break; - default: + } else { abort(); } - BT_ASSERT(next_field); + BT_ASSERT_DBG(next_field); return next_field; } @@ -1856,7 +1879,7 @@ void update_default_clock(struct bt_msg_iter *notit, uint64_t new_val, uint64_t new_val_mask; uint64_t cur_value_masked; - BT_ASSERT(new_val_size > 0); + BT_ASSERT_DBG(new_val_size > 0); /* * Special case for a 64-bit new value, which is the limit @@ -1960,17 +1983,15 @@ update_def_clock: (uint64_t) int_fc->storing_index) = value; } - if (G_UNLIKELY(!fc->in_ir)) { + if (G_UNLIKELY(!fc->in_ir || notit->dry_run)) { goto end; } field = borrow_next_field(notit); - BT_ASSERT(field); - BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc); - BT_ASSERT(bt_field_get_class_type(field) == - BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER || - bt_field_get_class_type(field) == - BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION); + BT_ASSERT_DBG(field); + BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); + BT_ASSERT_DBG(bt_field_class_type_is(bt_field_get_class_type(field), + BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER)); bt_field_integer_unsigned_set_value(field, value); stack_top(notit->stack)->index++; @@ -1993,11 +2014,11 @@ enum bt_bfcr_status bfcr_unsigned_int_char_cb(uint64_t value, "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, " "fc-type=%d, fc-in-ir=%d, value=%" PRIu64, notit, notit->bfcr, fc, fc->type, fc->in_ir, value); - BT_ASSERT(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE); - BT_ASSERT(!int_fc->mapped_clock_class); - BT_ASSERT(int_fc->storing_index < 0); + BT_ASSERT_DBG(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE); + BT_ASSERT_DBG(!int_fc->mapped_clock_class); + BT_ASSERT_DBG(int_fc->storing_index < 0); - if (G_UNLIKELY(!fc->in_ir)) { + if (G_UNLIKELY(!fc->in_ir || notit->dry_run)) { goto end; } @@ -2011,8 +2032,8 @@ enum bt_bfcr_status bfcr_unsigned_int_char_cb(uint64_t value, } string_field = stack_top(notit->stack)->base; - BT_ASSERT(bt_field_get_class_type(string_field) == - BT_FIELD_CLASS_TYPE_STRING); + BT_ASSERT_DBG(bt_field_get_class_type(string_field) == + BT_FIELD_CLASS_TYPE_STRING); /* Append character */ str[0] = (char) value; @@ -2042,24 +2063,22 @@ enum bt_bfcr_status bfcr_signed_int_cb(int64_t value, "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, " "fc-type=%d, fc-in-ir=%d, value=%" PRId64, notit, notit->bfcr, fc, fc->type, fc->in_ir, value); - BT_ASSERT(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE); + BT_ASSERT_DBG(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE); if (G_UNLIKELY(int_fc->storing_index >= 0)) { g_array_index(notit->stored_values, uint64_t, (uint64_t) int_fc->storing_index) = (uint64_t) value; } - if (G_UNLIKELY(!fc->in_ir)) { + if (G_UNLIKELY(!fc->in_ir || notit->dry_run)) { goto end; } field = borrow_next_field(notit); - BT_ASSERT(field); - BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc); - BT_ASSERT(bt_field_get_class_type(field) == - BT_FIELD_CLASS_TYPE_SIGNED_INTEGER || - bt_field_get_class_type(field) == - BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION); + BT_ASSERT_DBG(field); + BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); + BT_ASSERT_DBG(bt_field_class_type_is(bt_field_get_class_type(field), + BT_FIELD_CLASS_TYPE_SIGNED_INTEGER)); bt_field_integer_signed_set_value(field, value); stack_top(notit->stack)->index++; @@ -2080,16 +2099,21 @@ enum bt_bfcr_status bfcr_floating_point_cb(double value, "fc-type=%d, fc-in-ir=%d, value=%f", notit, notit->bfcr, fc, fc->type, fc->in_ir, value); - if (G_UNLIKELY(!fc->in_ir)) { + if (G_UNLIKELY(!fc->in_ir || notit->dry_run)) { goto end; } field = borrow_next_field(notit); - BT_ASSERT(field); - BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc); - BT_ASSERT(bt_field_get_class_type(field) == - BT_FIELD_CLASS_TYPE_REAL); - bt_field_real_set_value(field, value); + bt_field_class_type type = bt_field_get_class_type(field); + BT_ASSERT_DBG(field); + BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); + BT_ASSERT_DBG(bt_field_class_type_is(type, BT_FIELD_CLASS_TYPE_REAL)); + + if (type == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) { + bt_field_real_single_precision_set_value(field, (float) value); + } else { + bt_field_real_double_precision_set_value(field, value); + } stack_top(notit->stack)->index++; end: @@ -2108,14 +2132,14 @@ enum bt_bfcr_status bfcr_string_begin_cb( "fc-type=%d, fc-in-ir=%d", notit, notit->bfcr, fc, fc->type, fc->in_ir); - if (G_UNLIKELY(!fc->in_ir)) { + if (G_UNLIKELY(!fc->in_ir || notit->dry_run)) { goto end; } field = borrow_next_field(notit); - BT_ASSERT(field); - BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc); - BT_ASSERT(bt_field_get_class_type(field) == + BT_ASSERT_DBG(field); + BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); + BT_ASSERT_DBG(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING); bt_field_string_clear(field); @@ -2145,12 +2169,12 @@ enum bt_bfcr_status bfcr_string_cb(const char *value, notit, notit->bfcr, fc, fc->type, fc->in_ir, len); - if (G_UNLIKELY(!fc->in_ir)) { + if (G_UNLIKELY(!fc->in_ir || notit->dry_run)) { goto end; } field = stack_top(notit->stack)->base; - BT_ASSERT(field); + BT_ASSERT_DBG(field); /* Append current substring */ ret = bt_field_string_append_with_length(field, value, len); @@ -2177,7 +2201,7 @@ enum bt_bfcr_status bfcr_string_end_cb( "fc-type=%d, fc-in-ir=%d", notit, notit->bfcr, fc, fc->type, fc->in_ir); - if (G_UNLIKELY(!fc->in_ir)) { + if (G_UNLIKELY(!fc->in_ir || notit->dry_run)) { goto end; } @@ -2202,7 +2226,7 @@ enum bt_bfcr_status bfcr_compound_begin_cb( "fc-type=%d, fc-in-ir=%d", notit, notit->bfcr, fc, fc->type, fc->in_ir); - if (!fc->in_ir) { + if (G_UNLIKELY(!fc->in_ir || notit->dry_run)) { goto end; } @@ -2212,12 +2236,12 @@ enum bt_bfcr_status bfcr_compound_begin_cb( field = notit->cur_dscope_field; } else { field = borrow_next_field(notit); - BT_ASSERT(field); + BT_ASSERT_DBG(field); } /* Push field */ - BT_ASSERT(field); - BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc); + BT_ASSERT_DBG(field); + BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); stack_push(notit->stack, field); /* @@ -2229,7 +2253,7 @@ enum bt_bfcr_status bfcr_compound_begin_cb( struct ctf_field_class_array_base *array_fc = (void *) fc; if (array_fc->is_text) { - BT_ASSERT(bt_field_get_class_type(field) == + BT_ASSERT_DBG(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING); notit->done_filling_string = false; bt_field_string_clear(field); @@ -2252,12 +2276,12 @@ enum bt_bfcr_status bfcr_compound_end_cb( "fc-type=%d, fc-in-ir=%d", notit, notit->bfcr, fc, fc->type, fc->in_ir); - if (!fc->in_ir) { + if (G_UNLIKELY(!fc->in_ir || notit->dry_run)) { goto end; } - BT_ASSERT(!stack_empty(notit->stack)); - BT_ASSERT(bt_field_borrow_class_const(stack_top(notit->stack)->base) == + BT_ASSERT_DBG(!stack_empty(notit->stack)); + BT_ASSERT_DBG(bt_field_borrow_class_const(stack_top(notit->stack)->base) == fc->ir_fc); /* @@ -2269,7 +2293,7 @@ enum bt_bfcr_status bfcr_compound_end_cb( struct ctf_field_class_array_base *array_fc = (void *) fc; if (array_fc->is_text) { - BT_ASSERT(bt_field_get_class_type( + BT_ASSERT_DBG(bt_field_get_class_type( stack_top(notit->stack)->base) == BT_FIELD_CLASS_TYPE_STRING); bt_bfcr_set_unsigned_int_cb(notit->bfcr, @@ -2300,8 +2324,13 @@ int64_t bfcr_get_sequence_length_cb(struct ctf_field_class *fc, void *data) length = (uint64_t) g_array_index(notit->stored_values, uint64_t, seq_fc->stored_length_index); + + if (G_UNLIKELY(notit->dry_run)){ + goto end; + } + seq_field = stack_top(notit->stack)->base; - BT_ASSERT(seq_field); + BT_ASSERT_DBG(seq_field); /* * bfcr_get_sequence_length_cb() also gets called back for a @@ -2310,8 +2339,9 @@ int64_t bfcr_get_sequence_length_cb(struct ctf_field_class *fc, void *data) * is a sequence field. */ if (!seq_fc->base.is_text) { - BT_ASSERT(bt_field_get_class_type(seq_field) == - BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY); + BT_ASSERT_DBG(bt_field_class_type_is( + bt_field_get_class_type(seq_field), + BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY)); ret = bt_field_array_dynamic_set_length(seq_field, (uint64_t) length); if (ret) { @@ -2321,6 +2351,7 @@ int64_t bfcr_get_sequence_length_cb(struct ctf_field_class *fc, void *data) } } +end: return length; } @@ -2383,7 +2414,7 @@ struct ctf_field_class *bfcr_borrow_variant_selected_field_class_cb( selected_option = ctf_field_class_variant_borrow_option_by_index( var_fc, (uint64_t) option_index); - if (selected_option->fc->in_ir) { + if (selected_option->fc->in_ir && !notit->dry_run) { bt_field *var_field = stack_top(notit->stack)->base; ret = bt_field_variant_select_option_field_by_index( @@ -2449,20 +2480,13 @@ void create_msg_stream_end(struct bt_msg_iter *notit, bt_message **message) static void create_msg_packet_beginning(struct bt_msg_iter *notit, - bt_message **message) + bt_message **message, bool use_default_cs) { int ret; - enum bt_msg_iter_status status; bt_message *msg = NULL; - const bt_stream_class *sc; - - status = set_current_packet(notit); - if (status != BT_MSG_ITER_STATUS_OK) { - goto end; - } + const bt_stream_class *sc = notit->meta.sc->ir_sc; BT_ASSERT(notit->packet); - sc = notit->meta.sc->ir_sc; BT_ASSERT(sc); if (notit->packet_context_field) { @@ -2488,9 +2512,21 @@ void create_msg_packet_beginning(struct bt_msg_iter *notit, if (notit->meta.sc->packets_have_ts_begin) { BT_ASSERT(notit->snapshots.beginning_clock != UINT64_C(-1)); + uint64_t raw_cs_value; + + /* + * Either use the decoded packet `timestamp_begin` field or the + * current stream's default clock_snapshot. + */ + if (use_default_cs) { + raw_cs_value = notit->default_clock_snapshot; + } else { + raw_cs_value = notit->snapshots.beginning_clock; + } + msg = bt_message_packet_beginning_create_with_default_clock_snapshot( notit->msg_iter, notit->packet, - notit->snapshots.beginning_clock); + raw_cs_value); } else { msg = bt_message_packet_beginning_create(notit->msg_iter, notit->packet); @@ -2509,17 +2545,86 @@ end: return; } +static +void emit_delayed_packet_beg_msg(struct bt_msg_iter *notit, + bt_message **message) +{ + bool packet_beg_ts_need_fix_up; + + notit->emit_delayed_packet_beginning_msg = false; + + /* + * Only fix the packet's timestamp_begin if it's larger than the first + * event of the packet. If there was no event in the packet, the + * `default_clock_snapshot` field will be either equal or greater than + * `snapshots.beginning_clock` so there is not fix needed. + */ + packet_beg_ts_need_fix_up = + notit->default_clock_snapshot < notit->snapshots.beginning_clock; + + /* create_msg_packet_beginning() logs errors */ + create_msg_packet_beginning(notit, message, packet_beg_ts_need_fix_up); + + return; +} + + static void create_msg_packet_end(struct bt_msg_iter *notit, bt_message **message) { bt_message *msg; + bool update_default_cs = true; if (!notit->packet) { return; } - /* Update default clock from packet's end time */ - if (notit->snapshots.end_clock != UINT64_C(-1)) { + /* + * Check if we need to emit the delayed packet + * beginning message instead of the packet end message. + */ + if (G_UNLIKELY(notit->emit_delayed_packet_beginning_msg)) { + emit_delayed_packet_beg_msg(notit, message); + /* Don't forget to emit the packet end message. */ + notit->state = STATE_EMIT_QUEUED_MSG_PACKET_END; + return; + } + + /* Check if may be affected by lttng-crash timestamp_end quirk. */ + if (G_UNLIKELY(notit->meta.tc->quirks.lttng_crash)) { + /* + * Check if the `timestamp_begin` field is non-zero but + * `timestamp_end` is zero. It means the trace is affected by + * the lttng-crash packet `timestamp_end` quirk and must be + * fixed up by omitting to update the default clock snapshot to + * the `timestamp_end` as is typically done. + */ + if (notit->snapshots.beginning_clock != 0 && + notit->snapshots.end_clock == 0) { + update_default_cs = false; + } + } + + /* + * Check if may be affected by lttng event-after-packet `timestamp_end` + * quirk. + */ + if (notit->meta.tc->quirks.lttng_event_after_packet) { + /* + * Check if `timestamp_end` is smaller then the current + * default_clock_snapshot (which is set to the last event + * decoded). It means the trace is affected by the lttng + * `event-after-packet` packet `timestamp_end` quirk and must + * be fixed up by omitting to update the default clock snapshot + * to the `timestamp_end` as is typically done. + */ + if (notit->snapshots.end_clock < notit->default_clock_snapshot) { + update_default_cs = false; + } + } + + /* Update default clock from packet's end time. */ + if (notit->snapshots.end_clock != UINT64_C(-1) && update_default_cs) { notit->default_clock_snapshot = notit->snapshots.end_clock; } @@ -2529,7 +2634,7 @@ void create_msg_packet_end(struct bt_msg_iter *notit, bt_message **message) BT_ASSERT(notit->snapshots.end_clock != UINT64_C(-1)); msg = bt_message_packet_end_create_with_default_clock_snapshot( notit->msg_iter, notit->packet, - notit->snapshots.end_clock); + notit->default_clock_snapshot); } else { msg = bt_message_packet_end_create(notit->msg_iter, notit->packet); @@ -2743,8 +2848,8 @@ enum bt_msg_iter_status bt_msg_iter_get_next_message( { enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK; - BT_ASSERT(notit); - BT_ASSERT(message); + BT_ASSERT_DBG(notit); + BT_ASSERT_DBG(message); notit->msg_iter = msg_iter; notit->set_stream = true; BT_COMP_LOGD("Getting next message: notit-addr=%p", notit); @@ -2762,9 +2867,28 @@ enum bt_msg_iter_status bt_msg_iter_get_next_message( switch (notit->state) { case STATE_EMIT_MSG_EVENT: - BT_ASSERT(notit->event_msg); - *message = notit->event_msg; - notit->event_msg = NULL; + BT_ASSERT_DBG(notit->event_msg); + + /* + * Check if we need to emit the delayed packet + * beginning message instead of the event message. + */ + if (G_UNLIKELY(notit->emit_delayed_packet_beginning_msg)) { + emit_delayed_packet_beg_msg(notit, message); + if (!*message) { + status = BT_MSG_ITER_STATUS_ERROR; + } + + /* + * Don't forget to emit the event message of + * the event record that was just decoded. + */ + notit->state = STATE_EMIT_QUEUED_MSG_EVENT; + + } else { + *message = notit->event_msg; + notit->event_msg = NULL; + } goto end; case STATE_EMIT_MSG_DISCARDED_EVENTS: /* create_msg_discared_events() logs errors */ @@ -2785,11 +2909,26 @@ enum bt_msg_iter_status bt_msg_iter_get_next_message( goto end; case STATE_EMIT_MSG_PACKET_BEGINNING: - /* create_msg_packet_beginning() logs errors */ - create_msg_packet_beginning(notit, message); + status = set_current_packet(notit); + if (status != BT_MSG_ITER_STATUS_OK) { + goto end; + } - if (!*message) { - status = BT_MSG_ITER_STATUS_ERROR; + if (G_UNLIKELY(notit->meta.tc->quirks.barectf_event_before_packet)) { + notit->emit_delayed_packet_beginning_msg = true; + /* + * There is no message to return yet as this + * packet beginning message is delayed until we + * decode the first event message of the + * packet. + */ + break; + } else { + /* create_msg_packet_beginning() logs errors */ + create_msg_packet_beginning(notit, message, false); + if (!*message) { + status = BT_MSG_ITER_STATUS_ERROR; + } } goto end; @@ -2835,21 +2974,24 @@ end: } static -enum bt_msg_iter_status read_packet_header_context_fields( - struct bt_msg_iter *notit) +enum bt_msg_iter_status decode_until_state( struct bt_msg_iter *notit, + enum state target_state_1, enum state target_state_2) { - int ret; enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK; - BT_ASSERT(notit); + BT_ASSERT_DBG(notit); notit->set_stream = false; - if (notit->state == STATE_EMIT_MSG_PACKET_BEGINNING) { - /* We're already there */ - goto end; - } + do { + /* + * Check if we reached the state at which we want to stop + * decoding. + */ + if (notit->state == target_state_1 || + notit->state == target_state_2) { + goto end; + } - while (true) { status = handle_state(notit); if (G_UNLIKELY(status == BT_MSG_ITER_STATUS_AGAIN)) { BT_COMP_LOGD_STR("Medium returned BT_MSG_ITER_STATUS_AGAIN."); @@ -2861,12 +3003,6 @@ enum bt_msg_iter_status read_packet_header_context_fields( } switch (notit->state) { - case STATE_EMIT_MSG_PACKET_BEGINNING: - /* - * Packet header and context fields are - * potentially decoded (or they don't exist). - */ - goto end; case STATE_INIT: case STATE_SWITCH_PACKET: case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN: @@ -2881,25 +3017,58 @@ enum bt_msg_iter_status read_packet_header_context_fields( case STATE_EMIT_MSG_DISCARDED_EVENTS: case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS: case STATE_EMIT_MSG_DISCARDED_PACKETS: - /* Non-emitting state: continue */ + case STATE_EMIT_MSG_PACKET_BEGINNING: + case STATE_DSCOPE_EVENT_HEADER_BEGIN: + case STATE_DSCOPE_EVENT_HEADER_CONTINUE: + case STATE_AFTER_EVENT_HEADER: + case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN: + case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE: + case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN: + case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE: + case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN: + case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE: + case STATE_EMIT_MSG_EVENT: + case STATE_EMIT_QUEUED_MSG_EVENT: + case STATE_SKIP_PACKET_PADDING: + case STATE_EMIT_MSG_PACKET_END_MULTI: + case STATE_EMIT_MSG_PACKET_END_SINGLE: + case STATE_EMIT_QUEUED_MSG_PACKET_END: + case STATE_CHECK_EMIT_MSG_STREAM_END: + case STATE_EMIT_MSG_STREAM_END: break; + case STATE_DONE: + /* fall-through */ default: - /* - * We should never get past the - * STATE_EMIT_MSG_PACKET_BEGINNING state. - */ + /* We should never get to the STATE_DONE state. */ BT_COMP_LOGF("Unexpected state: notit-addr=%p, state=%s", notit, state_string(notit->state)); abort(); } - } + } while (true); end: + return status; +} + +static +enum bt_msg_iter_status read_packet_header_context_fields( + struct bt_msg_iter *notit) +{ + int ret; + enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK; + + status = decode_until_state(notit, STATE_EMIT_MSG_PACKET_BEGINNING, -1); + if (status != BT_MSG_ITER_STATUS_OK) { + goto end; + } + ret = set_current_packet_content_sizes(notit); if (ret) { status = BT_MSG_ITER_STATUS_ERROR; + goto end; } +end: return status; } @@ -2949,6 +3118,42 @@ end: return ret; } +static +enum bt_msg_iter_status clock_snapshot_at_msg_iter_state( + struct bt_msg_iter *notit, enum state target_state_1, + enum state target_state_2, uint64_t *clock_snapshot) +{ + enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK; + + BT_ASSERT_DBG(notit); + BT_ASSERT_DBG(clock_snapshot); + status = decode_until_state(notit, target_state_1, target_state_2); + if (status != BT_MSG_ITER_STATUS_OK) { + goto end; + } + + *clock_snapshot = notit->default_clock_snapshot; +end: + return status; +} + +BT_HIDDEN +enum bt_msg_iter_status bt_msg_iter_curr_packet_first_event_clock_snapshot( + struct bt_msg_iter *notit, uint64_t *first_clock_snapshot) +{ + return clock_snapshot_at_msg_iter_state(notit, + STATE_AFTER_EVENT_HEADER, -1, first_clock_snapshot); +} + +BT_HIDDEN +enum bt_msg_iter_status bt_msg_iter_curr_packet_last_event_clock_snapshot( + struct bt_msg_iter *notit, uint64_t *last_clock_snapshot) +{ + return clock_snapshot_at_msg_iter_state(notit, + STATE_EMIT_MSG_PACKET_END_SINGLE, + STATE_EMIT_MSG_PACKET_END_MULTI, last_clock_snapshot); +} + BT_HIDDEN enum bt_msg_iter_status bt_msg_iter_get_packet_properties( struct bt_msg_iter *notit, @@ -2956,8 +3161,8 @@ enum bt_msg_iter_status bt_msg_iter_get_packet_properties( { enum bt_msg_iter_status status; - BT_ASSERT(notit); - BT_ASSERT(props); + BT_ASSERT_DBG(notit); + BT_ASSERT_DBG(props); status = read_packet_header_context_fields(notit); if (status != BT_MSG_ITER_STATUS_OK) { goto end; @@ -2989,3 +3194,10 @@ void bt_msg_iter_set_emit_stream_end_message(struct bt_msg_iter *notit, { notit->emit_stream_end_msg = val; } + +BT_HIDDEN +void bt_msg_iter_set_dry_run(struct bt_msg_iter *notit, + bool val) +{ + notit->dry_run = val; +}