fix trace_find_hook
[lttv.git] / ltt / branches / poly / lttv / lttv / tracecontext.c
index 7e757ba7662b90afb33a34fc0a613dde4e06cd25..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 = 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;
+}
+
+typedef struct _LttvTracefileContextPosition {
+  LttEventPosition *event;
+  LttvTracefileContext *tfc;
+  gboolean used; /* Tells if the tfc is at end of traceset position */
+} LttvTracefileContextPosition;
+
+
+struct _LttvTracesetContextPosition {
+  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)
 {
@@ -60,18 +104,17 @@ lttv_context_new_tracefile_context(LttvTracesetContext *self)
 /****************************************************************************
  * lttv_traceset_context_compute_time_span
  *
- * Keep the Time_Span is sync with on the fly addition and removal of traces
+ * Keep the time span is sync with on the fly addition and removal of traces
  * in a trace set. It must be called each time a trace is added/removed from
  * the traceset. It could be more efficient to call it only once a bunch
  * of traces are loaded, but the calculation is not long, so it's not
  * critical.
  *
  * Author : Xang Xiu Yang
- * Imported from gtkTraceSet.c by Mathieu Desnoyers
  ***************************************************************************/
 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);
@@ -80,50 +123,70 @@ 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;
   self->traces = g_new(LttvTraceContext *, nb_trace);
-  self->before = lttv_hooks_new();
-  self->after = lttv_hooks_new();
   self->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
   self->ts_a = lttv_traceset_attribute(ts);
   for(i = 0 ; i < nb_trace ; i++) {
@@ -134,11 +197,22 @@ init(LttvTracesetContext *self, LttvTraceset *ts)
     tc->index = i;
     tc->vt = lttv_traceset_get(ts, i);
     tc->t = lttv_trace(tc->vt);
-    tc->check = lttv_hooks_new();
-    tc->before = lttv_hooks_new();
-    tc->after = lttv_hooks_new();
     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;
@@ -157,23 +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->check = lttv_hooks_new();
-      tfc->before = lttv_hooks_new();
-      tfc->after = lttv_hooks_new();
-      tfc->check_event = lttv_hooks_new();
-      tfc->before_event = lttv_hooks_new();
-      tfc->before_event_by_id = lttv_hooks_by_id_new();
-      tfc->after_event = lttv_hooks_new();
-      tfc->after_event_by_id = lttv_hooks_by_id_new();
+      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);
     }
+#endif //0
+
   }
-  lttv_process_traceset_seek_time(self, null_time);
-  /*CHECK why dynamically allocate the time span... and the casing is wroNg*/
-  self->Time_Span = g_new(TimeInterval,1);
-  lttv_traceset_context_compute_time_span(self, self->Time_Span);
-  self->e = NULL;
+  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);
+
 }
 
 
@@ -183,44 +255,31 @@ void fini(LttvTracesetContext *self)
 
   LttvTraceContext *tc;
 
-  LttvTracefileContext *tfc;
+  LttvTracefileContext **tfc;
 
   LttvTraceset *ts = self->ts;
 
-  g_free(self->Time_Span);
-
-  lttv_hooks_destroy(self->before);
-  lttv_hooks_destroy(self->after);
-  //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);
 
   for(i = 0 ; i < nb_trace ; i++) {
     tc = self->traces[i];
 
-    lttv_hooks_destroy(tc->check);
-    lttv_hooks_destroy(tc->before);
-    lttv_hooks_destroy(tc->after);
     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->check);
