correct statedump end
[lttv.git] / ltt / branches / poly / lttv / lttv / state.c
index 914ab728b86cc032185a0d4464568b933a0fc03d..6dd2663f10bd49d1fd51ad1bab614e3ca30b97ac 100644 (file)
@@ -70,6 +70,7 @@ GQuark
     LTT_EVENT_FREE,
     LTT_EVENT_EXEC,
     LTT_EVENT_ENUM_PROCESS_STATE,
+    LTT_EVENT_STATEDUMP_END,
     LTT_EVENT_FUNCTION_ENTRY,
     LTT_EVENT_FUNCTION_EXIT,
     LTT_EVENT_THREAD_BRAND;
@@ -342,6 +343,7 @@ state_load_saved_states(LttvTraceState *tcs)
   } while(1);
 
   fclose(fp);
+
   // saved_states : open, test
   strncpy(path, trace_path, PATH_MAX-1);
   count = strnlen(trace_path, PATH_MAX-1);
@@ -782,8 +784,13 @@ static void read_process_state_raw(LttvTraceState *self, FILE *fp,
     /* We must link to the parent */
     parent_process = lttv_state_find_process_or_create(self, ANY_CPU, tmp.ppid,
         &ltt_time_zero);
-    process = lttv_state_find_process_or_create(self, tmp.cpu, tmp.pid,
-        &tmp.creation_time);
+    process = lttv_state_find_process(self, ANY_CPU, tmp.pid);
+    if(process == NULL) {
+      process = lttv_state_create_process(self, parent_process, tmp.cpu,
+      tmp.pid, tmp.tgid,
+      g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name)),
+          &tmp.creation_time);
+    }
   }
   process->insertion_time = tmp.insertion_time;
   process->creation_time = tmp.creation_time;
@@ -796,6 +803,7 @@ static void read_process_state_raw(LttvTraceState *self, FILE *fp,
   process->name = 
     g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name));
 
+
   do {
     if(feof(fp) || ferror(fp)) goto end_loop;
 
@@ -809,6 +817,7 @@ static void read_process_state_raw(LttvTraceState *self, FILE *fp,
                            process->execution_stack->len + 1);
         es = &g_array_index(process->execution_stack, LttvExecutionState,
                 process->execution_stack->len-1);
+        process->state = es;
 
         fread(&es->t, sizeof(es->t), 1, fp);
         es->t = g_quark_from_string(
@@ -864,6 +873,7 @@ void lttv_state_read_raw(LttvTraceState *self, FILE *fp, GPtrArray *quarktable)
   LttvAttribute *saved_states_tree, *saved_state_tree;
 
   LttvAttributeValue value;
+  GTree *pqueue = self->parent.ts_context->pqueue;
   ep = ltt_event_position_new();
   
   restore_init_state(self);
@@ -920,6 +930,7 @@ end_loop:
   //  fprintf(fp, "  <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu", 
   //      tfcs->parent.timestamp.tv_sec, 
   //      tfcs->parent.timestamp.tv_nsec);
+    g_tree_remove(pqueue, &tfcs->parent);
     hdr = fgetc(fp);
     g_assert(hdr == HDR_TRACEFILE);
     fread(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
@@ -932,6 +943,7 @@ end_loop:
       ltt_event_position_set(ep, tfcs->parent.tf, nb_block, offset, tsc);
       gint ret = ltt_tracefile_seek_position(tfcs->parent.tf, ep);
       g_assert(ret == 0);
+      g_tree_insert(pqueue, &tfcs->parent, &tfcs->parent);
     }
   }
   g_free(ep);
@@ -949,6 +961,7 @@ end_loop:
     t.tv_nsec);
 
   *(self->max_time_state_recomputed_in_seek) = t;
+
 }
 
 /* Called when a HDR_TRACE is found */
@@ -987,8 +1000,10 @@ void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
     };
   } while(1);
 end_loop:
-
   *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
+  restore_init_state(tcs);
+  lttv_process_trace_seek_time(tcs, ltt_time_zero);
+  return;
 }
 
 
@@ -1788,7 +1803,10 @@ lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
                 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
     /* We are not sure is it's a kernel thread or normal thread, put the
       * bottom stack state to unknown */
