update compat
[lttv.git] / ltt / branches / poly / lttv / lttv / state.c
index dee43252eaf4ddd1eb6c3eb838cb07e71c7c9d58..18518e87f557fcb5636df6c17fdf9c6c65a3051d 100644 (file)
@@ -35,6 +35,7 @@
 
 GQuark
     LTT_FACILITY_KERNEL,
+    LTT_FACILITY_KERNEL_ARCH,
     LTT_FACILITY_PROCESS,
     LTT_FACILITY_FS;
 
@@ -47,6 +48,8 @@ GQuark
     LTT_EVENT_TRAP_EXIT,
     LTT_EVENT_IRQ_ENTRY,
     LTT_EVENT_IRQ_EXIT,
+    LTT_EVENT_SOFT_IRQ_ENTRY,
+    LTT_EVENT_SOFT_IRQ_EXIT,
     LTT_EVENT_SCHEDCHANGE,
     LTT_EVENT_FORK,
     LTT_EVENT_EXIT,
@@ -59,6 +62,7 @@ GQuark
     LTT_FIELD_SYSCALL_ID,
     LTT_FIELD_TRAP_ID,
     LTT_FIELD_IRQ_ID,
+    LTT_FIELD_SOFT_IRQ_ID,
     LTT_FIELD_OUT,
     LTT_FIELD_IN,
     LTT_FIELD_OUT_STATE,
@@ -72,7 +76,8 @@ LttvExecutionMode
   LTTV_STATE_USER_MODE,
   LTTV_STATE_SYSCALL,
   LTTV_STATE_TRAP,
-  LTTV_STATE_IRQ;
+  LTTV_STATE_IRQ,
+  LTTV_STATE_SOFT_IRQ;
 
 LttvExecutionSubmode
   LTTV_STATE_SUBMODE_UNKNOWN,
@@ -85,7 +90,8 @@ LttvProcessStatus
   LTTV_STATE_EXIT,
   LTTV_STATE_ZOMBIE,
   LTTV_STATE_WAIT,
-  LTTV_STATE_RUN;
+  LTTV_STATE_RUN,
+  LTTV_STATE_DEAD;
 
 static GQuark
   LTTV_STATE_TRACEFILES,
@@ -726,6 +732,7 @@ typedef struct _LttvNameTables {
   GQuark *syscall_names;
   GQuark *trap_names;
   GQuark *irq_names;
+  GQuark *soft_irq_names;
 } LttvNameTables;
 
 
@@ -767,7 +774,7 @@ create_name_tables(LttvTraceState *tcs)
   }
 #endif //0
   if(lttv_trace_find_hook(tcs->parent.t,
-      LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
+      LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
       LTT_FIELD_SYSCALL_ID, 0, 0,
       NULL, NULL, &h))
     return;
@@ -779,20 +786,17 @@ create_name_tables(LttvTraceState *tcs)
   
   lttv_trace_hook_destroy(&h);
 
-  /* CHECK syscalls should be an enum but currently are not!  
   name_tables->syscall_names = g_new(GQuark, nb);
 
   for(i = 0 ; i < nb ; i++) {
-    name_tables->syscall_names[i] = g_quark_from_string(
-        ltt_enum_string_get(t, i));
+    name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
   }
-  */
 
-  name_tables->syscall_names = g_new(GQuark, 256);
-  for(i = 0 ; i < 256 ; i++) {
-    g_string_printf(fe_name, "syscall %d", i);
-    name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
-  }
+  //name_tables->syscall_names = g_new(GQuark, 256);
+  //for(i = 0 ; i < 256 ; i++) {
+  //  g_string_printf(fe_name, "syscall %d", i);
+  //  name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
+  //}
 
   if(lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL,
         LTT_EVENT_TRAP_ENTRY,
@@ -803,7 +807,7 @@ create_name_tables(LttvTraceState *tcs)
   thf = lttv_trace_hook_get_first(&h);
 
   t = ltt_field_type(thf->f1);
-  nb = ltt_type_element_number(t);
+  //nb = ltt_type_element_number(t);
 
   lttv_trace_hook_destroy(&h);
 
@@ -830,7 +834,7 @@ create_name_tables(LttvTraceState *tcs)
   thf = lttv_trace_hook_get_first(&h);
   
   t = ltt_field_type(thf->f1);
-  nb = ltt_type_element_number(t);
+  //nb = ltt_type_element_number(t);
 
   lttv_trace_hook_destroy(&h);
 
@@ -847,6 +851,20 @@ create_name_tables(LttvTraceState *tcs)
     name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
   }
 
