X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=plugins%2Fctf%2Fcommon%2Fnotif-iter%2Fnotif-iter.c;h=8fa8877bee77ab7acf1ce03ffba1547e22c99c95;hb=65300d60e4b4f167e5fc8f584677757ce09a3844;hp=e596b532666e2c0ddd696a8da45256910b037ad6;hpb=f42867e2d049c1e7cad50cd097290a3adef8d54c;p=babeltrace.git diff --git a/plugins/ctf/common/notif-iter/notif-iter.c b/plugins/ctf/common/notif-iter/notif-iter.c index e596b532..8fa8877b 100644 --- a/plugins/ctf/common/notif-iter/notif-iter.c +++ b/plugins/ctf/common/notif-iter/notif-iter.c @@ -1,8 +1,8 @@ /* * Babeltrace - CTF notification iterator * - * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2015-2016 Philippe Proulx + * Copyright (c) 2015-2018 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015-2018 Philippe Proulx * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,13 +34,12 @@ #include #include #include -#include -#include +#include #include #include #include "notif-iter.h" -#include "../btr/btr.h" +#include "../bfcr/bfcr.h" struct bt_notif_iter; @@ -55,18 +54,21 @@ struct stack_entry { * * sequence * * variant * - * Field is owned by this. + * Field is borrowed. */ struct bt_field *base; - /* index of next field to set */ + /* Index of next field to set */ size_t index; }; /* Visit stack */ struct stack { - /* Entries (struct stack_entry *) (top is last element) */ - GPtrArray *entries; + /* Entries (struct stack_entry) */ + GArray *entries; + + /* Number of active entries */ + size_t size; }; /* State */ @@ -80,13 +82,13 @@ enum state { STATE_AFTER_STREAM_PACKET_CONTEXT, STATE_EMIT_NOTIF_NEW_STREAM, STATE_EMIT_NOTIF_NEW_PACKET, - STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN, - STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE, - STATE_AFTER_STREAM_EVENT_HEADER, - STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN, - STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE, - STATE_DSCOPE_EVENT_CONTEXT_BEGIN, - STATE_DSCOPE_EVENT_CONTEXT_CONTINUE, + STATE_DSCOPE_EVENT_HEADER_BEGIN, + STATE_DSCOPE_EVENT_HEADER_CONTINUE, + STATE_AFTER_EVENT_HEADER, + STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN, + STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE, + STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN, + STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN, STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE, STATE_EMIT_NOTIF_EVENT, @@ -95,96 +97,66 @@ enum state { STATE_SKIP_PACKET_PADDING, }; -struct trace_field_path_cache { - /* - * Indexes of the stream_id and stream_instance_id field in the packet - * header structure, -1 if unset. - */ - int stream_id; - int stream_instance_id; -}; - -struct stream_class_field_path_cache { - /* - * Indexes of the v and id fields in the stream event header structure, - * -1 if unset. - */ - int v; - int id; - - /* - * index of the timestamp_end, packet_size and content_size fields in - * the stream packet context structure. Set to -1 if the fields were - * not found. - */ - int timestamp_end; - int packet_size; - int content_size; -}; - -struct field_cb_override { - enum bt_btr_status (* func)(void *value, - struct bt_field_type *type, void *data); - void *data; -}; - /* CTF notification iterator */ struct bt_notif_iter { /* Visit stack */ struct stack *stack; + /* Current notification iterator to create notifications (weak) */ + struct bt_private_connection_private_notification_iterator *notif_iter; + /* * Current dynamic scope field pointer. * - * This is set when a dynamic scope field is first created by - * btr_compound_begin_cb(). It points to one of the fields in - * dscopes below. + * This is set by read_dscope_begin_state() and contains the + * value of one of the pointers in `dscopes` below. + */ + struct bt_field *cur_dscope_field; + + /* + * True if we're done filling a string field from a text + * array/sequence payload. */ - struct bt_field **cur_dscope_field; + bool done_filling_string; - /* Trace and classes (owned by this) */ + /* Trace and classes */ struct { - struct bt_trace *trace; - struct bt_stream_class *stream_class; - struct bt_event_class *event_class; + struct ctf_trace_class *tc; + struct ctf_stream_class *sc; + struct ctf_event_class *ec; } meta; + /* Current packet header field wrapper (NULL if not created yet) */ + struct bt_packet_header_field *packet_header_field; + + /* Current packet header field wrapper (NULL if not created yet) */ + struct bt_packet_context_field *packet_context_field; + + /* Current event header field (NULL if not created yet) */ + struct bt_event_header_field *event_header_field; + /* Current packet (NULL if not created yet) */ struct bt_packet *packet; /* Current stream (NULL if not set yet) */ struct bt_stream *stream; - /* - * Current timestamp_end field (to consider before switching packets). - */ - struct bt_field *cur_timestamp_end; + /* Current event (NULL if not created yet) */ + struct bt_event *event; - /* Database of current dynamic scopes (owned by this) */ + /* Current event notification (NULL if not created yet) */ + struct bt_notification *event_notif; + + /* Database of current dynamic scopes */ struct { struct bt_field *trace_packet_header; struct bt_field *stream_packet_context; - struct bt_field *stream_event_header; - struct bt_field *stream_event_context; - struct bt_field *event_context; + struct bt_field *event_header; + struct bt_field *event_common_context; + struct bt_field *event_spec_context; struct bt_field *event_payload; } dscopes; - /* - * Special field overrides. - * - * Overrides are used to implement the behaviours of special fields such - * as "timestamp_end" (which must be ignored until the end of the - * packet), "id" (event id) which can be present multiple times and must - * be updated multiple time. - * - * This should be used to implement the behaviour of integer fields - * mapped to clocks and other "tagged" fields (in CTF 2). - * - * bt_field_type to struct field_cb_override - */ - GHashTable *field_overrides; - /* Current state */ enum state state; @@ -207,7 +179,7 @@ struct bt_notif_iter { } buf; /* Binary type reader */ - struct bt_btr *btr; + struct bt_bfcr *bfcr; /* Current medium data */ struct { @@ -220,34 +192,39 @@ struct bt_notif_iter { bool stream_begin_emitted; /* Current packet size (bits) (-1 if unknown) */ - int64_t cur_packet_size; + int64_t cur_exp_packet_total_size; /* Current content size (bits) (-1 if unknown) */ - int64_t cur_content_size; + int64_t cur_exp_packet_content_size; - /* - * Offset, in the underlying media, of the current packet's start - * (-1 if unknown). - */ - off_t cur_packet_offset; + /* Current stream class ID */ + int64_t cur_stream_class_id; - /* bt_clock_class to uint64_t. */ - GHashTable *clock_states; + /* Current event class ID */ + int64_t cur_event_class_id; - /* - * Cache of the trace-constant field paths (event header type) - * associated to the current trace. - */ - struct trace_field_path_cache trace_field_path_cache; + /* Current data stream ID */ + int64_t cur_data_stream_id; /* - * Field path cache associated with the current stream class. - * Ownership of this structure belongs to the field_path_caches HT. + * Offset, in the underlying media, of the current packet's + * start (-1 if unknown). */ - struct stream_class_field_path_cache *cur_sc_field_path_cache; + off_t cur_packet_offset; + + /* Default clock's current value */ + uint64_t default_clock_val; - /* bt_stream_class to struct stream_class_field_path_cache. */ - GHashTable *sc_field_path_caches; + /* End of packet snapshots */ + struct { + uint64_t discarded_events; + uint64_t packets; + uint64_t beginning_clock; + uint64_t end_clock; + } snapshots; + + /* Stored values (for sequence lengths, variant tags) */ + GArray *stored_values; }; static inline @@ -272,20 +249,20 @@ const char *state_string(enum state state) return "STATE_EMIT_NOTIF_NEW_PACKET"; case STATE_EMIT_NOTIF_NEW_STREAM: return "STATE_EMIT_NOTIF_NEW_STREAM"; - case STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN: - return "STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN"; - case STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE: - return "STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE"; - case STATE_AFTER_STREAM_EVENT_HEADER: - return "STATE_AFTER_STREAM_EVENT_HEADER"; - case STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN: - return "STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN"; - case STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE: - return "STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE"; - case STATE_DSCOPE_EVENT_CONTEXT_BEGIN: - return "STATE_DSCOPE_EVENT_CONTEXT_BEGIN"; - case STATE_DSCOPE_EVENT_CONTEXT_CONTINUE: - return "STATE_DSCOPE_EVENT_CONTEXT_CONTINUE"; + case STATE_DSCOPE_EVENT_HEADER_BEGIN: + return "STATE_DSCOPE_EVENT_HEADER_BEGIN"; + case STATE_DSCOPE_EVENT_HEADER_CONTINUE: + return "STATE_DSCOPE_EVENT_HEADER_CONTINUE"; + case STATE_AFTER_EVENT_HEADER: + return "STATE_AFTER_EVENT_HEADER"; + case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN: + return "STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN"; + case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE: + return "STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE"; + case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN: + return "STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN"; + case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE: + return "STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE"; case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN: return "STATE_DSCOPE_EVENT_PAYLOAD_BEGIN"; case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE: @@ -306,19 +283,6 @@ const char *state_string(enum state state) static int bt_notif_iter_switch_packet(struct bt_notif_iter *notit); -static -enum bt_btr_status btr_timestamp_end_cb(void *value, - struct bt_field_type *type, void *data); - -static -void stack_entry_free_func(gpointer data) -{ - struct stack_entry *entry = data; - - bt_put(entry->base); - g_free(entry); -} - static struct stack *stack_new(struct bt_notif_iter *notit) { @@ -330,18 +294,21 @@ struct stack *stack_new(struct bt_notif_iter *notit) goto error; } - stack->entries = g_ptr_array_new_with_free_func(stack_entry_free_func); + stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry)); if (!stack->entries) { - BT_LOGE_STR("Failed to allocate a GPtrArray."); + BT_LOGE_STR("Failed to allocate a GArray."); goto error; } BT_LOGD("Created stack: notit-addr=%p, stack-addr=%p", notit, stack); - return stack; + goto end; error: g_free(stack); - return NULL; + stack = NULL; + +end: + return stack; } static @@ -349,41 +316,40 @@ void stack_destroy(struct stack *stack) { BT_ASSERT(stack); BT_LOGD("Destroying stack: addr=%p", stack); - g_ptr_array_free(stack->entries, TRUE); + + if (stack->entries) { + g_array_free(stack->entries, TRUE); + } + g_free(stack); } static -int stack_push(struct stack *stack, struct bt_field *base) +void stack_push(struct stack *stack, struct bt_field *base) { - int ret = 0; struct stack_entry *entry; BT_ASSERT(stack); BT_ASSERT(base); BT_LOGV("Pushing base field on stack: stack-addr=%p, " - "stack-size-before=%u, stack-size-after=%u", - stack, stack->entries->len, stack->entries->len + 1); - entry = g_new0(struct stack_entry, 1); - if (!entry) { - BT_LOGE_STR("Failed to allocate one stack entry."); - ret = -1; - goto end; - } + "stack-size-before=%zu, stack-size-after=%zu", + stack, stack->size, stack->size + 1); - entry->base = bt_get(base); - g_ptr_array_add(stack->entries, entry); + if (stack->entries->len == stack->size) { + g_array_set_size(stack->entries, stack->size + 1); + } -end: - return ret; + entry = &g_array_index(stack->entries, struct stack_entry, stack->size); + entry->base = base; + entry->index = 0; + stack->size++; } static inline unsigned int stack_size(struct stack *stack) { BT_ASSERT(stack); - - return stack->entries->len; + return stack->size; } static @@ -392,9 +358,9 @@ void stack_pop(struct stack *stack) BT_ASSERT(stack); BT_ASSERT(stack_size(stack)); BT_LOGV("Popping from stack: " - "stack-addr=%p, stack-size-before=%u, stack-size-after=%u", - stack, stack->entries->len, stack->entries->len - 1); - g_ptr_array_remove_index(stack->entries, stack->entries->len - 1); + "stack-addr=%p, stack-size-before=%zu, stack-size-after=%zu", + stack, stack->size, stack->size - 1); + stack->size--; } static inline @@ -402,8 +368,8 @@ struct stack_entry *stack_top(struct stack *stack) { BT_ASSERT(stack); BT_ASSERT(stack_size(stack)); - - return g_ptr_array_index(stack->entries, stack->entries->len - 1); + return &g_array_index(stack->entries, struct stack_entry, + stack->size - 1); } static inline @@ -416,20 +382,14 @@ static void stack_clear(struct stack *stack) { BT_ASSERT(stack); - - if (!stack_empty(stack)) { - BT_LOGV("Clearing stack: stack-addr=%p, stack-size=%u", - stack, stack->entries->len); - g_ptr_array_remove_range(stack->entries, 0, stack_size(stack)); - } - - BT_ASSERT(stack_empty(stack)); + stack->size = 0; } static inline enum bt_notif_iter_status notif_iter_status_from_m_status( enum bt_notif_iter_medium_status m_status) { + /* They are the same */ return (int) m_status; } @@ -503,8 +463,9 @@ enum bt_notif_iter_status request_medium_bytes( * in the middle of a packet header, packet context, or * event. */ - if (notit->cur_packet_size >= 0) { - if (packet_at(notit) == notit->cur_packet_size) { + if (notit->cur_exp_packet_total_size >= 0) { + if (packet_at(notit) == + notit->cur_exp_packet_total_size) { goto end; } } else { @@ -524,7 +485,7 @@ enum bt_notif_iter_status request_medium_bytes( "packet-cur=%zu, last-eh-at=%zu", bt_notif_iter_medium_status_string(m_status), state_string(notit->state), - notit->cur_packet_size, + notit->cur_exp_packet_total_size, notit->buf.at, packet_at(notit), notit->buf.last_eh_at); m_status = BT_NOTIF_ITER_MEDIUM_STATUS_ERROR; @@ -543,7 +504,7 @@ enum bt_notif_iter_status buf_ensure_available_bits( { enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; - if (buf_available_bits(notit) == 0) { + if (unlikely(buf_available_bits(notit) == 0)) { /* * This _cannot_ return BT_NOTIF_ITER_STATUS_OK * _and_ no bits. @@ -557,37 +518,36 @@ enum bt_notif_iter_status buf_ensure_available_bits( static enum bt_notif_iter_status read_dscope_begin_state( struct bt_notif_iter *notit, - struct bt_field_type *dscope_field_type, + struct ctf_field_class *dscope_fc, enum state done_state, enum state continue_state, - struct bt_field **dscope_field) + struct bt_field *dscope_field) { enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; - enum bt_btr_status btr_status; + enum bt_bfcr_status bfcr_status; size_t consumed_bits; - bt_put(*dscope_field); notit->cur_dscope_field = dscope_field; - BT_LOGV("Starting BTR: notit-addr=%p, btr-addr=%p, ft-addr=%p", - notit, notit->btr, dscope_field_type); - consumed_bits = bt_btr_start(notit->btr, dscope_field_type, + BT_LOGV("Starting BFCR: notit-addr=%p, bfcr-addr=%p, fc-addr=%p", + notit, notit->bfcr, dscope_fc); + consumed_bits = bt_bfcr_start(notit->bfcr, dscope_fc, notit->buf.addr, notit->buf.at, packet_at(notit), - notit->buf.sz, &btr_status); - BT_LOGV("BTR consumed bits: size=%zu", consumed_bits); + notit->buf.sz, &bfcr_status); + BT_LOGV("BFCR consumed bits: size=%zu", consumed_bits); - switch (btr_status) { - case BT_BTR_STATUS_OK: - /* type was read completely */ + switch (bfcr_status) { + case BT_BFCR_STATUS_OK: + /* Field class was read completely */ BT_LOGV_STR("Field was completely decoded."); notit->state = done_state; break; - case BT_BTR_STATUS_EOF: - BT_LOGV_STR("BTR needs more data to decode field completely."); + case BT_BFCR_STATUS_EOF: + BT_LOGV_STR("BFCR needs more data to decode field completely."); notit->state = continue_state; break; default: - BT_LOGW("BTR failed to start: notit-addr=%p, btr-addr=%p, " - "status=%s", notit, notit->btr, - bt_btr_status_string(btr_status)); + BT_LOGW("BFCR failed to start: notit-addr=%p, bfcr-addr=%p, " + "status=%s", notit, notit->bfcr, + bt_bfcr_status_string(bfcr_status)); status = BT_NOTIF_ITER_STATUS_ERROR; goto end; } @@ -604,11 +564,11 @@ enum bt_notif_iter_status read_dscope_continue_state( struct bt_notif_iter *notit, enum state done_state) { enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; - enum bt_btr_status btr_status; + enum bt_bfcr_status bfcr_status; size_t consumed_bits; - BT_LOGV("Continuing BTR: notit-addr=%p, btr-addr=%p", - notit, notit->btr); + BT_LOGV("Continuing BFCR: notit-addr=%p, bfcr-addr=%p", + notit, notit->bfcr); status = buf_ensure_available_bits(notit); if (status != BT_NOTIF_ITER_STATUS_OK) { @@ -625,25 +585,24 @@ enum bt_notif_iter_status read_dscope_continue_state( goto end; } + consumed_bits = bt_bfcr_continue(notit->bfcr, notit->buf.addr, + notit->buf.sz, &bfcr_status); + BT_LOGV("BFCR consumed bits: size=%zu", consumed_bits); - consumed_bits = bt_btr_continue(notit->btr, notit->buf.addr, - notit->buf.sz, &btr_status); - BT_LOGV("BTR consumed bits: size=%zu", consumed_bits); - - switch (btr_status) { - case BT_BTR_STATUS_OK: + switch (bfcr_status) { + case BT_BFCR_STATUS_OK: /* Type was read completely. */ BT_LOGV_STR("Field was completely decoded."); notit->state = done_state; break; - case BT_BTR_STATUS_EOF: + case BT_BFCR_STATUS_EOF: /* Stay in this continue state. */ - BT_LOGV_STR("BTR needs more data to decode field completely."); + BT_LOGV_STR("BFCR needs more data to decode field completely."); break; default: - BT_LOGW("BTR failed to continue: notit-addr=%p, btr-addr=%p, " - "status=%s", notit, notit->btr, - bt_btr_status_string(btr_status)); + BT_LOGW("BFCR failed to continue: notit-addr=%p, bfcr-addr=%p, " + "status=%s", notit, notit->bfcr, + bt_bfcr_status_string(bfcr_status)); status = BT_NOTIF_ITER_STATUS_ERROR; goto end; } @@ -655,33 +614,45 @@ end: } static -void put_event_dscopes(struct bt_notif_iter *notit) +void release_event_dscopes(struct bt_notif_iter *notit) { - BT_LOGV_STR("Putting event header field."); - BT_PUT(notit->dscopes.stream_event_header); - BT_LOGV_STR("Putting stream event context field."); - BT_PUT(notit->dscopes.stream_event_context); - BT_LOGV_STR("Putting event context field."); - BT_PUT(notit->dscopes.event_context); - BT_LOGV_STR("Putting event payload field."); - BT_PUT(notit->dscopes.event_payload); + notit->dscopes.event_header = NULL; + + if (notit->event_header_field) { + bt_event_header_field_release(notit->event_header_field); + notit->event_header_field = NULL; + } + + notit->dscopes.event_common_context = NULL; + notit->dscopes.event_spec_context = NULL; + notit->dscopes.event_payload = NULL; } static -void put_all_dscopes(struct bt_notif_iter *notit) +void release_all_dscopes(struct bt_notif_iter *notit) { - BT_LOGV_STR("Putting packet header field."); - BT_PUT(notit->dscopes.trace_packet_header); - BT_LOGV_STR("Putting packet context field."); - BT_PUT(notit->dscopes.stream_packet_context); - put_event_dscopes(notit); + notit->dscopes.trace_packet_header = NULL; + + if (notit->packet_header_field) { + bt_packet_header_field_release(notit->packet_header_field); + notit->packet_header_field = NULL; + } + + notit->dscopes.stream_packet_context = NULL; + + if (notit->packet_context_field) { + bt_packet_context_field_release(notit->packet_context_field); + notit->packet_context_field = NULL; + } + + release_event_dscopes(notit); } static enum bt_notif_iter_status read_packet_header_begin_state( struct bt_notif_iter *notit) { - struct bt_field_type *packet_header_type = NULL; + struct ctf_field_class *packet_header_fc = NULL; enum bt_notif_iter_status ret = BT_NOTIF_ITER_STATUS_OK; if (bt_notif_iter_switch_packet(notit)) { @@ -690,32 +661,60 @@ enum bt_notif_iter_status read_packet_header_begin_state( goto end; } - /* Packet header type is common to the whole trace. */ - packet_header_type = bt_trace_get_packet_header_type( - notit->meta.trace); - if (!packet_header_type) { + /* Packet header class is common to the whole trace. */ + packet_header_fc = notit->meta.tc->packet_header_fc; + if (!packet_header_fc) { notit->state = STATE_AFTER_TRACE_PACKET_HEADER; goto end; } + BT_ASSERT(!notit->packet_header_field); + + if (packet_header_fc->in_ir) { + /* + * Create free packet header field from trace. This + * field is going to be moved to the packet once we + * create it. We cannot create the packet now because: + * + * 1. A packet is created from a stream. + * 2. A stream is created from a stream class. + * 3. We need the packet header field's content to know + * the ID of the stream class to select. + */ + notit->packet_header_field = bt_packet_header_field_create( + notit->meta.tc->ir_tc); + if (!notit->packet_header_field) { + BT_LOGE_STR("Cannot create packet header field wrapper from trace."); + ret = BT_NOTIF_ITER_STATUS_ERROR; + goto end; + } + + notit->dscopes.trace_packet_header = + bt_packet_header_field_borrow_field(notit->packet_header_field); + BT_ASSERT(notit->dscopes.trace_packet_header); + } + + notit->cur_stream_class_id = -1; + notit->cur_event_class_id = -1; + notit->cur_data_stream_id = -1; BT_LOGV("Decoding packet header field:" - "notit-addr=%p, trace-addr=%p, trace-name=\"%s\", ft-addr=%p", - notit, notit->meta.trace, - bt_trace_get_name(notit->meta.trace), packet_header_type); - ret = read_dscope_begin_state(notit, packet_header_type, + "notit-addr=%p, trace-addr=%p, trace-name=\"%s\", fc-addr=%p", + notit, notit->meta.tc, + notit->meta.tc->name->str, packet_header_fc); + ret = read_dscope_begin_state(notit, packet_header_fc, STATE_AFTER_TRACE_PACKET_HEADER, STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE, - ¬it->dscopes.trace_packet_header); + notit->dscopes.trace_packet_header); if (ret < 0) { BT_LOGW("Cannot decode packet header field: " "notit-addr=%p, trace-addr=%p, " - "trace-name=\"%s\", ft-addr=%p", - notit, notit->meta.trace, - bt_trace_get_name(notit->meta.trace), - packet_header_type); + "trace-name=\"%s\", fc-addr=%p", + notit, notit->meta.tc, + notit->meta.tc->name->str, + packet_header_fc); } + end: - BT_PUT(packet_header_type); return ret; } @@ -724,301 +723,147 @@ enum bt_notif_iter_status read_packet_header_continue_state( struct bt_notif_iter *notit) { return read_dscope_continue_state(notit, - STATE_AFTER_TRACE_PACKET_HEADER); -} - -static inline -bool is_struct_type(struct bt_field_type *field_type) -{ - return bt_field_type_get_type_id(field_type) == - BT_FIELD_TYPE_ID_STRUCT; -} - -static inline -bool is_variant_type(struct bt_field_type *field_type) -{ - return bt_field_type_get_type_id(field_type) == - BT_FIELD_TYPE_ID_VARIANT; -} - -static -struct stream_class_field_path_cache * -create_stream_class_field_path_cache_entry( - struct bt_notif_iter *notit, - struct bt_stream_class *stream_class) -{ - int v = -1; - int id = -1; - int timestamp_end = -1; - int packet_size = -1; - int content_size = -1; - struct stream_class_field_path_cache *cache_entry = g_new0( - struct stream_class_field_path_cache, 1); - struct bt_field_type *event_header = NULL, *packet_context = NULL; - - if (!cache_entry) { - BT_LOGE_STR("Failed to allocate one stream class field path cache."); - goto end; - } - - event_header = bt_stream_class_get_event_header_type(stream_class); - if (event_header && bt_field_type_is_structure(event_header)) { - int i, count; - - count = bt_field_type_structure_get_field_count( - event_header); - BT_ASSERT(count >= 0); - - for (i = 0; i < count; i++) { - int ret; - const char *name; - - ret = bt_field_type_structure_get_field_by_index( - event_header, &name, NULL, i); - if (ret) { - BT_LOGE("Cannot get event header structure field type's field: " - "notit-addr=%p, stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", " - "ft-addr=%p, index=%d", - notit, stream_class, - bt_stream_class_get_name(stream_class), - bt_stream_class_get_id(stream_class), - event_header, i); - goto error; - } - - if (v != -1 && id != -1) { - break; - } - - if (v == -1 && strcmp(name, "v") == 0) { - v = i; - } else if (id == -1 && !strcmp(name, "id")) { - id = i; - } - } - } - - packet_context = bt_stream_class_get_packet_context_type( - stream_class); - if (packet_context && bt_field_type_is_structure(packet_context)) { - int i, count; - - count = bt_field_type_structure_get_field_count( - packet_context); - BT_ASSERT(count >= 0); - - for (i = 0; i < count; i++) { - int ret; - const char *name; - struct bt_field_type *field_type; - - if (timestamp_end != -1 && packet_size != -1 && - content_size != -1) { - break; - } - - ret = bt_field_type_structure_get_field_by_index( - packet_context, &name, &field_type, i); - if (ret) { - BT_LOGE("Cannot get packet context structure field type's field: " - "notit-addr=%p, stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", " - "ft-addr=%p, index=%d", - notit, stream_class, - bt_stream_class_get_name(stream_class), - bt_stream_class_get_id(stream_class), - event_header, i); - goto error; - } - - if (timestamp_end == -1 && - strcmp(name, "timestamp_end") == 0) { - struct field_cb_override *override = g_new0( - struct field_cb_override, 1); - - if (!override) { - BT_PUT(field_type); - goto error; - } - - override->func = btr_timestamp_end_cb; - override->data = notit; - g_hash_table_insert(notit->field_overrides, - bt_get(field_type), override); - timestamp_end = i; - } else if (packet_size == -1 && - !strcmp(name, "packet_size")) { - packet_size = i; - } else if (content_size == -1 && - !strcmp(name, "content_size")) { - content_size = i; - } - BT_PUT(field_type); - } - } - - cache_entry->v = v; - cache_entry->id = id; - cache_entry->timestamp_end = timestamp_end; - cache_entry->packet_size = packet_size; - cache_entry->content_size = content_size; -end: - BT_PUT(event_header); - BT_PUT(packet_context); - return cache_entry; -error: - g_free(cache_entry); - cache_entry = NULL; - goto end; -} - -static -struct stream_class_field_path_cache *get_stream_class_field_path_cache( - struct bt_notif_iter *notit, - struct bt_stream_class *stream_class) -{ - bool cache_entry_found; - struct stream_class_field_path_cache *cache_entry; - - cache_entry_found = g_hash_table_lookup_extended( - notit->sc_field_path_caches, - stream_class, NULL, (gpointer) &cache_entry); - if (unlikely(!cache_entry_found)) { - cache_entry = create_stream_class_field_path_cache_entry(notit, - stream_class); - g_hash_table_insert(notit->sc_field_path_caches, - bt_get(stream_class), (gpointer) cache_entry); - } - - return cache_entry; + STATE_AFTER_TRACE_PACKET_HEADER); } static inline -enum bt_notif_iter_status set_current_stream_class( - struct bt_notif_iter *notit) +enum bt_notif_iter_status set_current_stream_class(struct bt_notif_iter *notit) { enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; - struct bt_field_type *packet_header_type = NULL; - struct bt_field_type *stream_id_field_type = NULL; - struct bt_stream_class *new_stream_class = NULL; - uint64_t stream_id; - - /* Clear the current stream class field path cache. */ - notit->cur_sc_field_path_cache = NULL; - - /* Is there any "stream_id" field in the packet header? */ - packet_header_type = bt_trace_get_packet_header_type( - notit->meta.trace); - if (!packet_header_type) { + struct ctf_stream_class *new_stream_class = NULL; + + if (notit->cur_stream_class_id == -1) { /* - * No packet header, therefore no `stream_id` field, - * therefore only one stream class. + * No current stream class ID field, therefore only one + * stream class. */ - goto single_stream_class; - } - - BT_ASSERT(is_struct_type(packet_header_type)); - - // TODO: optimalize! - stream_id_field_type = - bt_field_type_structure_get_field_type_by_name( - packet_header_type, "stream_id"); - if (stream_id_field_type) { - /* Find appropriate stream class using current stream ID */ - int ret; - struct bt_field *stream_id_field = NULL; - - BT_ASSERT(notit->dscopes.trace_packet_header); + if (notit->meta.tc->stream_classes->len != 1) { + BT_LOGW("Need exactly one stream class since there's " + "no stream class ID field: " + "notit-addr=%p, trace-name=\"%s\"", + notit, notit->meta.tc->name->str); + status = BT_NOTIF_ITER_STATUS_ERROR; + goto end; + } - // TODO: optimalize! - stream_id_field = bt_field_structure_get_field_by_name( - notit->dscopes.trace_packet_header, "stream_id"); - BT_ASSERT(stream_id_field); - ret = bt_field_unsigned_integer_get_value( - stream_id_field, &stream_id); - BT_ASSERT(!ret); - BT_PUT(stream_id_field); - } else { -single_stream_class: - /* Only one stream: pick the first stream class */ - BT_ASSERT(bt_trace_get_stream_class_count( - notit->meta.trace) == 1); - stream_id = 0; + new_stream_class = notit->meta.tc->stream_classes->pdata[0]; + notit->cur_stream_class_id = new_stream_class->id; + goto end; } - BT_LOGV("Found stream class ID to use: notit-addr=%p, " - "stream-class-id=%" PRIu64 ", " - "trace-addr=%p, trace-name=\"%s\"", - notit, stream_id, notit->meta.trace, - bt_trace_get_name(notit->meta.trace)); - - new_stream_class = bt_trace_get_stream_class_by_id( - notit->meta.trace, stream_id); + new_stream_class = ctf_trace_class_borrow_stream_class_by_id( + notit->meta.tc, notit->cur_stream_class_id); if (!new_stream_class) { BT_LOGW("No stream class with ID of stream class ID to use in trace: " "notit-addr=%p, stream-class-id=%" PRIu64 ", " "trace-addr=%p, trace-name=\"%s\"", - notit, stream_id, notit->meta.trace, - bt_trace_get_name(notit->meta.trace)); + notit, notit->cur_stream_class_id, notit->meta.tc, + notit->meta.tc->name->str); status = BT_NOTIF_ITER_STATUS_ERROR; goto end; } - if (notit->meta.stream_class) { - if (new_stream_class != notit->meta.stream_class) { + if (notit->meta.sc) { + if (new_stream_class != notit->meta.sc) { BT_LOGW("Two packets refer to two different stream classes within the same packet sequence: " "notit-addr=%p, prev-stream-class-addr=%p, " - "prev-stream-class-name=\"%s\", " "prev-stream-class-id=%" PRId64 ", " "next-stream-class-addr=%p, " - "next-stream-class-name=\"%s\", " "next-stream-class-id=%" PRId64 ", " "trace-addr=%p, trace-name=\"%s\"", - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class), + notit, notit->meta.sc, + notit->meta.sc->id, new_stream_class, - bt_stream_class_get_name(new_stream_class), - bt_stream_class_get_id(new_stream_class), - notit->meta.trace, - bt_trace_get_name(notit->meta.trace)); + new_stream_class->id, + notit->meta.tc, + notit->meta.tc->name->str); status = BT_NOTIF_ITER_STATUS_ERROR; goto end; } } else { - BT_MOVE(notit->meta.stream_class, new_stream_class); + notit->meta.sc = new_stream_class; } BT_LOGV("Set current stream class: " "notit-addr=%p, stream-class-addr=%p, " - "stream-class-name=\"%s\", stream-class-id=%" PRId64, - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class)); + "stream-class-id=%" PRId64, + notit, notit->meta.sc, notit->meta.sc->id); - /* - * Retrieve (or lazily create) the current stream class field path - * cache. - */ - notit->cur_sc_field_path_cache = get_stream_class_field_path_cache( - notit, notit->meta.stream_class); - if (!notit->cur_sc_field_path_cache) { - BT_LOGW("Cannot retrieve stream class field path from cache: " - "notit-addr=%p, stream-class-addr=%p, " - "stream-class-name=\"%s\", stream-class-id=%" PRId64, - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class)); +end: + return status; +} + +static inline +enum bt_notif_iter_status set_current_stream(struct bt_notif_iter *notit) +{ + enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; + struct bt_stream *stream = NULL; + + BT_LOGV("Calling user function (get stream): notit-addr=%p, " + "stream-class-addr=%p, stream-class-id=%" PRId64, + notit, notit->meta.sc, + notit->meta.sc->id); + stream = bt_object_get_ref(notit->medium.medops.borrow_stream( + notit->meta.sc->ir_sc, notit->cur_data_stream_id, + notit->medium.data)); + BT_LOGV("User function returned: stream-addr=%p", stream); + if (!stream) { + BT_LOGW_STR("User function failed to return a stream object " + "for the given stream class."); + status = BT_NOTIF_ITER_STATUS_ERROR; + goto end; + } + + if (notit->stream && stream != notit->stream) { + BT_LOGW("User function returned a different stream than the " + "previous one for the same sequence of packets."); status = BT_NOTIF_ITER_STATUS_ERROR; goto end; } + + BT_OBJECT_MOVE_REF(notit->stream, stream); + +end: + bt_object_put_ref(stream); + return status; +} + +static inline +enum bt_notif_iter_status set_current_packet(struct bt_notif_iter *notit) +{ + enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; + struct bt_packet *packet = NULL; + + BT_LOGV("Creating packet for packet notification: " + "notit-addr=%p", notit); + BT_LOGV("Creating packet from stream: " + "notit-addr=%p, stream-addr=%p, " + "stream-class-addr=%p, " + "stream-class-id=%" PRId64, + notit, notit->stream, notit->meta.sc, + notit->meta.sc->id); + + /* Create packet */ + BT_ASSERT(notit->stream); + packet = bt_packet_create(notit->stream); + if (!packet) { + BT_LOGE("Cannot create packet from stream: " + "notit-addr=%p, stream-addr=%p, " + "stream-class-addr=%p, " + "stream-class-id=%" PRId64, + notit, notit->stream, notit->meta.sc, + notit->meta.sc->id); + goto error; + } + + goto end; + +error: + BT_OBJECT_PUT_REF_AND_RESET(packet); + status = BT_NOTIF_ITER_STATUS_ERROR; + end: - BT_PUT(packet_header_type); - BT_PUT(stream_id_field_type); - bt_put(new_stream_class); + BT_OBJECT_MOVE_REF(notit->packet, packet); return status; } @@ -1029,10 +874,13 @@ enum bt_notif_iter_status after_packet_header_state( enum bt_notif_iter_status status; status = set_current_stream_class(notit); - if (status == BT_NOTIF_ITER_STATUS_OK) { - notit->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN; + if (status != BT_NOTIF_ITER_STATUS_OK) { + goto end; } + notit->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN; + +end: return status; } @@ -1041,47 +889,64 @@ enum bt_notif_iter_status read_packet_context_begin_state( struct bt_notif_iter *notit) { enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; - struct bt_field_type *packet_context_type; + struct ctf_field_class *packet_context_fc; - BT_ASSERT(notit->meta.stream_class); - packet_context_type = bt_stream_class_get_packet_context_type( - notit->meta.stream_class); - if (!packet_context_type) { - BT_LOGV("No packet packet context field type in stream class: continuing: " + BT_ASSERT(notit->meta.sc); + packet_context_fc = notit->meta.sc->packet_context_fc; + if (!packet_context_fc) { + BT_LOGV("No packet packet context field class in stream class: continuing: " "notit-addr=%p, stream-class-addr=%p, " - "stream-class-name=\"%s\", stream-class-id=%" PRId64, - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class)); + "stream-class-id=%" PRId64, + notit, notit->meta.sc, + notit->meta.sc->id); notit->state = STATE_AFTER_STREAM_PACKET_CONTEXT; goto end; } + BT_ASSERT(!notit->packet_context_field); + + if (packet_context_fc->in_ir) { + /* + * Create free packet context field from stream class. + * This field is going to be moved to the packet once we + * create it. We cannot create the packet now because a + * packet is created from a stream, and this API must be + * able to return the packet header and context fields + * without creating a stream + * (bt_notif_iter_borrow_packet_header_context_fields()). + */ + notit->packet_context_field = + bt_packet_context_field_create(notit->meta.sc->ir_sc); + if (!notit->packet_context_field) { + BT_LOGE_STR("Cannot create packet context field wrapper from stream class."); + status = BT_NOTIF_ITER_STATUS_ERROR; + goto end; + } + + notit->dscopes.stream_packet_context = + bt_packet_context_field_borrow_field(notit->packet_context_field); + BT_ASSERT(notit->dscopes.stream_packet_context); + } + BT_LOGV("Decoding packet context field: " "notit-addr=%p, stream-class-addr=%p, " - "stream-class-name=\"%s\", stream-class-id=%" PRId64 ", " - "ft-addr=%p", - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class), - packet_context_type); - status = read_dscope_begin_state(notit, packet_context_type, + "stream-class-id=%" PRId64 ", fc-addr=%p", + notit, notit->meta.sc, + notit->meta.sc->id, packet_context_fc); + status = read_dscope_begin_state(notit, packet_context_fc, STATE_AFTER_STREAM_PACKET_CONTEXT, STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE, - ¬it->dscopes.stream_packet_context); + notit->dscopes.stream_packet_context); if (status < 0) { BT_LOGW("Cannot decode packet context field: " "notit-addr=%p, stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", ft-addr=%p", - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class), - packet_context_type); + "stream-class-id=%" PRId64 ", fc-addr=%p", + notit, notit->meta.sc, + notit->meta.sc->id, + packet_context_fc); } end: - BT_PUT(packet_context_type); return status; } @@ -1098,76 +963,43 @@ enum bt_notif_iter_status set_current_packet_content_sizes( struct bt_notif_iter *notit) { enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; - struct bt_field *packet_size_field = NULL; - struct bt_field *content_size_field = NULL; - uint64_t content_size = -1ULL, packet_size = -1ULL; - if (!notit->dscopes.stream_packet_context) { - goto end; - } - - packet_size_field = bt_field_structure_get_field_by_name( - notit->dscopes.stream_packet_context, "packet_size"); - content_size_field = bt_field_structure_get_field_by_name( - notit->dscopes.stream_packet_context, "content_size"); - if (packet_size_field) { - int ret = bt_field_unsigned_integer_get_value( - packet_size_field, &packet_size); - - BT_ASSERT(ret == 0); - if (packet_size == 0) { - BT_LOGW("Invalid packet size: packet context field indicates packet size is zero: " - "notit-addr=%p, packet-context-field-addr=%p", - notit, notit->dscopes.stream_packet_context); - status = BT_NOTIF_ITER_STATUS_ERROR; - goto end; - } else if ((packet_size % 8) != 0) { - BT_LOGW("Invalid packet size: packet context field indicates packet size is not a multiple of 8: " + if (notit->cur_exp_packet_total_size == -1) { + if (notit->cur_exp_packet_content_size != -1) { + BT_LOGW("Content size is set, but packet size is not: " "notit-addr=%p, packet-context-field-addr=%p, " - "packet-size=%" PRIu64, + "packet-size=%" PRId64 ", content-size=%" PRId64, notit, notit->dscopes.stream_packet_context, - packet_size); + notit->cur_exp_packet_total_size, + notit->cur_exp_packet_content_size); status = BT_NOTIF_ITER_STATUS_ERROR; goto end; } - } - - if (content_size_field) { - int ret = bt_field_unsigned_integer_get_value( - content_size_field, &content_size); - - BT_ASSERT(ret == 0); } else { - content_size = packet_size; + if (notit->cur_exp_packet_content_size == -1) { + notit->cur_exp_packet_content_size = + notit->cur_exp_packet_total_size; + } } - if (content_size > packet_size) { - BT_LOGW("Invalid packet or content size: packet context field indicates content size is greater than packet size: " + if (notit->cur_exp_packet_content_size > + notit->cur_exp_packet_total_size) { + BT_LOGW("Invalid packet or content size: " + "content size is greater than packet size: " "notit-addr=%p, packet-context-field-addr=%p, " - "packet-size=%" PRIu64 ", content-size=%" PRIu64, + "packet-size=%" PRId64 ", content-size=%" PRId64, notit, notit->dscopes.stream_packet_context, - packet_size, content_size); + notit->cur_exp_packet_total_size, + notit->cur_exp_packet_content_size); status = BT_NOTIF_ITER_STATUS_ERROR; goto end; } - if (packet_size != -1ULL) { - notit->cur_packet_size = packet_size; - } else { - /* - * Use the content size as packet size indicator if the - * packet size field is missing. This means there is no - * padding in this stream. - */ - notit->cur_packet_size = content_size; - } - notit->cur_content_size = content_size; BT_LOGV("Set current packet and content sizes: " "notit-addr=%p, packet-size=%" PRIu64 ", content-size=%" PRIu64, - notit, packet_size, content_size); + notit, notit->cur_exp_packet_total_size, + notit->cur_exp_packet_content_size); end: - BT_PUT(packet_size_field); - BT_PUT(content_size_field); return status; } @@ -1178,14 +1010,17 @@ enum bt_notif_iter_status after_packet_context_state( enum bt_notif_iter_status status; status = set_current_packet_content_sizes(notit); - if (status == BT_NOTIF_ITER_STATUS_OK) { - if (notit->stream_begin_emitted) { - notit->state = STATE_EMIT_NOTIF_NEW_PACKET; - } else { - notit->state = STATE_EMIT_NOTIF_NEW_STREAM; - } + if (status != BT_NOTIF_ITER_STATUS_OK) { + goto end; + } + + if (notit->stream_begin_emitted) { + notit->state = STATE_EMIT_NOTIF_NEW_PACKET; + } else { + notit->state = STATE_EMIT_NOTIF_NEW_STREAM; } +end: return status; } @@ -1194,63 +1029,102 @@ enum bt_notif_iter_status read_event_header_begin_state( struct bt_notif_iter *notit) { enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; - struct bt_field_type *event_header_type = NULL; + struct ctf_field_class *event_header_fc = NULL; /* Reset the position of the last event header */ notit->buf.last_eh_at = notit->buf.at; + notit->cur_event_class_id = -1; /* Check if we have some content left */ - if (notit->cur_content_size >= 0) { - if (packet_at(notit) == notit->cur_content_size) { + if (notit->cur_exp_packet_content_size >= 0) { + if (unlikely(packet_at(notit) == + notit->cur_exp_packet_content_size)) { /* No more events! */ BT_LOGV("Reached end of packet: notit-addr=%p, " "cur=%zu", notit, packet_at(notit)); notit->state = STATE_EMIT_NOTIF_END_OF_PACKET; goto end; - } else if (packet_at(notit) > notit->cur_content_size) { + } else if (unlikely(packet_at(notit) > + notit->cur_exp_packet_content_size)) { /* That's not supposed to happen */ BT_LOGV("Before decoding event header field: cursor is passed the packet's content: " "notit-addr=%p, content-size=%" PRId64 ", " - "cur=%zu", notit, notit->cur_content_size, + "cur=%zu", notit, + notit->cur_exp_packet_content_size, packet_at(notit)); status = BT_NOTIF_ITER_STATUS_ERROR; goto end; } - } - - event_header_type = bt_stream_class_get_event_header_type( - notit->meta.stream_class); - if (!event_header_type) { - notit->state = STATE_AFTER_STREAM_EVENT_HEADER; - goto end; - } - - put_event_dscopes(notit); - BT_LOGV("Decoding event header field: " - "notit-addr=%p, stream-class-addr=%p, " - "stream-class-name=\"%s\", stream-class-id=%" PRId64 ", " - "ft-addr=%p", - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class), - event_header_type); - status = read_dscope_begin_state(notit, event_header_type, - STATE_AFTER_STREAM_EVENT_HEADER, - STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE, - ¬it->dscopes.stream_event_header); + } else { + /* + * "Infinite" content: we're done when the medium has + * nothing else for us. + */ + status = buf_ensure_available_bits(notit); + if (status != BT_NOTIF_ITER_STATUS_OK) { + /* + * If this function returns + * `BT_NOTIF_ITER_STATUS_EOF`: + * + * 1. bt_notif_iter_get_next_notification() + * emits a "packet end" notification. This + * resets the current packet. The state + * remains unchanged otherwise. + * 2. This function is called again. It returns + * `BT_NOTIF_ITER_STATUS_EOF` again. + * 3. bt_notif_iter_get_next_notification() + * emits a "stream end" notification because + * there's no current packet. It sets the + * current state to `STATE_DONE`. + */ + goto end; + } + } + + release_event_dscopes(notit); + BT_ASSERT(notit->meta.sc); + event_header_fc = notit->meta.sc->event_header_fc; + if (!event_header_fc) { + notit->state = STATE_AFTER_EVENT_HEADER; + goto end; + } + + if (event_header_fc->in_ir) { + BT_ASSERT(!notit->event_header_field); + notit->event_header_field = bt_event_header_field_create( + notit->meta.sc->ir_sc); + if (!notit->event_header_field) { + BT_LOGE_STR("Cannot create event header field wrapper from trace."); + status = BT_NOTIF_ITER_STATUS_ERROR; + goto end; + } + + notit->dscopes.event_header = + bt_event_header_field_borrow_field(notit->event_header_field); + BT_ASSERT(notit->dscopes.event_header); + } + + BT_LOGV("Decoding event header field: " + "notit-addr=%p, stream-class-addr=%p, " + "stream-class-id=%" PRId64 ", " + "fc-addr=%p", + notit, notit->meta.sc, + notit->meta.sc->id, + event_header_fc); + status = read_dscope_begin_state(notit, event_header_fc, + STATE_AFTER_EVENT_HEADER, + STATE_DSCOPE_EVENT_HEADER_CONTINUE, + notit->dscopes.event_header); if (status < 0) { BT_LOGW("Cannot decode event header field: " "notit-addr=%p, stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", ft-addr=%p", - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class), - event_header_type); + "stream-class-id=%" PRId64 ", fc-addr=%p", + notit, notit->meta.sc, + notit->meta.sc->id, + event_header_fc); } -end: - BT_PUT(event_header_type); +end: return status; } @@ -1259,166 +1133,95 @@ enum bt_notif_iter_status read_event_header_continue_state( struct bt_notif_iter *notit) { return read_dscope_continue_state(notit, - STATE_AFTER_STREAM_EVENT_HEADER); + STATE_AFTER_EVENT_HEADER); } static inline enum bt_notif_iter_status set_current_event_class(struct bt_notif_iter *notit) { - /* - * The assert() calls in this function are okay because it is - * assumed here that all the metadata objects have been - * validated for CTF correctness before decoding actual streams. - */ - enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; - struct bt_field_type *event_header_type; - struct bt_field_type *id_field_type = NULL; - struct bt_field_type *v_field_type = NULL; - uint64_t event_id = -1ULL; - int ret; - event_header_type = bt_stream_class_get_event_header_type( - notit->meta.stream_class); - if (!event_header_type) { - /* - * No event header, therefore no event class ID field, - * therefore only one event class. - */ - goto single_event_class; - } + struct ctf_event_class *new_event_class = NULL; - /* Is there any "id"/"v" field in the event header? */ - BT_ASSERT(is_struct_type(event_header_type)); - id_field_type = bt_field_type_structure_get_field_type_by_name( - event_header_type, "id"); - v_field_type = bt_field_type_structure_get_field_type_by_name( - event_header_type, "v"); - BT_ASSERT(notit->dscopes.stream_event_header); - if (v_field_type) { + if (notit->cur_event_class_id == -1) { /* - * _ _____ _____ - * | | |_ _|_ _| __ __ _ - * | | | | | || '_ \ / _` | - * | |___| | | || | | | (_| | S P E C I A L - * |_____|_| |_||_| |_|\__, | C A S E ™ - * |___/ + * No current event class ID field, therefore only one + * event class. */ - struct bt_field *v_field = NULL; - struct bt_field *v_struct_field = NULL; - struct bt_field *v_struct_id_field = NULL; - - // TODO: optimalize! - v_field = bt_field_structure_get_field_by_name( - notit->dscopes.stream_event_header, "v"); - BT_ASSERT(v_field); - - v_struct_field = - bt_field_variant_get_current_field(v_field); - if (!v_struct_field) { - goto end_v_field_type; - } - - // TODO: optimalize! - v_struct_id_field = - bt_field_structure_get_field_by_name(v_struct_field, "id"); - if (!v_struct_id_field) { - goto end_v_field_type; - } - - if (bt_field_is_integer(v_struct_id_field)) { - ret = bt_field_unsigned_integer_get_value( - v_struct_id_field, &event_id); - if (ret) { - BT_LOGV("Cannot get value of unsigned integer field (`id`): continuing: " - "notit=%p, field-addr=%p", - notit, v_struct_id_field); - event_id = -1ULL; - } - } - -end_v_field_type: - BT_PUT(v_field); - BT_PUT(v_struct_field); - BT_PUT(v_struct_id_field); - } - - if (id_field_type && event_id == -1ULL) { - /* Check "id" field */ - struct bt_field *id_field = NULL; - int ret_get_value = 0; - - // TODO: optimalize! - id_field = bt_field_structure_get_field_by_name( - notit->dscopes.stream_event_header, "id"); - if (!id_field) { - goto check_event_id; - } - - if (bt_field_is_integer(id_field)) { - ret_get_value = bt_field_unsigned_integer_get_value( - id_field, &event_id); - } else if (bt_field_is_enumeration(id_field)) { - struct bt_field *container; - - container = bt_field_enumeration_get_container( - id_field); - BT_ASSERT(container); - ret_get_value = bt_field_unsigned_integer_get_value( - container, &event_id); - BT_PUT(container); + if (notit->meta.sc->event_classes->len != 1) { + BT_LOGW("Need exactly one event class since there's " + "no event class ID field: " + "notit-addr=%p, trace-name=\"%s\"", + notit, notit->meta.tc->name->str); + status = BT_NOTIF_ITER_STATUS_ERROR; + goto end; } - BT_ASSERT(ret_get_value == 0); - BT_PUT(id_field); - } - -check_event_id: - if (event_id == -1ULL) { -single_event_class: - /* Event ID not found: single event? */ - BT_ASSERT(bt_stream_class_get_event_class_count( - notit->meta.stream_class) == 1); - event_id = 0; + new_event_class = notit->meta.sc->event_classes->pdata[0]; + notit->cur_event_class_id = new_event_class->id; + goto end; } - BT_LOGV("Found event class ID to use: notit-addr=%p, " - "stream-class-addr=%p, stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", " - "event-class-id=%" PRIu64, - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class), - event_id); - BT_PUT(notit->meta.event_class); - notit->meta.event_class = bt_stream_class_get_event_class_by_id( - notit->meta.stream_class, event_id); - if (!notit->meta.event_class) { + new_event_class = ctf_stream_class_borrow_event_class_by_id( + notit->meta.sc, notit->cur_event_class_id); + if (!new_event_class) { BT_LOGW("No event class with ID of event class ID to use in stream class: " - "notit-addr=%p, stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", " - "event-class-id=%" PRIu64, - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class), - event_id); + "notit-addr=%p, stream-class-id=%" PRIu64 ", " + "event-class-id=%" PRIu64 ", " + "trace-addr=%p, trace-name=\"%s\"", + notit, notit->meta.sc->id, notit->cur_event_class_id, + notit->meta.tc, notit->meta.tc->name->str); status = BT_NOTIF_ITER_STATUS_ERROR; goto end; } + notit->meta.ec = new_event_class; BT_LOGV("Set current event class: " "notit-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64, - notit, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class)); + "event-class-id=%" PRId64 ", " + "event-class-name=\"%s\"", + notit, notit->meta.ec, notit->meta.ec->id, + notit->meta.ec->name->str); end: - BT_PUT(event_header_type); - BT_PUT(id_field_type); - BT_PUT(v_field_type); + return status; +} + +static inline +enum bt_notif_iter_status set_current_event_notification( + struct bt_notif_iter *notit) +{ + enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; + struct bt_notification *notif = NULL; + + BT_ASSERT(notit->meta.ec); + BT_ASSERT(notit->packet); + BT_LOGV("Creating event notification 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->notif_iter); + notif = bt_notification_event_create(notit->notif_iter, + notit->meta.ec->ir_ec, notit->packet); + if (!notif) { + BT_LOGE("Cannot create event notification: " + "notit-addr=%p, ec-addr=%p, ec-name=\"%s\", " + "packet-addr=%p", + notit, notit->meta.ec, + notit->meta.ec->name->str, + notit->packet); + goto error; + } + + goto end; +error: + BT_OBJECT_PUT_REF_AND_RESET(notif); + status = BT_NOTIF_ITER_STATUS_ERROR; + +end: + BT_OBJECT_MOVE_REF(notit->event_notif, notif); return status; } @@ -1433,108 +1236,143 @@ enum bt_notif_iter_status after_event_header_state( goto end; } - notit->state = STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN; + status = set_current_event_notification(notit); + if (status != BT_NOTIF_ITER_STATUS_OK) { + goto end; + } + + notit->event = bt_notification_event_borrow_event(notit->event_notif); + BT_ASSERT(notit->event); + + if (notit->event_header_field) { + int ret; + + BT_ASSERT(notit->event); + ret = bt_event_move_header(notit->event, + notit->event_header_field); + if (ret) { + status = BT_NOTIF_ITER_STATUS_ERROR; + goto end; + } + + notit->event_header_field = NULL; + + /* + * At this point notit->dscopes.event_header has + * the same value as the event header field within + * notit->event. + */ + BT_ASSERT(bt_event_borrow_header_field(notit->event) == + notit->dscopes.event_header); + } + + notit->state = STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN; end: return status; } static -enum bt_notif_iter_status read_stream_event_context_begin_state( +enum bt_notif_iter_status read_event_common_context_begin_state( struct bt_notif_iter *notit) { enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; - struct bt_field_type *stream_event_context_type; + struct ctf_field_class *event_common_context_fc; - stream_event_context_type = bt_stream_class_get_event_context_type( - notit->meta.stream_class); - if (!stream_event_context_type) { - notit->state = STATE_DSCOPE_EVENT_CONTEXT_BEGIN; + event_common_context_fc = notit->meta.sc->event_common_context_fc; + if (!event_common_context_fc) { + notit->state = STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN; goto end; } - BT_LOGV("Decoding stream event context field: " + if (event_common_context_fc->in_ir) { + BT_ASSERT(!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_LOGV("Decoding event common context field: " "notit-addr=%p, stream-class-addr=%p, " - "stream-class-name=\"%s\", stream-class-id=%" PRId64 ", " - "ft-addr=%p", - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class), - stream_event_context_type); - status = read_dscope_begin_state(notit, stream_event_context_type, - STATE_DSCOPE_EVENT_CONTEXT_BEGIN, - STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE, - ¬it->dscopes.stream_event_context); + "stream-class-id=%" PRId64 ", " + "fc-addr=%p", + notit, notit->meta.sc, + notit->meta.sc->id, + event_common_context_fc); + status = read_dscope_begin_state(notit, event_common_context_fc, + STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN, + STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE, + notit->dscopes.event_common_context); if (status < 0) { - BT_LOGW("Cannot decode stream event context field: " + BT_LOGW("Cannot decode event common context field: " "notit-addr=%p, stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", ft-addr=%p", - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class), - stream_event_context_type); + "stream-class-id=%" PRId64 ", fc-addr=%p", + notit, notit->meta.sc, + notit->meta.sc->id, + event_common_context_fc); } end: - BT_PUT(stream_event_context_type); - return status; } static -enum bt_notif_iter_status read_stream_event_context_continue_state( +enum bt_notif_iter_status read_event_common_context_continue_state( struct bt_notif_iter *notit) { return read_dscope_continue_state(notit, - STATE_DSCOPE_EVENT_CONTEXT_BEGIN); + STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN); } static -enum bt_notif_iter_status read_event_context_begin_state( +enum bt_notif_iter_status read_event_spec_context_begin_state( struct bt_notif_iter *notit) { enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; - struct bt_field_type *event_context_type; + struct ctf_field_class *event_spec_context_fc; - event_context_type = bt_event_class_get_context_type( - notit->meta.event_class); - if (!event_context_type) { + event_spec_context_fc = notit->meta.ec->spec_context_fc; + if (!event_spec_context_fc) { notit->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN; goto end; } - BT_LOGV("Decoding event context field: " + if (event_spec_context_fc->in_ir) { + BT_ASSERT(!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_LOGV("Decoding event specific context field: " "notit-addr=%p, event-class-addr=%p, " "event-class-name=\"%s\", event-class-id=%" PRId64 ", " - "ft-addr=%p", - notit, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class), - event_context_type); - status = read_dscope_begin_state(notit, event_context_type, + "fc-addr=%p", + notit, notit->meta.ec, + notit->meta.ec->name->str, + notit->meta.ec->id, + event_spec_context_fc); + status = read_dscope_begin_state(notit, event_spec_context_fc, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN, - STATE_DSCOPE_EVENT_CONTEXT_CONTINUE, - ¬it->dscopes.event_context); + STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE, + notit->dscopes.event_spec_context); if (status < 0) { - BT_LOGW("Cannot decode event context field: " + BT_LOGW("Cannot decode event specific context field: " "notit-addr=%p, event-class-addr=%p, " "event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", ft-addr=%p", - notit, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class), - event_context_type); + "event-class-id=%" PRId64 ", fc-addr=%p", + notit, notit->meta.ec, + notit->meta.ec->name->str, + notit->meta.ec->id, + event_spec_context_fc); } end: - BT_PUT(event_context_type); - return status; } static -enum bt_notif_iter_status read_event_context_continue_state( +enum bt_notif_iter_status read_event_spec_context_continue_state( struct bt_notif_iter *notit) { return read_dscope_continue_state(notit, @@ -1546,41 +1384,45 @@ enum bt_notif_iter_status read_event_payload_begin_state( struct bt_notif_iter *notit) { enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; - struct bt_field_type *event_payload_type; + struct ctf_field_class *event_payload_fc; - event_payload_type = bt_event_class_get_payload_type( - notit->meta.event_class); - if (!event_payload_type) { + event_payload_fc = notit->meta.ec->payload_fc; + if (!event_payload_fc) { notit->state = STATE_EMIT_NOTIF_EVENT; goto end; } + if (event_payload_fc->in_ir) { + BT_ASSERT(!notit->dscopes.event_payload); + notit->dscopes.event_payload = bt_event_borrow_payload_field( + notit->event); + BT_ASSERT(notit->dscopes.event_payload); + } + BT_LOGV("Decoding event payload field: " "notit-addr=%p, event-class-addr=%p, " "event-class-name=\"%s\", event-class-id=%" PRId64 ", " - "ft-addr=%p", - notit, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class), - event_payload_type); - status = read_dscope_begin_state(notit, event_payload_type, + "fc-addr=%p", + notit, notit->meta.ec, + notit->meta.ec->name->str, + notit->meta.ec->id, + event_payload_fc); + status = read_dscope_begin_state(notit, event_payload_fc, STATE_EMIT_NOTIF_EVENT, STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE, - ¬it->dscopes.event_payload); + notit->dscopes.event_payload); if (status < 0) { BT_LOGW("Cannot decode event payload field: " "notit-addr=%p, event-class-addr=%p, " "event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", ft-addr=%p", - notit, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class), - event_payload_type); + "event-class-id=%" PRId64 ", fc-addr=%p", + notit, notit->meta.ec, + notit->meta.ec->name->str, + notit->meta.ec->id, + event_payload_fc); } end: - BT_PUT(event_payload_type); - return status; } @@ -1598,8 +1440,8 @@ enum bt_notif_iter_status skip_packet_padding_state( enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; size_t bits_to_skip; - BT_ASSERT(notit->cur_packet_size > 0); - bits_to_skip = notit->cur_packet_size - packet_at(notit); + BT_ASSERT(notit->cur_exp_packet_total_size > 0); + bits_to_skip = notit->cur_exp_packet_total_size - packet_at(notit); if (bits_to_skip == 0) { notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN; goto end; @@ -1617,7 +1459,8 @@ enum bt_notif_iter_status skip_packet_padding_state( BT_LOGV("Skipping %zu bits of padding: notit-addr=%p, size=%zu", bits_to_consume, notit, bits_to_consume); buf_consume_bits(notit, bits_to_consume); - bits_to_skip = notit->cur_packet_size - packet_at(notit); + bits_to_skip = notit->cur_exp_packet_total_size - + packet_at(notit); if (bits_to_skip == 0) { notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN; goto end; @@ -1664,28 +1507,28 @@ enum bt_notif_iter_status handle_state(struct bt_notif_iter *notit) notit->state = STATE_EMIT_NOTIF_NEW_PACKET; break; case STATE_EMIT_NOTIF_NEW_PACKET: - notit->state = STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN; + notit->state = STATE_DSCOPE_EVENT_HEADER_BEGIN; break; - case STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN: + case STATE_DSCOPE_EVENT_HEADER_BEGIN: status = read_event_header_begin_state(notit); break; - case STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE: + case STATE_DSCOPE_EVENT_HEADER_CONTINUE: status = read_event_header_continue_state(notit); break; - case STATE_AFTER_STREAM_EVENT_HEADER: + case STATE_AFTER_EVENT_HEADER: status = after_event_header_state(notit); break; - case STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN: - status = read_stream_event_context_begin_state(notit); + case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN: + status = read_event_common_context_begin_state(notit); break; - case STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE: - status = read_stream_event_context_continue_state(notit); + case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE: + status = read_event_common_context_continue_state(notit); break; - case STATE_DSCOPE_EVENT_CONTEXT_BEGIN: - status = read_event_context_begin_state(notit); + case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN: + status = read_event_spec_context_begin_state(notit); break; - case STATE_DSCOPE_EVENT_CONTEXT_CONTINUE: - status = read_event_context_continue_state(notit); + case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE: + status = read_event_spec_context_continue_state(notit); break; case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN: status = read_event_payload_begin_state(notit); @@ -1694,7 +1537,7 @@ enum bt_notif_iter_status handle_state(struct bt_notif_iter *notit) status = read_event_payload_continue_state(notit); break; case STATE_EMIT_NOTIF_EVENT: - notit->state = STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN; + notit->state = STATE_DSCOPE_EVENT_HEADER_BEGIN; break; case STATE_SKIP_PACKET_PADDING: status = skip_packet_padding_state(notit); @@ -1724,20 +1567,41 @@ void bt_notif_iter_reset(struct bt_notif_iter *notit) BT_ASSERT(notit); BT_LOGD("Resetting notification iterator: addr=%p", notit); stack_clear(notit->stack); - BT_PUT(notit->meta.stream_class); - BT_PUT(notit->meta.event_class); - BT_PUT(notit->packet); - BT_PUT(notit->stream); - put_all_dscopes(notit); + notit->meta.sc = NULL; + notit->meta.ec = NULL; + BT_OBJECT_PUT_REF_AND_RESET(notit->packet); + BT_OBJECT_PUT_REF_AND_RESET(notit->stream); + BT_OBJECT_PUT_REF_AND_RESET(notit->event_notif); + release_all_dscopes(notit); + notit->cur_dscope_field = NULL; + + if (notit->packet_header_field) { + bt_packet_header_field_release(notit->packet_header_field); + notit->packet_header_field = NULL; + } + + if (notit->packet_context_field) { + bt_packet_context_field_release(notit->packet_context_field); + notit->packet_context_field = NULL; + } + + if (notit->event_header_field) { + bt_event_header_field_release(notit->event_header_field); + notit->event_header_field = NULL; + } + notit->buf.addr = NULL; notit->buf.sz = 0; notit->buf.at = 0; notit->buf.last_eh_at = SIZE_MAX; notit->buf.packet_offset = 0; notit->state = STATE_INIT; - notit->cur_content_size = -1; - notit->cur_packet_size = -1; + notit->cur_exp_packet_content_size = -1; + notit->cur_exp_packet_total_size = -1; notit->cur_packet_offset = -1; + notit->cur_stream_class_id = -1; + notit->cur_event_class_id = -1; + notit->cur_data_stream_id = -1; notit->stream_begin_emitted = false; } @@ -1752,17 +1616,20 @@ int bt_notif_iter_switch_packet(struct bt_notif_iter *notit) * iterator refer to the same stream class (the first one). */ BT_ASSERT(notit); - if (notit->cur_packet_size != -1) { - notit->cur_packet_offset += notit->cur_packet_size; + + if (notit->cur_exp_packet_total_size != -1) { + notit->cur_packet_offset += notit->cur_exp_packet_total_size; } + BT_LOGV("Switching packet: notit-addr=%p, cur=%zu, " "packet-offset=%" PRId64, notit, notit->buf.at, notit->cur_packet_offset); stack_clear(notit->stack); - BT_PUT(notit->meta.event_class); - BT_PUT(notit->packet); - BT_PUT(notit->cur_timestamp_end); - put_all_dscopes(notit); + notit->meta.ec = NULL; + BT_OBJECT_PUT_REF_AND_RESET(notit->packet); + BT_OBJECT_PUT_REF_AND_RESET(notit->event_notif); + release_all_dscopes(notit); + notit->cur_dscope_field = NULL; /* * Adjust current buffer so that addr points to the beginning of the new @@ -1787,456 +1654,354 @@ int bt_notif_iter_switch_packet(struct bt_notif_iter *notit) notit->buf.addr, notit->buf.sz); } - notit->cur_content_size = -1; - notit->cur_packet_size = -1; - notit->cur_sc_field_path_cache = NULL; + notit->cur_exp_packet_content_size = -1; + notit->cur_exp_packet_total_size = -1; + notit->cur_stream_class_id = -1; + notit->cur_event_class_id = -1; + notit->cur_data_stream_id = -1; + notit->snapshots.discarded_events = UINT64_C(-1); + notit->snapshots.packets = UINT64_C(-1); + notit->snapshots.beginning_clock = UINT64_C(-1); + notit->snapshots.end_clock = UINT64_C(-1); end: return ret; } static -struct bt_field *get_next_field(struct bt_notif_iter *notit) +struct bt_field *borrow_next_field(struct bt_notif_iter *notit) { struct bt_field *next_field = NULL; struct bt_field *base_field; - struct bt_field_type *base_type; + struct bt_field_class *base_fc; size_t index; BT_ASSERT(!stack_empty(notit->stack)); index = stack_top(notit->stack)->index; base_field = stack_top(notit->stack)->base; BT_ASSERT(base_field); - base_type = bt_field_get_type(base_field); - BT_ASSERT(base_type); + base_fc = bt_field_borrow_class(base_field); + BT_ASSERT(base_fc); - switch (bt_field_type_get_type_id(base_type)) { - case BT_FIELD_TYPE_ID_STRUCT: + switch (bt_field_class_get_type(base_fc)) { + case BT_FIELD_CLASS_TYPE_STRUCTURE: { - next_field = bt_field_structure_get_field_by_index( + BT_ASSERT(index < + bt_field_class_structure_get_member_count( + bt_field_borrow_class(base_field))); + next_field = bt_field_structure_borrow_member_field_by_index( base_field, index); - const char *name; - bt_field_type_structure_get_field_by_index(base_type, - &name, NULL, index); break; } - case BT_FIELD_TYPE_ID_ARRAY: - next_field = bt_field_array_get_field(base_field, index); - break; - case BT_FIELD_TYPE_ID_SEQUENCE: - next_field = bt_field_sequence_get_field(base_field, index); + case BT_FIELD_CLASS_TYPE_STATIC_ARRAY: + case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: + BT_ASSERT(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_TYPE_ID_VARIANT: - next_field = bt_field_variant_get_current_field(base_field); + case BT_FIELD_CLASS_TYPE_VARIANT: + BT_ASSERT(index == 0); + next_field = bt_field_variant_borrow_selected_option_field( + base_field); break; default: - BT_LOGF("Unknown base field type ID: " - "notit-addr=%p, ft-addr=%p, ft-id=%s", - notit, base_type, - bt_field_type_id_string( - bt_field_type_get_type_id(base_type))); abort(); } - BT_PUT(base_type); + BT_ASSERT(next_field); return next_field; } static -void update_clock_state(uint64_t *state, - struct bt_field *value_field) +void update_default_clock(struct bt_notif_iter *notit, uint64_t new_val, + uint64_t new_val_size) { - struct bt_field_type *value_type = NULL; - uint64_t requested_new_value; - uint64_t requested_new_value_mask; + uint64_t new_val_mask; uint64_t cur_value_masked; - int requested_new_value_size; - int ret; - value_type = bt_field_get_type(value_field); - BT_ASSERT(value_type); - BT_ASSERT(bt_field_type_is_integer(value_type)); - requested_new_value_size = - bt_field_type_integer_get_size(value_type); - BT_ASSERT(requested_new_value_size > 0); - ret = bt_field_unsigned_integer_get_value(value_field, - &requested_new_value); - BT_ASSERT(!ret); + BT_ASSERT(new_val_size > 0); /* * 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; + if (new_val_size == 64) { + notit->default_clock_val = new_val; goto end; } - requested_new_value_mask = (1ULL << requested_new_value_size) - 1; - cur_value_masked = *state & requested_new_value_mask; + new_val_mask = (1ULL << new_val_size) - 1; + cur_value_masked = notit->default_clock_val & new_val_mask; - if (requested_new_value < cur_value_masked) { + if (new_val < 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; + notit->default_clock_val += new_val_mask + 1; } /* Clear the low bits of the current clock value. */ - *state &= ~requested_new_value_mask; + notit->default_clock_val &= ~new_val_mask; /* Set the low bits of the current clock value. */ - *state |= requested_new_value; + notit->default_clock_val |= new_val; + end: - BT_LOGV("Updated clock's value from integer field's value: " - "value=%" PRIu64, *state); - bt_put(value_type); + BT_LOGV("Updated default clock's value from integer field's value: " + "value=%" PRIu64, notit->default_clock_val); } static -enum bt_btr_status update_clock(struct bt_notif_iter *notit, - struct bt_field *int_field) -{ - gboolean clock_class_found; - uint64_t *clock_state = NULL; - struct bt_field_type *int_field_type = NULL; - enum bt_btr_status ret = BT_BTR_STATUS_OK; - struct bt_clock_class *clock_class = NULL; - - int_field_type = bt_field_get_type(int_field); - BT_ASSERT(int_field_type); - clock_class = bt_field_type_integer_get_mapped_clock_class( - int_field_type); - if (likely(!clock_class)) { - goto end; - } +enum bt_bfcr_status bfcr_unsigned_int_cb(uint64_t value, + struct ctf_field_class *fc, void *data) +{ + struct bt_notif_iter *notit = data; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + struct bt_field *field = NULL; + struct ctf_field_class_int *int_fc = (void *) fc; - clock_class_found = g_hash_table_lookup_extended(notit->clock_states, - clock_class, NULL, (gpointer) &clock_state); - if (!clock_class_found) { - clock_state = g_new0(uint64_t, 1); - if (!clock_state) { - BT_LOGE_STR("Failed to allocate a uint64_t."); - ret = BT_BTR_STATUS_ENOMEM; - goto end; - } + BT_LOGV("Unsigned integer function called from BFCR: " + "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); - g_hash_table_insert(notit->clock_states, bt_get(clock_class), - clock_state); + if (likely(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE)) { + goto update_def_clock; } - /* Update the clock's state. */ - BT_LOGV("Updating notification iterator's clock's value from integer field: " - "notit-addr=%p, clock-class-addr=%p, " - "clock-class-name=\"%s\", value=%" PRIu64, - notit, clock_class, - bt_clock_class_get_name(clock_class), *clock_state); - update_clock_state(clock_state, int_field); -end: - bt_put(int_field_type); - bt_put(clock_class); - return ret; -} - -static -enum bt_btr_status btr_unsigned_int_common(uint64_t value, - struct bt_field_type *type, void *data, - struct bt_field **out_int_field) -{ - enum bt_btr_status status = BT_BTR_STATUS_OK; - struct bt_field *field = NULL; - struct bt_field *int_field = NULL; - struct bt_notif_iter *notit = data; - int ret; + switch (int_fc->meaning) { + case CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID: + notit->cur_event_class_id = value; + break; + case CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID: + notit->cur_data_stream_id = value; + break; + case CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME: + notit->snapshots.beginning_clock = value; + break; + case CTF_FIELD_CLASS_MEANING_PACKET_END_TIME: + notit->snapshots.end_clock = value; + break; + case CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID: + notit->cur_stream_class_id = value; + break; + case CTF_FIELD_CLASS_MEANING_MAGIC: + if (value != 0xc1fc1fc1) { + BT_LOGW("Invalid CTF magic number: notit-addr=%p, " + "magic=%" PRIx64, notit, value); + status = BT_BFCR_STATUS_ERROR; + goto end; + } - BT_LOGV("Common unsigned integer function called from BTR: " - "notit-addr=%p, btr-addr=%p, ft-addr=%p, " - "ft-id=%s, value=%" PRIu64, - notit, notit->btr, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type)), - value); - - /* Create next field */ - field = get_next_field(notit); - if (!field) { - BT_LOGW("Cannot get next field: notit-addr=%p", notit); - status = BT_BTR_STATUS_ERROR; - goto end_no_put; - } - - switch(bt_field_type_get_type_id(type)) { - case BT_FIELD_TYPE_ID_INTEGER: - /* Integer field is created field */ - BT_MOVE(int_field, field); - bt_get(type); break; - case BT_FIELD_TYPE_ID_ENUM: - int_field = bt_field_enumeration_get_container(field); - BT_ASSERT(int_field); - type = bt_field_get_type(int_field); - BT_ASSERT(type); + case CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT: + notit->snapshots.packets = value; + break; + case CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT: + notit->snapshots.discarded_events = value; + break; + case CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE: + notit->cur_exp_packet_total_size = value; + break; + case CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE: + notit->cur_exp_packet_content_size = value; break; default: - BT_LOGF("Unexpected field type ID: " - "notit-addr=%p, ft-addr=%p, ft-id=%s", - notit, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type))); abort(); } - BT_ASSERT(int_field); - ret = bt_field_unsigned_integer_set_value(int_field, value); - BT_ASSERT(ret == 0); +update_def_clock: + if (unlikely(int_fc->mapped_clock_class)) { + update_default_clock(notit, value, int_fc->base.size); + } + + if (unlikely(int_fc->storing_index >= 0)) { + g_array_index(notit->stored_values, uint64_t, + (uint64_t) int_fc->storing_index) = value; + } + + if (unlikely(!fc->in_ir)) { + goto end; + } + + field = borrow_next_field(notit); + BT_ASSERT(field); + BT_ASSERT(bt_field_borrow_class(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_field_unsigned_integer_set_value(field, value); stack_top(notit->stack)->index++; - *out_int_field = int_field; - BT_PUT(field); - BT_PUT(type); -end_no_put: +end: return status; } static -enum bt_btr_status btr_timestamp_end_cb(void *value, - struct bt_field_type *type, void *data) +enum bt_bfcr_status bfcr_unsigned_int_char_cb(uint64_t value, + struct ctf_field_class *fc, void *data) { - enum bt_btr_status status; - struct bt_field *field = NULL; + int ret; struct bt_notif_iter *notit = data; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + struct bt_field *string_field = NULL; + struct ctf_field_class_int *int_fc = (void *) fc; + char str[2] = {'\0', '\0'}; + + BT_LOGV("Unsigned integer character function called from BFCR: " + "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); + + if (unlikely(!fc->in_ir)) { + goto end; + } - BT_LOGV("`timestamp_end` unsigned integer function called from BTR: " - "notit-addr=%p, btr-addr=%p, ft-addr=%p, " - "ft-id=%s", - notit, notit->btr, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type))); - status = btr_unsigned_int_common(*((uint64_t *) value), type, data, - &field); - - /* Set as the current packet's timestamp_end field. */ - BT_MOVE(notit->cur_timestamp_end, field); - return status; -} + if (notit->done_filling_string) { + goto end; + } -static -enum bt_btr_status btr_unsigned_int_cb(uint64_t value, - struct bt_field_type *type, void *data) -{ - struct bt_notif_iter *notit = data; - enum bt_btr_status status = BT_BTR_STATUS_OK; - struct bt_field *field = NULL; - struct field_cb_override *override; - - BT_LOGV("Unsigned integer function called from BTR: " - "notit-addr=%p, btr-addr=%p, ft-addr=%p, " - "ft-id=%s, value=%" PRIu64, - notit, notit->btr, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type)), - value); - override = g_hash_table_lookup(notit->field_overrides, type); - if (unlikely(override)) { - /* Override function logs errors */ - status = override->func(&value, type, override->data); + if (value == 0) { + notit->done_filling_string = true; goto end; } - status = btr_unsigned_int_common(value, type, data, &field); - if (status != BT_BTR_STATUS_OK) { - /* btr_unsigned_int_common() logs errors */ + string_field = stack_top(notit->stack)->base; + BT_ASSERT(bt_field_get_class_type(string_field) == BT_FIELD_CLASS_TYPE_STRING); + + /* Append character */ + str[0] = (char) value; + ret = bt_field_string_append_with_length(string_field, str, 1); + if (ret) { + BT_LOGE("Cannot append character to string field's value: " + "notit-addr=%p, field-addr=%p, ret=%d", + notit, string_field, ret); + status = BT_BFCR_STATUS_ERROR; goto end; } - status = update_clock(notit, field); - BT_PUT(field); end: return status; } static -enum bt_btr_status btr_signed_int_cb(int64_t value, - struct bt_field_type *type, void *data) +enum bt_bfcr_status bfcr_signed_int_cb(int64_t value, + struct ctf_field_class *fc, void *data) { - enum bt_btr_status status = BT_BTR_STATUS_OK; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; struct bt_field *field = NULL; - struct bt_field *int_field = NULL; struct bt_notif_iter *notit = data; - int ret; + struct ctf_field_class_int *int_fc = (void *) fc; - BT_LOGV("Signed integer function called from BTR: " - "notit-addr=%p, btr-addr=%p, ft-addr=%p, " - "ft-id=%s, value=%" PRId64, - notit, notit->btr, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type)), - value); - - /* create next field */ - field = get_next_field(notit); - if (!field) { - BT_LOGW("Cannot get next field: notit-addr=%p", notit); - status = BT_BTR_STATUS_ERROR; - goto end_no_put; - } - - switch(bt_field_type_get_type_id(type)) { - case BT_FIELD_TYPE_ID_INTEGER: - /* Integer field is created field */ - BT_MOVE(int_field, field); - bt_get(type); - break; - case BT_FIELD_TYPE_ID_ENUM: - int_field = bt_field_enumeration_get_container(field); - BT_ASSERT(int_field); - type = bt_field_get_type(int_field); - BT_ASSERT(type); - break; - default: - BT_LOGF("Unexpected field type ID: " - "notit-addr=%p, ft-addr=%p, ft-id=%s", - notit, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type))); - abort(); + BT_LOGV("Signed integer function called from BFCR: " + "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); + + if (unlikely(int_fc->storing_index >= 0)) { + g_array_index(notit->stored_values, uint64_t, + (uint64_t) int_fc->storing_index) = (uint64_t) value; + } + + if (unlikely(!fc->in_ir)) { + goto end; } - BT_ASSERT(int_field); - ret = bt_field_signed_integer_set_value(int_field, value); - BT_ASSERT(!ret); + field = borrow_next_field(notit); + BT_ASSERT(field); + BT_ASSERT(bt_field_borrow_class(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_field_signed_integer_set_value(field, value); stack_top(notit->stack)->index++; - status = update_clock(notit, int_field); - BT_PUT(field); - BT_PUT(int_field); - BT_PUT(type); -end_no_put: +end: return status; } static -enum bt_btr_status btr_floating_point_cb(double value, - struct bt_field_type *type, void *data) +enum bt_bfcr_status bfcr_floating_point_cb(double value, + struct ctf_field_class *fc, void *data) { - enum bt_btr_status status = BT_BTR_STATUS_OK; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; struct bt_field *field = NULL; struct bt_notif_iter *notit = data; - int ret; - - BT_LOGV("Floating point number function called from BTR: " - "notit-addr=%p, btr-addr=%p, ft-addr=%p, " - "ft-id=%s, value=%f", - notit, notit->btr, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type)), - value); - - /* Create next field */ - field = get_next_field(notit); - if (!field) { - BT_LOGW("Cannot get next field: notit-addr=%p", notit); - status = BT_BTR_STATUS_ERROR; - goto end; - } - ret = bt_field_floating_point_set_value(field, value); - BT_ASSERT(!ret); + BT_LOGV("Floating point number function called from BFCR: " + "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d, value=%f", + notit, notit->bfcr, fc, fc->type, fc->in_ir, value); + BT_ASSERT(fc->in_ir); + field = borrow_next_field(notit); + BT_ASSERT(field); + BT_ASSERT(bt_field_borrow_class(field) == fc->ir_fc); + BT_ASSERT(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_REAL); + bt_field_real_set_value(field, value); stack_top(notit->stack)->index++; - -end: - BT_PUT(field); return status; } static -enum bt_btr_status btr_string_begin_cb( - struct bt_field_type *type, void *data) +enum bt_bfcr_status bfcr_string_begin_cb( + struct ctf_field_class *fc, void *data) { - enum bt_btr_status status = BT_BTR_STATUS_OK; struct bt_field *field = NULL; struct bt_notif_iter *notit = data; int ret; - BT_LOGV("String (beginning) function called from BTR: " - "notit-addr=%p, btr-addr=%p, ft-addr=%p, " - "ft-id=%s", - notit, notit->btr, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type))); - - /* Create next field */ - field = get_next_field(notit); - if (!field) { - BT_LOGW("Cannot get next field: notit-addr=%p", notit); - status = BT_BTR_STATUS_ERROR; - goto end; - } + BT_LOGV("String (beginning) function called from BFCR: " + "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d", + notit, notit->bfcr, fc, fc->type, fc->in_ir); - /* - * Push on stack. Not a compound type per se, but we know that only - * btr_string_cb() may be called between this call and a subsequent - * call to btr_string_end_cb(). - */ - ret = stack_push(notit->stack, field); - if (ret) { - BT_LOGE("Cannot push string field on stack: " - "notit-addr=%p, field-addr=%p", notit, field); - status = BT_BTR_STATUS_ERROR; - goto end; - } + BT_ASSERT(fc->in_ir); + field = borrow_next_field(notit); + BT_ASSERT(field); + BT_ASSERT(bt_field_borrow_class(field) == fc->ir_fc); + BT_ASSERT(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING); + ret = bt_field_string_clear(field); + BT_ASSERT(ret == 0); /* - * 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. + * Push on stack. Not a compound class per se, but we know that + * only bfcr_string_cb() may be called between this call and a + * subsequent call to bfcr_string_end_cb(). */ - ret = bt_field_string_set_value(field, ""); - if (ret) { - BT_LOGE("Cannot initialize string field's value to an empty string: " - "notit-addr=%p, field-addr=%p, ret=%d", - notit, field, ret); - status = BT_BTR_STATUS_ERROR; - goto end; - } - -end: - BT_PUT(field); - - return status; + stack_push(notit->stack, field); + return BT_BFCR_STATUS_OK; } static -enum bt_btr_status btr_string_cb(const char *value, - size_t len, struct bt_field_type *type, void *data) +enum bt_bfcr_status bfcr_string_cb(const char *value, + size_t len, struct ctf_field_class *fc, void *data) { - enum bt_btr_status status = BT_BTR_STATUS_OK; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; struct bt_field *field = NULL; struct bt_notif_iter *notit = data; int ret; - BT_LOGV("String (substring) function called from BTR: " - "notit-addr=%p, btr-addr=%p, ft-addr=%p, " - "ft-id=%s, string-length=%zu", - notit, notit->btr, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type)), + BT_LOGV("String (substring) function called from BFCR: " + "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d, string-length=%zu", + notit, notit->bfcr, fc, fc->type, fc->in_ir, len); - - /* Get string field */ + BT_ASSERT(fc->in_ir); field = stack_top(notit->stack)->base; BT_ASSERT(field); - /* Append current string */ - ret = bt_field_string_append_len(field, value, len); + /* Append current substring */ + ret = bt_field_string_append_with_length(field, value, len); if (ret) { BT_LOGE("Cannot append substring to string field's value: " "notit-addr=%p, field-addr=%p, string-length=%zu, " "ret=%d", notit, field, len, ret); - status = BT_BTR_STATUS_ERROR; + status = BT_BFCR_STATUS_ERROR; goto end; } @@ -2245,105 +2010,113 @@ end: } static -enum bt_btr_status btr_string_end_cb( - struct bt_field_type *type, void *data) +enum bt_bfcr_status bfcr_string_end_cb( + struct ctf_field_class *fc, void *data) { struct bt_notif_iter *notit = data; - BT_LOGV("String (end) function called from BTR: " - "notit-addr=%p, btr-addr=%p, ft-addr=%p, " - "ft-id=%s", - notit, notit->btr, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type))); + BT_LOGV("String (end) function called from BFCR: " + "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d", + notit, notit->bfcr, fc, fc->type, fc->in_ir); + BT_ASSERT(fc->in_ir); /* Pop string field */ stack_pop(notit->stack); /* Go to next field */ stack_top(notit->stack)->index++; - return BT_BTR_STATUS_OK; + return BT_BFCR_STATUS_OK; } -enum bt_btr_status btr_compound_begin_cb( - struct bt_field_type *type, void *data) +enum bt_bfcr_status bfcr_compound_begin_cb( + struct ctf_field_class *fc, void *data) { - enum bt_btr_status status = BT_BTR_STATUS_OK; struct bt_notif_iter *notit = data; struct bt_field *field; - int ret; - BT_LOGV("Compound (beginning) function called from BTR: " - "notit-addr=%p, btr-addr=%p, ft-addr=%p, " - "ft-id=%s", - notit, notit->btr, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type))); + BT_LOGV("Compound (beginning) function called from BFCR: " + "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d", + notit, notit->bfcr, fc, fc->type, fc->in_ir); - /* Create field */ - if (stack_empty(notit->stack)) { - /* Root: create dynamic scope field */ - *notit->cur_dscope_field = bt_field_create(type); - field = *notit->cur_dscope_field; + if (!fc->in_ir) { + goto end; + } - /* - * Field will be put at the end of this function - * (stack_push() will take one reference, but this - * reference is lost upon the equivalent stack_pop() - * later), so also get it for our context to own it. - */ - bt_get(*notit->cur_dscope_field); - - if (!field) { - BT_LOGE("Cannot create compound field: " - "notit-addr=%p, ft-addr=%p, ft-id=%s", - notit, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type))); - status = BT_BTR_STATUS_ERROR; - goto end; - } + /* Borrow field */ + if (stack_empty(notit->stack)) { + /* Root: already set by read_dscope_begin_state() */ + field = notit->cur_dscope_field; } else { - field = get_next_field(notit); - if (!field) { - BT_LOGW("Cannot get next field: notit-addr=%p", notit); - status = BT_BTR_STATUS_ERROR; - goto end; - } + field = borrow_next_field(notit); + BT_ASSERT(field); } /* Push field */ BT_ASSERT(field); - ret = stack_push(notit->stack, field); - if (ret) { - BT_LOGE("Cannot push compound field onto the stack: " - "notit-addr=%p, ft-addr=%p, ft-id=%s, ret=%d", - notit, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type)), - ret); - status = BT_BTR_STATUS_ERROR; - goto end; + BT_ASSERT(bt_field_borrow_class(field) == fc->ir_fc); + stack_push(notit->stack, field); + + /* + * Change BFCR "unsigned int" callback if it's a text + * array/sequence. + */ + if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || + fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { + struct ctf_field_class_array_base *array_fc = (void *) fc; + + if (array_fc->is_text) { + int ret; + + BT_ASSERT(bt_field_get_class_type(field) == + BT_FIELD_CLASS_TYPE_STRING); + notit->done_filling_string = false; + ret = bt_field_string_clear(field); + BT_ASSERT(ret == 0); + bt_bfcr_set_unsigned_int_cb(notit->bfcr, + bfcr_unsigned_int_char_cb); + } } end: - BT_PUT(field); - - return status; + return BT_BFCR_STATUS_OK; } -enum bt_btr_status btr_compound_end_cb( - struct bt_field_type *type, void *data) +enum bt_bfcr_status bfcr_compound_end_cb( + struct ctf_field_class *fc, void *data) { struct bt_notif_iter *notit = data; - BT_LOGV("Compound (end) function called from BTR: " - "notit-addr=%p, btr-addr=%p, ft-addr=%p, " - "ft-id=%s", - notit, notit->btr, type, - bt_field_type_id_string( - bt_field_type_get_type_id(type))); + BT_LOGV("Compound (end) function called from BFCR: " + "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d", + notit, notit->bfcr, fc, fc->type, fc->in_ir); + + if (!fc->in_ir) { + goto end; + } + BT_ASSERT(!stack_empty(notit->stack)); + BT_ASSERT(bt_field_borrow_class(stack_top(notit->stack)->base) == + fc->ir_fc); + + /* + * Reset BFCR "unsigned int" callback if it's a text + * array/sequence. + */ + if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || + fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { + struct ctf_field_class_array_base *array_fc = (void *) fc; + + if (array_fc->is_text) { + BT_ASSERT(bt_field_get_class_type( + stack_top(notit->stack)->base) == + BT_FIELD_CLASS_TYPE_STRING); + bt_bfcr_set_unsigned_int_cb(notit->bfcr, + bfcr_unsigned_int_cb); + } + } /* Pop stack */ stack_pop(notit->stack); @@ -2353,536 +2126,146 @@ enum bt_btr_status btr_compound_end_cb( stack_top(notit->stack)->index++; } - return BT_BTR_STATUS_OK; +end: + return BT_BFCR_STATUS_OK; } static -struct bt_field *resolve_field(struct bt_notif_iter *notit, - struct bt_field_path *path) +int64_t bfcr_get_sequence_length_cb(struct ctf_field_class *fc, void *data) { - struct bt_field *field = NULL; - unsigned int i; + struct bt_field *seq_field; + struct bt_notif_iter *notit = data; + struct ctf_field_class_sequence *seq_fc = (void *) fc; + int64_t length = -1; + int ret; + + length = (uint64_t) g_array_index(notit->stored_values, uint64_t, + seq_fc->stored_length_index); + seq_field = stack_top(notit->stack)->base; + BT_ASSERT(seq_field); + ret = bt_field_dynamic_array_set_length(seq_field, (uint64_t) length); + if (ret) { + BT_LOGE("Cannot set dynamic array field's length field: " + "notit-addr=%p, field-addr=%p, " + "length=%" PRIu64, notit, seq_field, length); + } - if (BT_LOG_ON_VERBOSE) { - GString *gstr = bt_field_path_string(path); + return length; +} - BT_LOGV("Resolving field path: notit-addr=%p, field-path=\"%s\"", - notit, gstr ? gstr->str : NULL); +static +struct ctf_field_class *bfcr_borrow_variant_selected_field_class_cb( + struct ctf_field_class *fc, void *data) +{ + int ret; + uint64_t i; + int64_t option_index = -1; + struct bt_notif_iter *notit = data; + struct ctf_field_class_variant *var_fc = (void *) fc; + struct ctf_named_field_class *selected_option = NULL; + struct ctf_field_class *ret_fc = NULL; + union { + uint64_t u; + int64_t i; + } tag; + + /* Get variant's tag */ + tag.u = g_array_index(notit->stored_values, uint64_t, + var_fc->stored_tag_index); - if (gstr) { - g_string_free(gstr, TRUE); + /* + * Check each range to find the selected option's index. + */ + if (var_fc->tag_fc->base.is_signed) { + for (i = 0; i < var_fc->ranges->len; i++) { + struct ctf_field_class_variant_range *range = + ctf_field_class_variant_borrow_range_by_index( + var_fc, i); + + if (tag.i >= range->range.lower.i && + tag.i <= range->range.upper.i) { + option_index = (int64_t) range->option_index; + break; + } + } + } else { + for (i = 0; i < var_fc->ranges->len; i++) { + struct ctf_field_class_variant_range *range = + ctf_field_class_variant_borrow_range_by_index( + var_fc, i); + + if (tag.u >= range->range.lower.u && + tag.u <= range->range.upper.u) { + option_index = (int64_t) range->option_index; + break; + } } } - switch (bt_field_path_get_root_scope(path)) { - case BT_SCOPE_TRACE_PACKET_HEADER: - field = notit->dscopes.trace_packet_header; - break; - case BT_SCOPE_STREAM_PACKET_CONTEXT: - field = notit->dscopes.stream_packet_context; - break; - case BT_SCOPE_STREAM_EVENT_HEADER: - field = notit->dscopes.stream_event_header; - break; - case BT_SCOPE_STREAM_EVENT_CONTEXT: - field = notit->dscopes.stream_event_context; - break; - case BT_SCOPE_EVENT_CONTEXT: - field = notit->dscopes.event_context; - break; - case BT_SCOPE_EVENT_FIELDS: - field = notit->dscopes.event_payload; - break; - default: - BT_LOGF("Cannot resolve field path: unknown scope: " - "notit-addr=%p, root-scope=%s", - notit, bt_scope_string( - bt_field_path_get_root_scope(path))); - abort(); - } - - if (!field) { - BT_LOGW("Cannot resolve field path: root field not found: " - "notit-addr=%p, root-scope=%s", - notit, bt_scope_string( - bt_field_path_get_root_scope(path))); - goto end; - } - - bt_get(field); - - for (i = 0; i < bt_field_path_get_index_count(path); ++i) { - struct bt_field *next_field = NULL; - struct bt_field_type *field_type; - int index = bt_field_path_get_index(path, i); - - field_type = bt_field_get_type(field); - BT_ASSERT(field_type); - - if (is_struct_type(field_type)) { - next_field = bt_field_structure_get_field_by_index( - field, index); - } else if (is_variant_type(field_type)) { - next_field = - bt_field_variant_get_current_field(field); - } - - BT_PUT(field); - BT_PUT(field_type); - - if (!next_field) { - BT_LOGW("Cannot find next field: " - "notit-addr=%p, ft-addr=%p, ft-id=%s, index=%d", - notit, field_type, - bt_field_type_id_string( - bt_field_type_get_type_id(field_type)), - index); - goto end; - } - - /* Move next field -> field */ - BT_MOVE(field, next_field); - } - -end: - return field; -} - -static -int64_t btr_get_sequence_length_cb(struct bt_field_type *type, void *data) -{ - int64_t ret = -1; - int iret; - struct bt_field *seq_field; - struct bt_field_path *field_path; - struct bt_notif_iter *notit = data; - struct bt_field *length_field = NULL; - uint64_t length; - - field_path = bt_field_type_sequence_get_length_field_path(type); - BT_ASSERT(field_path); - length_field = resolve_field(notit, field_path); - if (!length_field) { - BT_LOGW("Cannot resolve sequence field type's length field path: " - "notit-addr=%p, ft-addr=%p", - notit, type); - goto end; - } - - iret = bt_field_unsigned_integer_get_value(length_field, &length); - if (iret) { - BT_LOGE("Cannot get value of sequence length field: " - "notit-addr=%p, field-addr=%p", - notit, length_field); - goto end; - } - - seq_field = stack_top(notit->stack)->base; - iret = bt_field_sequence_set_length(seq_field, length_field); - if (iret) { - BT_LOGE("Cannot set sequence field's length field: " - "notit-addr=%p, seq-field-addr=%p, " - "length-field-addr=%p, ", - notit, seq_field, length_field); - goto end; - } - - ret = (int64_t) length; - -end: - BT_PUT(length_field); - BT_PUT(field_path); - - return ret; -} - -static -struct bt_field_type *btr_get_variant_type_cb( - struct bt_field_type *type, void *data) -{ - struct bt_field_path *path; - struct bt_notif_iter *notit = data; - struct bt_field *var_field; - struct bt_field *tag_field = NULL; - struct bt_field *selected_field = NULL; - struct bt_field_type *selected_field_type = NULL; - - path = bt_field_type_variant_get_tag_field_path(type); - BT_ASSERT(path); - tag_field = resolve_field(notit, path); - if (!tag_field) { - BT_LOGW("Cannot resolve variant field type's tag field path: " - "notit-addr=%p, ft-addr=%p", - notit, type); + if (option_index < 0) { + BT_LOGW("Cannot find variant field class's option: " + "notit-addr=%p, var-fc-addr=%p, u-tag=%" PRIu64 ", " + "i-tag=%" PRId64, notit, var_fc, tag.u, tag.i); goto end; } - /* - * We found the enumeration tag field instance which should be - * able to select a current field for this variant. This - * callback function we're in is called _after_ - * compound_begin(), so the current stack top's base field is - * the variant field in question. We get the selected field here - * thanks to this tag field (thus creating the selected field), - * which will also provide us with its type. Then, this field - * will remain the current selected one until the next callback - * function call which is used to fill the current selected - * field. - */ - var_field = stack_top(notit->stack)->base; - selected_field = bt_field_variant_get_field(var_field, tag_field); - if (!selected_field) { - BT_LOGW("Cannot get variant field's selection using tag field: " - "notit-addr=%p, var-field-addr=%p, tag-field-addr=%p", - notit, var_field, tag_field); - goto end; - } + selected_option = ctf_field_class_variant_borrow_option_by_index( + var_fc, (uint64_t) option_index); - selected_field_type = bt_field_get_type(selected_field); - -end: - BT_PUT(tag_field); - BT_PUT(selected_field); - BT_PUT(path); + if (selected_option->fc->in_ir) { + struct bt_field *var_field = stack_top(notit->stack)->base; - return selected_field_type; -} - -static -int set_event_clocks(struct bt_event *event, - struct bt_notif_iter *notit) -{ - int ret; - GHashTableIter iter; - struct bt_clock_class *clock_class; - uint64_t *clock_state; - - g_hash_table_iter_init(&iter, notit->clock_states); - - while (g_hash_table_iter_next(&iter, (gpointer) &clock_class, - (gpointer) &clock_state)) { - struct bt_clock_value *clock_value; - - clock_value = bt_clock_value_create(clock_class, - *clock_state); - if (!clock_value) { - BT_LOGE("Cannot create clock value from clock class: " - "notit-addr=%p, clock-class-addr=%p, " - "clock-class-name=\"%s\"", - notit, clock_class, - bt_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - ret = bt_event_set_clock_value(event, clock_value); - bt_put(clock_value); + ret = bt_field_variant_select_option_field(var_field, + option_index); if (ret) { - struct bt_event_class *event_class = - bt_event_get_class(event); - - BT_ASSERT(event_class); - BT_LOGE("Cannot set event's clock value: " - "notit-addr=%p, event-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", " - "clock-class-addr=%p, " - "clock-class-name=\"%s\", " - "clock-value-addr=%p", - notit, event, - bt_event_class_get_name(event_class), - bt_event_class_get_id(event_class), - clock_class, - bt_clock_class_get_name(clock_class), - clock_value); - bt_put(event_class); + BT_LOGW("Cannot select variant field's option field: " + "notit-addr=%p, var-field-addr=%p, " + "opt-index=%" PRId64, notit, var_field, + option_index); goto end; } } - ret = 0; -end: - return ret; -} - -static -struct bt_event *create_event(struct bt_notif_iter *notit) -{ - int ret; - struct bt_event *event; - - BT_LOGV("Creating event for event notification: " - "notit-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64, - notit, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class)); - - /* Create event object. */ - event = bt_event_create(notit->meta.event_class); - if (!event) { - BT_LOGE("Cannot create event: " - "notit-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64, - notit, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class)); - goto error; - } - - /* Set header, stream event context, context, and payload fields. */ - ret = bt_event_set_header(event, - notit->dscopes.stream_event_header); - if (ret) { - BT_LOGE("Cannot set event's header field: " - "notit-addr=%p, event-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", field-addr=%p", - notit, event, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class), - notit->dscopes.stream_event_header); - goto error; - } - - ret = bt_event_set_stream_event_context(event, - notit->dscopes.stream_event_context); - if (ret) { - BT_LOGE("Cannot set event's context field: " - "notit-addr=%p, event-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", field-addr=%p", - notit, event, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class), - notit->dscopes.stream_event_context); - goto error; - } - - ret = bt_event_set_event_context(event, - notit->dscopes.event_context); - if (ret) { - BT_LOGE("Cannot set event's stream event context field: " - "notit-addr=%p, event-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", field-addr=%p", - notit, event, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class), - notit->dscopes.event_context); - goto error; - } - - ret = bt_event_set_event_payload(event, - notit->dscopes.event_payload); - if (ret) { - BT_LOGE("Cannot set event's payload field: " - "notit-addr=%p, event-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", field-addr=%p", - notit, event, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class), - notit->dscopes.event_payload); - goto error; - } - - ret = set_event_clocks(event, notit); - if (ret) { - BT_LOGE("Cannot set event's clock values: " - "notit-addr=%p, event-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64, - notit, event, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class)); - goto error; - } - - /* Associate with current packet. */ - BT_ASSERT(notit->packet); - ret = bt_event_set_packet(event, notit->packet); - if (ret) { - BT_LOGE("Cannot set event's header field: " - "notit-addr=%p, event-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", packet-addr=%p", - notit, event, notit->meta.event_class, - bt_event_class_get_name(notit->meta.event_class), - bt_event_class_get_id(notit->meta.event_class), - notit->packet); - goto error; - } - - goto end; - -error: - BT_PUT(event); + ret_fc = selected_option->fc; end: - return event; + return ret_fc; } static -uint64_t get_cur_stream_instance_id(struct bt_notif_iter *notit) +void set_event_default_clock_value(struct bt_notif_iter *notit) { - struct bt_field *stream_instance_id_field = NULL; - uint64_t stream_instance_id = -1ULL; - int ret; + struct bt_event *event = bt_notification_event_borrow_event( + notit->event_notif); + struct bt_stream_class *sc = notit->meta.sc->ir_sc; - if (!notit->dscopes.trace_packet_header) { - goto end; - } - - stream_instance_id_field = bt_field_structure_get_field_by_name( - notit->dscopes.trace_packet_header, "stream_instance_id"); - if (!stream_instance_id_field) { - goto end; - } + BT_ASSERT(event); - ret = bt_field_unsigned_integer_get_value(stream_instance_id_field, - &stream_instance_id); - if (ret) { - stream_instance_id = -1ULL; - goto end; - } + if (bt_stream_class_borrow_default_clock_class(sc)) { + int ret = bt_event_set_default_clock_value(event, + notit->default_clock_val); -end: - bt_put(stream_instance_id_field); - return stream_instance_id; -} - -static -int set_stream(struct bt_notif_iter *notit) -{ - int ret = 0; - struct bt_stream *stream = NULL; - - BT_LOGV("Calling user function (get stream): notit-addr=%p, " - "stream-class-addr=%p, stream-class-name=\"%s\", " - "stream-class-id=%" PRId64, - notit, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class)); - stream = bt_get(notit->medium.medops.get_stream( - notit->meta.stream_class, get_cur_stream_instance_id(notit), - notit->medium.data)); - BT_LOGV("User function returned: stream-addr=%p", stream); - if (!stream) { - BT_LOGW_STR("User function failed to return a stream object for the given stream class."); - ret = -1; - goto end; - } - - if (notit->stream && stream != notit->stream) { - BT_LOGW("User function returned a different stream than the previous one for the same sequence of packets."); - ret = -1; - goto end; - } - - BT_MOVE(notit->stream, stream); - -end: - bt_put(stream); - return ret; -} - -static -void create_packet(struct bt_notif_iter *notit) -{ - int ret; - struct bt_packet *packet = NULL; - - BT_LOGV("Creating packet for packet notification: " - "notit-addr=%p", notit); - BT_LOGV("Creating packet from stream: " - "notit-addr=%p, stream-addr=%p, " - "stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64, - notit, notit->stream, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class)); - - /* Create packet */ - BT_ASSERT(notit->stream); - packet = bt_packet_create(notit->stream); - if (!packet) { - BT_LOGE("Cannot create packet from stream: " - "notit-addr=%p, stream-addr=%p, " - "stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64, - notit, notit->stream, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class)); - goto error; - } - - /* Set packet's context and header fields */ - if (notit->dscopes.trace_packet_header) { - ret = bt_packet_set_header(packet, - notit->dscopes.trace_packet_header); - if (ret) { - BT_LOGE("Cannot set packet's header field: " - "notit-addr=%p, packet-addr=%p, " - "stream-addr=%p, " - "stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", " - "field-addr=%p", - notit, packet, notit->stream, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class), - notit->dscopes.trace_packet_header); - goto error; - } - } - - if (notit->dscopes.stream_packet_context) { - ret = bt_packet_set_context(packet, - notit->dscopes.stream_packet_context); - if (ret) { - BT_LOGE("Cannot set packet's context field: " - "notit-addr=%p, packet-addr=%p, " - "stream-addr=%p, " - "stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", " - "field-addr=%p", - notit, packet, notit->stream, notit->meta.stream_class, - bt_stream_class_get_name(notit->meta.stream_class), - bt_stream_class_get_id(notit->meta.stream_class), - notit->dscopes.trace_packet_header); - goto error; - } + BT_ASSERT(ret == 0); } - - goto end; - -error: - BT_PUT(packet); - -end: - BT_MOVE(notit->packet, packet); } static void notify_new_stream(struct bt_notif_iter *notit, struct bt_notification **notification) { + enum bt_notif_iter_status status; struct bt_notification *ret = NULL; - int iret; - /* Ask the user for the stream */ - iret = set_stream(notit); - if (iret) { + status = set_current_stream(notit); + if (status != BT_NOTIF_ITER_STATUS_OK) { + BT_OBJECT_PUT_REF_AND_RESET(ret); goto end; } BT_ASSERT(notit->stream); - ret = bt_notification_stream_begin_create(notit->stream); + BT_ASSERT(notit->notif_iter); + ret = bt_notification_stream_begin_create(notit->notif_iter, + notit->stream); if (!ret) { BT_LOGE("Cannot create stream beginning notification: " "notit-addr=%p, stream-addr=%p", @@ -2906,7 +2289,9 @@ void notify_end_of_stream(struct bt_notif_iter *notit, return; } - ret = bt_notification_stream_end_create(notit->stream); + BT_ASSERT(notit->notif_iter); + ret = bt_notification_stream_end_create(notit->notif_iter, + notit->stream); if (!ret) { BT_LOGE("Cannot create stream beginning notification: " "notit-addr=%p, stream-addr=%p", @@ -2920,209 +2305,188 @@ static void notify_new_packet(struct bt_notif_iter *notit, struct bt_notification **notification) { - struct bt_notification *ret; + int ret; + enum bt_notif_iter_status status; + struct bt_notification *notif = NULL; + struct bt_stream_class *sc; - /* Initialize the iterator's current packet */ - create_packet(notit); - if (!notit->packet) { - BT_LOGE("Cannot create packet for packet notification: " - "notit-addr=%p", notit); - return; + status = set_current_packet(notit); + if (status != BT_NOTIF_ITER_STATUS_OK) { + goto end; } - ret = bt_notification_packet_begin_create(notit->packet); - if (!ret) { - BT_LOGE("Cannot create packet beginning notification: " - "notit-addr=%p, packet-addr=%p", - notit, notit->packet); - return; + BT_ASSERT(notit->packet); + sc = notit->meta.sc->ir_sc; + BT_ASSERT(sc); + + if (bt_stream_class_packets_have_discarded_event_counter_snapshot(sc)) { + BT_ASSERT(notit->snapshots.discarded_events != UINT64_C(-1)); + ret = bt_packet_set_discarded_event_counter_snapshot( + notit->packet, notit->snapshots.discarded_events); + BT_ASSERT(ret == 0); } - *notification = ret; -} -static -void notify_end_of_packet(struct bt_notif_iter *notit, - struct bt_notification **notification) -{ - struct bt_notification *ret; + if (bt_stream_class_packets_have_packet_counter_snapshot(sc)) { + BT_ASSERT(notit->snapshots.packets != UINT64_C(-1)); + ret = bt_packet_set_packet_counter_snapshot( + notit->packet, notit->snapshots.packets); + BT_ASSERT(ret == 0); + } - if (!notit->packet) { - return; + if (bt_stream_class_packets_have_default_beginning_clock_value(sc)) { + BT_ASSERT(notit->snapshots.beginning_clock != UINT64_C(-1)); + ret = bt_packet_set_default_beginning_clock_value( + notit->packet, notit->snapshots.beginning_clock); + BT_ASSERT(ret == 0); } - ret = bt_notification_packet_end_create(notit->packet); - if (!ret) { - BT_LOGE("Cannot create packet end notification: " - "notit-addr=%p, packet-addr=%p", - notit, notit->packet); - return; + if (bt_stream_class_packets_have_default_end_clock_value(sc)) { + BT_ASSERT(notit->snapshots.end_clock != UINT64_C(-1)); + ret = bt_packet_set_default_end_clock_value( + notit->packet, notit->snapshots.end_clock); + BT_ASSERT(ret == 0); } - BT_PUT(notit->packet); - *notification = ret; -} -static -void notify_event(struct bt_notif_iter *notit, - struct bt_clock_class_priority_map *cc_prio_map, - struct bt_notification **notification) -{ - struct bt_event *event = NULL; - struct bt_notification *ret = NULL; + if (notit->packet_header_field) { + ret = bt_packet_move_header_field(notit->packet, + notit->packet_header_field); + if (ret) { + goto end; + } - /* Make sure that the event contains at least one bit of data */ - if (notit->buf.at == notit->buf.last_eh_at) { - BT_LOGE("Cannot create empty event with 0 bits of data: " - "notit-addr=%p, packet-cur=%zu", - notit, packet_at(notit)); - goto end; + notit->packet_header_field = NULL; + + /* + * At this point notit->dscopes.trace_packet_header has + * the same value as the packet header field within + * notit->packet. + */ + BT_ASSERT(bt_packet_borrow_header_field(notit->packet) == + notit->dscopes.trace_packet_header); } - /* Create event */ - event = create_event(notit); - if (!event) { - BT_LOGE("Cannot create event for event notification: " - "notit-addr=%p", notit); - goto end; + if (notit->packet_context_field) { + ret = bt_packet_move_context_field(notit->packet, + notit->packet_context_field); + if (ret) { + goto end; + } + + notit->packet_context_field = NULL; + + /* + * At this point notit->dscopes.trace_packet_header has + * the same value as the packet header field within + * notit->packet. + */ + BT_ASSERT(bt_packet_borrow_context_field(notit->packet) == + notit->dscopes.stream_packet_context); } - ret = bt_notification_event_create(event, cc_prio_map); - if (!ret) { - BT_LOGE("Cannot create event notification: " - "notit-addr=%p, event-addr=%p, " - "cc-prio-map-addr=%p", - notit, event, cc_prio_map); + BT_ASSERT(notit->notif_iter); + notif = bt_notification_packet_begin_create(notit->notif_iter, + notit->packet); + if (!notif) { + BT_LOGE("Cannot create packet beginning notification: " + "notit-addr=%p, packet-addr=%p", + notit, notit->packet); goto end; } - *notification = ret; + + *notification = notif; + end: - BT_PUT(event); + return; } static -void init_trace_field_path_cache(struct bt_trace *trace, - struct trace_field_path_cache *trace_field_path_cache) +void notify_end_of_packet(struct bt_notif_iter *notit, + struct bt_notification **notification) { - int stream_id = -1; - int stream_instance_id = -1; - int i, count; - struct bt_field_type *packet_header = NULL; + struct bt_notification *notif; - packet_header = bt_trace_get_packet_header_type(trace); - if (!packet_header) { - goto end; + if (!notit->packet) { + return; } - if (!bt_field_type_is_structure(packet_header)) { - goto end; + /* Update default clock from packet's end time */ + if (notit->snapshots.end_clock != UINT64_C(-1)) { + notit->default_clock_val = notit->snapshots.end_clock; } - count = bt_field_type_structure_get_field_count(packet_header); - BT_ASSERT(count >= 0); - - for (i = 0; (i < count && (stream_id == -1 || stream_instance_id == -1)); i++) { - int ret; - const char *field_name; - - ret = bt_field_type_structure_get_field_by_index(packet_header, - &field_name, NULL, i); - if (ret) { - BT_LOGE("Cannot get structure field's field: " - "field-addr=%p, index=%d", - packet_header, i); - goto end; - } + BT_ASSERT(notit->notif_iter); + notif = bt_notification_packet_end_create(notit->notif_iter, + notit->packet); + if (!notif) { + BT_LOGE("Cannot create packet end notification: " + "notit-addr=%p, packet-addr=%p", + notit, notit->packet); + return; - if (stream_id == -1 && !strcmp(field_name, "stream_id")) { - stream_id = i; - } else if (stream_instance_id == -1 && - !strcmp(field_name, "stream_instance_id")) { - stream_instance_id = i; - } } -end: - trace_field_path_cache->stream_id = stream_id; - trace_field_path_cache->stream_instance_id = stream_instance_id; - BT_PUT(packet_header); + BT_OBJECT_PUT_REF_AND_RESET(notit->packet); + *notification = notif; } BT_HIDDEN -struct bt_notif_iter *bt_notif_iter_create(struct bt_trace *trace, +struct bt_notif_iter *bt_notif_iter_create(struct ctf_trace_class *tc, size_t max_request_sz, struct bt_notif_iter_medium_ops medops, void *data) { struct bt_notif_iter *notit = NULL; - struct bt_btr_cbs cbs = { - .types = { - .signed_int = btr_signed_int_cb, - .unsigned_int = btr_unsigned_int_cb, - .floating_point = btr_floating_point_cb, - .string_begin = btr_string_begin_cb, - .string = btr_string_cb, - .string_end = btr_string_end_cb, - .compound_begin = btr_compound_begin_cb, - .compound_end = btr_compound_end_cb, + struct bt_bfcr_cbs cbs = { + .classes = { + .signed_int = bfcr_signed_int_cb, + .unsigned_int = bfcr_unsigned_int_cb, + .floating_point = bfcr_floating_point_cb, + .string_begin = bfcr_string_begin_cb, + .string = bfcr_string_cb, + .string_end = bfcr_string_end_cb, + .compound_begin = bfcr_compound_begin_cb, + .compound_end = bfcr_compound_end_cb, }, .query = { - .get_sequence_length = btr_get_sequence_length_cb, - .get_variant_type = btr_get_variant_type_cb, + .get_sequence_length = bfcr_get_sequence_length_cb, + .borrow_variant_selected_field_class = bfcr_borrow_variant_selected_field_class_cb, }, }; - BT_ASSERT(trace); + BT_ASSERT(tc); BT_ASSERT(medops.request_bytes); - BT_ASSERT(medops.get_stream); + BT_ASSERT(medops.borrow_stream); BT_LOGD("Creating CTF plugin notification iterator: " "trace-addr=%p, trace-name=\"%s\", max-request-size=%zu, " - "data=%p", - trace, bt_trace_get_name(trace), max_request_sz, data); + "data=%p", tc, tc->name->str, max_request_sz, data); notit = g_new0(struct bt_notif_iter, 1); if (!notit) { BT_LOGE_STR("Failed to allocate one CTF plugin notification iterator."); goto end; } - notit->clock_states = g_hash_table_new_full(g_direct_hash, - g_direct_equal, bt_put, g_free); - if (!notit->clock_states) { - BT_LOGE_STR("Failed to allocate a GHashTable."); - goto error; - } - notit->meta.trace = bt_get(trace); + notit->meta.tc = tc; notit->medium.medops = medops; notit->medium.max_request_sz = max_request_sz; notit->medium.data = data; notit->stack = stack_new(notit); + notit->stored_values = g_array_new(FALSE, TRUE, sizeof(uint64_t)); + g_array_set_size(notit->stored_values, tc->stored_value_count); + if (!notit->stack) { BT_LOGE_STR("Failed to create field stack."); goto error; } - notit->btr = bt_btr_create(cbs, notit); - if (!notit->btr) { - BT_LOGE_STR("Failed to create binary type reader (BTR)."); + notit->bfcr = bt_bfcr_create(cbs, notit); + if (!notit->bfcr) { + BT_LOGE_STR("Failed to create binary class reader (BFCR)."); goto error; } bt_notif_iter_reset(notit); - init_trace_field_path_cache(trace, ¬it->trace_field_path_cache); - notit->sc_field_path_caches = g_hash_table_new_full(g_direct_hash, - g_direct_equal, bt_put, g_free); - if (!notit->sc_field_path_caches) { - BT_LOGE_STR("Failed to allocate a GHashTable."); - goto error; - } - - notit->field_overrides = g_hash_table_new_full(g_direct_hash, - g_direct_equal, bt_put, g_free); - if (!notit->field_overrides) { - BT_LOGE_STR("Failed to allocate a GHashTable."); - goto error; - } - BT_LOGD("Created CTF plugin notification iterator: " "trace-addr=%p, trace-name=\"%s\", max-request-size=%zu, " "data=%p, notit-addr=%p", - trace, bt_trace_get_name(trace), max_request_sz, data, + tc, tc->name->str, max_request_sz, data, notit); notit->cur_packet_offset = 0; @@ -3137,13 +2501,9 @@ error: void bt_notif_iter_destroy(struct bt_notif_iter *notit) { - BT_PUT(notit->meta.trace); - BT_PUT(notit->meta.stream_class); - BT_PUT(notit->meta.event_class); - BT_PUT(notit->packet); - BT_PUT(notit->stream); - BT_PUT(notit->cur_timestamp_end); - put_all_dscopes(notit); + BT_OBJECT_PUT_REF_AND_RESET(notit->packet); + BT_OBJECT_PUT_REF_AND_RESET(notit->stream); + release_all_dscopes(notit); BT_LOGD("Destroying CTF plugin notification iterator: addr=%p", notit); @@ -3152,21 +2512,13 @@ void bt_notif_iter_destroy(struct bt_notif_iter *notit) stack_destroy(notit->stack); } - if (notit->btr) { - BT_LOGD("Destroying BTR: btr-addr=%p", notit->btr); - bt_btr_destroy(notit->btr); - } - - if (notit->clock_states) { - g_hash_table_destroy(notit->clock_states); - } - - if (notit->sc_field_path_caches) { - g_hash_table_destroy(notit->sc_field_path_caches); + if (notit->bfcr) { + BT_LOGD("Destroying BFCR: bfcr-addr=%p", notit->bfcr); + bt_bfcr_destroy(notit->bfcr); } - if (notit->field_overrides) { - g_hash_table_destroy(notit->field_overrides); + if (notit->stored_values) { + g_array_free(notit->stored_values, TRUE); } g_free(notit); @@ -3174,7 +2526,7 @@ void bt_notif_iter_destroy(struct bt_notif_iter *notit) enum bt_notif_iter_status bt_notif_iter_get_next_notification( struct bt_notif_iter *notit, - struct bt_clock_class_priority_map *cc_prio_map, + struct bt_private_connection_private_notification_iterator *notif_iter, struct bt_notification **notification) { enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK; @@ -3187,8 +2539,9 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification( goto end; } - BT_LOGV("Getting next notification: notit-addr=%p, cc-prio-map-addr=%p", - notit, cc_prio_map); + notit->notif_iter = notif_iter; + + BT_LOGV("Getting next notification: notit-addr=%p", notit); while (true) { status = handle_state(notit); @@ -3196,6 +2549,7 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification( BT_LOGV_STR("Medium returned BT_NOTIF_ITER_STATUS_AGAIN."); goto end; } + if (status != BT_NOTIF_ITER_STATUS_OK) { if (status == BT_NOTIF_ITER_STATUS_EOF) { enum state next_state = notit->state; @@ -3203,9 +2557,11 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification( BT_LOGV_STR("Medium returned BT_NOTIF_ITER_STATUS_EOF."); if (notit->packet) { - notify_end_of_packet(notit, notification); + notify_end_of_packet(notit, + notification); } else { - notify_end_of_stream(notit, notification); + notify_end_of_stream(notit, + notification); next_state = STATE_DONE; } @@ -3216,12 +2572,12 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification( status = BT_NOTIF_ITER_STATUS_OK; notit->state = next_state; - goto end; } else { BT_LOGW("Cannot handle state: " "notit-addr=%p, state=%s", notit, state_string(notit->state)); } + goto end; } @@ -3229,50 +2585,36 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification( case STATE_EMIT_NOTIF_NEW_STREAM: /* notify_new_stream() logs errors */ notify_new_stream(notit, notification); + if (!*notification) { status = BT_NOTIF_ITER_STATUS_ERROR; } + notit->stream_begin_emitted = true; goto end; case STATE_EMIT_NOTIF_NEW_PACKET: /* notify_new_packet() logs errors */ notify_new_packet(notit, notification); + if (!*notification) { status = BT_NOTIF_ITER_STATUS_ERROR; } + goto end; case STATE_EMIT_NOTIF_EVENT: - /* notify_event() logs errors */ - notify_event(notit, cc_prio_map, notification); - if (!*notification) { - status = BT_NOTIF_ITER_STATUS_ERROR; - } + BT_ASSERT(notit->event_notif); + set_event_default_clock_value(notit); + *notification = notit->event_notif; + notit->event_notif = NULL; goto end; case STATE_EMIT_NOTIF_END_OF_PACKET: - /* Update clock with timestamp_end field. */ - if (notit->cur_timestamp_end) { - enum bt_btr_status btr_status; - struct bt_field_type *field_type = - bt_field_get_type( - notit->cur_timestamp_end); - - BT_ASSERT(field_type); - btr_status = update_clock(notit, - notit->cur_timestamp_end); - BT_PUT(field_type); - if (btr_status != BT_BTR_STATUS_OK) { - BT_LOGW("Cannot update stream's clock value: " - "notit-addr=%p", notit); - status = BT_NOTIF_ITER_STATUS_ERROR; - goto end; - } - } - /* notify_end_of_packet() logs errors */ notify_end_of_packet(notit, notification); + if (!*notification) { status = BT_NOTIF_ITER_STATUS_ERROR; } + goto end; default: /* Non-emitting state: continue */ @@ -3285,7 +2627,7 @@ end: } BT_HIDDEN -enum bt_notif_iter_status bt_notif_iter_get_packet_header_context_fields( +enum bt_notif_iter_status bt_notif_iter_borrow_packet_header_context_fields( struct bt_notif_iter *notit, struct bt_field **packet_header_field, struct bt_field **packet_context_field) @@ -3346,19 +2688,20 @@ enum bt_notif_iter_status bt_notif_iter_get_packet_header_context_fields( } set_fields: + ret = set_current_packet_content_sizes(notit); + if (ret) { + status = BT_NOTIF_ITER_STATUS_ERROR; + goto end; + } + if (packet_header_field) { - *packet_header_field = bt_get(notit->dscopes.trace_packet_header); + *packet_header_field = notit->dscopes.trace_packet_header; } if (packet_context_field) { - *packet_context_field = bt_get(notit->dscopes.stream_packet_context); + *packet_context_field = notit->dscopes.stream_packet_context; } - ret = set_current_packet_content_sizes(notit); - if (ret) { - status = BT_NOTIF_ITER_STATUS_ERROR; - goto end; - } end: return status; } @@ -3392,8 +2735,7 @@ enum bt_notif_iter_status bt_notif_iter_seek( } medium_status = notit->medium.medops.seek( - BT_NOTIF_ITER_SEEK_WHENCE_SET, offset, - notit->medium.data); + BT_NOTIF_ITER_SEEK_WHENCE_SET, offset, notit->medium.data); if (medium_status != BT_NOTIF_ITER_MEDIUM_STATUS_OK) { if (medium_status == BT_NOTIF_ITER_MEDIUM_STATUS_EOF) { ret = BT_NOTIF_ITER_STATUS_EOF; @@ -3405,13 +2747,13 @@ enum bt_notif_iter_status bt_notif_iter_seek( bt_notif_iter_reset(notit); notit->cur_packet_offset = offset; + end: return ret; } BT_HIDDEN -off_t bt_notif_iter_get_current_packet_offset( - struct bt_notif_iter *notit) +off_t bt_notif_iter_get_current_packet_offset(struct bt_notif_iter *notit) { BT_ASSERT(notit); return notit->cur_packet_offset; @@ -3422,5 +2764,36 @@ off_t bt_notif_iter_get_current_packet_size( struct bt_notif_iter *notit) { BT_ASSERT(notit); - return notit->cur_packet_size; + return notit->cur_exp_packet_total_size; +} + +BT_HIDDEN +void bt_notif_trace_class_changed(struct bt_notif_iter *notit) +{ + if (notit->meta.tc->stored_value_count > notit->stored_values->len) { + g_array_set_size(notit->stored_values, + notit->meta.tc->stored_value_count); + } +} + +BT_HIDDEN +enum bt_notif_iter_status bt_notif_iter_get_packet_properties( + struct bt_notif_iter *notit, + struct bt_notif_iter_packet_properties *props) +{ + BT_ASSERT(notit); + BT_ASSERT(props); + + props->exp_packet_total_size = + (uint64_t) notit->cur_exp_packet_total_size; + props->exp_packet_content_size = + (uint64_t) notit->cur_exp_packet_content_size; + BT_ASSERT(props->stream_class_id >= 0); + props->stream_class_id = (uint64_t) notit->cur_stream_class_id; + props->data_stream_id = notit->cur_data_stream_id; + props->snapshots.discarded_events = notit->snapshots.discarded_events; + props->snapshots.packets = notit->snapshots.packets; + props->snapshots.beginning_clock = notit->snapshots.beginning_clock; + props->snapshots.end_clock = notit->snapshots.end_clock; + return BT_NOTIF_ITER_STATUS_OK; }