#include <ltt/type.h>
#include <stdio.h>
+#define PREALLOCATED_EXECUTION_STACK 10
+
LttvExecutionMode
LTTV_STATE_MODE_UNKNOWN,
LTTV_STATE_USER_MODE,
LTTV_STATE_WAIT_FORK,
LTTV_STATE_WAIT_CPU,
LTTV_STATE_EXIT,
+ LTTV_STATE_ZOMBIE,
LTTV_STATE_WAIT,
LTTV_STATE_RUN;
}
-void lttv_state__state_saved_free(LttvTraceState *self,
+void lttv_state_state_saved_free(LttvTraceState *self,
LttvAttribute *container)
{
LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
guint process_hash(gconstpointer key)
{
- return ((LttvProcessState *)key)->pid;
+ guint pid = ((const LttvProcessState *)key)->pid;
+ return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
}
gboolean process_equal(gconstpointer a, gconstpointer b)
{
- LttvProcessState *process_a, *process_b;
+ const LttvProcessState *process_a, *process_b;
- process_a = (LttvProcessState *)a;
- process_b = (LttvProcessState *)b;
+ process_a = (const LttvProcessState *)a;
+ process_b = (const LttvProcessState *)b;
if(process_a->pid != process_b->pid) return FALSE;
if(process_a->pid == 0 &&
LttvTracefileState *tfcs;
- LttTime null_time = {0,0};
-
if(self->processes != NULL) lttv_state_free_process_table(self->processes);
self->processes = g_hash_table_new(process_hash, process_equal);
self->nb_event = 0;
for(i = 0 ; i < nb_tracefile ; i++) {
tfcs = LTTV_TRACEFILE_STATE(self->parent.tracefiles[i]);
- tfcs->parent.timestamp = null_time;
+ ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
tfcs->saved_position = 0;
tfcs->process = lttv_state_create_process(tfcs, NULL,0);
tfcs->process->state->s = LTTV_STATE_RUN;
tfcs->process->last_cpu = tfcs->cpu_name;
+ tfcs->process->last_cpu_index = ((LttvTracefileContext*)tfcs)->index;
}
}
static void
fini(LttvTracesetState *self)
{
- guint i, j, nb_trace;
+ guint i, nb_trace;
LttvTraceState *tcs;
tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
LTTV_UINT, &v);
+
+ g_assert(*(v.v_uint) != 0);
(*v.v_uint)--;
- g_assert(*(v.v_uint) >= 0);
if(*(v.v_uint) == 0) {
free_name_tables(tcs);
free_max_time(tcs);
process = (LttvProcessState *)value;
new_process = g_new(LttvProcessState, 1);
*new_process = *process;
- new_process->execution_stack = g_array_new(FALSE, FALSE,
- sizeof(LttvExecutionState));
+ new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
+ sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
g_array_set_size(new_process->execution_stack,process->execution_stack->len);
for(i = 0 ; i < process->execution_stack->len; i++) {
g_array_index(new_process->execution_stack, LttvExecutionState, i) =
if(*(value.v_pointer) == NULL) tfcs->parent.e = NULL;
else {
ep = *(value.v_pointer);
- lttv_process_tracefile_seek_position(tfcs->parent, ep);
+ g_assert(tfcs->parent.t_context != NULL);
+ lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs), ep);
}
}
}
tracefiles_tree = lttv_attribute_find_subdir(container,
LTTV_STATE_TRACEFILES);
+ g_object_ref(G_OBJECT(tracefiles_tree));
lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
g_assert(type == LTTV_POINTER);
if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
}
- lttv_attribute_recursive_free(tracefiles_tree);
+ g_object_unref(G_OBJECT(tracefiles_tree));
}
}
lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
- lttv_attribute_recursive_free(saved_states);
}
guint depth = process->execution_stack->len;
if(process->state->t != t){
- g_info("Different execution mode type (%d.%09d): ignore it\n",
+ g_info("Different execution mode type (%lu.%09lu): ignore it\n",
tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
g_info("process state has %s when pop_int is %s\n",
g_quark_to_string(process->state->t),
}
if(depth == 1){
- g_info("Trying to pop last state on stack (%d.%09d): ignore it\n",
+ g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
return;
}
process->pid = pid;
process->last_cpu = tfs->cpu_name;
+ process->last_cpu_index = ((LttvTracefileContext*)tfs)->index;
g_warning("Process %u, core %p", process->pid, process);
g_hash_table_insert(tcs->processes, process, process);
process->creation_time.tv_nsec);
process->pid_time = g_quark_from_string(buffer);
process->last_cpu = tfs->cpu_name;
- process->execution_stack = g_array_new(FALSE, FALSE,
- sizeof(LttvExecutionState));
+ process->last_cpu_index = ((LttvTracefileContext*)tfs)->index;
+ process->execution_stack = g_array_sized_new(FALSE, FALSE,
+ sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
g_array_set_size(process->execution_stack, 1);
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 = tfs->parent.timestamp;
+ g_assert(tfs->parent.timestamp.tv_sec != 0);
es->change = tfs->parent.timestamp;
es->s = LTTV_STATE_WAIT_FORK;
return process;
}
-
-LttvProcessState *
-lttv_state_find_process_from_trace(LttvTraceState *ts, GQuark cpu, guint pid)
+LttvProcessState *lttv_state_find_process(LttvTracefileState *tfs,
+ guint pid)
{
LttvProcessState key;
LttvProcessState *process;
+ LttvTraceState* ts = (LttvTraceState*)tfs->parent.t_context;
+
key.pid = pid;
- key.last_cpu = cpu;
+ key.last_cpu = tfs->cpu_name;
process = g_hash_table_lookup(ts->processes, &key);
return process;
}
-
-LttvProcessState *lttv_state_find_process(LttvTracefileState *tfs,
- guint pid)
-{
- LttvTraceState *ts =(LttvTraceState *)tfs->parent.t_context;
- return lttv_state_find_process_from_trace(ts, tfs->cpu_name, pid);
-}
-
-
LttvProcessState *
lttv_state_find_process_or_create(LttvTracefileState *tfs, guint pid)
{
return process;
}
-
+/* FIXME : this function should be called when we receive an event telling that
+ * release_task has been called in the kernel. In happens generally when
+ * the parent waits for its child terminaison, but may also happen in special
+ * cases in the child's exit : when the parent ignores its children SIGCCHLD or
+ * has the flag SA_NOCLDWAIT. It can also happen when the child is part
+ * of a killed thread ground, but isn't the leader.
+ */
static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
{
LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
g_assert(s->process->pid == 0);
}
- if(state_out == 0) s->process->state->s = LTTV_STATE_WAIT_CPU;
- else if(s->process->state->s == LTTV_STATE_EXIT)
- exit_process(s, s->process);
- else s->process->state->s = LTTV_STATE_WAIT;
+ if(s->process->state->s == LTTV_STATE_EXIT) {
+ s->process->state->s = LTTV_STATE_ZOMBIE;
+ } else {
+ if(state_out == 0) s->process->state->s = LTTV_STATE_WAIT_CPU;
+ else s->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, s->process);
s->process->state->change = s->parent.timestamp;
}
s->process = lttv_state_find_process_or_create(s, pid_in);
s->process->state->s = LTTV_STATE_RUN;
s->process->last_cpu = s->cpu_name;
+ s->process->last_cpu_index = ((LttvTracefileContext*)s)->index;
s->process->state->change = s->parent.timestamp;
return FALSE;
}
-static gboolean process_fork(void *hook_data, void *call_data)
+static gboolean process_fork(LttvTraceHook *trace_hook, LttvTracefileState *s)
{
- LttField *f = ((LttvTraceHook *)hook_data)->f1;
-
- LttvTracefileState *s = (LttvTracefileState *)call_data;
-
+ LttField *f;
guint child_pid;
+ LttvProcessState *zombie_process;
+ /* Child PID */
+ f = trace_hook->f2;
child_pid = ltt_event_get_unsigned(s->parent.e, f);
+
+ zombie_process = lttv_state_find_process(s, child_pid);
+
+ if(zombie_process != NULL) {
+ /* Reutilisation of PID. Only now we are sure that the old PID
+ * has been released. FIXME : sould know when release_task happens instead.
+ */
+ exit_process(s, zombie_process);
+ }
+ g_assert(s->process->pid != child_pid);
lttv_state_create_process(s, s->process, child_pid);
+
return FALSE;
}
-static gboolean process_exit(void *hook_data, void *call_data)
+static gboolean process_exit(LttvTraceHook *trace_hook, LttvTracefileState *s)
{
- LttvTracefileState *s = (LttvTracefileState *)call_data;
-
if(s->process != NULL) {
s->process->state->s = LTTV_STATE_EXIT;
}
return FALSE;
}
+gboolean process(void *hook_data, void *call_data)
+{
+ LttvTraceHook *trace_hook = (LttvTraceHook *)hook_data;
+ LttField *f = trace_hook->f1;
+
+ LttvTracefileState *s = (LttvTracefileState *)call_data;
+
+ guint sub_id = ltt_event_get_unsigned(s->parent.e, f);
+
+ /* CHECK : do not hardcode the sub_id values here ? */
+ if(sub_id == 2) {
+ return process_fork(trace_hook, s);
+ } else if(sub_id == 3) {
+ return process_exit(trace_hook, s);
+ }
+ return 0;
+}
+
+gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
+{
+ LttvTracesetState *tss = (LttvTracesetState*)(call_data);
+
+ lttv_state_add_event_hooks(tss);
+
+ return 0;
+}
void lttv_state_add_event_hooks(LttvTracesetState *self)
{
associated by id hooks. */
hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
- g_array_set_size(hooks, 9);
+ g_array_set_size(hooks, 8);
lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id",
NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0));
lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out",
"out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6));
+ lttv_trace_find_hook(ts->parent.t, "core", "process", "event_sub_id",
+ "event_data1", "event_data2", process,
+ &g_array_index(hooks, LttvTraceHook, 7));
+
+#if 0
lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid",
NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7));
lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL,
NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8));
-
+#endif //0
/* Add these hooks to each event_by_id hooks list */
nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
}
}
+gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
+{
+ LttvTracesetState *tss = (LttvTracesetState*)(call_data);
+
+ lttv_state_remove_event_hooks(tss);
+
+ return 0;
+}
void lttv_state_remove_event_hooks(LttvTracesetState *self)
{
self->saved_position = 0;
*(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
g_free(ep);
+
+ return FALSE;
}
{
LttvTraceset *traceset = self->parent.ts;
- guint i, j, k, nb_trace, nb_tracefile;
+ guint i, j, nb_trace, nb_tracefile;
LttvTraceState *ts;
}
}
+gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
+{
+ LttvTracesetState *tss = (LttvTracesetState*)(call_data);
+
+ lttv_state_save_add_event_hooks(tss);
+
+ return 0;
+}
+
void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
{
LttvTraceset *traceset = self->parent.ts;
- guint i, j, k, nb_trace, nb_tracefile;
+ guint i, j, nb_trace, nb_tracefile;
LttvTraceState *ts;
}
}
+gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
+{
+ LttvTracesetState *tss = (LttvTracesetState*)(call_data);
+
+ lttv_state_save_remove_event_hooks(tss);
+
+ return 0;
+}
void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
{
LttvTraceset *traceset = self->parent.ts;
- guint i, j, nb_trace, nb_saved_state;
+ guint i, nb_trace;
int min_pos, mid_pos, max_pos;
NULL, /* class_data */
sizeof (LttvTracesetState),
0, /* n_preallocs */
- (GInstanceInitFunc) traceset_state_instance_init /* instance_init */
+ (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
+ NULL /* value handling */
};
type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
NULL, /* class_data */
sizeof (LttvTraceState),
0, /* n_preallocs */
- (GInstanceInitFunc) trace_state_instance_init /* instance_init */
+ (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
+ NULL /* value handling */
};
type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
NULL, /* class_data */
sizeof (LttvTracefileState),
0, /* n_preallocs */
- (GInstanceInitFunc) tracefile_state_instance_init /* instance_init */
+ (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
+ NULL /* value handling */
};
type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
LTTV_STATE_EXIT = g_quark_from_string("exiting");
+ 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_TRACEFILES = g_quark_from_string("tracefiles");