+  /*
+  name_tables->soft_irq_names = g_new(GQuark, nb);
+  for(i = 0 ; i < nb ; i++) {
+    name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
+  }
+  */
+
+  name_tables->soft_irq_names = g_new(GQuark, 256);
+  for(i = 0 ; i < 256 ; i++) {
+    g_string_printf(fe_name, "softirq %d", i);
+    name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
+  }
+
+
   g_string_free(fe_name, TRUE);
 }
 
@@ -866,6 +884,7 @@ get_name_tables(LttvTraceState *tcs)
   tcs->syscall_names = name_tables->syscall_names;
   tcs->trap_names = name_tables->trap_names;
   tcs->irq_names = name_tables->irq_names;
+  tcs->soft_irq_names = name_tables->soft_irq_names;
 }
 
 
@@ -885,6 +904,7 @@ free_name_tables(LttvTraceState *tcs)
   g_free(name_tables->syscall_names);
   g_free(name_tables->trap_names);
   g_free(name_tables->irq_names);
+  g_free(name_tables->soft_irq_names);
   g_free(name_tables);
 } 
 
@@ -1017,7 +1037,7 @@ lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
   //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
   process->execution_stack = g_array_sized_new(FALSE, FALSE, 
       sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
-  process->execution_stack = g_array_set_size(process->execution_stack, 1);
+  process->execution_stack = g_array_set_size(process->execution_stack, 2);
   es = process->state = &g_array_index(process->execution_stack, 
       LttvExecutionState, 0);
   es->t = LTTV_STATE_USER_MODE;
@@ -1025,6 +1045,15 @@ lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
   es->entry = *timestamp;
   //g_assert(timestamp->tv_sec != 0);
   es->change = *timestamp;
+  es->s = LTTV_STATE_RUN;
+
+  es = process->state = &g_array_index(process->execution_stack, 
+      LttvExecutionState, 1);
+  es->t = LTTV_STATE_SYSCALL;
+  es->n = LTTV_STATE_SUBMODE_NONE;
+  es->entry = *timestamp;
+  //g_assert(timestamp->tv_sec != 0);
+  es->change = *timestamp;
   es->s = LTTV_STATE_WAIT_FORK;
 
   return process;
@@ -1169,6 +1198,37 @@ static gboolean irq_exit(void *hook_data, void *call_data)
   return FALSE;
 }
 
+static gboolean soft_irq_entry(void *hook_data, void *call_data)
+{
+  LttvTracefileState *s = (LttvTracefileState *)call_data;
+  LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
+  guint8 fac_id = ltt_event_facility_id(e);
+  guint8 ev_id = ltt_event_eventtype_id(e);
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
+ // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
+  g_assert(thf->f1 != NULL);
+ // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
+  LttField *f = thf->f1;
+
+  LttvExecutionSubmode submode;
+
+  submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[
+      ltt_event_get_unsigned(e, f)];
+
+  /* Do something with the info about being in user or system mode when int? */
+  push_state(s, LTTV_STATE_SOFT_IRQ, submode);
+  return FALSE;
+}
+
+
+static gboolean soft_irq_exit(void *hook_data, void *call_data)
+{
+  LttvTracefileState *s = (LttvTracefileState *)call_data;
+
+  pop_state(s, LTTV_STATE_SOFT_IRQ);
+  return FALSE;
+}
+
 
 static gboolean schedchange(void *hook_data, void *call_data)
 {
@@ -1202,18 +1262,16 @@ static gboolean schedchange(void *hook_data, void *call_data)
 
     if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
       process->state->s = LTTV_STATE_ZOMBIE;
+      process->state->change = s->parent.timestamp;
     } else {
       if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
       else process->state->s = LTTV_STATE_WAIT;
-    } /* FIXME : we do not remove process here, because the kernel
-       * still has them : they may be zombies. We need to know
-       * exactly when release_task is executed on the PID to 
-       * know when the zombie is destroyed.
-       */
-    //else
-    //  exit_process(s, process);
-
-    process->state->change = s->parent.timestamp;
+      process->state->change = s->parent.timestamp;
+    }
+
+    if(state_out == 32)
+       exit_process(s, process); /* EXIT_DEAD */
+          /* see sched.h for states */
   }
   process = ts->running_process[cpu] =
               lttv_state_find_process_or_create(
@@ -1251,8 +1309,10 @@ static gboolean process_fork(void *hook_data, void *call_data)
 
   /* Mathieu : it seems like the process might have been scheduled in before the
    * fork, and, in a rare case, might be the current process. This might happen
-   * in a SMP case where we don't have enough precision on the clocks */
-#if 0
+   * in a SMP case where we don't have enough precision on the clocks.
+   *
+   * Test reenabled after precision fixes on time. (Mathieu) */
+#if 0 
   zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
 
   if(unlikely(zombie_process != NULL)) {
@@ -1262,7 +1322,7 @@ static gboolean process_fork(void *hook_data, void *call_data)
     guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
     guint i;
     for(i=0; i< num_cpus; i++) {
-      g_assert(process != ts->running_process[i]);
+      g_assert(zombie_process != ts->running_process[i]);
     }
 
     exit_process(s, zombie_process);
@@ -1277,10 +1337,13 @@ static gboolean process_fork(void *hook_data, void *call_data)
                               child_pid, &s->parent.timestamp);
   } else {
     /* The process has already been created :  due to time imprecision between
-     * multiple CPUs : it has been scheduled in before creation.
+     * multiple CPUs : it has been scheduled in before creation. Note that we
+     * shouldn't have this kind of imprecision.
      *
      * Simply put a correct parent.
      */
+    g_assert(0); /* This is a problematic case : the process has been created
+                    before the fork event */
     child_process->ppid = process->pid;
   }
 
