fix trace_find_hook
[lttv.git] / ltt / branches / poly / lttv / lttv / tracecontext.c
index 5b6cdba7f379122440a57b3aa212ff5547d4315b..39ee2950b66c443350c6dafb23c7e5e309c543d6 100644 (file)
  * MA 02111-1307, USA.
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
+#include <string.h>
+#include <lttv/lttv.h>
 #include <lttv/tracecontext.h>
 #include <ltt/event.h>
-#include <ltt/facility.h>
 #include <ltt/trace.h>
-#include <ltt/type.h>
-
+#include <lttv/filter.h>
+#include <errno.h>
 
+#define min(a,b) (((a)<(b))?(a):(b))
 
 
 gint compare_tracefile(gconstpointer a, gconstpointer b)
 {
-  gint comparison;
-
-  LttvTracefileContext *trace_a = (LttvTracefileContext *)a;
-
-  LttvTracefileContext *trace_b = (LttvTracefileContext *)b;
-
-  if(trace_a == trace_b) return 0;
-  comparison = ltt_time_compare(trace_a->timestamp, trace_b->timestamp);
-  if(comparison != 0) return comparison;
-  if(trace_a->index < trace_b->index) return -1;
-  else if(trace_a->index > trace_b->index) return 1;
-  if(trace_a->t_context->index < trace_b->t_context->index) return -1;
-  else if(trace_a->t_context->index > trace_b->t_context->index) return 1;
-  g_assert(FALSE);
+  gint comparison = 0;
+
+  const LttvTracefileContext *trace_a = (const LttvTracefileContext *)a;
+  const LttvTracefileContext *trace_b = (const LttvTracefileContext *)b;
+
+  if(likely(trace_a != trace_b)) {
+    comparison = ltt_time_compare(trace_a->timestamp, trace_b->timestamp);
+    if(unlikely(comparison == 0)) {
+      if(trace_a->index < trace_b->index) comparison = -1;
+      else if(trace_a->index > trace_b->index) comparison = 1;
+      else if(trace_a->t_context->index < trace_b->t_context->index) 
+        comparison = -1;
+      else if(trace_a->t_context->index > trace_b->t_context->index)
+        comparison = 1;
+    }
+  }
+  return comparison;
 }
 
-struct _LttvTraceContextPosition {
-  LttEventPosition **tf_pos;          /* Position in each trace           */
-  guint nb_tracefile;                /* Number of tracefiles (check)     */
-};
+typedef struct _LttvTracefileContextPosition {
+  LttEventPosition *event;
+  LttvTracefileContext *tfc;
+  gboolean used; /* Tells if the tfc is at end of traceset position */
+} LttvTracefileContextPosition;
+
 
 struct _LttvTracesetContextPosition {
-  LttvTraceContextPosition *t_pos;    /* Position in each trace           */
-  guint nb_trace;                    /* Number of traces (check)         */
+  GArray *tfcp;                      /* Array of LttvTracefileContextPosition */
+  LttTime timestamp;                 /* Current time at the saved position */ 
+                                     /* If ltt_time_infinite : no position is
+                                      * set, else, a position is set (may be end
+                                      * of trace, with ep->len == 0) */
 };
 
 void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts)
@@ -101,7 +114,7 @@ lttv_context_new_tracefile_context(LttvTracesetContext *self)
  ***************************************************************************/
 static void lttv_traceset_context_compute_time_span(
                                           LttvTracesetContext *self,
-                                                                 TimeInterval time_span)
+                                                                 TimeInterval *time_span)
 {
   LttvTraceset * traceset = self->ts;
   int numTraces = lttv_traceset_number(traceset);
@@ -110,44 +123,66 @@ static void lttv_traceset_context_compute_time_span(
   LttvTraceContext *tc;
   LttTrace * trace;
 
-  time_span.startTime.tv_sec = 0;
-  time_span.startTime.tv_nsec = 0;
-  time_span.endTime.tv_sec = 0;
-  time_span.endTime.tv_nsec = 0;
+  time_span->start_time.tv_sec = 0;
+  time_span->start_time.tv_nsec = 0;
+  time_span->end_time.tv_sec = 0;
+  time_span->end_time.tv_nsec = 0;
   
   for(i=0; i<numTraces;i++){
     tc = self->traces[i];
     trace = tc->t;
 
     ltt_trace_time_span_get(trace, &s, &e);
+    tc->time_span.start_time = s;
+    tc->time_span.end_time = e;
 
     if(i==0){
-      time_span.startTime = s;
-      time_span.endTime   = e;
+      time_span->start_time = s;
+      time_span->end_time   = e;
     }else{
-      if(s.tv_sec < time_span.startTime.tv_sec 
-          || (s.tv_sec == time_span.startTime.tv_sec 
-               && s.tv_nsec < time_span.startTime.tv_nsec))
-             time_span.startTime = s;
-      if(e.tv_sec > time_span.endTime.tv_sec
-          || (e.tv_sec == time_span.endTime.tv_sec 
-               && e.tv_nsec > time_span.endTime.tv_nsec))
-        time_span.endTime = e;      
+      if(s.tv_sec < time_span->start_time.tv_sec 
+          || (s.tv_sec == time_span->start_time.tv_sec 
+               && s.tv_nsec < time_span->start_time.tv_nsec))
+             time_span->start_time = s;
+      if(e.tv_sec > time_span->end_time.tv_sec
+          || (e.tv_sec == time_span->end_time.tv_sec 
+               && e.tv_nsec > time_span->end_time.tv_nsec))
+        time_span->end_time = e;      
     }
   }
 }
 
+static void init_tracefile_context(LttTracefile *tracefile,
+                                    LttvTraceContext *tc)
+{
+  LttvTracefileContext *tfc;
+  LttvTracesetContext *tsc = tc->ts_context;
+  
+  tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(tsc)->new_tracefile_context(tsc);
+
+  tfc->index = tc->tracefiles->len;
+  tc->tracefiles = g_array_append_val(tc->tracefiles, tfc);
+
+  tfc->tf = tracefile;
+
+  tfc->t_context = tc;
+  tfc->event = lttv_hooks_new();
+  tfc->event_by_id = lttv_hooks_by_id_new();
+  tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
+  tfc->target_pid = -1;
+}
+
 
 static void
 init(LttvTracesetContext *self, LttvTraceset *ts)
 {
-  guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile;
+  guint i, nb_trace;
 
   LttvTraceContext *tc;
 
-  LttvTracefileContext *tfc;
+  GData **tracefiles_groups;
 
-  LttTime null_time = {0, 0};
+  struct compute_tracefile_group_args args;
 
   nb_trace = lttv_traceset_number(ts);
   self->ts = ts;
@@ -164,6 +199,20 @@ init(LttvTracesetContext *self, LttvTraceset *ts)
     tc->t = lttv_trace(tc->vt);
     tc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
     tc->t_a = lttv_trace_attribute(tc->vt);
+    tc->tracefiles = g_array_sized_new(FALSE, TRUE,
+                        sizeof(LttvTracefileContext*), 10);
+
+    tracefiles_groups = ltt_trace_get_tracefiles_groups(tc->t);
+    if(tracefiles_groups != NULL) {
+      args.func = (ForEachTraceFileFunc)init_tracefile_context;
+      args.func_args = tc;
+
+      g_datalist_foreach(tracefiles_groups, 
+                            (GDataForeachFunc)compute_tracefile_group,
+                            &args);
+    }
+      
+#if 0
     nb_control = ltt_trace_control_tracefile_number(tc->t);
     nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t);
     nb_tracefile = nb_control + nb_per_cpu;
@@ -182,17 +231,21 @@ init(LttvTracesetContext *self, LttvTraceset *ts)
         tfc->control = FALSE;
         tfc->tf = ltt_trace_per_cpu_tracefile_get(tc->t, j - nb_control);
       }
