int bt_iter_next(struct bt_iter *iter) { struct ctf_file_stream *file_stream, *removed; int ret; bool event_outside_interval = false; if (!iter) return -EINVAL; file_stream = bt_heap_maximum(iter->stream_heap); if (!file_stream) { /* end of file for all streams */ ret = 0; goto end; } ret = stream_read_event(file_stream); if (file_stream->pos.parent.trace && file_stream->pos.parent.trace->interval_set) { event_outside_interval = file_stream->parent.real_timestamp > file_stream->pos.parent.trace->interval_real.timestamp_end; } if (ret == EOF || event_outside_interval) { removed = bt_heap_remove(iter->stream_heap); assert(removed == file_stream); ret = 0; goto end; } else if (ret == EAGAIN) { /* * Live streaming: the stream is inactive for now, we * just updated the timestamp_end to skip over this * stream up to a certain point in time. * * Since we can't guarantee that a stream will ever have * any activity, we can't rely on the fact that * bt_iter_next will be called for each stream and deal * with inactive streams. So instead, we return 0 here * to the caller and let the read API handle the * retry case. */ ret = 0; goto reinsert; } else if (ret) { goto end; } reinsert: /* Reinsert the file stream into the heap, and rebalance. */ removed = bt_heap_replace_max(iter->stream_heap, file_stream); assert(removed == file_stream); end: return ret; }
struct bt_ctf_event *bt_ctf_iter_read_event_flags(struct bt_ctf_iter *iter, int *flags) { struct ctf_file_stream *file_stream; struct bt_ctf_event *ret; struct ctf_stream_definition *stream; struct packet_index *packet_index; /* * We do not want to fail for any other reason than end of * trace, hence the assert. */ assert(iter); ret = &iter->current_ctf_event; file_stream = bt_heap_maximum(iter->parent.stream_heap); if (!file_stream) { /* end of file for all streams */ goto stop; } stream = &file_stream->parent; ret->parent = g_ptr_array_index(stream->events_by_id, stream->event_id); if (flags) *flags = 0; if (!file_stream->pos.packet_cycles_index) packet_index = NULL; else packet_index = &g_array_index(file_stream->pos.packet_cycles_index, struct packet_index, file_stream->pos.cur_index); iter->events_lost = 0; if (packet_index && packet_index->events_discarded > file_stream->pos.last_events_discarded) { if (flags) *flags |= BT_ITER_FLAG_LOST_EVENTS; iter->events_lost += packet_index->events_discarded - file_stream->pos.last_events_discarded; file_stream->pos.last_events_discarded = packet_index->events_discarded; } if (ret->parent->stream->stream_id > iter->callbacks->len) goto end; process_callbacks(iter, ret->parent->stream); end: return ret; stop: return NULL; }
struct bt_iter_pos *bt_iter_get_pos(struct bt_iter *iter) { struct bt_iter_pos *pos; struct trace_collection *tc; struct ctf_file_stream *file_stream = NULL, *removed; struct ptr_heap iter_heap_copy; int ret; if (!iter) return NULL; tc = iter->ctx->tc; pos = g_new0(struct bt_iter_pos, 1); pos->type = BT_SEEK_RESTORE; pos->u.restore = g_new0(struct bt_saved_pos, 1); pos->u.restore->tc = tc; pos->u.restore->stream_saved_pos = g_array_new(FALSE, TRUE, sizeof(struct stream_saved_pos)); if (!pos->u.restore->stream_saved_pos) goto error; ret = bt_heap_copy(&iter_heap_copy, iter->stream_heap); if (ret < 0) goto error_heap; /* iterate over each stream in the heap */ file_stream = bt_heap_maximum(&iter_heap_copy); while (file_stream != NULL) { struct stream_saved_pos saved_pos; assert(file_stream->pos.last_offset != LAST_OFFSET_POISON); saved_pos.offset = file_stream->pos.last_offset; saved_pos.file_stream = file_stream; saved_pos.cur_index = file_stream->pos.cur_index; saved_pos.current_real_timestamp = file_stream->parent.real_timestamp; saved_pos.current_cycles_timestamp = file_stream->parent.cycles_timestamp; g_array_append_val( pos->u.restore->stream_saved_pos, saved_pos); printf_debug("stream : %" PRIu64 ", cur_index : %zd, " "offset : %zd, " "timestamp = %" PRIu64 "\n", file_stream->parent.stream_id, saved_pos.cur_index, saved_pos.offset, saved_pos.current_real_timestamp); /* remove the stream from the heap copy */ removed = bt_heap_remove(&iter_heap_copy); assert(removed == file_stream); file_stream = bt_heap_maximum(&iter_heap_copy); } bt_heap_free(&iter_heap_copy); return pos; error_heap: g_array_free(pos->u.restore->stream_saved_pos, TRUE); error: g_free(pos); return NULL; }
struct bt_ctf_event *bt_ctf_iter_read_event_flags(struct bt_ctf_iter *iter, int *flags) { struct ctf_file_stream *file_stream; struct bt_ctf_event *ret; struct ctf_stream_definition *stream; struct packet_index *packet_index; /* * We do not want to fail for any other reason than end of * trace, hence the assert. */ assert(iter); if (flags) *flags = 0; ret = &iter->current_ctf_event; file_stream = bt_heap_maximum(iter->parent.stream_heap); if (!file_stream) { /* end of file for all streams */ goto stop; } /* * If the packet is empty (contains only headers or is of size 0), the * caller has to know that we can't read the current event and we need * to do a bt_iter_next. */ if (file_stream->pos.data_offset == file_stream->pos.content_size || file_stream->pos.content_size == 0) { /* More events may come. */ ret = NULL; if (flags) *flags |= BT_ITER_FLAG_RETRY; goto end; } stream = &file_stream->parent; if (iter->parent.end_pos && iter->parent.end_pos->type == BT_SEEK_TIME && stream->real_timestamp > iter->parent.end_pos->u.seek_time) { goto stop; } ret->parent = g_ptr_array_index(stream->events_by_id, stream->event_id); if (!file_stream->pos.packet_index) packet_index = NULL; else packet_index = &g_array_index(file_stream->pos.packet_index, struct packet_index, file_stream->pos.cur_index); iter->events_lost = 0; if (packet_index && packet_index->events_discarded > file_stream->pos.last_events_discarded) { if (flags) *flags |= BT_ITER_FLAG_LOST_EVENTS; iter->events_lost += packet_index->events_discarded - file_stream->pos.last_events_discarded; file_stream->pos.last_events_discarded = packet_index->events_discarded; } if (ret->parent->stream->stream_id > iter->callbacks->len) goto end; process_callbacks(iter, ret->parent->stream); end: return ret; stop: return NULL; }