-      lttv_hooks_destroy(tfc->before);
-      lttv_hooks_destroy(tfc->after);
-      lttv_hooks_destroy(tfc->check_event);
-      lttv_hooks_destroy(tfc->before_event);
-      lttv_hooks_by_id_destroy(tfc->before_event_by_id);
-      lttv_hooks_destroy(tfc->after_event);
-      lttv_hooks_by_id_destroy(tfc->after_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);
@@ -228,169 +287,168 @@ void fini(LttvTracesetContext *self)
 
 
 void lttv_traceset_context_add_hooks(LttvTracesetContext *self,
-    LttvHooks *before_traceset, 
-    LttvHooks *after_traceset,
-    LttvHooks *check_trace, 
+    LttvHooks *before_traceset,
     LttvHooks *before_trace, 
-    LttvHooks *after_trace, 
-    LttvHooks *check_tracefile,
     LttvHooks *before_tracefile,
-    LttvHooks *after_tracefile,
-    LttvHooks *check_event, 
-    LttvHooks *before_event, 
-    LttvHooks *after_event)
+    LttvHooks *event,
+    LttvHooksById *event_by_id)
 {
   LttvTraceset *ts = self->ts;
 
-  guint i, j, nb_trace, nb_tracefile;
+  guint i, nb_trace;
 
   LttvTraceContext *tc;
 
-  LttvTracefileContext *tfc;
-
-  void *hook_data;
+  lttv_hooks_call(before_traceset, self);
 
-  lttv_hooks_add_list(self->before, before_traceset);
-  lttv_hooks_add_list(self->after, after_traceset);
   nb_trace = lttv_traceset_number(ts);
 
   for(i = 0 ; i < nb_trace ; i++) {
     tc = self->traces[i];
-    lttv_hooks_add_list(tc->check, check_trace);
-    lttv_hooks_add_list(tc->before, before_trace);
-    lttv_hooks_add_list(tc->after, after_trace);
-    nb_tracefile = ltt_trace_control_tracefile_number(tc->t) +
-        ltt_trace_per_cpu_tracefile_number(tc->t);
-
-    for(j = 0 ; j < nb_tracefile ; j++) {
-      tfc = tc->tracefiles[j];
-      lttv_hooks_add_list(tfc->check, check_tracefile);
-      lttv_hooks_add_list(tfc->before, before_tracefile);
-      lttv_hooks_add_list(tfc->after, after_tracefile);
-      lttv_hooks_add_list(tfc->check_event, check_event);
-      lttv_hooks_add_list(tfc->before_event, before_event);
-      lttv_hooks_add_list(tfc->after_event, after_event);
-    }
+    lttv_trace_context_add_hooks(tc,
+                                 before_trace,
+                                 before_tracefile,
+                                 event,
+                                 event_by_id);
   }
 }
 
 
 void lttv_traceset_context_remove_hooks(LttvTracesetContext *self,
-    LttvHooks *before_traceset, 
     LttvHooks *after_traceset,
-    LttvHooks *check_trace, 
-    LttvHooks *before_trace, 
     LttvHooks *after_trace, 
-    LttvHooks *check_tracefile,
-    LttvHooks *before_tracefile,
     LttvHooks *after_tracefile,
-    LttvHooks *check_event, 
-    LttvHooks *before_event, 
-    LttvHooks *after_event)
+    LttvHooks *event, 
+    LttvHooksById *event_by_id)
 {
+
   LttvTraceset *ts = self->ts;
 
-  guint i, j, nb_trace, nb_tracefile;
+  guint i, nb_trace;
 
   LttvTraceContext *tc;
 
-  LttvTracefileContext *tfc;
-
-  void *hook_data;
-
-  lttv_hooks_remove_list(self->before, before_traceset);
-  lttv_hooks_remove_list(self->after, after_traceset);
   nb_trace = lttv_traceset_number(ts);
 
   for(i = 0 ; i < nb_trace ; i++) {
     tc = self->traces[i];
-    lttv_hooks_remove_list(tc->check, check_trace);
-    lttv_hooks_remove_list(tc->before, before_trace);
-    lttv_hooks_remove_list(tc->after, after_trace);
-    nb_tracefile = ltt_trace_control_tracefile_number(tc->t) +
-        ltt_trace_per_cpu_tracefile_number(tc->t);
-
-    for(j = 0 ; j < nb_tracefile ; j++) {
-      tfc = tc->tracefiles[j];
-      lttv_hooks_remove_list(tfc->check, check_tracefile);
-      lttv_hooks_remove_list(tfc->before, before_tracefile);
-      lttv_hooks_remove_list(tfc->after, after_tracefile);
-      lttv_hooks_remove_list(tfc->check_event, check_event);
-      lttv_hooks_remove_list(tfc->before_event, before_event);
-      lttv_hooks_remove_list(tfc->after_event, after_event);
-    }
+    lttv_trace_context_remove_hooks(tc,
+                                    after_trace,
+                                    after_tracefile,
+                                    event,
+                                    event_by_id);
   }
+
+  lttv_hooks_call(after_traceset, self);
+
+
 }
 