+
       tfc->t_context = tc;
+      tfc->e = ltt_event_new();
       tfc->event = lttv_hooks_new();
       tfc->event_by_id = lttv_hooks_by_id_new();
       tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
     }
-  }
-  lttv_process_traceset_seek_time(self, null_time);
-  lttv_traceset_context_compute_time_span(self, self->time_span);
-  self->e = NULL;
+#endif //0
 
+  }
+  self->sync_position = lttv_traceset_context_position_new(self);
   self->pqueue = g_tree_new(compare_tracefile);
+  lttv_process_traceset_seek_time(self, ltt_time_zero);
+  lttv_traceset_context_compute_time_span(self, &self->time_span);
+
 }
 
 
@@ -202,14 +255,13 @@ void fini(LttvTracesetContext *self)
 
   LttvTraceContext *tc;
 
-  LttvTracefileContext *tfc;
+  LttvTracefileContext **tfc;
 
   LttvTraceset *ts = self->ts;
 
-  //FIXME : segfault
-
   g_tree_destroy(self->pqueue);
   g_object_unref(self->a);
+  lttv_traceset_context_position_destroy(self->sync_position);
 
   nb_trace = lttv_traceset_number(ts);
 
@@ -218,17 +270,16 @@ void fini(LttvTracesetContext *self)
 
     g_object_unref(tc->a);
 
-    nb_tracefile = ltt_trace_control_tracefile_number(tc->t) +
-        ltt_trace_per_cpu_tracefile_number(tc->t);
+    nb_tracefile = tc->tracefiles->len;
 
     for(j = 0 ; j < nb_tracefile ; j++) {
-      tfc = tc->tracefiles[j];
-      lttv_hooks_destroy(tfc->event);
-      lttv_hooks_by_id_destroy(tfc->event_by_id);
-      g_object_unref(tfc->a);
-      g_object_unref(tfc);
+      tfc = &g_array_index(tc->tracefiles, LttvTracefileContext*, j);
+      lttv_hooks_destroy((*tfc)->event);
+      lttv_hooks_by_id_destroy((*tfc)->event_by_id);
+      g_object_unref((*tfc)->a);
+      g_object_unref(*tfc);
     }
-    g_free(tc->tracefiles);
+    g_array_free(tc->tracefiles, TRUE);
     g_object_unref(tc);
   }
   g_free(self->traces);