@@ -1329,12 +1392,27 @@ static gboolean process_free(void *hook_data, void *call_data)
   if(likely(process != NULL)) {
     /* release_task is happening at kernel level : we can now safely release
      * the data structure of the process */
+    //This test is fun, though, as it may happen that 
+    //at time t : CPU 0 : process_free
+    //at time t+150ns : CPU 1 : schedule out
+    //Clearly due to time imprecision, we disable it. (Mathieu)
+    //If this weird case happen, we have no choice but to put the 
+    //Currently running process on the cpu to 0.
+    //I re-enable it following time precision fixes. (Mathieu)
+    //Well, in the case where an process is freed by a process on another CPU
+    //and still scheduled, it happens that this is the schedchange that will
+    //drop the last reference count. Do not free it here!
     guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
     guint i;
     for(i=0; i< num_cpus; i++) {
-      g_assert(process != ts->running_process[i]);
+      //g_assert(process != ts->running_process[i]);
+      if(process == ts->running_process[i]) {
+        //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
+        break;
+      }
     }
-    exit_process(s, process);
+    if(i == num_cpus) /* process is not scheduled */
+      exit_process(s, process);
   }
 
   return FALSE;
@@ -1347,15 +1425,22 @@ static gboolean process_exec(void *hook_data, void *call_data)
   LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
   LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
   LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
-  gchar *name;
+  //gchar *name;
   guint cpu = ltt_tracefile_num(s->parent.tf);
   LttvProcessState *process = ts->running_process[cpu];
 
   /* PID of the process to release */
-  name = ltt_event_get_string(e, thf->f1);
-
-  process->name = g_quark_from_string(name);
-
+  guint64 name_len = ltt_event_field_element_number(e, thf->f1);
+  //name = ltt_event_get_string(e, thf->f1);
+  LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
+  gchar *name_begin = 
+    (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
+  gchar *null_term_name = g_new(gchar, name_len+1);
+  memcpy(null_term_name, name_begin, name_len);
+  null_term_name[name_len] = '\0';
+
+  process->name = g_quark_from_string(null_term_name);
+  g_free(null_term_name);
   return FALSE;
 }
 
@@ -1398,17 +1483,17 @@ void lttv_state_add_event_hooks(LttvTracesetState *self)
     /* Find the eventtype id for the following events and register the
        associated by id hooks. */
 
-    hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 11);
-    hooks = g_array_set_size(hooks, 11);
+    hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 13);
+    hooks = g_array_set_size(hooks, 13);
 
     ret = lttv_trace_find_hook(ts->parent.t,
-        LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
+        LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
         LTT_FIELD_SYSCALL_ID, 0, 0,
         syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
     g_assert(!ret);
 
     ret = lttv_trace_find_hook(ts->parent.t,
-        LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_EXIT,
+        LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
         0, 0, 0,
         syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
     g_assert(!ret);
@@ -1437,34 +1522,46 @@ void lttv_state_add_event_hooks(LttvTracesetState *self)
         irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
     g_assert(!ret);
 
+    ret = lttv_trace_find_hook(ts->parent.t,
+        LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
+        LTT_FIELD_SOFT_IRQ_ID, 0, 0,
+        soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 6));
+    g_assert(!ret);
+
+    ret = lttv_trace_find_hook(ts->parent.t,
+        LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
+        0, 0, 0, 
+        soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 7));
+    g_assert(!ret);
+
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
         LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
