Refine the interactions between the hooks provided by the different modules.
[lttv.git] / ltt / branches / poly / lttv / state.c
CommitLineData
dc877563 1
2#include <lttv/state.h>
3
4
5static void
6init(LttvTracesetState *self, LttvTraceset *ts)
7{
8 guint i, j, nb_trace, nb_tracefile;
9
10 LttvTraceState *tc;
11
12 LttvTracefileState *tfc;
13
14 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_TYPE))->init(self, ts);
15
16 nb_trace = lttv_traceset_number(ts);
17 for(i = 0 ; i < nb_trace ; i++) {
18 tc = (LttvTraceState *)self->traces[i];
19 tc->processes = g_hash_table_new(g_direct_hash, g_direct_equal);
20
21 nb_tracefile = ltt_trace_control_tracefile_number(tc->t);
22 for(j = 0 ; j < nb_tracefile ; j++) {
23 tfc = tc->control_tracefiles[j];
24 tfc->process = NULL;
25 }
26
27 nb_tracefile = ltt_trace_per_cpu_tracefile_number(tc->t);
28 for(j = 0 ; j < nb_tracefile ; j++) {
29 tfc = tc->per_cpu_tracefiles[j];
30 tfc->process = NULL;
31 }
32 }
33}
34
35
36static void
37fini(LttvTracesetState *self)
38{
39 guint i, j, nb_trace, nb_tracefile;
40
41 LttvTraceState *tc;
42
43 LttvTracefileState *tfc;
44
45 nb_trace = lttv_traceset_number(ts);
46 for(i = 0 ; i < nb_trace ; i++) {
47 tc = (LttvTraceState *)self->traces[i];
48 remove_all_processes(tc->processes);
49 g_hash_table_destroy(tc->processes);
50 }
51 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_TYPE))->fini(self);
52}
53
54
55LttvTracesetContext *
56new_traceset_context(LttvTracesetContext *self)
57{
58 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE));
59}
60
61
62LttvTraceContext *
63new_trace_context(LttvTracesetContext *self)
64{
65 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE));
66}
67
68
69LttvTracefileContext *
70new_tracefile_context(LttvTracesetContext *self)
71{
72 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE));
73}
74
75
76GType
77lttv_traceset_state_get_type(void)
78{
79 static GType type = 0;
80 if (type == 0) {
81 static const GTypeInfo info = {
82 sizeof (LttvTracesetStateClass),
83 NULL, /* base_init */
84 NULL, /* base_finalize */
85 traceset_state_class_init, /* class_init */
86 NULL, /* class_finalize */
87 NULL, /* class_data */
88 sizeof (LttvTracesetContext),
89 0, /* n_preallocs */
90 traceset_state_instance_init /* instance_init */
91 };
92
93 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
94 &info, 0);
95 }
96 return type;
97}
98
99
100static void
101traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
102{
103}
104
105
106static void
107traceset_context_finalize (LttvTracesetContext *self)
108{
109 G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_TYPE))->finalize(self);
110}
111
112
113static void
114traceset_state_class_init (LttvTracesetContextClass *klass)
115{
116 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
117
118 gobject_class->finalize = traceset_state_finalize;
119 klass->init = init;
120 klass->fini = fini;
121 klass->new_traceset_context = new_traceset_context;
122 klass->new_trace_context = new_trace_context;
123 klass->new_tracefile_context = new_tracefile_context;
124}
125
126
127GType
128lttv_trace_state_get_type(void)
129{
130 static GType type = 0;
131 if (type == 0) {
132 static const GTypeInfo info = {
133 sizeof (LttvTraceStateClass),
134 NULL, /* base_init */
135 NULL, /* base_finalize */
136 trace_state_class_init, /* class_init */
137 NULL, /* class_finalize */
138 NULL, /* class_data */
139 sizeof (LttvTracesetState),
140 0, /* n_preallocs */
141 trace_state_instance_init /* instance_init */
142 };
143
144 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
145 "LttvTraceStateType", &info, 0);
146 }
147 return type;
148}
149
150
151static void
152trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
153{
154}
155
156
157static void
158trace_state_finalize (LttvTraceContext *self)
159{
160 G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACE_STATE_TYPE))->finalize(self);
161}
162
163
164static void
165trace_state_class_init (LttvTraceContextClass *klass)
166{
167 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
168
169 gobject_class->finalize = trace_state_finalize;
170}
171
172
173GType
174lttv_tracefile_state_get_type(void)
175{
176 static GType type = 0;
177 if (type == 0) {
178 static const GTypeInfo info = {
179 sizeof (LttvTracefileStateClass),
180 NULL, /* base_init */
181 NULL, /* base_finalize */
182 tracefile_state_class_init, /* class_init */
183 NULL, /* class_finalize */
184 NULL, /* class_data */
185 sizeof (LttvTracefileState),
186 0, /* n_preallocs */
187 tracefile_state_instance_init /* instance_init */
188 };
189
190 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
191 "LttvTracefileStateType", &info, 0);
192 }
193 return type;
194}
195
196
197static void
198tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
199{
200}
201
202
203static void
204tracefile_state_finalize (LttvTracefileState *self)
205{
206 G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_TRACEFILE_STATE_TYPE))->finalize(self);
207}
208
209
210static void
211tracefile_state_class_init (LttvTracefileStateClass *klass)
212{
213 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
214
215 gobject_class->finalize = tracefile_state_finalize;
216}
217
218
219struct HookData {
220 LttField *f1;
221 LttField *f2;
222 LttField *f3;
223}
224
225
226struct HookId {
227 LttvHook h;
228 guint id;
229 void *hook_data;
230 gboolean free_hook_data;
231}
232
233
234void push_state(LttvTracefileState *tfs, LttvInterruptType t, guint state_id)
235{
236 LttvInterruptState intr;
237
238 LttvProcessState *process = tfs->process;
239
240 guint depth = process->interrupt_stack->len;
241
242 g_array_set_size(process->interrupt_stack, depth + 1);
243 intr = &g_array_index(process->interrupt_stack, LttvInterruptState, depth);
244 intr->t = t;
245 intr->n = state_id;
246 intr->entry = tfs->time;
247 intr->last_change = tfs->time;
248 intr->s = process->state->s;
249}
250
251
252void pop_state(LttvTracefileState *tfs, LttvInterruptType t)
253{
254 LttvProcessState *process = tfs->process;
255
256 guint depth = process->interrupt_stack->len - 1;
257
258 g_assert(process->state->t == t);
259 g_array_remove_index(process->interrupt_stack, depth);
260 depth--;
261 process->state = &g_array_index(process->interrupt_stack, LttvInterruptState,
262 depth);
263}
264
265
266LttvProcessState *create_process(LttvTraceState *tfs, LttvProcessState *parent,
267 guint pid)
268{
269 LttvProcessState *process = g_new(LttvProcessState, 1);
270
271 LttvInterruptState *intr;
272
273 g_hash_table_insert(tfs->ts->processes, pid, process);
274 process->pid = pid;
275 process->birth = tfs->time;
276 process->name = LTTV_STATE_UNNAMED;
277 process->interrupt_stack = g_array_new(FALSE, FALSE,
278 sizeof(LttvInterruptState));
279 g_array_set_size(process->interrupt_stack, 1);
280 intr = process->state = process->interrupt_stack->data;
281 intr->t = LTTV_STATE_USER_MODE
282 intr->n = 0;
283 intr->entry = tfs->time;
284 intr->last_change = tfs->time;
285 intr->s = LTTV_STATE_WAIT_FORK;
286}
287
288
289LttvProcessState *find_process(LttvTraceState *tfs, guint pid)
290{
291 LttvProcessState *process = g_hash_table_lookup(tfs->processes, pid);
292 if(process == NULL) process = create_process(tfs, NULL, pid);
293 return process;
294}
295
296
297void exit_process(LttvTraceState *ts, LttvProcessState *process)
298{
299 g_hash_table_remove(tfs-ts->processes, process->pid);
300 g_array_free(process->interrupt_stack, TRUE);
301 g_free(process);
302}
303
304
305void free_process_state(gpointer key, gpointer value, gpointer user_data)
306{
307 g_array_free(((LttvProcessState *)value)->interrupt_stack, TRUE);
308 g_free(value);
309}
310
311
312void remove_all_processes(GHashTable *processes)
313{
314 g_hash_table_foreach(processes, free_process_state, NULL);
315}
316
317
318gboolean syscall_entry(void *hook_data, void *call_data)
319{
320 LttField *f = (LttField *)hook_data;
321
322 struct LttvTracefileState *s = (LttvTraceFileState *)call_data;
323
324 push_state(s, STATE_SYSCALL, ltt_event_get_unsigned(s->e, f));
325 return FALSE;
326}
327
328
329gboolean syscall_exit(void *hook_data, void *call_data)
330{
331 struct LttvTracefileState *s = (LttvTraceFileState *)call_data;
332
333 pop_state(s, STATE_SYSCALL);
334 return FALSE;
335}
336
337
338gboolean trap_entry(void *hook_data, void *call_data)
339{
340 LttField *f = (LttField *)hook_data;
341
342 struct LttvTracefileState *s = (LttvTraceFileState *)call_data;
343
344 push_state(s, STATE_TRAP, ltt_event_get_unsigned(s->e, f));
345 return FALSE;
346}
347
348
349gboolean trap_exit(void *hook_data, void *call_data)
350{
351 struct LttvTracefileState *s = (LttvTraceFileState *)call_data;
352
353 pop_state(s, STATE_TRAP);
354 return FALSE;
355}
356
357
358gboolean irq_entry(void *hook_data, void *call_data)
359{
360 LttField *f = (LttField *)hook_data;
361
362 struct LttvTracefileState *s = (LttvTraceFileState *)call_data;
363
364 /* Do something with the info about being in user or system mode when int? */
365 push_state(s, STATE_IRQ, ltt_event_get_unsigned(s->e, f));
366 return FALSE;
367}
368
369
370gboolean irq_exit(void *hook_data, void *call_data)
371{
372 struct LttvTracefileState *s = (LttvTraceFileState *)call_data;
373
374 pop_state(s, STATE_IRQ);
375 return FALSE;
376}
377
378
379gboolean schedchange(void *hook_data, void *call_data)
380{
381 struct HookData *h = (struct HookData *)hook_data;
382
383 struct LttvTracefileState *s = (LttvTraceFileState *)call_data;
384
385 guint pid_in, pid_out, state_out;
386
387 pid_in = ltt_event_get_int(s->e, h->f1);
388 pid_out = ltt_event_get_int(s->e, h->f2);
389 state_out = ltt_event_get_int(s->e, h->f3);
390 if(s->process != NULL) {
391 if(state_out == 0) s->process->state->s = STATE_WAIT_CPU;
392 else if(s->process->state->s == STATE_EXIT)
393 exit_process(s->tc, s->process);
394 else s->process->state->s = STATE_WAIT;
395 }
396 s->process = find_process(s->tc, pid_in);
397 s->process->state->s = STATE_RUN;
398 return FALSE;
399}
400
401
402gboolean process_fork(void *hook_data, void *call_data)
403{
404 LttField *f = (LttField *)hook_data;
405
406 struct LttvTracefileState *s = (LttvTraceFileState *)call_data;
407
408 guint child_pid;
409
410 child_pid = ltt_event_get_int(s->e, f);
411 create_process(s->tc, s->process, child_pid);
412 return FALSE;
413}
414
415
416gboolean process_exit(void *hook_data, void *call_data)
417{
418 struct LttvTracefileState *s = (LttvTraceFileState *)call_data;
419
420 if(s->process != NULL) {
421 s->process->state->s = STATE_EXIT;
422 }
423 return FALSE;
424}
425
426
427static LttField *
428find_field(LttEventType *et, const char *field)
429{
430 LttType *t;
431
432 LttField *f;
433
434 guint i, nb;
435
436 char *name;
437
438 if(field == NULL) return NULL;
439
440 f = ltt_eventtype_field(et);
441 t = ltt_eventtype_type(et);
442 g_assert(ltt_type_class(t) == LTT_STRUCT);
443 nb = ltt_type_member_number(t);
444 for(i = 0 ; i < nb ; i++) {
445 ltt_type_member_type(t, i, &name);
446 if(strcmp(name, field) == 0) break;
447 }
448 g_assert(i < nb);
449 return ltt_field_member(f, i);
450}
451
452
453static HookId
454find_hook(LttTrace *t, const char *facility, const char *event,
455 const char *field1, *field2, *field3, LttHook h)
456{
457 LttFacility *f;
458
459 LttEventType *et;
460
461 guint nb, pos, i;
462
463 struct HookId hook_id;
464
465 struct HookData hook_data, *phook_data;
466
467 char *name;
468
469 nb = ltt_trace_facility_find(t, facility, &pos);
470 if(nb < 1) g_error("No %s facility", facility);
471 f = ltt_facility_get(t, pos);
472 et = ltt_facility_get_by_name(f, event);
473 if(et == NULL) g_error("Event %s does not exist", event);
474
475 hook_id.id = ltt_eventtype_id(et);
476 hook_id.h = h;
477 hook_id.free_hook_data = FALSE;
478 hook_data.f1 = find_field(et, field1);
479 hook_data.f2 = find_field(et, field2);
480 hook_data.f3 = find_field(et, field3);
481 if(hook_data->f1 == NULL) hook_id->hook_data = NULL;
482 else if(hook_data->f2 == NULL) hook_id->hook_data = hook_data->f1;
483 else {
484 phook_data = g_new(struct HookData, 1);
485 *phook_data = hook_data;
486 hook_id.hook_data = phook_data;
487 hook_id.free_hook_data = TRUE;
488 }
489 return hook_id;
490}
491
492
493lttv_state_add_event_hooks(LttvTracesetState *self)
494{
495 LttvTraceset *ts = self->ts;
496
497 guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile;
498
499 LttFacility *f;
500
501 LttEventType *et;
502
503 LttvTraceState *tc;
504
505 LttvTracefileState *tfc;
506
507 void *hook_data;
508
509 GArray *hooks;
510
511 struct HookId hook_id;
512
513 LttvAttributeValue val;
514
515 nb_trace = lttv_traceset_number(ts);
516 for(i = 0 ; i < nb_trace ; i++) {
517 tc = (LttvTraceState *)self->traces[i];
518
519 /* Find the eventtype id for the following events and register the
520 associated by id hooks. */
521
522 hooks = g_array_new(FALSE, FALSE, struct HookId);
523 g_array_add(hooks, find_hook(tc->t, "core","syscall_entry", "syscall_id",
524 NULL, NULL, syscall_entry));
525 g_array_add(hooks, find_hook(tc->t, "core", "syscall_exit", NULL, NULL,
526 NULL, syscall_exit));
527 g_array_add(hooks, find_hook(tc->t, "core", "trap_entry", "trap_id",
528 NULL, trap_entry));
529 g_array_add(hooks, find_hook(tc->t, "core", "trap_exit", NULL, NULL,
530 NULL, trap_exit));
531 g_array_add(hooks, find_hook(tc->t, "core", "irq_entry", "irq_id",
532 NULL, irq_entry));
533 g_array_add(hooks, find_hook(tc->t, "core", "irq_exit", NULL, NULL,
534 NULL, irq_exit));
535 g_array_add(hooks, find_hook(tc->t, "core", "schedchange", "in", "out",
536 "out_state", schedchange));
537 g_array_add(hooks, find_hook(tc->t, "core", "process_fork", "child_pid",
538 NULL, NULL, process_fork));
539 g_array_add(hooks, find_hook(tc->t, "core", "process_exit", NULL, NULL,
540 NULL, process_exit));
541
542 /* Add these hooks to each before_event_by_id hooks list */
543
544 nb_control = ltt_trace_control_tracefile_number(tc->t);
545 nb_per_cpu = ltt_trace_control_tracefile_number(tc->t);
546 nb_tracefile = nb_control + nb_per_cpu;
547 for(j = 0 ; j < nb_tracefile ; j++) {
548 if(j < nb_control) {
549 tfc = tc->control_tracefiles[j];
550 }
551 else {
552 tfc = tc->per_cpu_tracefiles[j];
553 }
554
555 for(k = 0 ; k < hooks->len ; k++) {
556 hook_id = g_array_index(hooks, struct HookId, k);
557 lttv_hooks_add(lttv_hooks_by_id_find(tfc->before_event_by_id,
558 hook_id->id), hook_id->h, hook_id->hook_data);
559 }
560 lttv_attribute_find(self->a, STATE_HOOKS, LTTV_POINTER, val);
561 val->v_pointer = hooks;
562 }
563}
564
565
566lttv_state_remove_event_hooks(LttvTracesetState *self)
567{
568 LttvTraceset *ts = self->ts;
569
570 guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile;
571
572 LttvTraceState *tc;
573
574 LttvTracefileState *tfc;
575
576 void *hook_data;
577
578 GArray *hooks;
579
580 struct HookId hook_id;
581
582 LttvAttributeValue val;
583
584 nb_trace = lttv_traceset_number(ts);
585 for(i = 0 ; i < nb_trace ; i++) {
586 tc = (LttvTraceState *)self->traces[i];
587 lttv_attribute_find(self->a, STATE_HOOKS, LTTV_POINTER, val);
588 hooks = val->v_pointer;
589
590 /* Add these hooks to each before_event_by_id hooks list */
591
592 nb_control = ltt_trace_control_tracefile_number(tc->t);
593 nb_per_cpu = ltt_trace_control_tracefile_number(tc->t);
594 nb_tracefile = nb_control + nb_per_cpu;
595 for(j = 0 ; j < nb_tracefile ; j++) {
596 if(j < nb_control) {
597 tfc = tc->control_tracefiles[j];
598 }
599 else {
600 tfc = tc->per_cpu_tracefiles[j];
601 }
602
603 for(k = 0 ; k < hooks->len ; k++) {
604 hook_id = g_array_index(hooks, struct HookId, k);
605 lttv_hooks_remove_data(lttv_hooks_by_id_find(tfc->before_event_by_id,
606 hook_id->id), hook_id->h, hook_id->hook_data);
607 }
608 for(k = 0 ; k < hooks->len ; k++) {
609 hook_id = g_array_index(hooks, struct HookId, k);
610 if(hook_id->free_hook_data) g_free(hook_id->hook_data);
611 }
612 g_array_free(hooks, TRUE);
613 }
614}
615
616
617
618
619
620
621
622
623
624
This page took 0.043098 seconds and 4 git commands to generate.