2 #include <lttv/state.h>
3 #include <ltt/facility.h>
24 void remove_all_processes(GHashTable
*processes
);
28 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
30 guint i
, j
, nb_trace
, nb_tracefile
;
36 LttvTracefileContext
*tfc
;
38 LttvTracefileState
*tfcs
;
40 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_GET_CLASS(self
)))->init((LttvTracesetContext
*)self
, ts
);
42 nb_trace
= lttv_traceset_number(ts
);
43 for(i
= 0 ; i
< nb_trace
; i
++) {
44 tcs
= (LttvTraceState
*)tc
= (LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
45 tcs
->processes
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
47 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
);
48 for(j
= 0 ; j
< nb_tracefile
; j
++) {
49 tfcs
= (LttvTracefileState
*)tfc
= tc
->control_tracefiles
[j
];
53 nb_tracefile
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
54 for(j
= 0 ; j
< nb_tracefile
; j
++) {
55 tfcs
= (LttvTracefileState
*)tfc
= tc
->per_cpu_tracefiles
[j
];
63 fini(LttvTracesetState
*self
)
65 guint i
, j
, nb_trace
, nb_tracefile
;
69 LttvTracefileState
*tfcs
;
71 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
72 for(i
= 0 ; i
< nb_trace
; i
++) {
73 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
74 remove_all_processes(tcs
->processes
);
75 g_hash_table_destroy(tcs
->processes
);
77 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_GET_CLASS(self
)))->fini((LttvTracesetContext
*)self
);
81 static LttvTracesetContext
*
82 new_traceset_context(LttvTracesetContext
*self
)
84 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
88 static LttvTraceContext
*
89 new_trace_context(LttvTracesetContext
*self
)
91 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
95 static LttvTracefileContext
*
96 new_tracefile_context(LttvTracesetContext
*self
)
98 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
103 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
109 traceset_state_finalize (LttvTracesetContext
*self
)
111 G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_GET_CLASS(self
)))->finalize(G_OBJECT(self
));
116 traceset_state_class_init (LttvTracesetContextClass
*klass
)
118 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
120 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
121 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
122 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
123 klass
->new_traceset_context
= new_traceset_context
;
124 klass
->new_trace_context
= new_trace_context
;
125 klass
->new_tracefile_context
= new_tracefile_context
;
130 lttv_traceset_state_get_type(void)
132 static GType type
= 0;
134 static const GTypeInfo info
= {
135 sizeof (LttvTracesetStateClass
),
136 NULL
, /* base_init */
137 NULL
, /* base_finalize */
138 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
139 NULL
, /* class_finalize */
140 NULL
, /* class_data */
141 sizeof (LttvTracesetContext
),
143 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
146 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
154 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
160 trace_state_finalize (LttvTraceContext
*self
)
162 G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACE_STATE_GET_CLASS(self
)))->finalize(G_OBJECT(self
));
167 trace_state_class_init (LttvTraceContextClass
*klass
)
169 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
171 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
176 lttv_trace_state_get_type(void)
178 static GType type
= 0;
180 static const GTypeInfo info
= {
181 sizeof (LttvTraceStateClass
),
182 NULL
, /* base_init */
183 NULL
, /* base_finalize */
184 (GClassInitFunc
) trace_state_class_init
, /* class_init */
185 NULL
, /* class_finalize */
186 NULL
, /* class_data */
187 sizeof (LttvTracesetState
),
189 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
192 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
193 "LttvTraceStateType", &info
, 0);
200 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
206 tracefile_state_finalize (LttvTracefileState
*self
)
208 G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACEFILE_STATE_GET_CLASS(self
)))->finalize(G_OBJECT(self
));
213 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
215 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
217 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
222 lttv_tracefile_state_get_type(void)
224 static GType type
= 0;
226 static const GTypeInfo info
= {
227 sizeof (LttvTracefileStateClass
),
228 NULL
, /* base_init */
229 NULL
, /* base_finalize */
230 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
231 NULL
, /* class_finalize */
232 NULL
, /* class_data */
233 sizeof (LttvTracefileState
),
235 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
238 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
239 "LttvTracefileStateType", &info
, 0);
256 gboolean free_hook_data
;
260 static void push_state(LttvTracefileState
*tfs
, LttvInterruptType t
,
263 LttvInterruptState
*intr
;
265 LttvProcessState
*process
= tfs
->process
;
267 guint depth
= process
->interrupt_stack
->len
;
269 g_array_set_size(process
->interrupt_stack
, depth
+ 1);
270 intr
= &g_array_index(process
->interrupt_stack
, LttvInterruptState
, depth
);
273 intr
->entry
= intr
->last_change
= LTTV_TRACEFILE_CONTEXT(tfs
)->timestamp
;
274 intr
->s
= process
->state
->s
;
275 process
->state
= intr
;
279 static void pop_state(LttvTracefileState
*tfs
, LttvInterruptType t
)
281 LttvProcessState
*process
= tfs
->process
;
283 guint depth
= process
->interrupt_stack
->len
- 1;
285 g_assert(process
->state
->t
== t
);
286 g_array_remove_index(process
->interrupt_stack
, depth
);
288 process
->state
= &g_array_index(process
->interrupt_stack
, LttvInterruptState
,
293 LttvProcessState
*create_process(LttvTracefileState
*tfs
,
294 LttvProcessState
*parent
, guint pid
)
296 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
298 LttvInterruptState
*intr
;
300 LttvTraceContext
*tc
;
304 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfs
);
306 tcs
= (LttvTraceState
*)tc
= tfc
->t_context
;
308 g_hash_table_insert(tcs
->processes
, GUINT_TO_POINTER(pid
), process
);
310 process
->birth
= tfc
->timestamp
;
311 process
->name
= LTTV_STATE_UNNAMED
;
312 process
->interrupt_stack
= g_array_new(FALSE
, FALSE
,
313 sizeof(LttvInterruptState
));
314 g_array_set_size(process
->interrupt_stack
, 1);
315 intr
= process
->state
= &g_array_index(process
->interrupt_stack
,
316 LttvInterruptState
, 0);
317 intr
->t
= LTTV_STATE_USER_MODE
;
319 intr
->entry
= tfc
->timestamp
;
320 intr
->last_change
= tfc
->timestamp
;
321 intr
->s
= LTTV_STATE_WAIT_FORK
;
325 LttvProcessState
*find_process(LttvTracefileState
*tfs
, guint pid
)
327 LttvTraceState
*ts
=(LttvTraceState
*)LTTV_TRACEFILE_CONTEXT(tfs
)->t_context
;
328 LttvProcessState
*process
= g_hash_table_lookup(ts
->processes
,
329 GUINT_TO_POINTER(pid
));
330 if(process
== NULL
) process
= create_process(tfs
, NULL
, pid
);
335 void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
337 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
339 g_hash_table_remove(ts
->processes
, GUINT_TO_POINTER(process
->pid
));
340 g_array_free(process
->interrupt_stack
, TRUE
);
345 void free_process_state(gpointer key
, gpointer value
, gpointer user_data
)
347 g_array_free(((LttvProcessState
*)value
)->interrupt_stack
, TRUE
);
352 void remove_all_processes(GHashTable
*processes
)
354 g_hash_table_foreach(processes
, free_process_state
, NULL
);
358 gboolean
syscall_entry(void *hook_data
, void *call_data
)
360 LttField
*f
= (LttField
*)hook_data
;
362 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
364 push_state(s
, LTTV_STATE_SYSCALL
, ltt_event_get_unsigned(
365 LTTV_TRACEFILE_CONTEXT(s
)->e
, f
));
370 gboolean
syscall_exit(void *hook_data
, void *call_data
)
372 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
374 pop_state(s
, LTTV_STATE_SYSCALL
);
379 gboolean
trap_entry(void *hook_data
, void *call_data
)
381 LttField
*f
= (LttField
*)hook_data
;
383 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
385 push_state(s
, LTTV_STATE_TRAP
, ltt_event_get_unsigned(s
->parent
.e
, f
));
390 gboolean
trap_exit(void *hook_data
, void *call_data
)
392 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
394 pop_state(s
, LTTV_STATE_TRAP
);
399 gboolean
irq_entry(void *hook_data
, void *call_data
)
401 LttField
*f
= (LttField
*)hook_data
;
403 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
405 /* Do something with the info about being in user or system mode when int? */
406 push_state(s
, LTTV_STATE_IRQ
, ltt_event_get_unsigned(s
->parent
.e
, f
));
411 gboolean
irq_exit(void *hook_data
, void *call_data
)
413 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
415 pop_state(s
, LTTV_STATE_IRQ
);
420 gboolean
schedchange(void *hook_data
, void *call_data
)
422 struct HookData
*h
= (struct HookData
*)hook_data
;
424 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
426 guint pid_in
, pid_out
, state_out
;
428 pid_in
= ltt_event_get_int(s
->parent
.e
, h
->f1
);
429 pid_out
= ltt_event_get_int(s
->parent
.e
, h
->f2
);
430 state_out
= ltt_event_get_int(s
->parent
.e
, h
->f3
);
431 if(s
->process
!= NULL
) {
432 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
433 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
434 exit_process(s
, s
->process
);
435 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
437 s
->process
= find_process(s
, pid_in
);
438 s
->process
->state
->s
= LTTV_STATE_RUN
;
443 gboolean
process_fork(void *hook_data
, void *call_data
)
445 LttField
*f
= (LttField
*)hook_data
;
447 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
451 child_pid
= ltt_event_get_int(s
->parent
.e
, f
);
452 create_process(s
, s
->process
, child_pid
);
457 gboolean
process_exit(void *hook_data
, void *call_data
)
459 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
461 if(s
->process
!= NULL
) {
462 s
->process
->state
->s
= LTTV_STATE_EXIT
;
469 find_field(LttEventType
*et
, const char *field
)
479 if(field
== NULL
) return NULL
;
481 f
= ltt_eventtype_field(et
);
482 t
= ltt_eventtype_type(et
);
483 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
484 nb
= ltt_type_member_number(t
);
485 for(i
= 0 ; i
< nb
; i
++) {
486 ltt_type_member_type(t
, i
, &name
);
487 if(strcmp(name
, field
) == 0) break;
490 return ltt_field_member(f
, i
);
495 find_hook(LttTrace
*t
, char *facility
, char *event
,
496 char *field1
, char *field2
, char *field3
, LttvHook h
)
504 struct HookId hook_id
;
506 struct HookData hook_data
, *phook_data
;
510 nb
= ltt_trace_facility_find(t
, facility
, &pos
);
511 if(nb
< 1) g_error("No %s facility", facility
);
512 f
= ltt_trace_facility_get(t
, pos
);
513 et
= ltt_facility_eventtype_get_by_name(f
, event
);
514 if(et
== NULL
) g_error("Event %s does not exist", event
);
516 hook_id
.id
= ltt_eventtype_id(et
);
518 hook_id
.free_hook_data
= FALSE
;
519 hook_data
.f1
= find_field(et
, field1
);
520 hook_data
.f2
= find_field(et
, field2
);
521 hook_data
.f3
= find_field(et
, field3
);
522 if(hook_data
.f1
== NULL
) hook_id
.hook_data
= NULL
;
523 else if(hook_data
.f2
== NULL
) hook_id
.hook_data
= hook_data
.f1
;
525 phook_data
= g_new(struct HookData
, 1);
526 *phook_data
= hook_data
;
527 hook_id
.hook_data
= phook_data
;
528 hook_id
.free_hook_data
= TRUE
;
534 lttv_state_add_event_hooks(LttvTracesetState
*self
)
536 LttvTraceset
*traceset
= self
->parent
.ts
;
538 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
546 LttvTracefileState
*tfs
;
552 struct HookId hook_id
;
554 LttvAttributeValue val
;
556 nb_trace
= lttv_traceset_number(traceset
);
557 for(i
= 0 ; i
< nb_trace
; i
++) {
558 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
560 /* Find the eventtype id for the following events and register the
561 associated by id hooks. */
563 hooks
= g_array_new(FALSE
, FALSE
, sizeof(struct HookId
));
564 g_array_add(hooks
, find_hook(ts
->parent
.t
, "core","syscall_entry",
565 "syscall_id", NULL
, NULL
, syscall_entry
));
566 g_array_add(hooks
, find_hook(ts
->parent
.t
, "core", "syscall_exit",
567 NULL
, NULL
, NULL
, syscall_exit
));
568 g_array_add(hooks
, find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
569 NULL
, NULL
, trap_entry
));
570 g_array_add(hooks
, find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
,
572 g_array_add(hooks
, find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id",
573 NULL
, NULL
, irq_entry
));
574 g_array_add(hooks
, find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
,
576 g_array_add(hooks
, find_hook(ts
->parent
.t
, "core", "schedchange",
577 "in", "out", "out_state", schedchange
));
578 g_array_add(hooks
, find_hook(ts
->parent
.t
, "core", "process_fork",
579 "child_pid", NULL
, NULL
, process_fork
));
580 g_array_add(hooks
, find_hook(ts
->parent
.t
, "core", "process_exit",
581 NULL
, NULL
, NULL
, process_exit
));
583 /* Add these hooks to each before_event_by_id hooks list */
585 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
586 nb_per_cpu
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
587 nb_tracefile
= nb_control
+ nb_per_cpu
;
588 for(j
= 0 ; j
< nb_tracefile
; j
++) {
590 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
593 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
]);
596 for(k
= 0 ; k
< hooks
->len
; k
++) {
597 hook_id
= g_array_index(hooks
, struct HookId
, k
);
598 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.before_event_by_id
,
599 hook_id
.id
), hook_id
.h
, hook_id
.hook_data
);
602 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
603 *(val
.v_pointer
) = hooks
;
608 lttv_state_remove_event_hooks(LttvTracesetState
*self
)
610 LttvTraceset
*traceset
= self
->parent
.ts
;
612 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
616 LttvTracefileState
*tfs
;
622 struct HookId hook_id
;
624 LttvAttributeValue val
;
626 nb_trace
= lttv_traceset_number(traceset
);
627 for(i
= 0 ; i
< nb_trace
; i
++) {
628 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
629 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
630 hooks
= *(val
.v_pointer
);
632 /* Add these hooks to each before_event_by_id hooks list */
634 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
635 nb_per_cpu
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
636 nb_tracefile
= nb_control
+ nb_per_cpu
;
637 for(j
= 0 ; j
< nb_tracefile
; j
++) {
639 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
642 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
]);
645 for(k
= 0 ; k
< hooks
->len
; k
++) {
646 hook_id
= g_array_index(hooks
, struct HookId
, k
);
647 lttv_hooks_remove_data(
648 lttv_hooks_by_id_find(tfs
->parent
.before_event_by_id
,
649 hook_id
.id
), hook_id
.h
, hook_id
.hook_data
);
652 for(k
= 0 ; k
< hooks
->len
; k
++) {
653 hook_id
= g_array_index(hooks
, struct HookId
, k
);
654 if(hook_id
.free_hook_data
) g_free(hook_id
.hook_data
);
657 g_array_free(hooks
, TRUE
);
662 void lttv_state_init(int argc
, char **argv
)
664 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
665 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
666 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
667 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
668 LTTV_STATE_TRAP
= g_quark_from_string("trap");
669 LTTV_STATE_IRQ
= g_quark_from_string("irq");
670 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
671 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
672 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
673 LTTV_STATE_RUN
= g_quark_from_string("running");
674 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
677 void lttv_state_destroy()