@@ -301,15 +352,15 @@ void lttv_trace_context_add_hooks(LttvTraceContext *self,
 {
   guint i, nb_tracefile;
 
-  LttvTracefileContext *tfc;
+  LttvTracefileContext **tfc;
 
   lttv_hooks_call(before_trace, self);
-  nb_tracefile = ltt_trace_control_tracefile_number(self->t) +
-      ltt_trace_per_cpu_tracefile_number(self->t);
+
+  nb_tracefile = self->tracefiles->len;
 
   for(i = 0 ; i < nb_tracefile ; i++) {
-    tfc = self->tracefiles[i];
-    lttv_tracefile_context_add_hooks(tfc,
+    tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
+    lttv_tracefile_context_add_hooks(*tfc,
                                      before_tracefile,
                                      event,
                                      event_by_id);
@@ -326,14 +377,13 @@ void lttv_trace_context_remove_hooks(LttvTraceContext *self,
 {
   guint i, nb_tracefile;
 
-  LttvTracefileContext *tfc;
+  LttvTracefileContext **tfc;
 
-  nb_tracefile = ltt_trace_control_tracefile_number(self->t) +
-      ltt_trace_per_cpu_tracefile_number(self->t);
+  nb_tracefile = self->tracefiles->len;
 
   for(i = 0 ; i < nb_tracefile ; i++) {
-    tfc = self->tracefiles[i];
-    lttv_tracefile_context_remove_hooks(tfc,
+    tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
+    lttv_tracefile_context_remove_hooks(*tfc,
                                         after_tracefile,
                                         event,
                                         event_by_id);
@@ -347,19 +397,19 @@ void lttv_tracefile_context_add_hooks(LttvTracefileContext *self,
           LttvHooks *event, 
           LttvHooksById *event_by_id)
 {
-  guint i;
+  guint i, index;
 
   LttvHooks *hook;
   
   lttv_hooks_call(before_tracefile, self);
   lttv_hooks_add_list(self->event, event);
-  if(event_by_id != NULL)
-    for(i = 0; i < lttv_hooks_by_id_max_id(event_by_id); i++) {
-      hook = lttv_hooks_by_id_get(self->event_by_id, i);
-      if(hook != NULL)
-        lttv_hooks_remove_list(hook, lttv_hooks_by_id_get(event_by_id, i));
+  if(event_by_id != NULL) {
+    for(i = 0; i < event_by_id->array->len; i++) {
+      index = g_array_index(event_by_id->array, guint, i);
+      hook = lttv_hooks_by_id_find(self->event_by_id, index);
+      lttv_hooks_add_list(hook, lttv_hooks_by_id_get(event_by_id, index));
     }
-
+  }
 }
 
 void lttv_tracefile_context_remove_hooks(LttvTracefileContext *self,
@@ -367,17 +417,19 @@ void lttv_tracefile_context_remove_hooks(LttvTracefileContext *self,
            LttvHooks *event, 
            LttvHooksById *event_by_id)
 {
-  guint i;
+  guint i, index;
 
   LttvHooks *hook;
   
-
   lttv_hooks_remove_list(self->event, event);
-  if(event_by_id != NULL)
-    for(i = 0; i < lttv_hooks_by_id_max_id(event_by_id); i++) {
-      hook = lttv_hooks_by_id_find(self->event_by_id, i);
-      lttv_hooks_add_list(hook, lttv_hooks_by_id_get(event_by_id, i));
+  if(event_by_id != NULL) {
+    for(i = 0; i < event_by_id->array->len; i++) {
+      index = g_array_index(event_by_id->array, guint, i);
+      hook = lttv_hooks_by_id_get(self->event_by_id, index);
+      if(hook != NULL)
+        lttv_hooks_remove_list(hook, lttv_hooks_by_id_get(event_by_id, index));
     }
+  }
 
   lttv_hooks_call(after_tracefile, self);
 }
@@ -463,7 +515,8 @@ lttv_traceset_context_get_type(void)
       NULL,   /* class_data */
       sizeof (LttvTracesetContext),
       0,      /* n_preallocs */
-      (GInstanceInitFunc) traceset_context_instance_init /* instance_init */
+      (GInstanceInitFunc) traceset_context_instance_init, /* instance_init */
+      NULL    /* Value handling */
     };
 
     type = g_type_register_static (G_TYPE_OBJECT, "LttvTracesetContextType", 
@@ -511,7 +564,8 @@ lttv_trace_context_get_type(void)
       NULL,   /* class_data */
       sizeof (LttvTraceContext),
       0,      /* n_preallocs */
-      (GInstanceInitFunc) trace_context_instance_init    /* instance_init */
+      (GInstanceInitFunc) trace_context_instance_init,    /* instance_init */
+      NULL    /* Value handling */
     };
 
     type = g_type_register_static (G_TYPE_OBJECT, "LttvTraceContextType", 
@@ -559,7 +613,8 @@ lttv_tracefile_context_get_type(void)
       NULL,   /* class_data */
       sizeof (LttvTracefileContext),
       0,      /* n_preallocs */
-      (GInstanceInitFunc) tracefile_context_instance_init    /* instance_init */
+      (GInstanceInitFunc) tracefile_context_instance_init,    /* instance_init */
+      NULL    /* Value handling */
     };
 
     type = g_type_register_static (G_TYPE_OBJECT, "LttvTracefileContextType", 
@@ -570,11 +625,41 @@ lttv_tracefile_context_get_type(void)
 
 
 
-gboolean get_first(gpointer key, gpointer value, gpointer user_data) {
+static gboolean get_first(gpointer key, gpointer value, gpointer user_data) {
+  g_assert(key == value);
   *((LttvTracefileContext **)user_data) = (LttvTracefileContext *)value;
   return TRUE;
 }
 
+#ifdef DEBUG
+// Test to see if pqueue is traversed in the right order.
+static LttTime test_time;
+
+static gboolean test_tree(gpointer key, gpointer value, gpointer user_data) {
+
+  LttvTracefileContext *tfc = (LttvTracefileContext *)key;
+
+  g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
+      g_quark_to_string(ltt_tracefile_name(tfc->tf)),
+      tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec,
+      tfc->index, tfc->t_context->index);
+  
+  if(user_data != NULL) {
+    if(((LttvTracefileContext *)user_data) == (LttvTracefileContext *)value) {
+      g_assert(compare_tracefile(user_data, value) == 0);
+    } else
+      g_assert(compare_tracefile(user_data, value) != 0);
+  }
+  g_assert(ltt_time_compare(test_time, tfc->timestamp) <= 0);
+  test_time.tv_sec = tfc->timestamp.tv_sec;
+  test_time.tv_nsec = tfc->timestamp.tv_nsec;
+
+  
+  //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
+  return FALSE;
+}
+#endif //DEBUG
+
 
 
 void lttv_process_traceset_begin(LttvTracesetContext *self,
@@ -596,22 +681,28 @@ void lttv_process_traceset_begin(LttvTracesetContext *self,
   
 }
 
+//enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
+
 /* Note : a _middle must be preceded from a _seek or another middle */
 guint lttv_process_traceset_middle(LttvTracesetContext *self,
                               LttTime end,
-                              unsigned nb_events,
+                              guint nb_events,
                               const LttvTracesetContextPosition *end_position)
 {
   GTree *pqueue = self->pqueue;
 
-  guint id;
-
   LttvTracefileContext *tfc;
 
-  LttEvent *event;
-
+  LttEvent *e;
+  
   unsigned count = 0;
 
+  guint read_ret;
+
+  //enum read_state last_read_state = LAST_NONE;
+
+  gint last_ret = 0; /* return value of the last hook list called */
+
   /* Get the next event from the pqueue, call its hooks, 
      reinsert in the pqueue the following event from the same tracefile 
      unless the tracefile is finished or the event is later than the 
@@ -620,9 +711,9 @@ guint lttv_process_traceset_middle(LttvTracesetContext *self,
   while(TRUE) {
     tfc = NULL;
     g_tree_foreach(pqueue, get_first, &tfc);
-    if(tfc == NULL)
+    /* End of traceset : tfc is NULL */
+    if(unlikely(tfc == NULL))
     {
-      self->e = event;
       return count;
     }
 
@@ -634,34 +725,81 @@ guint lttv_process_traceset_middle(LttvTracesetContext *self,
      * break the loop.
      */
 
-    if(count >= nb_events ||
-       lttv_traceset_context_ctx_pos_compare(self,
-                                             end_position) >= 0 ||
-       ltt_time_compare(tfc->timestamp, end) >= 0)
+    if(unlikely(last_ret == TRUE ||
+                ((count >= nb_events) && (nb_events != G_MAXULONG)) ||
+     (end_position!=NULL&&lttv_traceset_context_ctx_pos_compare(self,
+                                                          end_position) == 0)||
+       ltt_time_compare(end, tfc->timestamp) <= 0))
     {
-      self->e = event;
       return count;
     }
-
+    
     /* Get the tracefile with an event for the smallest time found. If two
        or more tracefiles have events for the same time, hope that lookup
        and remove are consistent. */
-
+#ifdef DEBUG
+    test_time.tv_sec = 0;
+    test_time.tv_nsec = 0;
+    g_debug("test tree before remove");
+    g_tree_foreach(pqueue, test_tree, tfc);
+#endif //DEBUG
     g_tree_remove(pqueue, tfc);
-    count++;
 
-    id = ltt_event_eventtype_id(tfc->e);
-    lttv_hooks_call_merge(tfc->event, tfc,
-                        lttv_hooks_by_id_get(tfc->event_by_id, id), tfc);
-
-    event = ltt_tracefile_read(tfc->tf);
-    if(event != NULL) {
-      tfc->e = event;
-      tfc->timestamp = ltt_event_time(event);
-      if(tfc->timestamp.tv_sec < end.tv_sec ||
-                 (tfc->timestamp.tv_sec == end.tv_sec &&
-                tfc->timestamp.tv_nsec <= end.tv_nsec))
-             g_tree_insert(pqueue, tfc, tfc);
+#ifdef DEBUG
+    test_time.tv_sec = 0;
+    test_time.tv_nsec = 0;
+    g_debug("test tree after remove");
+    g_tree_foreach(pqueue, test_tree, tfc);
+#endif //DEBUG
+
+
+    e = ltt_tracefile_get_event(tfc->tf);
+
+    //if(last_read_state != LAST_EMPTY) {
+    /* Only call hooks if the last read has given an event or if we are at the
+     * first pass (not if last read returned end of tracefile) */
+    count++;
+    
+    tfc->target_pid = -1; /* unset target PID */
+    /* Hooks : 
+     * return values : 0 : continue read, 1 : go to next position and stop read,
+     * 2 : stay at the current position and stop read */
+    last_ret = lttv_hooks_call_merge(tfc->event, tfc,
+                        lttv_hooks_by_id_get(tfc->event_by_id, e->event_id), tfc);
+
+#if 0
+    /* This is buggy : it won't work well with state computation */
+   if(unlikely(last_ret == 2)) {
+      /* This is a case where we want to stay at this position and stop read. */
+           g_tree_insert(pqueue, tfc, tfc);
+      return count - 1;
+    }
+#endif //0
+    read_ret = ltt_tracefile_read(tfc->tf);
+    
+   
+    if(likely(!read_ret)) {
+      //g_debug("An event is ready");
+      tfc->timestamp = ltt_event_time(e);
+      g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
+           g_tree_insert(pqueue, tfc, tfc);
+#ifdef DEBUG
+      test_time.tv_sec = 0;
+      test_time.tv_nsec = 0;
+      g_debug("test tree after event ready");
+      g_tree_foreach(pqueue, test_tree, NULL);
+#endif //DEBUG
+
+      //last_read_state = LAST_OK;
+    } else {
+      tfc->timestamp = ltt_time_infinite;
+
+      if(read_ret == ERANGE) {
+      //  last_read_state = LAST_EMPTY;
+        g_debug("End of trace");
+      } else
+        g_error("Error happened in lttv_process_traceset_middle");
     }
   }
 }
@@ -684,27 +822,49 @@ void lttv_process_traceset_end(LttvTracesetContext *self,
                                      event_by_id);
 }
 
+/* Subtile modification : 
+ * if tracefile has no event at or after the time requested, it is not put in
+ * the queue, as the next read would fail.
+ *
+ * Don't forget to empty the traceset pqueue before calling this.
+ */
 void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
 {
   guint i, nb_tracefile;
 
-  LttvTracefileContext *tfc;
+  gint ret;
+  
+  LttvTracefileContext **tfc;
 
-  LttEvent *event;
+  nb_tracefile = self->tracefiles->len;
 
-  nb_tracefile = ltt_trace_control_tracefile_number(self->t) +
-      ltt_trace_per_cpu_tracefile_number(self->t);
+  GTree *pqueue = self->ts_context->pqueue;
 
   for(i = 0 ; i < nb_tracefile ; i++) {
-    tfc = self->tracefiles[i];
-    ltt_tracefile_seek_time(tfc->tf, start);
-    event = ltt_tracefile_read(tfc->tf);
-    tfc->e = event;
-    if(event != NULL) {
-      tfc->timestamp = ltt_event_time(event);
-      g_tree_insert(self->ts_context->pqueue, tfc, tfc);
+    tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
+
+    g_tree_remove(pqueue, *tfc);
+    
+    ret = ltt_tracefile_seek_time((*tfc)->tf, start);
+    if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
+
+    if(ret == 0) { /* not ERANGE especially */
+      (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
+      g_assert(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0);
+      g_tree_insert(pqueue, (*tfc), (*tfc));
+    } else {
+      (*tfc)->timestamp = ltt_time_infinite;
     }
   }
+#ifdef DEBUG
+  test_time.tv_sec = 0;
+  test_time.tv_nsec = 0;
+  g_debug("test tree after seek_time");
+  g_tree_foreach(pqueue, test_tree, NULL);
+#endif //DEBUG
+
+
+
 }
 
 
@@ -714,16 +874,8 @@ void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
 
   LttvTraceContext *tc;
 
-  LttvTracefileContext *tfc;
-
-  /* Empty the pqueue */
-
-  while(TRUE){
-    tfc = NULL;
-    g_tree_foreach(self->pqueue, get_first, &tfc);
-    if(tfc == NULL) break;
-    g_tree_remove(self->pqueue, &(tfc->timestamp));
-  }
+  //g_tree_destroy(self->pqueue);
+  //self->pqueue = g_tree_new(compare_tracefile);
 
   nb_trace = lttv_traceset_number(self->ts);
   for(i = 0 ; i < nb_trace ; i++) {
@@ -733,246 +885,733 @@ void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
 }
 
 
-gboolean lttv_process_trace_seek_position(LttvTraceContext *self, 
-                                        const LttvTraceContextPosition *pos)
+gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self, 
+                                        const LttvTracesetContextPosition *pos)
 {
-  guint i, nb_tracefile;
+  guint i;
+   /* If a position is set, seek the traceset to this position */
+  if(ltt_time_compare(pos->timestamp, ltt_time_infinite) != 0) {
+
+    /* Test to see if the traces has been added to the trace set :
+     * It should NEVER happen. Clear all positions if a new trace comes in. */
+    /* FIXME I know this test is not optimal : should keep a number of
+     * tracefiles variable in the traceset.. eventually */
+    guint num_traces = lttv_traceset_number(self->ts);
+    guint tf_count = 0;
+    for(i=0; i<num_traces;i++) {
+      GArray * tracefiles = self->traces[i]->tracefiles;
+      guint j;
+      guint num_tracefiles = tracefiles->len;
+      for(j=0;j<num_tracefiles;j++)
+        tf_count++;
+    }
+    g_assert(tf_count == pos->tfcp->len);
+     
 
-  LttvTracefileContext *tfc;
+    //g_tree_destroy(self->pqueue);
+    //self->pqueue = g_tree_new(compare_tracefile);
+    
+    for(i=0;i<pos->tfcp->len; i++) {
+      LttvTracefileContextPosition *tfcp = 
+        &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
 
-  LttEvent *event;
+      g_tree_remove(self->pqueue, tfcp->tfc);
+      
+      if(tfcp->used == TRUE) {
+        if(ltt_tracefile_seek_position(tfcp->tfc->tf, tfcp->event) != 0)
+          return 1;
+        tfcp->tfc->timestamp =
+          ltt_event_time(ltt_tracefile_get_event(tfcp->tfc->tf));
+        g_assert(ltt_time_compare(tfcp->tfc->timestamp,
+                                  ltt_time_infinite) != 0);
+        g_tree_insert(self->pqueue, tfcp->tfc, tfcp->tfc);
+
+      } else {
+        tfcp->tfc->timestamp = ltt_time_infinite;
+      }
+    }
+  }
+#ifdef DEBUG
+  test_time.tv_sec = 0;
+  test_time.tv_nsec = 0;
+  g_debug("test tree after seek_position");
+  g_tree_foreach(self->pqueue, test_tree, NULL);
+#endif //DEBUG
 
-  nb_tracefile = ltt_trace_control_tracefile_number(self->t) +
-      ltt_trace_per_cpu_tracefile_number(self->t);
 
-  if(nb_tracefile != pos->nb_tracefile)
-    return FALSE; /* Error */
 
-  for(i = 0 ; i < nb_tracefile ; i++) {
-    tfc = self->tracefiles[i];
-    ltt_tracefile_seek_position(tfc->tf, pos->tf_pos[i]);
-    event = ltt_tracefile_read(tfc->tf);
-    tfc->e = event;
-    if(event != NULL) {
-      tfc->timestamp = ltt_event_time(event);
-      g_tree_insert(self->ts_context->pqueue, tfc, tfc);
-    }
+  return 0;
+}
+
+
+#if 0 // pmf: temporary disable
+static LttField *
+find_field(LttEventType *et, const GQuark field)
+{
+  LttField *f;
+
+  if(field == 0) return NULL;
+  
+  f = ltt_eventtype_field_by_name(et, field);
+  if (!f) {
+    g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field),
+       g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et))),
+       g_quark_to_string(ltt_eventtype_name(et)));
   }
 
-  return TRUE;
+  return f;
 }
+#endif
 
+struct marker_info *lttv_trace_hook_get_marker(LttTrace *t, LttvTraceHook *th)
+{
+  return marker_get_info_from_id(t, th->id);
+}
 
 
-gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self, 
-                                        const LttvTracesetContextPosition *pos)
+int lttv_trace_find_hook(LttTrace *t, GQuark marker_name,
+    GQuark fields[], LttvHook h, gpointer hook_data, GArray **trace_hooks)
 {
-  guint i, nb_trace;
-  gboolean sum_ret = TRUE;
+  struct marker_info *info;
+  struct marker_field *field;
+  guint16 marker_id;
+  int init_array_size;
+
+  info = marker_get_info_from_name(t, marker_name);
+  if(unlikely(info == NULL)) {
+    return NULL;
+  }
 
-  LttvTraceContext *tc;
+  init_array_size = (*trace_hooks)->len;
+
+  /* for each marker with the requested name */
+  do {
+    LttvTraceHook tmpth;
+    int found;
+    GQuark f;
+
+    marker_id = marker_get_id_from_info(t, info);
+
+    tmpth.h = h;
+    tmpth.id = marker_id;
+    tmpth.hook_data = hook_data;
+    tmpth.fields = g_ptr_array_new();
+
+    /* for each field requested */
+    for(f = fields; *f != 0; f++) {
+      found = 0;
+      for_each_marker_field(marker_field, info) {
+        if(marker_fieldfield->name == *f) {
+          found = 1;
+          g_ptr_array_add(tmpth.fields, marker_field);
+          break;
+        }
+      }
+      if(!found) {
+        /* Did not find the one of the fields in this instance of the
+           marker. Print a warning and skip this marker completely.
+          Still iterate on other markers with same name. */
+        g_ptr_array_free(tmpth.fields, TRUE);
+        g_warning("Field %s cannot be found in marker %s",
+                g_quark_to_string(*f), g_quark_to_string(marker_name));
+        goto skip_marker;
+      }
+    }
+    /* all fields were found: add the tracehook to the array */
+    *trace_hooks = g_array_append_val(*trace_hooks, tmpth);
+skip_marker:
+    info = info->next;
+  } while(info != NULL);
+
+  /* Error if no new trace hook has been added */
+  return (init_array_size == (*trace_hooks)->len);
+}
 
-  LttvTracefileContext *tfc;
+void lttv_trace_hook_destroy(GArray **th)
+{
+  int i;
+  for(i=0; i<th->len; i++) {
+    g_ptr_array_free(g_array_index(th, LttvTraceHook, i).fields, TRUE);
+  }
+  *th = g_array_remove_range(*th, 0, th->len);
+}
 
-  nb_trace = lttv_traceset_number(self->ts);
+LttvTracesetContextPosition *lttv_traceset_context_position_new(
+                                        const LttvTracesetContext *self)
+{
+  guint num_traces = lttv_traceset_number(self->ts);
+  guint tf_count = 0;
+  guint i;
   
-  if(nb_trace != pos->nb_trace)
-    return FALSE; /* Error */
+  for(i=0; i<num_traces;i++) {
+    GArray * tracefiles = self->traces[i]->tracefiles;
+    guint j;
+    guint num_tracefiles = tracefiles->len;
+    for(j=0;j<num_tracefiles;j++)
+      tf_count++;
+  }
+  LttvTracesetContextPosition *pos =
+          g_new(LttvTracesetContextPosition, 1);
+  pos->tfcp = g_array_sized_new(FALSE, TRUE,
+                                sizeof(LttvTracefileContextPosition),
+                                tf_count);
+  g_array_set_size(pos->tfcp, tf_count);
+  for(i=0;i<pos->tfcp->len;i++) {
+    LttvTracefileContextPosition *tfcp = 
+      &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
+    tfcp->event = ltt_event_position_new();
+  }
 
-  /* Empty the pqueue */
+  pos->timestamp = ltt_time_infinite;
+  return pos;
+}
 
-  while(TRUE){
-    tfc = NULL;
-    g_tree_foreach(self->pqueue, get_first, &tfc);
-    if(tfc == NULL) break;
-    g_tree_remove(self->pqueue, &(tfc->timestamp));
-  }
+/* Save all positions, the ones with infinite time will have NULL
+ * ep. */
+/* note : a position must be destroyed when a trace is added/removed from a
+ * traceset */
+void lttv_traceset_context_position_save(const LttvTracesetContext *self,
+                                    LttvTracesetContextPosition *pos)
+{
+  guint i;
+  guint num_traces = lttv_traceset_number(self->ts);
+  guint tf_count = 0;
+  
+  pos->timestamp = ltt_time_infinite;
+  
+  for(i=0; i<num_traces;i++) {
+    GArray * tracefiles = self->traces[i]->tracefiles;
+    guint j;
+    guint num_tracefiles = tracefiles->len;
+
+    for(j=0;j<num_tracefiles;j++) {
+      g_assert(tf_count < pos->tfcp->len);
+      LttvTracefileContext **tfc = &g_array_index(tracefiles,
+          LttvTracefileContext*, j);
+      LttvTracefileContextPosition *tfcp = 
+        &g_array_index(pos->tfcp, LttvTracefileContextPosition, tf_count);
+
+      tfcp->tfc = *tfc;
+
+      if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) {
+        LttEvent *event = ltt_tracefile_get_event((*tfc)->tf);
+        ltt_event_position(event, tfcp->event);
+        if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0)
+          pos->timestamp = (*tfc)->timestamp;
+        tfcp->used = TRUE;
+      } else {
+        tfcp->used = FALSE;
+      }
+      
+      //g_array_append_val(pos->tfc, *tfc);
+      //g_array_append_val(pos->ep, ep);
+      tf_count++;
+    }
 
-  for(i = 0 ; i < nb_trace ; i++) {
-    tc = self->traces[i];
-    sum_ret = sum_ret && lttv_process_trace_seek_position(tc, &pos->t_pos[i]);
   }
-
-  return sum_ret;
 }
 
+void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
+{
+  int i;
+  
+  for(i=0;i<pos->tfcp->len;i++) {
+    LttvTracefileContextPosition *tfcp = 
+      &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
+    g_free(tfcp->event);
+    tfcp->event = NULL;
+    tfcp->used = FALSE;
+  }
+  g_array_free(pos->tfcp, TRUE);
+  g_free(pos);
+}
 
+void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
+                                   const LttvTracesetContextPosition *src)
+{
+  int i;
+  LttvTracefileContextPosition *src_tfcp, *dest_tfcp;
+  
+  g_assert(src->tfcp->len == src->tfcp->len);
+  
+  for(i=0;i<src->tfcp->len;i++) {
+    src_tfcp = 
+      &g_array_index(src->tfcp, LttvTracefileContextPosition, i);
+    dest_tfcp = 
+      &g_array_index(dest->tfcp, LttvTracefileContextPosition, i);
+    
+    dest_tfcp->used = src_tfcp->used;
+    dest_tfcp->tfc = src_tfcp->tfc;
+
+    if(src_tfcp->used) {
+      ltt_event_position_copy(
+          dest_tfcp->event,
+          src_tfcp->event);
+    }
+  }
+  dest->timestamp = src->timestamp;
+}
 
-static LttField *
-find_field(LttEventType *et, const char *field)
+gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
+                                        const LttvTracesetContextPosition *pos)
 {
-  LttType *t;
+  int i;
+  int ret = 0;
+  
+  if(pos->tfcp->len == 0) {
+    if(lttv_traceset_number(self->ts) == 0) return 0;
+    else return 1;
+  }
+  if(lttv_traceset_number(self->ts) == 0)
+    return -1;
+  
+  for(i=0;i<pos->tfcp->len;i++) {
+    LttvTracefileContextPosition *tfcp = 
+      &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
+    
+    if(tfcp->used == FALSE) {
+      if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) < 0) {
+        ret = -1;
+      }
+    } else {
+      if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) == 0) {
+        ret = 1;
+      } else {
+        LttEvent *event = ltt_tracefile_get_event(tfcp->tfc->tf);
+
+        ret = ltt_event_position_compare((LttEventPosition*)event, 
+                                          tfcp->event);
+      }
+    }
+    if(ret != 0) return ret;
 
-  LttField *f;
+  }
+  return 0;
+}
 
-  guint i, nb;
 
-  char *name;
+gint lttv_traceset_context_pos_pos_compare(
+                                  const LttvTracesetContextPosition *pos1,
+                                  const LttvTracesetContextPosition *pos2)
+{
+  int i, j;
+  int ret = 0;
+  
+  if(ltt_time_compare(pos1->timestamp, ltt_time_infinite) == 0) {
+    if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0)
+      return 0;
+    else 
+      return 1;
+  }
+  if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0)
+    return -1;
+  
+  for(i=0;i<pos1->tfcp->len;i++) {
+    LttvTracefileContextPosition *tfcp1 = 
+      &g_array_index(pos1->tfcp, LttvTracefileContextPosition, i);
+    
+    if(tfcp1->used == TRUE) {
+      for(j=0;j<pos2->tfcp->len;j++) {
+        LttvTracefileContextPosition *tfcp2 = 
+          &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
+
+        if(tfcp1->tfc == tfcp2->tfc) {
+          if(tfcp2->used == TRUE)
+            ret = ltt_event_position_compare(tfcp1->event, tfcp2->event);
+          else
+            ret = -1;
+
+          if(ret != 0) return ret;
+        }
+      }
 
-  if(field == NULL) return NULL;
+    } else {
+      for(j=0;j<pos2->tfcp->len;j++) {
+        LttvTracefileContextPosition *tfcp2 = 
+          &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
 
-  f = ltt_eventtype_field(et);
-  t = ltt_eventtype_type(et);
-  g_assert(ltt_type_class(t) == LTT_STRUCT);
-  nb = ltt_type_member_number(t);
-  for(i = 0 ; i < nb ; i++) {
-    ltt_type_member_type(t, i, &name);
-    if(strcmp(name, field) == 0) break;
+        if(tfcp1->tfc == tfcp2->tfc)
+          if(tfcp2->used == TRUE) ret = 1;
+        if(ret != 0) return ret;
+      }
+    }
   }
-  g_assert(i < nb);
-  return ltt_field_member(f, i);
+  return 0;
 }
 
 