-    es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
+    process->execution_stack = 
+      g_array_set_size(process->execution_stack, 1);
+    process->state = es =
+      &g_array_index(process->execution_stack, LttvExecutionState, 0);
     es->t = LTTV_STATE_MODE_UNKNOWN;
   }
   return process;
@@ -2332,6 +2350,64 @@ static gboolean thread_brand(void *hook_data, void *call_data)
   return FALSE;
 }
 
+static void fix_process(gpointer key, gpointer value,
+   gpointer user_data)
+{
+  LttvProcessState *process;
+  LttvExecutionState *es;
+  process = (LttvProcessState *)value;
+  LttvTracefileContext *tfc = (LttvTracefileContext *)user_data;
+  LttTime *timestamp = (LttTime*)user_data;
+
+printf("%s %s\n", g_quark_to_string(process->type), g_quark_to_string(process->state->t));
+
+  if(process->type == LTTV_STATE_KERNEL_THREAD) {
+    if(process->state->t == LTTV_STATE_MODE_UNKNOWN) {
+      process->state->t = LTTV_STATE_SYSCALL;
+      process->state->s = LTTV_STATE_WAIT;
+      process->state->n = LTTV_STATE_SUBMODE_NONE;
+    }
+  } else {
+    if(process->state->t == LTTV_STATE_MODE_UNKNOWN) {
+      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;
+      es->n = LTTV_STATE_SUBMODE_NONE;
+      es->entry = *timestamp;
+      //g_assert(timestamp->tv_sec != 0);
+      es->change = *timestamp;
+      es->cum_cpu_time = ltt_time_zero;
+      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->cum_cpu_time = ltt_time_zero;
+      es->s = LTTV_STATE_WAIT;
+    }
+  }
+}
+
+static gboolean statedump_end(void *hook_data, void *call_data)
+{
+  LttvTracefileState *s = (LttvTracefileState *)call_data;
+  LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
+  LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+  LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
+  LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
+  
+  /* For all processes */
+    /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
+    /* else, if stack[0] is unknown, set to user mode, running */
+
+  g_hash_table_foreach(ts->processes, fix_process, &tfc->timestamp);
+}
+
 static gboolean enum_process_state(void *hook_data, void *call_data)
 {
   LttvTracefileState *s = (LttvTracefileState *)call_data;
@@ -2399,20 +2475,50 @@ static gboolean enum_process_state(void *hook_data, void *call_data)
     /* Keep the stack bottom : a running user mode */
     /* Disabled because of inconsistencies in the current statedump states. */
     if(type == LTTV_STATE_KERNEL_THREAD) {
-      /* Only keep the bottom */
+      /* Only keep the bottom 
+       * FIXME Kernel thread : can be in syscall or interrupt or trap. */
+      /* Will cause expected trap when in fact being syscall (even after end of
+       * statedump event)
+       * Will cause expected interrupt when being syscall. (only before end of
+       * statedump event) */
+      // This will cause a "popping last state on stack, ignoring it."
       process->execution_stack = g_array_set_size(process->execution_stack, 1);
       es = process->state = &g_array_index(process->execution_stack, 
           LttvExecutionState, 0);
+      process->type = LTTV_STATE_KERNEL_THREAD;
+      es->t = LTTV_STATE_MODE_UNKNOWN;
+      es->s = LTTV_STATE_UNNAMED;
+      es->n = LTTV_STATE_SUBMODE_UNKNOWN;
+#if 0
       es->t = LTTV_STATE_SYSCALL;
       es->s = status;
       es->n = submode;
+#endif //0
     } else {
-      /* On top of it : */
+      /* User space process :
+       * bottom : user mode
+       * either currently running or scheduled out.
+       * can be scheduled out because interrupted in (user mode or in syscall)
+       * or because of an explicit call to the scheduler in syscall. Note that
+       * the scheduler call comes after the irq_exit, so never in interrupt
+       * context. */
+      // temp workaround : set size to 1 : only have user mode bottom of stack.
+      // will cause g_info message of expected syscall mode when in fact being
+      // in user mode. Can also cause expected trap when in fact being user
+      // mode in the event of a page fault reenabling interrupts in the handler.
+      // Expected syscall and trap can also happen after the end of statedump
+      // This will cause a "popping last state on stack, ignoring it."
+      process->execution_stack = g_array_set_size(process->execution_stack, 1);
       es = process->state = &g_array_index(process->execution_stack, 
-          LttvExecutionState, 1);
+          LttvExecutionState, 0);
+      es->t = LTTV_STATE_MODE_UNKNOWN;
+      es->s = LTTV_STATE_UNNAMED;
+      es->n = LTTV_STATE_SUBMODE_UNKNOWN;
+#if 0
       es->t = LTTV_STATE_USER_MODE;
       es->s = status;
       es->n = submode;
+#endif //0
     }
 #if 0
     /* UNKNOWN STATE */
