X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=plugins%2Fctf%2Fcommon%2Fnotif-iter%2Fnotif-iter.c;h=bc20f8814b1de423158fa04961a9134d42f4a599;hb=7cdc2bab17acd56d035b204518ef845fa5a9f1c7;hp=260d15ee21d4dcd76cd2cfcc37089c16ea922ca4;hpb=1556a1afe8d70a3a89155ff25815e203333a93e9;p=babeltrace.git diff --git a/plugins/ctf/common/notif-iter/notif-iter.c b/plugins/ctf/common/notif-iter/notif-iter.c index 260d15ee..bc20f881 100644 --- a/plugins/ctf/common/notif-iter/notif-iter.c +++ b/plugins/ctf/common/notif-iter/notif-iter.c @@ -36,16 +36,18 @@ #include #include #include -#include +#include #include -#include -#include +#include +#include +#include +#include #include #include #define PRINT_ERR_STREAM notit->err_stream #define PRINT_PREFIX "ctf-notif-iter" -#include "print.h" +#include "../print.h" #include "notif-iter.h" #include "../btr/btr.h" @@ -103,6 +105,39 @@ 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_ctf_btr_status (* func)(void *value, + struct bt_ctf_field_type *type, void *data); + void *data; +}; + /* CTF notification iterator */ struct bt_ctf_notif_iter { /* Visit stack */ @@ -130,6 +165,11 @@ struct bt_ctf_notif_iter { /* Current packet (NULL if not created yet) */ struct bt_ctf_packet *packet; + /* + * Current timestamp_end field (to consider before switching packets). + */ + struct bt_ctf_field *cur_timestamp_end; + /* Database of current dynamic scopes (owned by this) */ struct { struct bt_ctf_field *trace_packet_header; @@ -140,6 +180,21 @@ struct bt_ctf_notif_iter { struct bt_ctf_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_ctf_field_type to struct field_cb_override + */ + GHashTable *field_overrides; + /* Current state */ enum state state; @@ -174,13 +229,32 @@ struct bt_ctf_notif_iter { /* Current content size (bits) (-1 if unknown) */ int64_t cur_content_size; - /* bt_ctf_clock to uint64_t. */ + /* bt_ctf_clock_class to uint64_t. */ GHashTable *clock_states; + + /* + * Cache of the trace-constant field paths (event header type) + * associated to the current trace. + */ + struct trace_field_path_cache trace_field_path_cache; + + /* + * Field path cache associated with the current stream class. + * Ownership of this structure belongs to the field_path_caches HT. + */ + struct stream_class_field_path_cache *cur_sc_field_path_cache; + + /* bt_ctf_stream_class to struct stream_class_field_path_cache. */ + GHashTable *sc_field_path_caches; }; static int bt_ctf_notif_iter_switch_packet(struct bt_ctf_notif_iter *notit); +static +enum bt_ctf_btr_status btr_timestamp_end_cb(void *value, + struct bt_ctf_field_type *type, void *data); + static void stack_entry_free_func(gpointer data) { @@ -287,7 +361,7 @@ static inline enum bt_ctf_notif_iter_status notif_iter_status_from_m_status( enum bt_ctf_notif_iter_medium_status m_status) { - return m_status; + return (int) m_status; } static inline @@ -308,38 +382,12 @@ size_t packet_at(struct bt_ctf_notif_iter *notit) return notit->buf.packet_offset + notit->buf.at; } -static inline -size_t remaining_content_bits(struct bt_ctf_notif_iter *notit) -{ - if (notit->cur_content_size == -1) { - return -1; - } - - return notit->cur_content_size - packet_at(notit); -} - -static inline -size_t remaining_packet_bits(struct bt_ctf_notif_iter *notit) -{ - if (notit->cur_packet_size == -1) { - return -1; - } - - return notit->cur_packet_size - packet_at(notit); -} - static inline void buf_consume_bits(struct bt_ctf_notif_iter *notit, size_t incr) { notit->buf.at += incr; } -static inline -bool buf_has_enough_bits(struct bt_ctf_notif_iter *notit, size_t sz) -{ - return buf_available_bits(notit) >= sz; -} - static enum bt_ctf_notif_iter_status request_medium_bytes( struct bt_ctf_notif_iter *notit) @@ -499,8 +547,7 @@ enum bt_ctf_notif_iter_status read_packet_header_begin_state( packet_header_type = bt_ctf_trace_get_packet_header_type( notit->meta.trace); if (!packet_header_type) { - PERR("Failed to retrieve trace's packet header type\n"); - ret = BT_CTF_NOTIF_ITER_STATUS_ERROR; + notit->state = STATE_AFTER_TRACE_PACKET_HEADER; goto end; } @@ -525,24 +572,167 @@ static inline bool is_struct_type(struct bt_ctf_field_type *field_type) { return bt_ctf_field_type_get_type_id(field_type) == - BT_CTF_TYPE_ID_STRUCT; + BT_CTF_FIELD_TYPE_ID_STRUCT; } static inline bool is_variant_type(struct bt_ctf_field_type *field_type) { return bt_ctf_field_type_get_type_id(field_type) == - BT_CTF_TYPE_ID_VARIANT; + BT_CTF_FIELD_TYPE_ID_VARIANT; +} + +static +struct stream_class_field_path_cache * +create_stream_class_field_path_cache_entry( + struct bt_ctf_notif_iter *notit, + struct bt_ctf_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_ctf_field_type *event_header = NULL, *packet_context = NULL; + + if (!cache_entry) { + goto end; + } + + event_header = bt_ctf_stream_class_get_event_header_type(stream_class); + if (event_header && bt_ctf_field_type_is_structure(event_header)) { + int i, count; + + count = bt_ctf_field_type_structure_get_field_count( + event_header); + if (count < 0) { + goto error; + } + for (i = 0; i < count; i++) { + int ret; + const char *name; + + ret = bt_ctf_field_type_structure_get_field( + event_header, &name, NULL, i); + if (ret) { + goto error; + } + + if (v != -1 && id != -1) { + break; + } + if (v == -1 && !strcmp(name, "v")) { + v = i; + } else if (id == -1 && !strcmp(name, "id")) { + id = i; + } + } + } + + packet_context = bt_ctf_stream_class_get_packet_context_type( + stream_class); + if (packet_context && bt_ctf_field_type_is_structure(packet_context)) { + int i, count; + + count = bt_ctf_field_type_structure_get_field_count( + packet_context); + if (count < 0) { + goto error; + } + for (i = 0; i < count; i++) { + int ret; + const char *name; + struct bt_ctf_field_type *field_type; + + if (timestamp_end != -1 && packet_size != -1 && + content_size != -1) { + break; + } + + ret = bt_ctf_field_type_structure_get_field( + packet_context, &name, &field_type, i); + if (ret) { + goto error; + } + + if (timestamp_end == -1 && + !strcmp(name, "timestamp_end")) { + 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_ctf_notif_iter *notit, + struct bt_ctf_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; } static inline -enum bt_ctf_notif_iter_status set_current_stream_class(struct bt_ctf_notif_iter *notit) +enum bt_ctf_notif_iter_status set_current_stream_class( + struct bt_ctf_notif_iter *notit) { enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK; - struct bt_ctf_field_type *packet_header_type; + struct bt_ctf_field_type *packet_header_type = NULL; struct bt_ctf_field_type *stream_id_field_type = 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_ctf_trace_get_packet_header_type( notit->meta.trace); @@ -560,8 +750,8 @@ enum bt_ctf_notif_iter_status set_current_stream_class(struct bt_ctf_notif_iter packet_header_type, "stream_id"); if (stream_id_field_type) { /* Find appropriate stream class using current stream ID */ - struct bt_ctf_field *stream_id_field = NULL; int ret; + struct bt_ctf_field *stream_id_field = NULL; assert(notit->dscopes.trace_packet_header); @@ -590,6 +780,17 @@ enum bt_ctf_notif_iter_status set_current_stream_class(struct bt_ctf_notif_iter goto end; } + /* + * 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) { + PERR("Failed to retrieve stream class field path cache\n"); + status = BT_CTF_NOTIF_ITER_STATUS_ERROR; + goto end; + } end: BT_PUT(packet_header_type); BT_PUT(stream_id_field_type); @@ -622,8 +823,7 @@ enum bt_ctf_notif_iter_status read_packet_context_begin_state( packet_context_type = bt_ctf_stream_class_get_packet_context_type( notit->meta.stream_class); if (!packet_context_type) { - PERR("Failed to retrieve stream class's packet context\n"); - status = BT_CTF_NOTIF_ITER_STATUS_ERROR; + notit->state = STATE_AFTER_STREAM_PACKET_CONTEXT; goto end; } @@ -734,8 +934,7 @@ enum bt_ctf_notif_iter_status read_event_header_begin_state( event_header_type = bt_ctf_stream_class_get_event_header_type( notit->meta.stream_class); if (!event_header_type) { - PERR("Failed to retrieve stream class's event header type\n"); - status = BT_CTF_NOTIF_ITER_STATUS_ERROR; + notit->state = STATE_AFTER_STREAM_EVENT_HEADER; goto end; } @@ -913,8 +1112,7 @@ enum bt_ctf_notif_iter_status read_stream_event_context_begin_state( stream_event_context_type = bt_ctf_stream_class_get_event_context_type( notit->meta.stream_class); if (!stream_event_context_type) { - PERR("Failed to retrieve stream class's event context type\n"); - status = BT_CTF_NOTIF_ITER_STATUS_ERROR; + notit->state = STATE_DSCOPE_EVENT_CONTEXT_BEGIN; goto end; } @@ -947,11 +1145,9 @@ enum bt_ctf_notif_iter_status read_event_context_begin_state( event_context_type = bt_ctf_event_class_get_context_type( notit->meta.event_class); if (!event_context_type) { - PERR("Failed to retrieve event class's context type\n"); - status = BT_CTF_NOTIF_ITER_STATUS_ERROR; + notit->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN; goto end; } - status = read_dscope_begin_state(notit, event_context_type, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN, STATE_DSCOPE_EVENT_CONTEXT_CONTINUE, @@ -981,8 +1177,7 @@ enum bt_ctf_notif_iter_status read_event_payload_begin_state( event_payload_type = bt_ctf_event_class_get_payload_type( notit->meta.event_class); if (!event_payload_type) { - PERR("Failed to retrieve event class's payload type\n"); - status = BT_CTF_NOTIF_ITER_STATUS_ERROR; + notit->state = STATE_EMIT_NOTIF_EVENT; goto end; } @@ -1110,17 +1305,8 @@ enum bt_ctf_notif_iter_status handle_state(struct bt_ctf_notif_iter *notit) return status; } - /** * Resets the internal state of a CTF notification iterator. - * - * This function can be used when it is desired to seek to the beginning - * of another packet. It is expected that the next call to - * bt_ctf_notif_iter_medium_ops::request_bytes() made by this - * notification iterator will return the \em first bytes of a \em - * packet. - * - * @param notif_iter CTF notification iterator */ static void bt_ctf_notif_iter_reset(struct bt_ctf_notif_iter *notit) @@ -1150,6 +1336,7 @@ int bt_ctf_notif_iter_switch_packet(struct bt_ctf_notif_iter *notit) BT_PUT(notit->meta.stream_class); BT_PUT(notit->meta.event_class); BT_PUT(notit->packet); + BT_PUT(notit->cur_timestamp_end); put_all_dscopes(notit); /* @@ -1173,6 +1360,7 @@ int bt_ctf_notif_iter_switch_packet(struct bt_ctf_notif_iter *notit) notit->cur_content_size = -1; notit->cur_packet_size = -1; + notit->cur_sc_field_path_cache = NULL; end: return ret; } @@ -1195,17 +1383,17 @@ struct bt_ctf_field *get_next_field(struct bt_ctf_notif_iter *notit) } switch (bt_ctf_field_type_get_type_id(base_type)) { - case BT_CTF_TYPE_ID_STRUCT: + case BT_CTF_FIELD_TYPE_ID_STRUCT: next_field = bt_ctf_field_structure_get_field_by_index( base_field, index); break; - case BT_CTF_TYPE_ID_ARRAY: + case BT_CTF_FIELD_TYPE_ID_ARRAY: next_field = bt_ctf_field_array_get_field(base_field, index); break; - case BT_CTF_TYPE_ID_SEQUENCE: + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: next_field = bt_ctf_field_sequence_get_field(base_field, index); break; - case BT_CTF_TYPE_ID_VARIANT: + case BT_CTF_FIELD_TYPE_ID_VARIANT: next_field = bt_ctf_field_variant_get_current_field(base_field); break; default: @@ -1213,10 +1401,6 @@ struct bt_ctf_field *get_next_field(struct bt_ctf_notif_iter *notit) break; } - if (!next_field) { - next_field = NULL; - } - end: BT_PUT(base_type); @@ -1278,26 +1462,33 @@ end: static enum bt_ctf_btr_status update_clock(struct bt_ctf_notif_iter *notit, - struct bt_ctf_field_type *int_field_type, struct bt_ctf_field *int_field) { - gboolean clock_found; + gboolean clock_class_found; uint64_t *clock_state; + struct bt_ctf_field_type *int_field_type = NULL; enum bt_ctf_btr_status ret = BT_CTF_BTR_STATUS_OK; - struct bt_ctf_clock *clock = bt_ctf_field_type_integer_get_mapped_clock( - int_field_type); + struct bt_ctf_clock_class *clock_class = NULL; - if (likely(!clock)) { - goto end_no_clock; + int_field_type = bt_ctf_field_get_type(int_field); + if (unlikely(!int_field_type)) { + goto end; + } + + clock_class = bt_ctf_field_type_integer_get_mapped_clock_class( + int_field_type); + if (likely(!clock_class)) { + goto end; } - clock_found = g_hash_table_lookup_extended(notit->clock_states, - clock, NULL, (gpointer) &clock_state); - if (unlikely(!clock_found)) { - const char *clock_name = bt_ctf_clock_get_name(clock); + clock_class_found = g_hash_table_lookup_extended(notit->clock_states, + clock_class, NULL, (gpointer) &clock_state); + if (unlikely(!clock_class_found)) { + const char *clock_class_name = + bt_ctf_clock_class_get_name(clock_class); - PERR("Unknown clock %s mapped to integer encountered in stream\n", - clock_name ? : "NULL"); + PERR("Unknown clock class %s mapped to integer encountered in stream\n", + clock_class_name ? : "NULL"); ret = BT_CTF_BTR_STATUS_ERROR; goto end; } @@ -1308,21 +1499,22 @@ enum bt_ctf_btr_status update_clock(struct bt_ctf_notif_iter *notit, ret = BT_CTF_BTR_STATUS_ENOMEM; goto end; } - g_hash_table_insert(notit->clock_states, bt_get(clock), + g_hash_table_insert(notit->clock_states, bt_get(clock_class), clock_state); } /* Update the clock's state. */ update_clock_state(clock_state, int_field); end: - bt_put(clock); -end_no_clock: + bt_put(int_field_type); + bt_put(clock_class); return ret; } static -enum bt_ctf_btr_status btr_signed_int_cb(int64_t value, - struct bt_ctf_field_type *type, void *data) +enum bt_ctf_btr_status btr_unsigned_int_common(uint64_t value, + struct bt_ctf_field_type *type, void *data, + struct bt_ctf_field **out_int_field) { enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK; struct bt_ctf_field *field = NULL; @@ -1330,21 +1522,21 @@ enum bt_ctf_btr_status btr_signed_int_cb(int64_t value, struct bt_ctf_notif_iter *notit = data; int ret; - /* create next field */ + /* Create next field */ field = get_next_field(notit); if (!field) { - PERR("Failed to get next field (signed int)\n"); + PERR("Failed to get next field (unsigned int)\n"); status = BT_CTF_BTR_STATUS_ERROR; goto end_no_put; } switch(bt_ctf_field_type_get_type_id(type)) { - case BT_CTF_TYPE_ID_INTEGER: + case BT_CTF_FIELD_TYPE_ID_INTEGER: /* Integer field is created field */ BT_MOVE(int_field, field); bt_get(type); break; - case BT_CTF_TYPE_ID_ENUM: + case BT_CTF_FIELD_TYPE_ID_ENUM: int_field = bt_ctf_field_enumeration_get_container(field); type = bt_ctf_field_get_type(int_field); break; @@ -1360,21 +1552,64 @@ enum bt_ctf_btr_status btr_signed_int_cb(int64_t value, goto end; } - ret = bt_ctf_field_signed_integer_set_value(int_field, value); + ret = bt_ctf_field_unsigned_integer_set_value(int_field, value); assert(!ret); stack_top(notit->stack)->index++; - status = update_clock(notit, type, int_field); + *out_int_field = int_field; + end: BT_PUT(field); - BT_PUT(int_field); BT_PUT(type); end_no_put: return status; } +static +enum bt_ctf_btr_status btr_timestamp_end_cb(void *value, + struct bt_ctf_field_type *type, void *data) +{ + enum bt_ctf_btr_status status; + struct bt_ctf_field *field = NULL; + struct bt_ctf_notif_iter *notit = data; + + 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; +} + static enum bt_ctf_btr_status btr_unsigned_int_cb(uint64_t value, struct bt_ctf_field_type *type, void *data) +{ + struct bt_ctf_notif_iter *notit = data; + enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK; + struct bt_ctf_field *field = NULL; + struct field_cb_override *override; + + override = g_hash_table_lookup(notit->field_overrides, + type); + if (unlikely(override)) { + status = override->func(&value, type, override->data); + goto end; + } + + status = btr_unsigned_int_common(value, type, data, &field); + if (status != BT_CTF_BTR_STATUS_OK) { + goto end; + } + + status = update_clock(notit, field); + BT_PUT(field); +end: + return status; +} + +static +enum bt_ctf_btr_status btr_signed_int_cb(int64_t value, + struct bt_ctf_field_type *type, void *data) { enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK; struct bt_ctf_field *field = NULL; @@ -1382,21 +1617,21 @@ enum bt_ctf_btr_status btr_unsigned_int_cb(uint64_t value, struct bt_ctf_notif_iter *notit = data; int ret; - /* Create next field */ + /* create next field */ field = get_next_field(notit); if (!field) { - PERR("Failed to get next field (unsigned int)\n"); + PERR("Failed to get next field (signed int)\n"); status = BT_CTF_BTR_STATUS_ERROR; goto end_no_put; } switch(bt_ctf_field_type_get_type_id(type)) { - case BT_CTF_TYPE_ID_INTEGER: + case BT_CTF_FIELD_TYPE_ID_INTEGER: /* Integer field is created field */ BT_MOVE(int_field, field); bt_get(type); break; - case BT_CTF_TYPE_ID_ENUM: + case BT_CTF_FIELD_TYPE_ID_ENUM: int_field = bt_ctf_field_enumeration_get_container(field); type = bt_ctf_field_get_type(int_field); break; @@ -1412,10 +1647,10 @@ enum bt_ctf_btr_status btr_unsigned_int_cb(uint64_t value, goto end; } - ret = bt_ctf_field_unsigned_integer_set_value(int_field, value); + ret = bt_ctf_field_signed_integer_set_value(int_field, value); assert(!ret); stack_top(notit->stack)->index++; - status = update_clock(notit, type, int_field); + status = update_clock(notit, int_field); end: BT_PUT(field); BT_PUT(int_field); @@ -1764,21 +1999,22 @@ int set_event_clocks(struct bt_ctf_event *event, { int ret; GHashTableIter iter; - struct bt_ctf_clock *clock; + struct bt_ctf_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, + while (g_hash_table_iter_next(&iter, (gpointer) &clock_class, (gpointer) &clock_state)) { struct bt_ctf_clock_value *clock_value; - clock_value = bt_ctf_clock_value_create(clock, *clock_state); + clock_value = bt_ctf_clock_value_create(clock_class, + *clock_state); if (!clock_value) { ret = -1; goto end; } - ret = bt_ctf_event_set_clock_value(event, clock, clock_value); + ret = bt_ctf_event_set_clock_value(event, clock_value); bt_put(clock_value); if (ret) { goto end; @@ -1820,7 +2056,7 @@ struct bt_ctf_event *create_event(struct bt_ctf_notif_iter *notit) goto error; } - ret = bt_ctf_event_set_payload_field(event, + ret = bt_ctf_event_set_event_payload(event, notit->dscopes.event_payload); if (ret) { goto error; @@ -1901,7 +2137,7 @@ void notify_new_packet(struct bt_ctf_notif_iter *notit, return; } - ret = bt_notification_packet_start_create(notit->packet); + ret = bt_notification_packet_begin_create(notit->packet); if (!ret) { return; } @@ -1928,6 +2164,7 @@ void notify_end_of_packet(struct bt_ctf_notif_iter *notit, static void notify_event(struct bt_ctf_notif_iter *notit, + struct bt_clock_class_priority_map *cc_prio_map, struct bt_notification **notification) { struct bt_ctf_event *event; @@ -1939,7 +2176,7 @@ void notify_event(struct bt_ctf_notif_iter *notit, goto end; } - ret = bt_notification_event_create(event); + ret = bt_notification_event_create(event, cc_prio_map); if (!ret) { goto end; } @@ -1949,52 +2186,76 @@ end: } static -void notify_eos(struct bt_ctf_notif_iter *notit, - struct bt_notification **notification) +int init_clock_states(GHashTable *clock_states, struct bt_ctf_trace *trace) { - struct bt_ctf_event *event; - struct bt_notification *ret = NULL; + int clock_class_count, i, ret = 0; - /* Create event */ - event = create_event(notit); - if (!event) { + clock_class_count = bt_ctf_trace_get_clock_class_count(trace); + if (clock_class_count <= 0) { + ret = -1; goto end; } - ret = bt_notification_stream_end_create(event); - if (!ret) { - goto end; + for (i = 0; i < clock_class_count; i++) { + struct bt_ctf_clock_class *clock_class; + + clock_class = bt_ctf_trace_get_clock_class_by_index(trace, i); + if (!clock_class) { + ret = -1; + goto end; + } + + g_hash_table_insert(clock_states, bt_get(clock_class), NULL); + bt_put(clock_class); } - *notification = ret; end: - BT_PUT(event); + return ret; } static -int init_clock_states(GHashTable *clock_states, struct bt_ctf_trace *trace) +void init_trace_field_path_cache(struct bt_ctf_trace *trace, + struct trace_field_path_cache *trace_field_path_cache) { - int clock_count, i, ret = 0; + int stream_id = -1; + int stream_instance_id = -1; + int i, count; + struct bt_ctf_field_type *packet_header = NULL; - clock_count = bt_ctf_trace_get_clock_count(trace); - if (clock_count <= 0) { - ret = -1; + packet_header = bt_ctf_trace_get_packet_header_type(trace); + if (!packet_header) { goto end; } - for (i = 0; i < clock_count; i++) { - struct bt_ctf_clock *clock; + if (!bt_ctf_field_type_is_structure(packet_header)) { + goto end; + } - clock = bt_ctf_trace_get_clock(trace, i); - if (!clock) { - ret = -1; + count = bt_ctf_field_type_structure_get_field_count(packet_header); + if (count < 0) { + goto end; + } + + for (i = 0; (i < count && (stream_id == -1 || stream_instance_id == -1)); i++) { + int ret; + const char *field_name; + + ret = bt_ctf_field_type_structure_get_field(packet_header, + &field_name, NULL, i); + if (ret) { goto end; } - g_hash_table_insert(clock_states, bt_get(clock), NULL); - bt_put(clock); + 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: - return ret; + trace_field_path_cache->stream_id = stream_id; + trace_field_path_cache->stream_instance_id = stream_instance_id; + BT_PUT(packet_header); } BT_HIDDEN @@ -2024,6 +2285,7 @@ struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace, assert(trace); assert(medops.request_bytes); + assert(medops.get_stream); notit = g_new0(struct bt_ctf_notif_iter, 1); if (!notit) { PERR("Failed to allocate memory for CTF notification iterator\n"); @@ -2059,6 +2321,20 @@ struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace, bt_ctf_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) { + PERR("Failed to create stream class field path caches\n"); + goto error; + } + + notit->field_overrides = g_hash_table_new_full(g_direct_hash, + g_direct_equal, bt_put, g_free); + if (!notit->field_overrides) { + goto error; + } + end: return notit; error: @@ -2073,6 +2349,7 @@ void bt_ctf_notif_iter_destroy(struct bt_ctf_notif_iter *notit) BT_PUT(notit->meta.stream_class); BT_PUT(notit->meta.event_class); BT_PUT(notit->packet); + BT_PUT(notit->cur_timestamp_end); put_all_dscopes(notit); if (notit->stack) { @@ -2086,11 +2363,20 @@ void bt_ctf_notif_iter_destroy(struct bt_ctf_notif_iter *notit) 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->field_overrides) { + g_hash_table_destroy(notit->field_overrides); + } g_free(notit); } enum bt_ctf_notif_iter_status bt_ctf_notif_iter_get_next_notification( struct bt_ctf_notif_iter *notit, + struct bt_clock_class_priority_map *cc_prio_map, struct bt_notification **notification) { enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK; @@ -2100,6 +2386,10 @@ enum bt_ctf_notif_iter_status bt_ctf_notif_iter_get_next_notification( while (true) { status = handle_state(notit); + if (status == BT_CTF_NOTIF_ITER_STATUS_AGAIN) { + PDBG("Medium operation reported \"try again later\""); + goto end; + } if (status != BT_CTF_NOTIF_ITER_STATUS_OK) { if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) { PDBG("Medium operation reported end of stream\n"); @@ -2120,12 +2410,28 @@ enum bt_ctf_notif_iter_status bt_ctf_notif_iter_get_next_notification( goto end; case STATE_EMIT_NOTIF_EVENT: PDBG("Emitting event notification\n"); - notify_event(notit, notification); + notify_event(notit, cc_prio_map, notification); if (!*notification) { status = BT_CTF_NOTIF_ITER_STATUS_ERROR; } goto end; case STATE_EMIT_NOTIF_END_OF_PACKET: + /* Update clock with timestamp_end field. */ + if (notit->cur_timestamp_end) { + enum bt_ctf_btr_status btr_status; + struct bt_ctf_field_type *field_type = + bt_ctf_field_get_type( + notit->cur_timestamp_end); + + btr_status = update_clock(notit, + notit->cur_timestamp_end); + BT_PUT(field_type); + if (btr_status != BT_CTF_BTR_STATUS_OK) { + status = BT_CTF_NOTIF_ITER_STATUS_ERROR; + goto end; + } + } + PDBG("Emitting end of packet notification\n"); notify_end_of_packet(notit, notification); if (!*notification) {