-void 
-lttv_trace_find_hook(LttTrace *t, char *facility, char *event_type, 
-    char *field1, char *field2, char *field3, LttvHook h, LttvTraceHook *th)
+LttTime lttv_traceset_context_position_get_time(
+                                  const LttvTracesetContextPosition *pos)
 {
-  LttFacility *f;
+  return pos->timestamp;
+}
 
-  LttEventType *et;
 
-  guint nb, pos, i;
+LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
+{
+  GTree *pqueue = self->pqueue;
+  LttvTracefileContext *tfc = NULL;
 
-  char *name;
+  g_tree_foreach(pqueue, get_first, &tfc);
 
-  nb = ltt_trace_facility_find(t, facility, &pos);
-  if(nb < 1) g_error("No %s facility", facility);
-  f = ltt_trace_facility_get(t, pos);
-  et = ltt_facility_eventtype_get_by_name(f, event_type);
-  if(et == NULL) g_error("Event %s does not exist", event_type);
+  return tfc;
+}
 
-  th->h = h;
-  th->id = ltt_eventtype_id(et);
-  th->f1 = find_field(et, field1);
-  th->f2 = find_field(et, field2);
-  th->f3 = find_field(et, field3);
+/* lttv_process_traceset_synchronize_tracefiles
+ *
+ * Use the sync_position field of the trace set context to synchronize each
+ * tracefile with the previously saved position.
+ *
+ * If no previous position has been saved, it simply does nothing.
+ */
+void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext *tsc)
+{
+  g_assert(lttv_process_traceset_seek_position(tsc, tsc->sync_position) == 0);
 }
 
 
