/* 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).
*/
/* 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 */
/* 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;
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));
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. */
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\"",
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,
end:
BT_PUT(packet_header_type);
BT_PUT(stream_id_field_type);
-
+ bt_put(new_stream_class);
return status;
}
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");
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) {
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;
{
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);
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;
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.");
}
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;
}
"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;
"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);
"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);
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) {
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)
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 = {
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;
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);
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;
+}