-void lttv_trace_context_add_hooks(LttvTraceContext *tc,
-                                 LttvHooks *check_trace, 
-                                 LttvHooks *before_trace, 
-                                 LttvHooks *after_trace)
+void lttv_trace_context_add_hooks(LttvTraceContext *self,
+    LttvHooks *before_trace, 
+    LttvHooks *before_tracefile,
+    LttvHooks *event, 
+    LttvHooksById *event_by_id)
 {
-  lttv_hooks_add_list(tc->check, check_trace);
-  lttv_hooks_add_list(tc->before, before_trace);
-  lttv_hooks_add_list(tc->after, after_trace);
+  guint i, nb_tracefile;
+
+  LttvTracefileContext **tfc;
+
+  lttv_hooks_call(before_trace, self);
+
+  nb_tracefile = self->tracefiles->len;
+
+  for(i = 0 ; i < nb_tracefile ; i++) {
+    tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
+    lttv_tracefile_context_add_hooks(*tfc,
+                                     before_tracefile,
+                                     event,
+                                     event_by_id);
+  }
 }
 
-void lttv_trace_context_remove_hooks(LttvTraceContext *tc,
-                                    LttvHooks *check_trace, 
-                                    LttvHooks *before_trace, 
-                                    LttvHooks *after_trace)
+
+
+void lttv_trace_context_remove_hooks(LttvTraceContext *self,
+    LttvHooks *after_trace, 
+    LttvHooks *after_tracefile,
+    LttvHooks *event, 
+    LttvHooksById *event_by_id)
 {
-  lttv_hooks_remove_list(tc->check, check_trace);
-  lttv_hooks_remove_list(tc->before, before_trace);
-  lttv_hooks_remove_list(tc->after, after_trace);
+  guint i, nb_tracefile;
+
+  LttvTracefileContext **tfc;
+
+  nb_tracefile = self->tracefiles->len;
+
+  for(i = 0 ; i < nb_tracefile ; i++) {
+    tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
+    lttv_tracefile_context_remove_hooks(*tfc,
+                                        after_tracefile,
+                                        event,
+                                        event_by_id);
+  }
+
+  lttv_hooks_call(after_trace, self);
 }
 
-void lttv_tracefile_context_add_hooks(LttvTracefileContext *tfc,
-                                     LttvHooks *check_tracefile,
-                                     LttvHooks *before_tracefile,
-                                     LttvHooks *after_tracefile,
-                                     LttvHooks *check_event, 
-                                     LttvHooks *before_event, 
-                                     LttvHooks *after_event)
+void lttv_tracefile_context_add_hooks(LttvTracefileContext *self,
+          LttvHooks *before_tracefile,
+          LttvHooks *event, 
+          LttvHooksById *event_by_id)
 {
-  lttv_hooks_add_list(tfc->check, check_tracefile);
-  lttv_hooks_add_list(tfc->before, before_tracefile);
-  lttv_hooks_add_list(tfc->after, after_tracefile);
-  lttv_hooks_add_list(tfc->check_event, check_event);
-  lttv_hooks_add_list(tfc->before_event, before_event);
-  lttv_hooks_add_list(tfc->after_event, after_event);
+  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 < 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 *tfc,
-                                        LttvHooks *check_tracefile,
-                                        LttvHooks *before_tracefile,
-                                        LttvHooks *after_tracefile,
-                                        LttvHooks *check_event, 
-                                        LttvHooks *before_event, 
-                                        LttvHooks *after_event)
+void lttv_tracefile_context_remove_hooks(LttvTracefileContext *self,
+           LttvHooks *after_tracefile,
+           LttvHooks *event, 
+           LttvHooksById *event_by_id)
 {
-  lttv_hooks_remove_list(tfc->check, check_tracefile);
-  lttv_hooks_remove_list(tfc->before, before_tracefile);
-  lttv_hooks_remove_list(tfc->after, after_tracefile);
-  lttv_hooks_remove_list(tfc->check_event, check_event);
-  lttv_hooks_remove_list(tfc->before_event, before_event);
-  lttv_hooks_remove_list(tfc->after_event, after_event);
+  guint i, index;
+
+  LttvHooks *hook;
+  
+  lttv_hooks_remove_list(self->event, event);
+  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);
 }
 