-void lttv_traceset_context_position_save(const LttvTracesetContext *self,
-                                    LttvTracesetContextPosition *pos)
+
+
+void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc)
 {
-  guint nb_trace, nb_tracefile;
-  guint iter_trace, iter_tracefile;
-  
-  LttvTraceContext *tc;
-  
-  LttvTracefileContext *tfc;
+  lttv_traceset_context_position_save(tsc, tsc->sync_position);
+}
 
-  LttEvent *event;
+struct seek_back_data {
+  guint first_event;   /* Index of the first event in the array : we will always
+                         overwrite at this position : this is a circular array. 
+                       */
+  guint events_found;
+  guint n;             /* number of events requested */
+  GPtrArray *array; /* array of LttvTracesetContextPositions pointers */
+  LttvFilter *filter1;
+  LttvFilter *filter2;
+  LttvFilter *filter3;
+  gpointer data;
+  check_handler *check;
+  gboolean *stop_flag;
+  guint raw_event_count;
+};
 
-  pos->nb_trace = nb_trace = lttv_traceset_number(self->ts);
-  pos->t_pos = g_new(LttvTraceContextPosition, nb_trace);
-  
-  for(iter_trace = 0 ; iter_trace < nb_trace ; iter_trace++) {
-    tc = self->traces[iter_trace];
-    pos->t_pos[iter_trace].nb_tracefile = nb_tracefile =
-                    ltt_trace_control_tracefile_number(tc->t) +
-                    ltt_trace_per_cpu_tracefile_number(tc->t);
-
-    pos->t_pos[iter_trace].tf_pos = g_new(LttEventPosition*, nb_tracefile);
-    for(iter_tracefile = 0; iter_tracefile < nb_tracefile; iter_tracefile++) {
-      pos->t_pos[iter_trace].tf_pos[iter_tracefile] 
-                                                = ltt_event_position_new();
-      tfc = tc->tracefiles[iter_tracefile];
-      event = tfc->e;
-      ltt_event_position(event, 
-                         pos->t_pos[iter_trace].tf_pos[iter_tracefile]);
-    }
+static gint seek_back_event_hook(void *hook_data, void* call_data)
+{
+  struct seek_back_data *sd = (struct seek_back_data*)hook_data;
+  LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
+  LttvTracesetContext *tsc = tfc->t_context->ts_context;
+  LttvTracesetContextPosition *pos;
+
+  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;
+  }
+
+  pos = (LttvTracesetContextPosition*)g_ptr_array_index (sd->array,
+                                                         sd->first_event);
+
+  lttv_traceset_context_position_save(tsc, pos);
+
+  if(sd->first_event >= sd->array->len - 1) sd->first_event = 0;
+  else sd->first_event++;
+
+  sd->events_found = min(sd->n, sd->events_found + 1);
+
+  return FALSE;
 }
 