@@ -2433,7 +2539,8 @@ static gboolean enum_process_state(void *hook_data, void *call_data)
     process->ppid = parent_pid;
     process->tgid = tgid;
     process->name = g_quark_from_string(command);
-    es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
+    es =
+      &g_array_index(process->execution_stack, LttvExecutionState, 0);
     if(type != LTTV_STATE_KERNEL_THREAD)
       es->t = LTTV_STATE_USER_MODE;
     /* Don't mess around with the stack, it will eventually become
@@ -2477,13 +2584,11 @@ void lttv_state_add_event_hooks(LttvTracesetState *self)
   for(i = 0 ; i < nb_trace ; i++) {
     ts = (LttvTraceState *)self->parent.traces[i];
 
-    if(ts->has_precomputed_states) continue;
-
     /* Find the eventtype id for the following events and register the
        associated by id hooks. */
 
-    hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 18);
-    hooks = g_array_set_size(hooks, 18); // Max possible number of hooks.
+    hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 19);
+    hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
     hn = 0;
 
     ret = lttv_trace_find_hook(ts->parent.t,
@@ -2584,6 +2689,12 @@ void lttv_state_add_event_hooks(LttvTracesetState *self)
         enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
     if(ret) hn--;
 
+    ret = lttv_trace_find_hook(ts->parent.t,
+        LTT_FACILITY_STATEDUMP, LTT_EVENT_STATEDUMP_END,
+        0, 0, 0,
+        statedump_end, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
+    if(ret) hn--;
+
     ret = lttv_trace_find_hook(ts->parent.t,
         LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
         LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
@@ -2655,8 +2766,6 @@ void lttv_state_remove_event_hooks(LttvTracesetState *self)
   for(i = 0 ; i < nb_trace ; i++) {
     ts = LTTV_TRACE_STATE(self->parent.traces[i]);
 
-    if(ts->has_precomputed_states) continue;
-
     lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
     hooks = *(val.v_pointer);
 
@@ -2880,6 +2989,8 @@ void lttv_state_save_add_event_hooks(LttvTracesetState *self)
     ts = (LttvTraceState *)self->parent.traces[i];
     nb_tracefile = ts->parent.tracefiles->len;
 
+    if(ts->has_precomputed_states) continue;
+
     guint *event_count = g_new(guint, 1);
     *event_count = 0;
 
@@ -2977,6 +3088,8 @@ void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
     ts = (LttvTraceState *)self->parent.traces[i];
     nb_tracefile = ts->parent.tracefiles->len;
 
+    if(ts->has_precomputed_states) continue;
+
     guint *event_count = NULL;
 
     for(j = 0 ; j < nb_tracefile ; j++) {
@@ -3288,6 +3401,7 @@ static void module_init()
   LTT_EVENT_FREE          = g_quark_from_string("free");
   LTT_EVENT_EXEC          = g_quark_from_string("exec");
   LTT_EVENT_ENUM_PROCESS_STATE  = g_quark_from_string("enumerate_process_state");
+  LTT_EVENT_STATEDUMP_END  = g_quark_from_string("statedump_end");
   LTT_EVENT_FUNCTION_ENTRY  = g_quark_from_string("function_entry");
   LTT_EVENT_FUNCTION_EXIT  = g_quark_from_string("function_exit");
   LTT_EVENT_THREAD_BRAND  = g_quark_from_string("thread_brand");
This page took 0.026331 seconds and 4 git commands to generate.