X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=plugins%2Fctf%2Fcommon%2Fnotif-iter%2Fnotif-iter.c;h=33ac24953ea56d89b0cd7f45c0e3f96677dd5b41;hb=1974687e6b7a08d8383a4a5c75265d0ed3b8c5c9;hp=0409ac01a90fbaa44214aa246dcccff96dfe3b63;hpb=55314f2a6c08045f6f7ca7700a4932628eff1b87;p=babeltrace.git diff --git a/plugins/ctf/common/notif-iter/notif-iter.c b/plugins/ctf/common/notif-iter/notif-iter.c index 0409ac01..33ac2495 100644 --- a/plugins/ctf/common/notif-iter/notif-iter.c +++ b/plugins/ctf/common/notif-iter/notif-iter.c @@ -162,6 +162,9 @@ struct bt_ctf_notif_iter { /* Current packet (NULL if not created yet) */ struct bt_ctf_packet *packet; + /* Current stream (NULL if not set yet) */ + struct bt_ctf_stream *stream; + /* * Current timestamp_end field (to consider before switching packets). */ @@ -208,6 +211,9 @@ struct bt_ctf_notif_iter { /* Current position from addr (bits) */ size_t at; + + /* Position of the last event header from addr (bits) */ + size_t last_eh_at; } buf; /* Binary type reader */ @@ -474,6 +480,7 @@ enum bt_ctf_notif_iter_status request_medium_bytes( /* Restart at the beginning of the new medium buffer */ notit->buf.at = 0; + notit->buf.last_eh_at = -1ULL; /* New medium buffer size */ notit->buf.sz = buffer_sz; @@ -487,6 +494,101 @@ enum bt_ctf_notif_iter_status request_medium_bytes( notit->buf.sz, notit->buf.addr); BT_LOGV_MEM(buffer_addr, buffer_sz, "Returned bytes at %p:", buffer_addr); + } else if (m_status == BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF) { + struct bt_ctf_field_type *eh_ft = NULL; + struct bt_ctf_field_type *sec_ft = NULL; + struct bt_ctf_field_type *ec_ft = NULL; + + /* + * User returned end of stream: validate that we're not + * in the middle of a packet header, packet context, or + * event. + */ + if (notit->state == STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN) { + /* Beginning of packet: always valid */ + goto good_state; + } + + if (!notit->meta.stream_class) { + goto bad_state; + } + + eh_ft = bt_ctf_stream_class_get_event_header_type( + notit->meta.stream_class); + sec_ft = bt_ctf_stream_class_get_event_context_type( + notit->meta.stream_class); + + if (notit->state == STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN) { + /* + * Beginning of event's header is only valid if + * the packet is not supposed to have a specific + * size (whole packet sequence has in fact only + * one packet). + */ + if (notit->cur_packet_size == -1) { + goto good_state; + } + } + + if (notit->state == STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN) { + /* + * Beginning of event's stream event context is + * only valid if the packet is not supposed to + * have a specific size (whole packet sequence + * has in fact only one packet), and there's no + * event header. + */ + if (notit->cur_packet_size == -1 && !eh_ft) { + goto good_state; + } + } + + if (!notit->meta.event_class) { + goto bad_state; + } + + ec_ft = bt_ctf_event_class_get_context_type( + notit->meta.event_class); + + if (notit->state == STATE_DSCOPE_EVENT_CONTEXT_BEGIN) { + /* + * Beginning of event's context is only valid if + * the packet is not supposed to have a specific + * size (whole packet sequence has in fact only + * one packet), and there's no event header and + * no stream event context. + */ + if (notit->cur_packet_size == -1 && !eh_ft && !sec_ft) { + goto good_state; + } + } + + if (notit->state == STATE_DSCOPE_EVENT_PAYLOAD_BEGIN) { + /* + * Beginning of event's context is only valid if + * the packet is not supposed to have a specific + * size (whole packet sequence has in fact only + * one packet), and there's no event header, no + * stream event context, and no event context. + */ + if (notit->cur_packet_size == -1 && !eh_ft && !sec_ft && + !ec_ft) { + goto good_state; + } + } + +bad_state: + /* All other states are invalid */ + BT_LOGW("User function returned %s, but notification iterator is in an unexpected state: " + "state=%s", + bt_ctf_notif_iter_medium_status_string(m_status), + state_string(notit->state)); + m_status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR; + +good_state: + bt_put(eh_ft); + bt_put(sec_ft); + bt_put(ec_ft); } else if (m_status < 0) { BT_LOGW("User function failed: status=%s", bt_ctf_notif_iter_medium_status_string(m_status)); @@ -874,6 +976,7 @@ enum bt_ctf_notif_iter_status set_current_stream_class( enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK; struct bt_ctf_field_type *packet_header_type = NULL; struct bt_ctf_field_type *stream_id_field_type = NULL; + struct bt_ctf_stream_class *new_stream_class = NULL; uint64_t stream_id; /* Clear the current stream class field path cache. */ @@ -925,10 +1028,9 @@ single_stream_class: notit, stream_id, notit->meta.trace, bt_ctf_trace_get_name(notit->meta.trace)); - BT_PUT(notit->meta.stream_class); - notit->meta.stream_class = bt_ctf_trace_get_stream_class_by_id( + new_stream_class = bt_ctf_trace_get_stream_class_by_id( notit->meta.trace, stream_id); - if (!notit->meta.stream_class) { + 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\"", @@ -938,6 +1040,31 @@ single_stream_class: goto end; } + if (notit->meta.stream_class) { + if (new_stream_class != notit->meta.stream_class) { + 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_ctf_stream_class_get_name(notit->meta.stream_class), + bt_ctf_stream_class_get_id(notit->meta.stream_class), + new_stream_class, + bt_ctf_stream_class_get_name(new_stream_class), + bt_ctf_stream_class_get_id(new_stream_class), + notit->meta.trace, + bt_ctf_trace_get_name(notit->meta.trace)); + status = BT_CTF_NOTIF_ITER_STATUS_ERROR; + goto end; + } + } else { + BT_MOVE(notit->meta.stream_class, new_stream_class); + } + BT_LOGV("Set current stream class: " "notit-addr=%p, stream-class-addr=%p, " "stream-class-name=\"%s\", stream-class-id=%" PRId64, @@ -964,7 +1091,7 @@ single_stream_class: end: BT_PUT(packet_header_type); BT_PUT(stream_id_field_type); - + bt_put(new_stream_class); return status; } @@ -1048,7 +1175,9 @@ enum bt_ctf_notif_iter_status set_current_packet_content_sizes( struct bt_ctf_field *content_size_field = NULL; uint64_t content_size = -1, packet_size = -1; - assert(notit->dscopes.stream_packet_context); + if (!notit->dscopes.stream_packet_context) { + goto end; + } packet_size_field = bt_ctf_field_structure_get_field( notit->dscopes.stream_packet_context, "packet_size"); @@ -1127,6 +1256,9 @@ enum bt_ctf_notif_iter_status read_event_header_begin_state( enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK; struct bt_ctf_field_type *event_header_type = NULL; + /* Reset the position of the last event header */ + notit->buf.last_eh_at = notit->buf.at; + /* Check if we have some content left */ if (notit->cur_content_size >= 0) { if (packet_at(notit) == notit->cur_content_size) { @@ -1138,7 +1270,7 @@ enum bt_ctf_notif_iter_status read_event_header_begin_state( } else if (packet_at(notit) > notit->cur_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=%zu, " + "notit-addr=%p, content-size=%" PRId64 ", " "cur=%zu", notit, notit->cur_content_size, packet_at(notit)); status = BT_CTF_NOTIF_ITER_STATUS_ERROR; @@ -1652,10 +1784,12 @@ void bt_ctf_notif_iter_reset(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->stream); put_all_dscopes(notit); notit->buf.addr = NULL; notit->buf.sz = 0; notit->buf.at = 0; + notit->buf.last_eh_at = -1ULL; notit->buf.packet_offset = 0; notit->state = STATE_INIT; notit->cur_content_size = -1; @@ -1667,11 +1801,15 @@ int bt_ctf_notif_iter_switch_packet(struct bt_ctf_notif_iter *notit) { int ret = 0; + /* + * We don't put the stream class here because we need to make + * sure that all the packets processed by the same notification + * iterator refer to the same stream class (the first one). + */ assert(notit); BT_LOGV("Switching packet: notit-addr=%p, cur=%zu", notit, notit->buf.at); stack_clear(notit->stack); - BT_PUT(notit->meta.stream_class); BT_PUT(notit->meta.event_class); BT_PUT(notit->packet); BT_PUT(notit->cur_timestamp_end); @@ -1809,7 +1947,7 @@ enum bt_ctf_btr_status update_clock(struct bt_ctf_notif_iter *notit, struct bt_ctf_field *int_field) { gboolean clock_class_found; - uint64_t *clock_state; + uint64_t *clock_state = NULL; struct bt_ctf_field_type *int_field_type = NULL; enum bt_ctf_btr_status ret = BT_CTF_BTR_STATUS_OK; struct bt_ctf_clock_class *clock_class = NULL; @@ -1824,12 +1962,7 @@ enum bt_ctf_btr_status update_clock(struct bt_ctf_notif_iter *notit, clock_class_found = g_hash_table_lookup_extended(notit->clock_states, clock_class, NULL, (gpointer) &clock_state); - if (unlikely(!clock_class_found)) { - ret = BT_CTF_BTR_STATUS_ERROR; - goto end; - } - - if (unlikely(!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."); @@ -2638,28 +2771,81 @@ end: } static -void create_packet(struct bt_ctf_notif_iter *notit) +uint64_t get_cur_stream_instance_id(struct bt_ctf_notif_iter *notit) { + struct bt_ctf_field *stream_instance_id_field = NULL; + uint64_t stream_instance_id = -1ULL; int ret; - struct bt_ctf_stream *stream = NULL; - struct bt_ctf_packet *packet = NULL; - BT_LOGV("Creating packet for packet notification: " - "notit-addr=%p", notit); + if (!notit->dscopes.trace_packet_header) { + goto end; + } + + stream_instance_id_field = bt_ctf_field_structure_get_field_by_name( + notit->dscopes.trace_packet_header, "stream_instance_id"); + if (!stream_instance_id_field) { + goto end; + } + + ret = bt_ctf_field_unsigned_integer_get_value(stream_instance_id_field, + &stream_instance_id); + if (ret) { + stream_instance_id = -1ULL; + goto end; + } + +end: + bt_put(stream_instance_id_field); + return stream_instance_id; +} + +static +int set_stream(struct bt_ctf_notif_iter *notit) +{ + int ret = 0; + struct bt_ctf_stream *stream = NULL; - /* Ask the user for the stream */ 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_ctf_stream_class_get_name(notit->meta.stream_class), bt_ctf_stream_class_get_id(notit->meta.stream_class)); - stream = notit->medium.medops.get_stream(notit->meta.stream_class, - notit->medium.data); - BT_LOGV("User function returned: stream-addr=%p", - stream); + 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_ctf_notif_iter *notit) +{ + int ret; + struct bt_ctf_packet *packet = NULL; + + BT_LOGV("Creating packet for packet notification: " + "notit-addr=%p", notit); + + /* Ask the user for the stream */ + ret = set_stream(notit); + if (ret) { goto error; } @@ -2668,19 +2854,19 @@ void create_packet(struct bt_ctf_notif_iter *notit) "stream-class-addr=%p, " "stream-class-name=\"%s\", " "stream-class-id=%" PRId64, - notit, stream, notit->meta.stream_class, + notit, notit->stream, notit->meta.stream_class, bt_ctf_stream_class_get_name(notit->meta.stream_class), bt_ctf_stream_class_get_id(notit->meta.stream_class)); /* Create packet */ - packet = bt_ctf_packet_create(stream); + packet = bt_ctf_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, stream, notit->meta.stream_class, + notit, notit->stream, notit->meta.stream_class, bt_ctf_stream_class_get_name(notit->meta.stream_class), bt_ctf_stream_class_get_id(notit->meta.stream_class)); goto error; @@ -2698,7 +2884,7 @@ void create_packet(struct bt_ctf_notif_iter *notit) "stream-class-name=\"%s\", " "stream-class-id=%" PRId64 ", " "field-addr=%p", - notit, packet, stream, notit->meta.stream_class, + notit, packet, notit->stream, notit->meta.stream_class, bt_ctf_stream_class_get_name(notit->meta.stream_class), bt_ctf_stream_class_get_id(notit->meta.stream_class), notit->dscopes.trace_packet_header); @@ -2717,7 +2903,7 @@ void create_packet(struct bt_ctf_notif_iter *notit) "stream-class-name=\"%s\", " "stream-class-id=%" PRId64 ", " "field-addr=%p", - notit, packet, stream, notit->meta.stream_class, + notit, packet, notit->stream, notit->meta.stream_class, bt_ctf_stream_class_get_name(notit->meta.stream_class), bt_ctf_stream_class_get_id(notit->meta.stream_class), notit->dscopes.trace_packet_header); @@ -2784,9 +2970,17 @@ 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; + struct bt_ctf_event *event = NULL; struct bt_notification *ret = NULL; + /* 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; + } + /* Create event */ event = create_event(notit); if (!event) { @@ -2808,27 +3002,6 @@ end: BT_PUT(event); } -static -int init_clock_states(GHashTable *clock_states, struct bt_ctf_trace *trace) -{ - int clock_class_count, i, ret = 0; - - assert(trace); - clock_class_count = bt_ctf_trace_get_clock_class_count(trace); - assert(clock_class_count >= 0); - - 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); - assert(clock_class); - g_hash_table_insert(clock_states, bt_get(clock_class), NULL); - bt_put(clock_class); - } - - return ret; -} - static void init_trace_field_path_cache(struct bt_ctf_trace *trace, struct trace_field_path_cache *trace_field_path_cache) @@ -2882,7 +3055,6 @@ struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace, size_t max_request_sz, struct bt_ctf_notif_iter_medium_ops medops, void *data) { - int ret; struct bt_ctf_notif_iter *notit = NULL; struct bt_ctf_btr_cbs cbs = { .types = { @@ -2919,11 +3091,6 @@ struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace, BT_LOGE_STR("Failed to allocate a GHashTable."); goto error; } - ret = init_clock_states(notit->clock_states, trace); - if (ret) { - BT_LOGW("Cannot initialize clock values."); - goto error; - } notit->meta.trace = bt_get(trace); notit->medium.medops = medops; notit->medium.max_request_sz = max_request_sz; @@ -2977,6 +3144,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->stream); BT_PUT(notit->cur_timestamp_end); put_all_dscopes(notit); @@ -3159,3 +3327,11 @@ set_fields: end: return status; } + +BT_HIDDEN +void bt_ctf_notif_iter_set_medops_data(struct bt_ctf_notif_iter *notit, + void *medops_data) +{ + assert(notit); + notit->medium.data = medops_data; +}