-void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
+/* Seek back n events back from the current position.
+ *
+ * Parameters :
+ * @self          The trace set context
+ * @n             number of events to jump over
+ * @first_offset  The initial offset value used.
+ *                never put first_offset at ltt_time_zero.
+ * @time_seeker   Function pointer of the function to use to seek time :
+ *                either lttv_process_traceset_seek_time
+ *                    or lttv_state_traceset_seek_time_closest
+ * @filter        The filter to call.
+ *
+ * Return value : the number of events found (might be lower than the number
+ * requested if beginning of traceset is reached).
+ *
+ * The first search will go back first_offset and try to find the last n events
+ * matching the filter. If there are not enough, it will try to go back from the
+ * new trace point from first_offset*2, and so on, until beginning of trace or n
+ * events are found.
+ *
+ * Note : this function does not take in account the LttvFilter : use the
+ * similar function found in state.c instead.
+ *
+ * Note2 : the caller must make sure that the LttvTracesetContext does not
+ * contain any hook, as process_traceset_middle is used in this routine.
+ */
+guint lttv_process_traceset_seek_n_backward(LttvTracesetContext *self,
+                                            guint n, LttTime first_offset,
+                                            seek_time_fct time_seeker,
+                                            check_handler *check,
+                                            gboolean *stop_flag,
+                                           LttvFilter *filter1,
+                                           LttvFilter *filter2,
+                                           LttvFilter *filter3,
+                                           gpointer data)
 {
-  guint nb_trace, nb_tracefile;
-  guint iter_trace, iter_tracefile;
+  if(lttv_traceset_number(self->ts) == 0) return 0;
+  g_assert(ltt_time_compare(first_offset, ltt_time_zero) != 0);
   
-  nb_trace = pos->nb_trace;
+  guint i;
+  LttvTracesetContextPosition *next_iter_end_pos =
+                                lttv_traceset_context_position_new(self);
+  LttvTracesetContextPosition *end_pos =
+    lttv_traceset_context_position_new(self);
+  LttvTracesetContextPosition *saved_pos =
+    lttv_traceset_context_position_new(self);
+  LttTime time;
+  LttTime asked_time;
+  LttTime time_offset;
+  struct seek_back_data sd;
+  LttvHooks *hooks = lttv_hooks_new();
   
-  for(iter_trace = 0 ; iter_trace < nb_trace ; iter_trace++) {
-    for(iter_tracefile = 0; iter_tracefile < 
-                        pos->t_pos[iter_trace].nb_tracefile;
-                        iter_tracefile++) {
-      
-      g_free(pos->t_pos[iter_trace].tf_pos[iter_tracefile]);
+  sd.first_event = 0;
+  sd.events_found = 0;
+  sd.array = g_ptr_array_sized_new(n);
+  sd.filter1 = filter1;
+  sd.filter2 = filter2;
+  sd.filter3 = filter3;
+  sd.data = data;
+  sd.n = n;
+  sd.check = check;
+  sd.stop_flag = stop_flag;
+  sd.raw_event_count = 0;
+  g_ptr_array_set_size(sd.array, n);
+  for(i=0;i<n;i++) {
+    g_ptr_array_index (sd.array, i) = lttv_traceset_context_position_new(self);
+  }
+  lttv_traceset_context_position_save(self, next_iter_end_pos);
+  lttv_traceset_context_position_save(self, saved_pos);
+  /* Get the current time from which we will offset */
+  time = lttv_traceset_context_position_get_time(next_iter_end_pos);
+  /* the position saved might be end of traceset... */
+  if(ltt_time_compare(time, self->time_span.end_time) > 0) {
+    time = self->time_span.end_time;
+  }
+  asked_time = time;
+  time_offset = first_offset;
+  lttv_hooks_add(hooks, seek_back_event_hook, &sd, LTTV_PRIO_DEFAULT);
+  
+  lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
+
+  while(1) {
+    /* stop criteria : - n events found
+     *                 - asked_time < beginning of trace */
+    if(ltt_time_compare(asked_time, self->time_span.start_time) < 0) break;
+
+    lttv_traceset_context_position_copy(end_pos, next_iter_end_pos);
+
+    /* We must seek the traceset back to time - time_offset */
+    /* this time becomes the new reference time */
+    time = ltt_time_sub(time, time_offset);
+    asked_time = time;
+    
+    time_seeker(self, time);
+    lttv_traceset_context_position_save(self, next_iter_end_pos);
+    /* Resync the time in case of a seek_closest */
+    time = lttv_traceset_context_position_get_time(next_iter_end_pos);
+    if(ltt_time_compare(time, self->time_span.end_time) > 0) {
+      time = self->time_span.end_time;
     }
-    g_free(pos->t_pos[iter_trace].tf_pos);
+
+    /* Process the traceset, calling a hook which adds events 
+     * to the array, overwriting the tail. It changes first_event and
+     * events_found too. */
+    /* We would like to have a clean context here : no other hook than our's */
+    
+    lttv_process_traceset_middle(self, ltt_time_infinite,
+        G_MAXUINT, end_pos);
+
+    if(sd.events_found < n) {
+      if(sd.first_event > 0) {
+        /* Save the first position */
+        LttvTracesetContextPosition *pos =
+          (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, 0);
+        lttv_traceset_context_position_copy(saved_pos, pos);
+      }
+      g_assert(n-sd.events_found <= sd.array->len);
+      /* Change array size to n - events_found */
+      for(i=n-sd.events_found;i<sd.array->len;i++) {
+        LttvTracesetContextPosition *pos =
+          (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
+        lttv_traceset_context_position_destroy(pos);
+      }
+      g_ptr_array_set_size(sd.array, n-sd.events_found);
+      sd.first_event = 0;
+      
+    } else break; /* Second end criterion : n events found */
+    
+    time_offset = ltt_time_mul(time_offset, BACKWARD_SEEK_MUL);
+  }
+  
+  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_free(pos->t_pos);
+  g_ptr_array_free(sd.array, TRUE);
 
-}
+  lttv_hooks_destroy(hooks);
 
-gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
-                                        const LttvTracesetContextPosition *pos)
-{
-  guint nb_trace, nb_tracefile;
-  guint iter_trace, iter_tracefile;
-  gint ret;
+  lttv_traceset_context_position_destroy(saved_pos);
 
-  LttvTraceContext *tc;
-  
-  LttvTracefileContext *tfc;
+  return sd.events_found;
+}
 
-  LttEvent *event;
 
-  nb_trace = lttv_traceset_number(self->ts);
+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 */
+};
 
-  if(pos->nb_trace != nb_trace)
-    g_error("lttv_traceset_context_ctx_pos_compare : nb_trace does not match.");
-  
-  for(iter_trace = 0 ; iter_trace < nb_trace ; iter_trace++) {
-    tc = self->traces[iter_trace];
-    nb_tracefile =  ltt_trace_control_tracefile_number(tc->t) +
-                    ltt_trace_per_cpu_tracefile_number(tc->t);
-
-    if(pos->t_pos[iter_trace].nb_tracefile != nb_tracefile)
-      g_error("lttv_traceset_context_ctx_pos_compare : nb_tracefile does not match.");
-
-    for(iter_tracefile = 0; iter_tracefile < nb_tracefile; iter_tracefile++) {
-      tfc = tc->tracefiles[iter_tracefile];
-      event = tfc->e;
-      if(
-          ret =
-            ltt_event_event_position_compare(event, 
-                            pos->t_pos[iter_trace].tf_pos[iter_tracefile])
-          != 0)
-        return ret;
-    }
+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;
   }
-  return 0;
-}
 