+
+
 void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext *tfc,
                                            unsigned i,
-                                           LttvHooks *before_event_by_id, 
-                                           LttvHooks *after_event_by_id)
+                                           LttvHooks *event_by_id)
 {
   LttvHooks * h;
-  h = lttv_hooks_by_id_find(tfc->before_event_by_id, i);
-  lttv_hooks_add_list(h, before_event_by_id);
-  h = lttv_hooks_by_id_find(tfc->after_event_by_id, i);
-  lttv_hooks_add_list(h, after_event_by_id);
+  h = lttv_hooks_by_id_find(tfc->event_by_id, i);
+  lttv_hooks_add_list(h, event_by_id);
 }
 
 void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext *tfc,
                                               unsigned i)
 {
-  lttv_hooks_by_id_remove(tfc->before_event_by_id, i);
-  lttv_hooks_by_id_remove(tfc->after_event_by_id, i);
+  lttv_hooks_by_id_remove(tfc->event_by_id, i);
 }
 
 static LttvTracesetContext *
@@ -457,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", 
@@ -505,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", 
@@ -553,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", 
@@ -563,286 +624,994 @@ lttv_tracefile_context_get_type(void)
 }
 
 
-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);
-}
-
-
-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;
 
-void lttv_process_traceset_begin(LttvTracesetContext *self, LttTime end)
-{
-  guint i, j, nbi, nb_tracefile;
-
-  LttvTraceContext *tc;
+static gboolean test_tree(gpointer key, gpointer value, gpointer user_data) {
 
-  LttvTracefileContext *tfc;
+  LttvTracefileContext *tfc = (LttvTracefileContext *)key;
 
-  /* Call all before_traceset, before_trace, and before_tracefile hooks.
-     For all qualifying tracefiles, seek to the start time, create a context,
-     read one event and insert in the pqueue based on the event time. */
-
-  lttv_hooks_call(self->before, self);
-  nbi = lttv_traceset_number(self->ts);
-  self->pqueue = g_tree_new(compare_tracefile);
+  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;
 
-  for(i = 0 ; i < nbi ; i++) {
-    tc = self->traces[i];
+  
+  //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
+  return FALSE;
+}
+#endif //DEBUG
 
-    if(!lttv_hooks_call_check(tc->check, tc)) {
-      lttv_hooks_call(tc->before, tc);
-      nb_tracefile = ltt_trace_control_tracefile_number(tc->t) +
-          ltt_trace_per_cpu_tracefile_number(tc->t);
 
-      for(j = 0 ; j < nb_tracefile ; j++) {
-        tfc = tc->tracefiles[j];
 
-        if(!lttv_hooks_call_check(tfc->check, tfc)) {
-          lttv_hooks_call(tfc->before, tfc);
+void lttv_process_traceset_begin(LttvTracesetContext *self,
+                                 LttvHooks       *before_traceset,
+                                 LttvHooks       *before_trace,
+                                 LttvHooks       *before_tracefile,
+                                 LttvHooks       *event,
+                                 LttvHooksById   *event_by_id)
+{
 
-          if(tfc->e != NULL) {
-           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(self->pqueue, tfc, tfc);
-           }
-          }
-        }
-      }
-    }
-  }
+  /* simply add hooks in context. _before hooks are called by add_hooks. */
+  /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
+  lttv_traceset_context_add_hooks(self,
+                                  before_traceset,
+                                  before_trace,
+                                  before_tracefile,
+                                  event,
+                                  event_by_id);
+  
 }
 
+//enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
 
