2 #include <lttv/state.h>
21 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
23 guint i
, j
, nb_trace
, nb_tracefile
;
29 LttvTracefileContext
*tfc
;
31 LttvTracefileState
*tfcs
;
33 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_GET_CLASS(self
)))->init((LttvTracesetContext
*)self
, ts
);
35 nb_trace
= lttv_traceset_number(ts
);
36 for(i
= 0 ; i
< nb_trace
; i
++) {
37 tcs
= (LttvTraceState
*)tc
= (LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
38 tcs
->processes
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
40 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
);
41 for(j
= 0 ; j
< nb_tracefile
; j
++) {
42 tfcs
= (LttvTracefileState
*)tfc
= tc
->control_tracefiles
[j
];
46 nb_tracefile
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
47 for(j
= 0 ; j
< nb_tracefile
; j
++) {
48 tfcs
= (LttvTracefileState
*)tfc
= tc
->per_cpu_tracefiles
[j
];
56 fini(LttvTracesetState
*self
)
58 guint i
, j
, nb_trace
, nb_tracefile
;
62 LttvTracefileState
*tfcs
;
64 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
65 for(i
= 0 ; i
< nb_trace
; i
++) {
66 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
67 remove_all_processes(tcs
->processes
);
68 g_hash_table_destroy(tcs
->processes
);
70 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_GET_CLASS(self
)))->fini((LttvTracesetContext
*)self
);
75 new_traceset_context(LttvTracesetContext
*self
)
77 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
82 new_trace_context(LttvTracesetContext
*self
)
84 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
88 LttvTracefileContext
*
89 new_tracefile_context(LttvTracesetContext
*self
)
91 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
96 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
102 traceset_state_finalize (LttvTracesetContext
*self
)
104 G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_GET_CLASS(self
)))->finalize(G_OBJECT(self
));
109 traceset_state_class_init (LttvTracesetContextClass
*klass
)
111 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
113 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
114 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
115 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
116 klass
->new_traceset_context
= new_traceset_context
;
117 klass
->new_trace_context
= new_trace_context
;
118 klass
->new_tracefile_context
= new_tracefile_context
;
123 lttv_traceset_state_get_type(void)
125 static GType type
= 0;
127 static const GTypeInfo info
= {
128 sizeof (LttvTracesetStateClass
),
129 NULL
, /* base_init */
130 NULL
, /* base_finalize */
131 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
132 NULL
, /* class_finalize */
133 NULL
, /* class_data */
134 sizeof (LttvTracesetContext
),
136 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
139 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
147 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
153 trace_state_finalize (LttvTraceContext
*self
)
155 G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACE_STATE_GET_CLASS(self
)))->finalize(G_OBJECT(self
));
160 trace_state_class_init (LttvTraceContextClass
*klass
)
162 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
164 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
169 lttv_trace_state_get_type(void)
171 static GType type
= 0;
173 static const GTypeInfo info
= {
174 sizeof (LttvTraceStateClass
),
175 NULL
, /* base_init */
176 NULL
, /* base_finalize */
177 (GClassInitFunc
) trace_state_class_init
, /* class_init */
178 NULL
, /* class_finalize */
179 NULL
, /* class_data */
180 sizeof (LttvTracesetState
),
182 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
185 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
186 "LttvTraceStateType", &info
, 0);
193 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
199 tracefile_state_finalize (LttvTracefileState
*self
)
201 G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACEFILE_STATE_GET_CLASS(self
)))->finalize(G_OBJECT(self
));
206 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
208 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
210 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
215 lttv_tracefile_state_get_type(void)
217 static GType type
= 0;
219 static const GTypeInfo info
= {
220 sizeof (LttvTracefileStateClass
),
221 NULL
, /* base_init */
222 NULL
, /* base_finalize */
223 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
224 NULL
, /* class_finalize */
225 NULL
, /* class_data */
226 sizeof (LttvTracefileState
),
228 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
231 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
232 "LttvTracefileStateType", &info
, 0);
249 gboolean free_hook_data
;
253 static void push_state(LttvTracefileState
*tfs
, LttvInterruptType t
,
256 LttvInterruptState
*intr
;
258 LttvProcessState
*process
= tfs
->process
;
260 guint depth
= process
->interrupt_stack
->len
;
262 g_array_set_size(process
->interrupt_stack
, depth
+ 1);
263 intr
= &g_array_index(process
->interrupt_stack
, LttvInterruptState
, depth
);
266 intr
->entry
= intr
->last_change
= LTTV_TRACEFILE_CONTEXT(tfs
)->timestamp
;
267 intr
->s
= process
->state
->s
;
271 static void pop_state(LttvTracefileState
*tfs
, LttvInterruptType t
)
273 LttvProcessState
*process
= tfs
->process
;
275 guint depth
= process
->interrupt_stack
->len
- 1;
277 g_assert(process
->state
->t
== t
);
278 g_array_remove_index(process
->interrupt_stack
, depth
);
280 process
->state
= &g_array_index(process
->interrupt_stack
, LttvInterruptState
,
285 LttvProcessState
*create_process(LttvTracefileState
*tfs
,
286 LttvProcessState
*parent
, guint pid
)
288 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
290 LttvInterruptState
*intr
;
292 LttvTraceContext
*tc
;
294 LttvTraceContext
*tcs
;
296 tcs
= (LttvTraceState
*)tc
= LTTV_TRACEFILE_CONTEXT(tfs
)->ts
;
298 g_hash_table_insert(tcs
->processes
, GUINT_TO_POINTER(pid
), process
);
300 process
->birth
= tfs
->timestamp
;
301 process
->name
= LTTV_STATE_UNNAMED
;
302 process
->interrupt_stack
= g_array_new(FALSE
, FALSE
,
303 sizeof(LttvInterruptState
));
304 g_array_set_size(process
->interrupt_stack
, 1);
305 intr
= process
->state
= &g_array_index(process
->interrupt_stack
,
306 LttvInterruptState
, 0);
307 intr
->t
= LTTV_STATE_USER_MODE
309 intr
->entry
= tfs
->timestamp
;
310 intr
->last_change
= tfs
->timestamp
;
311 intr
->s
= LTTV_STATE_WAIT_FORK
;
315 LttvProcessState
*find_process(LttvTraceState
*tfs
, guint pid
)
317 LttvProcessState
*process
= g_hash_table_lookup(tfs
->processes
, pid
);
318 if(process
== NULL
) process
= create_process(tfs
, NULL
, pid
);
323 void exit_process(LttvTraceState
*ts
, LttvProcessState
*process
)
325 g_hash_table_remove(tfs
-ts
->processes
, process
->pid
);
326 g_array_free(process
->interrupt_stack
, TRUE
);
331 void free_process_state(gpointer key
, gpointer value
, gpointer user_data
)
333 g_array_free(((LttvProcessState
*)value
)->interrupt_stack
, TRUE
);
338 void remove_all_processes(GHashTable
*processes
)
340 g_hash_table_foreach(processes
, free_process_state
, NULL
);
344 gboolean
syscall_entry(void *hook_data
, void *call_data
)
346 LttField
*f
= (LttField
*)hook_data
;
348 struct LttvTracefileState
*s
= (LttvTraceFileState
*)call_data
;
350 push_state(s
, LTTV_STATE_SYSCALL
, ltt_event_get_unsigned(s
->e
, f
));
355 gboolean
syscall_exit(void *hook_data
, void *call_data
)
357 struct LttvTracefileState
*s
= (LttvTraceFileState
*)call_data
;
359 pop_state(s
, LTTV_STATE_SYSCALL
);
364 gboolean
trap_entry(void *hook_data
, void *call_data
)
366 LttField
*f
= (LttField
*)hook_data
;
368 struct LttvTracefileState
*s
= (LttvTraceFileState
*)call_data
;
370 push_state(s
, LTTV_STATE_TRAP
, ltt_event_get_unsigned(s
->e
, f
));
375 gboolean
trap_exit(void *hook_data
, void *call_data
)
377 struct LttvTracefileState
*s
= (LttvTraceFileState
*)call_data
;
379 pop_state(s
, LTTV_STATE_TRAP
);
384 gboolean
irq_entry(void *hook_data
, void *call_data
)
386 LttField
*f
= (LttField
*)hook_data
;
388 struct LttvTracefileState
*s
= (LttvTraceFileState
*)call_data
;
390 /* Do something with the info about being in user or system mode when int? */
391 push_state(s
, LTTV_STATE_IRQ
, ltt_event_get_unsigned(s
->e
, f
));
396 gboolean
irq_exit(void *hook_data
, void *call_data
)
398 struct LttvTracefileState
*s
= (LttvTraceFileState
*)call_data
;
400 pop_state(s
, LTTV_STATE_IRQ
);
405 gboolean
schedchange(void *hook_data
, void *call_data
)
407 struct HookData
*h
= (struct HookData
*)hook_data
;
409 struct LttvTracefileState
*s
= (LttvTraceFileState
*)call_data
;
411 guint pid_in
, pid_out
, state_out
;
413 pid_in
= ltt_event_get_int(s
->e
, h
->f1
);
414 pid_out
= ltt_event_get_int(s
->e
, h
->f2
);
415 state_out
= ltt_event_get_int(s
->e
, h
->f3
);
416 if(s
->process
!= NULL
) {
417 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
418 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
419 exit_process(s
->tc
, s
->process
);
420 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
422 s
->process
= find_process(s
->tc
, pid_in
);
423 s
->process
->state
->s
= LTTV_STATE_RUN
;
428 gboolean
process_fork(void *hook_data
, void *call_data
)
430 LttField
*f
= (LttField
*)hook_data
;
432 struct LttvTracefileState
*s
= (LttvTraceFileState
*)call_data
;
436 child_pid
= ltt_event_get_int(s
->e
, f
);
437 create_process(s
->tc
, s
->process
, child_pid
);
442 gboolean
process_exit(void *hook_data
, void *call_data
)
444 struct LttvTracefileState
*s
= (LttvTraceFileState
*)call_data
;
446 if(s
->process
!= NULL
) {
447 s
->process
->state
->s
= LTTV_STATE_EXIT
;
454 find_field(LttEventType
*et
, const char *field
)
464 if(field
== NULL
) return NULL
;
466 f
= ltt_eventtype_field(et
);
467 t
= ltt_eventtype_type(et
);
468 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
469 nb
= ltt_type_member_number(t
);
470 for(i
= 0 ; i
< nb
; i
++) {
471 ltt_type_member_type(t
, i
, &name
);
472 if(strcmp(name
, field
) == 0) break;
475 return ltt_field_member(f
, i
);
480 find_hook(LttTrace
*t
, const char *facility
, const char *event
,
481 const char *field1
, *field2
, *field3
, LttHook h
)
489 struct HookId hook_id
;
491 struct HookData hook_data
, *phook_data
;
495 nb
= ltt_trace_facility_find(t
, facility
, &pos
);
496 if(nb
< 1) g_error("No %s facility", facility
);
497 f
= ltt_facility_get(t
, pos
);
498 et
= ltt_facility_get_by_name(f
, event
);
499 if(et
== NULL
) g_error("Event %s does not exist", event
);
501 hook_id
.id
= ltt_eventtype_id(et
);
503 hook_id
.free_hook_data
= FALSE
;
504 hook_data
.f1
= find_field(et
, field1
);
505 hook_data
.f2
= find_field(et
, field2
);
506 hook_data
.f3
= find_field(et
, field3
);
507 if(hook_data
->f1
== NULL
) hook_id
->hook_data
= NULL
;
508 else if(hook_data
->f2
== NULL
) hook_id
->hook_data
= hook_data
->f1
;
510 phook_data
= g_new(struct HookData
, 1);
511 *phook_data
= hook_data
;
512 hook_id
.hook_data
= phook_data
;
513 hook_id
.free_hook_data
= TRUE
;
519 lttv_state_add_event_hooks(LttvTracesetState
*self
)
521 LttvTraceset
*ts
= self
->ts
;
523 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
531 LttvTracefileState
*tfc
;
537 struct HookId hook_id
;
539 LttvAttributeValue val
;
541 nb_trace
= lttv_traceset_number(ts
);
542 for(i
= 0 ; i
< nb_trace
; i
++) {
543 tc
= (LttvTraceState
*)self
->traces
[i
];
545 /* Find the eventtype id for the following events and register the
546 associated by id hooks. */
548 hooks
= g_array_new(FALSE
, FALSE
, struct HookId
);
549 g_array_add(hooks
, find_hook(tc
->t
, "core","syscall_entry", "syscall_id",
550 NULL
, NULL
, syscall_entry
));
551 g_array_add(hooks
, find_hook(tc
->t
, "core", "syscall_exit", NULL
, NULL
,
552 NULL
, syscall_exit
));
553 g_array_add(hooks
, find_hook(tc
->t
, "core", "trap_entry", "trap_id",
555 g_array_add(hooks
, find_hook(tc
->t
, "core", "trap_exit", NULL
, NULL
,
557 g_array_add(hooks
, find_hook(tc
->t
, "core", "irq_entry", "irq_id",
559 g_array_add(hooks
, find_hook(tc
->t
, "core", "irq_exit", NULL
, NULL
,
561 g_array_add(hooks
, find_hook(tc
->t
, "core", "schedchange", "in", "out",
562 "out_state", schedchange
));
563 g_array_add(hooks
, find_hook(tc
->t
, "core", "process_fork", "child_pid",
564 NULL
, NULL
, process_fork
));
565 g_array_add(hooks
, find_hook(tc
->t
, "core", "process_exit", NULL
, NULL
,
566 NULL
, process_exit
));
568 /* Add these hooks to each before_event_by_id hooks list */
570 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
571 nb_per_cpu
= ltt_trace_control_tracefile_number(tc
->t
);
572 nb_tracefile
= nb_control
+ nb_per_cpu
;
573 for(j
= 0 ; j
< nb_tracefile
; j
++) {
575 tfc
= tc
->control_tracefiles
[j
];
578 tfc
= tc
->per_cpu_tracefiles
[j
];
581 for(k
= 0 ; k
< hooks
->len
; k
++) {
582 hook_id
= g_array_index(hooks
, struct HookId
, k
);
583 lttv_hooks_add(lttv_hooks_by_id_find(tfc
->before_event_by_id
,
584 hook_id
->id
), hook_id
->h
, hook_id
->hook_data
);
587 lttv_attribute_find(self
->a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, val
);
588 val
->v_pointer
= hooks
;
593 lttv_state_remove_event_hooks(LttvTracesetState
*self
)
595 LttvTraceset
*ts
= self
->ts
;
597 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
601 LttvTracefileState
*tfc
;
607 struct HookId hook_id
;
609 LttvAttributeValue val
;
611 nb_trace
= lttv_traceset_number(ts
);
612 for(i
= 0 ; i
< nb_trace
; i
++) {
613 tc
= (LttvTraceState
*)self
->traces
[i
];
614 lttv_attribute_find(self
->a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, val
);
615 hooks
= val
->v_pointer
;
617 /* Add these hooks to each before_event_by_id hooks list */
619 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
620 nb_per_cpu
= ltt_trace_control_tracefile_number(tc
->t
);
621 nb_tracefile
= nb_control
+ nb_per_cpu
;
622 for(j
= 0 ; j
< nb_tracefile
; j
++) {
624 tfc
= tc
->control_tracefiles
[j
];
627 tfc
= tc
->per_cpu_tracefiles
[j
];
630 for(k
= 0 ; k
< hooks
->len
; k
++) {
631 hook_id
= g_array_index(hooks
, struct HookId
, k
);
632 lttv_hooks_remove_data(lttv_hooks_by_id_find(tfc
->before_event_by_id
,
633 hook_id
->id
), hook_id
->h
, hook_id
->hook_data
);
636 for(k
= 0 ; k
< hooks
->len
; k
++) {
637 hook_id
= g_array_index(hooks
, struct HookId
, k
);
638 if(hook_id
->free_hook_data
) g_free(hook_id
->hook_data
);
641 g_array_free(hooks
, TRUE
);
646 void lttv_state_init(int argc
, char **argv
)
648 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
649 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
650 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
651 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
652 LTTV_STATE_TRAP
= g_quark_from_string("trap");
653 LTTV_STATE_IRQ
= g_quark_from_string("irq");
654 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
655 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
656 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
657 LTTV_STATE_RUN
= g_quark_from_string("running");
658 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
661 void lttv_state_destroy()