-        schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 6));
+        schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 8));
     g_assert(!ret);
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
         LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
-        process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 7));
+        process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 9));
     g_assert(!ret);
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
         LTT_FIELD_PID, 0, 0,
-        process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 8));
+        process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 10));
     g_assert(!ret);
     
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
         LTT_FIELD_PID, 0, 0,
-        process_free, NULL, &g_array_index(hooks, LttvTraceHook, 9));
+        process_free, NULL, &g_array_index(hooks, LttvTraceHook, 11));
     g_assert(!ret);
 
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_FS, LTT_EVENT_EXEC,
         LTT_FIELD_FILENAME, 0, 0,
-        process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 10));
+        process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 12));
     g_assert(!ret);
 
 
@@ -1838,7 +1935,7 @@ void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
     ts = (LttvTraceState *)self->parent.traces[i];
     nb_tracefile = ts->parent.tracefiles->len;
 
-    guint *event_count;
+    guint *event_count = NULL;
 
     for(j = 0 ; j < nb_tracefile ; j++) {
       tfs = 
@@ -1847,7 +1944,7 @@ void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
       event_count = lttv_hooks_remove(tfs->parent.event,
                         state_save_event_hook);
     }
-    g_free(event_count);
+    if(event_count) g_free(event_count);
   }
 }
 
@@ -2097,6 +2194,7 @@ static void module_init()
   LTTV_STATE_SYSCALL = g_quark_from_string("system call");
   LTTV_STATE_TRAP = g_quark_from_string("trap");
   LTTV_STATE_IRQ = g_quark_from_string("irq");
+  LTTV_STATE_SOFT_IRQ = g_quark_from_string("softirq");
   LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
   LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
   LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
@@ -2104,6 +2202,7 @@ static void module_init()
   LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
   LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
   LTTV_STATE_RUN = g_quark_from_string("running");
+  LTTV_STATE_DEAD = g_quark_from_string("dead");
   LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
   LTTV_STATE_PROCESSES = g_quark_from_string("processes");
   LTTV_STATE_PROCESS = g_quark_from_string("process");
@@ -2119,6 +2218,7 @@ static void module_init()
 
   
   LTT_FACILITY_KERNEL     = g_quark_from_string("kernel");
+  LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
   LTT_FACILITY_PROCESS    = g_quark_from_string("process");
   LTT_FACILITY_FS    = g_quark_from_string("fs");
 
@@ -2129,6 +2229,8 @@ static void module_init()
   LTT_EVENT_TRAP_EXIT     = g_quark_from_string("trap_exit");
   LTT_EVENT_IRQ_ENTRY     = g_quark_from_string("irq_entry");
   LTT_EVENT_IRQ_EXIT      = g_quark_from_string("irq_exit");
+  LTT_EVENT_SOFT_IRQ_ENTRY     = g_quark_from_string("soft_irq_entry");
+  LTT_EVENT_SOFT_IRQ_EXIT      = g_quark_from_string("soft_irq_exit");
   LTT_EVENT_SCHEDCHANGE   = g_quark_from_string("schedchange");
   LTT_EVENT_FORK          = g_quark_from_string("fork");
   LTT_EVENT_EXIT          = g_quark_from_string("exit");
@@ -2139,6 +2241,7 @@ static void module_init()
   LTT_FIELD_SYSCALL_ID    = g_quark_from_string("syscall_id");
   LTT_FIELD_TRAP_ID       = g_quark_from_string("trap_id");
   LTT_FIELD_IRQ_ID        = g_quark_from_string("irq_id");
+  LTT_FIELD_SOFT_IRQ_ID        = g_quark_from_string("softirq_id");
   LTT_FIELD_OUT           = g_quark_from_string("out");
   LTT_FIELD_IN            = g_quark_from_string("in");
   LTT_FIELD_OUT_STATE     = g_quark_from_string("out_state");
This page took 0.027316 seconds and 4 git commands to generate.