-guint lttv_process_traceset_middle(LttvTracesetContext *self, LttTime end, 
-    unsigned nb_events)
+/* Note : a _middle must be preceded from a _seek or another middle */
+guint lttv_process_traceset_middle(LttvTracesetContext *self,
+                              LttTime end,
+                              guint nb_events,
+                              const LttvTracesetContextPosition *end_position)
 {
   GTree *pqueue = self->pqueue;
 
-  guint id;
-
-  LttvTraceContext *tc;
-
   LttvTracefileContext *tfc;
 
-  LttEvent *event;
-
+  LttEvent *e;
+  
   unsigned count = 0;
 
-  LttTime previous_timestamp = {0, 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 
-     start time. */
+     end time. */
 
   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;
     }
 
-    /* Have we reached the maximum number of events specified? However,
-       continue for all the events with the same time stamp (CHECK?). Then,
-       empty the queue and break from the loop. */
-
-    if(count >= nb_events && 
-        ltt_time_compare(tfc->timestamp, previous_timestamp) != 0) 
+    /* Have we reached :
+     * - the maximum number of events specified?
+     * - the end position ?
+     * - the end time ?
+     * then the read is finished. We leave the queue in the same state and
+     * break the loop.
+     */
+
+    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;
     }
-
-    previous_timestamp = tfc->timestamp;
-
-
+    
     /* 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++;
 
-    if(!lttv_hooks_call(tfc->check_event, tfc)) {
-      id = ltt_event_eventtype_id(tfc->e);
-      lttv_hooks_call(lttv_hooks_by_id_get(tfc->before_event_by_id, id), tfc);
-      lttv_hooks_call(tfc->before_event, tfc);
-      lttv_hooks_call(lttv_hooks_by_id_get(tfc->after_event_by_id, id), tfc);
-      lttv_hooks_call(tfc->after_event, 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");
     }
+  }
+}
+
+
+void lttv_process_traceset_end(LttvTracesetContext *self,
+                               LttvHooks           *after_traceset,
+                               LttvHooks           *after_trace,
+                               LttvHooks           *after_tracefile,
+                               LttvHooks           *event,
+                               LttvHooksById       *event_by_id)
+{
+  /* Remove hooks from context. _after hooks are called by remove_hooks. */
+  /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
+  lttv_traceset_context_remove_hooks(self,
+                                     after_traceset,
+                                     after_trace,
+                                     after_tracefile,
+                                     event,
+                                     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;
+
+  gint ret;
+  
+  LttvTracefileContext **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);
+  nb_tracefile = self->tracefiles->len;
+
+  GTree *pqueue = self->ts_context->pqueue;
+
+  for(i = 0 ; i < nb_tracefile ; i++) {
+    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
+
+
+
 }
 
 
-void lttv_process_traceset_end(LttvTracesetContext *self)
+void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
 {
-  guint i, j, nbi, nb_tracefile;
+  guint i, nb_trace;
 
   LttvTraceContext *tc;
 
-  LttvTracefileContext *tfc;
+  //g_tree_destroy(self->pqueue);
+  //self->pqueue = g_tree_new(compare_tracefile);
 
-  /* Call all after_traceset, after_trace, and after_tracefile hooks. */
+  nb_trace = lttv_traceset_number(self->ts);
+  for(i = 0 ; i < nb_trace ; i++) {
+    tc = self->traces[i];
+    lttv_process_trace_seek_time(tc, start);
+  }
+}
 
-  nbi = lttv_traceset_number(self->ts);
 
-  for(i = 0 ; i < nbi ; i++) {
-    tc = self->traces[i];
+gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self, 
+                                        const LttvTracesetContextPosition *pos)
+{
+  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);
+     
+
+    //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);
+
+      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
+
+
+
+  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)));
+  }
 
-    /* The check hooks are called again to avoid memorizing the results
-       obtained at the beginning. CHECK if it poses a problem */
+  return f;
+}
+#endif
 
-    if(!lttv_hooks_call_check(tc->check, tc)) {
-      nb_tracefile = ltt_trace_control_tracefile_number(tc->t) +
-          ltt_trace_per_cpu_tracefile_number(tc->t);
+struct marker_info *lttv_trace_hook_get_marker(LttTrace *t, LttvTraceHook *th)
+{
+  return marker_get_info_from_id(t, th->id);
+}
 
-      for(j = 0 ; j < nb_tracefile ; j++) {
-        tfc = tc->tracefiles[j];
 
-        if(!lttv_hooks_call_check(tfc->check, tfc)) {
-          lttv_hooks_call(tfc->after, tfc);
+int lttv_trace_find_hook(LttTrace *t, GQuark marker_name,
+    GQuark fields[], LttvHook h, gpointer hook_data, GArray **trace_hooks)
+{
+  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;
+  }
+
+  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;
         }
       }
-      lttv_hooks_call(tc->after, tc);
+      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;
+      }
     }