+  sd->event_count++;
+  if(sd->event_count >= sd->n)
+      return TRUE;
+}
 
-gint lttv_traceset_context_pos_pos_compare(
-                                  const LttvTracesetContextPosition *pos1,
-                                  const LttvTracesetContextPosition *pos2)
+/* 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)
 {
-  guint nb_trace, nb_tracefile;
-  guint iter_trace, iter_tracefile;
+  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;
   
-  gint ret;
+  if(sd.event_count >= sd.n) return sd.event_count;
+  
+  LttvHooks *hooks = lttv_hooks_new();
 
-  nb_trace = pos1->nb_trace;
-  if(nb_trace != pos2->nb_trace)
-    g_error("lttv_traceset_context_pos_pos_compare : nb_trace does not match.");
+  lttv_hooks_add(hooks, seek_forward_event_hook, &sd, LTTV_PRIO_DEFAULT);
 
-  for(iter_trace = 0 ; iter_trace < nb_trace ; iter_trace++) {
+  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);
 
-    nb_tracefile = pos1->t_pos[iter_trace].nb_tracefile;
-    if(nb_tracefile != pos2->t_pos[iter_trace].nb_tracefile)
-      g_error("lttv_traceset_context_ctx_pos_compare : nb_tracefile does not match.");
+  /* 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. */
 
-    for(iter_tracefile = 0; iter_tracefile < nb_tracefile; iter_tracefile++) {
-      if(ret = 
-          ltt_event_position_compare(
-                pos1->t_pos[iter_trace].tf_pos[iter_tracefile],
-                pos2->t_pos[iter_trace].tf_pos[iter_tracefile])
-          != 0)
-        return ret;
-    }
-  }
-  return 0;
+  lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
+
+  lttv_hooks_destroy(hooks);
+
+  return sd.event_count;
 }
 
 
This page took 0.038688 seconds and 4 git commands to generate.