X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=plugins%2Fctf%2Fcommon%2Fnotif-iter%2Fnotif-iter.c;h=a5d9e5c8aeaf1235510ccf70ac9f238f4f53b64c;hb=0b0bf6828fd92630e50b6ea7474eacdff9264b5f;hp=b8af7e15a13dfe603f4599b104cbedbee8a52f13;hpb=0659c536a413b39e3cec87992499bca17ef95546;p=babeltrace.git diff --git a/plugins/ctf/common/notif-iter/notif-iter.c b/plugins/ctf/common/notif-iter/notif-iter.c index b8af7e15..a5d9e5c8 100644 --- a/plugins/ctf/common/notif-iter/notif-iter.c +++ b/plugins/ctf/common/notif-iter/notif-iter.c @@ -33,21 +33,9 @@ #include #include #include -#include +#include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include @@ -211,6 +199,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 */ @@ -229,6 +220,12 @@ struct bt_ctf_notif_iter { /* Current content size (bits) (-1 if unknown) */ int64_t cur_content_size; + /* + * Offset, in the underlying media, of the current packet's start + * (-1 if unknown). + */ + off_t cur_packet_offset; + /* bt_ctf_clock_class to uint64_t. */ GHashTable *clock_states; @@ -477,6 +474,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 = SIZE_MAX; /* New medium buffer size */ notit->buf.sz = buffer_sz; @@ -490,6 +488,114 @@ 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 *ph_ft = + bt_ctf_trace_get_packet_header_type(notit->meta.trace); + 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; + } + + if (notit->state == STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN) { + /* + * Beginning of packet context context is only + * valid if there's no packet header. + */ + if (!ph_ft) { + goto good_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(ph_ft); + 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)); @@ -1074,7 +1180,7 @@ enum bt_ctf_notif_iter_status set_current_packet_content_sizes( enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK; struct bt_ctf_field *packet_size_field = NULL; struct bt_ctf_field *content_size_field = NULL; - uint64_t content_size = -1, packet_size = -1; + uint64_t content_size = -1ULL, packet_size = -1ULL; if (!notit->dscopes.stream_packet_context) { goto end; @@ -1125,7 +1231,16 @@ enum bt_ctf_notif_iter_status set_current_packet_content_sizes( goto end; } - notit->cur_packet_size = packet_size; + 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, @@ -1157,6 +1272,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) { @@ -1168,7 +1286,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; @@ -1304,7 +1422,7 @@ end_v_field_type: if (id_field_type && event_id == -1ULL) { /* Check "id" field */ struct bt_ctf_field *id_field = NULL; - int ret = 0; + int ret_get_value = 0; // TODO: optimalize! id_field = bt_ctf_field_structure_get_field( @@ -1314,7 +1432,7 @@ end_v_field_type: } if (bt_ctf_field_is_integer(id_field)) { - ret = bt_ctf_field_unsigned_integer_get_value( + ret_get_value = bt_ctf_field_unsigned_integer_get_value( id_field, &event_id); } else if (bt_ctf_field_is_enumeration(id_field)) { struct bt_ctf_field *container; @@ -1322,12 +1440,12 @@ end_v_field_type: container = bt_ctf_field_enumeration_get_container( id_field); assert(container); - ret = bt_ctf_field_unsigned_integer_get_value( + ret_get_value = bt_ctf_field_unsigned_integer_get_value( container, &event_id); BT_PUT(container); } - assert(ret == 0); + assert(ret_get_value == 0); BT_PUT(id_field); } @@ -1687,10 +1805,12 @@ void bt_ctf_notif_iter_reset(struct bt_ctf_notif_iter *notit) 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_packet_offset = -1; } static @@ -1704,8 +1824,12 @@ int bt_ctf_notif_iter_switch_packet(struct bt_ctf_notif_iter *notit) * 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); + if (notit->cur_packet_size != -1) { + notit->cur_packet_offset += notit->cur_packet_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); @@ -2867,9 +2991,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) { @@ -3017,6 +3149,7 @@ struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace, "data=%p, notit-addr=%p", trace, bt_ctf_trace_get_name(trace), max_request_sz, data, notit); + notit->cur_packet_offset = 0; end: return notit; @@ -3151,6 +3284,7 @@ enum bt_ctf_notif_iter_status bt_ctf_notif_iter_get_packet_header_context_fields struct bt_ctf_field **packet_header_field, struct bt_ctf_field **packet_context_field) { + int ret; enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK; assert(notit); @@ -3213,6 +3347,11 @@ set_fields: *packet_context_field = bt_get(notit->dscopes.stream_packet_context); } + ret = set_current_packet_content_sizes(notit); + if (ret) { + status = BT_CTF_NOTIF_ITER_STATUS_ERROR; + goto end; + } end: return status; } @@ -3224,3 +3363,57 @@ void bt_ctf_notif_iter_set_medops_data(struct bt_ctf_notif_iter *notit, assert(notit); notit->medium.data = medops_data; } + +BT_HIDDEN +enum bt_ctf_notif_iter_status bt_ctf_notif_iter_seek( + struct bt_ctf_notif_iter *notit, off_t offset) +{ + enum bt_ctf_notif_iter_status ret = BT_CTF_NOTIF_ITER_STATUS_OK; + enum bt_ctf_notif_iter_medium_status medium_status; + + assert(notit); + if (offset < 0) { + BT_LOGE("Cannot seek to negative offset: offset=%jd", offset); + ret = BT_CTF_NOTIF_ITER_STATUS_INVAL; + goto end; + } + + if (!notit->medium.medops.seek) { + ret = BT_CTF_NOTIF_ITER_STATUS_UNSUPPORTED; + BT_LOGD("Aborting seek as the iterator's underlying media does not implement seek support."); + goto end; + } + + medium_status = notit->medium.medops.seek( + BT_CTF_NOTIF_ITER_SEEK_WHENCE_SET, offset, + notit->medium.data); + if (medium_status != BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK) { + if (medium_status == BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF) { + ret = BT_CTF_NOTIF_ITER_STATUS_EOF; + } else { + ret = BT_CTF_NOTIF_ITER_STATUS_ERROR; + goto end; + } + } + + bt_ctf_notif_iter_reset(notit); + notit->cur_packet_offset = offset; +end: + return ret; +} + +BT_HIDDEN +off_t bt_ctf_notif_iter_get_current_packet_offset( + struct bt_ctf_notif_iter *notit) +{ + assert(notit); + return notit->cur_packet_offset; +} + +BT_HIDDEN +off_t bt_ctf_notif_iter_get_current_packet_size( + struct bt_ctf_notif_iter *notit) +{ + assert(notit); + return notit->cur_packet_size; +}