+
+ lttv_traceset_context_position_destroy(end_pos);
+ lttv_traceset_context_position_destroy(next_iter_end_pos);
+
+ lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
+
+ if(sd.events_found >= n) {
+ /* Seek the traceset to the first event in the circular array */
+ LttvTracesetContextPosition *pos =
+ (LttvTracesetContextPosition*)g_ptr_array_index (sd.array,
+ sd.first_event);
+ g_assert(lttv_process_traceset_seek_position(self, pos) == 0);
+ } else {
+ /* Will seek to the last saved position : in the worst case, it will be the
+ * original position (if events_found is 0) */
+ g_assert(lttv_process_traceset_seek_position(self, saved_pos) == 0);
+ }
+
+ for(i=0;i<sd.array->len;i++) {
+ LttvTracesetContextPosition *pos =
+ (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
+ lttv_traceset_context_position_destroy(pos);
+ }
+ g_ptr_array_free(sd.array, TRUE);
+
+ lttv_hooks_destroy(hooks);
+
+ lttv_traceset_context_position_destroy(saved_pos);
+
+ return sd.events_found;
+}
+
+
+struct seek_forward_data {
+ guint event_count; /* event counter */
+ guint n; /* requested number of events to jump over */
+ LttvFilter *filter1;
+ LttvFilter *filter2;
+ LttvFilter *filter3;
+ gpointer data;
+ check_handler *check;
+ gboolean *stop_flag;
+ guint raw_event_count; /* event counter */
+};
+
+static gint seek_forward_event_hook(void *hook_data, void* call_data)
+{
+ struct seek_forward_data *sd = (struct seek_forward_data*)hook_data;
+ LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
+
+ if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag, sd->data))
+ return TRUE;
+ sd->raw_event_count++;
+
+ if(sd->filter1 != NULL && sd->filter1->head != NULL &&
+ !lttv_filter_tree_parse(sd->filter1->head,
+ ltt_tracefile_get_event(tfc->tf),
+ tfc->tf,
+ tfc->t_context->t,
+ tfc,NULL,NULL)) {
+ return FALSE;
+ }
+ if(sd->filter2 != NULL && sd->filter2->head != NULL &&
+ !lttv_filter_tree_parse(sd->filter2->head,
+ ltt_tracefile_get_event(tfc->tf),
+ tfc->tf,
+ tfc->t_context->t,
+ tfc,NULL,NULL)) {
+ return FALSE;
+ }
+ if(sd->filter3 != NULL && sd->filter3->head != NULL &&
+ !lttv_filter_tree_parse(sd->filter3->head,
+ ltt_tracefile_get_event(tfc->tf),
+ tfc->tf,
+ tfc->t_context->t,
+ tfc,NULL,NULL)) {
+ return FALSE;
+ }
+
+ sd->event_count++;
+ if(sd->event_count >= sd->n)
+ return TRUE;
+}
+
+/* Seek back n events forward from the current position (1 to n)
+ * 0 is ok too, but it will actually do nothing.
+ *
+ * Parameters :
+ * @self the trace set context
+ * @n number of events to jump over
+ * @filter filter to call.
+ *
+ * returns : the number of events jumped over (may be less than requested if end
+ * of traceset reached) */
+guint lttv_process_traceset_seek_n_forward(LttvTracesetContext *self,
+ guint n,
+ check_handler *check,
+ gboolean *stop_flag,
+ LttvFilter *filter1,
+ LttvFilter *filter2,
+ LttvFilter *filter3,
+ gpointer data)
+{
+ struct seek_forward_data sd;
+ sd.event_count = 0;
+ sd.n = n;
+ sd.filter1 = filter1;
+ sd.filter2 = filter2;
+ sd.filter3 = filter3;
+ sd.data = data;
+ sd.check = check;
+ sd.stop_flag = stop_flag;
+ sd.raw_event_count = 0;
+
+ if(sd.event_count >= sd.n) return sd.event_count;
+
+ LttvHooks *hooks = lttv_hooks_new();
+
+ lttv_hooks_add(hooks, seek_forward_event_hook, &sd, LTTV_PRIO_DEFAULT);
+
+ lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
+
+ /* it will end on the end of traceset, or the fact that the
+ * hook returns TRUE.
+ */
+ lttv_process_traceset_middle(self, ltt_time_infinite,
+ G_MAXUINT, NULL);
+
+ /* Here, our position is either the end of traceset, or the exact position
+ * after n events : leave it like this. This might be placed on an event that
+ * will be filtered out, we don't care : all we know is that the following
+ * event filtered in will be the right one. */
+
+ lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
+
+ lttv_hooks_destroy(hooks);
+
+ return sd.event_count;