-  }
-  lttv_hooks_call(self->after, self);
+    /* 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);
+}
 
-  /* Empty and free the pqueue */
+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);
+}
 
-  while(TRUE){
-    tfc = NULL;
-    g_tree_foreach(self->pqueue, get_first, &tfc);
-    if(tfc == NULL) break;
-    g_tree_remove(self->pqueue, &(tfc->timestamp));
+LttvTracesetContextPosition *lttv_traceset_context_position_new(
+                                        const LttvTracesetContext *self)
+{
+  guint num_traces = lttv_traceset_number(self->ts);
+  guint tf_count = 0;
+  guint i;
+  
+  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_tree_destroy(self->pqueue);
+  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();
+  }
+
+  pos->timestamp = ltt_time_infinite;
+  return pos;
 }
 
+/* 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++;
+    }
 
-void lttv_process_traceset(LttvTracesetContext *self, LttTime end, 
-    unsigned nb_events)
+  }
+}
+
+void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
 {
-  lttv_process_traceset_begin(self, end);
-  lttv_process_traceset_middle(self, end, nb_events);
-  lttv_process_traceset_end(self);
+  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;
+}
 
-void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
+gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
+                                        const LttvTracesetContextPosition *pos)
 {
-  guint i, nb_tracefile;
+  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;
+
+  }
+  return 0;
+}
 
-  LttvTracefileContext *tfc;
 
-  LttEvent *event;
+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;
+        }
+      }
 
-  nb_tracefile = ltt_trace_control_tracefile_number(self->t) +
-      ltt_trace_per_cpu_tracefile_number(self->t);
+    } else {
+      for(j=0;j<pos2->tfcp->len;j++) {
+        LttvTracefileContextPosition *tfcp2 = 
+          &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
 
-  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);
+        if(tfcp1->tfc == tfcp2->tfc)
+          if(tfcp2->used == TRUE) ret = 1;
+        if(ret != 0) return ret;
+      }
+    }
   }
+  return 0;
 }
 
 
-void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
+LttTime lttv_traceset_context_position_get_time(
+                                  const LttvTracesetContextPosition *pos)
 {
-  guint i, nb_trace;
+  return pos->timestamp;
+}
 
-  LttvTraceContext *tc;
 
-  nb_trace = lttv_traceset_number(self->ts);
-  for(i = 0 ; i < nb_trace ; i++) {
-    tc = self->traces[i];
-    lttv_process_trace_seek_time(tc, start);
-  }
+LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
+{
+  GTree *pqueue = self->pqueue;
+  LttvTracefileContext *tfc = NULL;
+
+  g_tree_foreach(pqueue, get_first, &tfc);
+
+  return tfc;
+}
+
+/* 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);
 }
 
 
-static LttField *
-find_field(LttEventType *et, const char *field)
+
+
+void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc)
 {
-  LttType *t;
+  lttv_traceset_context_position_save(tsc, tsc->sync_position);
+}
 
-  LttField *f;
+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;
+};
+
+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++;
 
-  guint i, nb;
+  sd->events_found = min(sd->n, sd->events_found + 1);
 
-  char *name;
+  return FALSE;
+}
 
-  if(field == NULL) return NULL;
+/* 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)
+{
+  if(lttv_traceset_number(self->ts) == 0) return 0;
+  g_assert(ltt_time_compare(first_offset, ltt_time_zero) != 0);
+  
+  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();
+  
+  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;
+    }
 
-  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;
+    /* 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);
   }
-  g_assert(i < nb);
-  return ltt_field_member(f, i);
+  
+  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;
 }
 
 
-void 
-lttv_trace_find_hook(LttTrace *t, char *facility, char *event_type, 
-    char *field1, char *field2, char *field3, LttvHook h, LttvTraceHook *th)
+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)
 {
-  LttFacility *f;
+  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;
+  }
 
-  LttEventType *et;
+  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);
 
-  guint nb, pos, i;
+  /* 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. */
 
-  char *name;
+  lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
 
-  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);
+  lttv_hooks_destroy(hooks);
 
-  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);
+  return sd.event_count;
 }
 
 
This page took 0.041099 seconds and 4 git commands to generate.