zombie test removed : can cause problems with fork and scheduling on another CPU...
[lttv.git] / ltt / branches / poly / lttv / lttv / state.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <lttv/lttv.h>
24 #include <lttv/module.h>
25 #include <lttv/state.h>
26 #include <ltt/facility.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
29 #include <ltt/type.h>
30 #include <stdio.h>
31
32 #define PREALLOCATED_EXECUTION_STACK 10
33
34 /* Facilities Quarks */
35
36 GQuark
37 LTT_FACILITY_KERNEL,
38 LTT_FACILITY_PROCESS,
39 LTT_FACILITY_FS;
40
41 /* Events Quarks */
42
43 GQuark
44 LTT_EVENT_SYSCALL_ENTRY,
45 LTT_EVENT_SYSCALL_EXIT,
46 LTT_EVENT_TRAP_ENTRY,
47 LTT_EVENT_TRAP_EXIT,
48 LTT_EVENT_IRQ_ENTRY,
49 LTT_EVENT_IRQ_EXIT,
50 LTT_EVENT_SCHEDCHANGE,
51 LTT_EVENT_FORK,
52 LTT_EVENT_EXIT,
53 LTT_EVENT_FREE,
54 LTT_EVENT_EXEC;
55
56 /* Fields Quarks */
57
58 GQuark
59 LTT_FIELD_SYSCALL_ID,
60 LTT_FIELD_TRAP_ID,
61 LTT_FIELD_IRQ_ID,
62 LTT_FIELD_OUT,
63 LTT_FIELD_IN,
64 LTT_FIELD_OUT_STATE,
65 LTT_FIELD_PARENT_PID,
66 LTT_FIELD_CHILD_PID,
67 LTT_FIELD_PID,
68 LTT_FIELD_FILENAME;
69
70 LttvExecutionMode
71 LTTV_STATE_MODE_UNKNOWN,
72 LTTV_STATE_USER_MODE,
73 LTTV_STATE_SYSCALL,
74 LTTV_STATE_TRAP,
75 LTTV_STATE_IRQ;
76
77 LttvExecutionSubmode
78 LTTV_STATE_SUBMODE_UNKNOWN,
79 LTTV_STATE_SUBMODE_NONE;
80
81 LttvProcessStatus
82 LTTV_STATE_UNNAMED,
83 LTTV_STATE_WAIT_FORK,
84 LTTV_STATE_WAIT_CPU,
85 LTTV_STATE_EXIT,
86 LTTV_STATE_ZOMBIE,
87 LTTV_STATE_WAIT,
88 LTTV_STATE_RUN;
89
90 static GQuark
91 LTTV_STATE_TRACEFILES,
92 LTTV_STATE_PROCESSES,
93 LTTV_STATE_PROCESS,
94 LTTV_STATE_RUNNING_PROCESS,
95 LTTV_STATE_EVENT,
96 LTTV_STATE_SAVED_STATES,
97 LTTV_STATE_SAVED_STATES_TIME,
98 LTTV_STATE_TIME,
99 LTTV_STATE_HOOKS,
100 LTTV_STATE_NAME_TABLES,
101 LTTV_STATE_TRACE_STATE_USE_COUNT;
102
103 static void create_max_time(LttvTraceState *tcs);
104
105 static void get_max_time(LttvTraceState *tcs);
106
107 static void free_max_time(LttvTraceState *tcs);
108
109 static void create_name_tables(LttvTraceState *tcs);
110
111 static void get_name_tables(LttvTraceState *tcs);
112
113 static void free_name_tables(LttvTraceState *tcs);
114
115 static void free_saved_state(LttvTraceState *tcs);
116
117 static void lttv_state_free_process_table(GHashTable *processes);
118
119
120 void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
121 {
122 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
123 }
124
125
126 void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
127 {
128 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
129 }
130
131
132 void lttv_state_state_saved_free(LttvTraceState *self,
133 LttvAttribute *container)
134 {
135 LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
136 }
137
138
139 guint process_hash(gconstpointer key)
140 {
141 guint pid = ((const LttvProcessState *)key)->pid;
142 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
143 }
144
145
146 /* If the hash table hash function is well distributed,
147 * the process_equal should compare different pid */
148 gboolean process_equal(gconstpointer a, gconstpointer b)
149 {
150 const LttvProcessState *process_a, *process_b;
151 gboolean ret = TRUE;
152
153 process_a = (const LttvProcessState *)a;
154 process_b = (const LttvProcessState *)b;
155
156 if(likely(process_a->pid != process_b->pid)) ret = FALSE;
157 else if(likely(process_a->pid == 0 &&
158 process_a->cpu != process_b->cpu)) ret = FALSE;
159
160 return ret;
161 }
162
163
164 static void
165 restore_init_state(LttvTraceState *self)
166 {
167 guint i, nb_cpus;
168
169 LttvTracefileState *tfcs;
170
171 /* Free the process tables */
172 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
173 self->processes = g_hash_table_new(process_hash, process_equal);
174 self->nb_event = 0;
175
176 /* Seek time to beginning */
177 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
178 // closest. It's the tracecontext job to seek the trace to the beginning
179 // anyway : the init state might be used at the middle of the trace as well...
180 //g_tree_destroy(self->parent.ts_context->pqueue);
181 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
182
183
184 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
185
186 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
187
188 /* Put the per cpu running_process to beginning state : process 0. */
189 for(i=0; i< nb_cpus; i++) {
190 self->running_process[i] = lttv_state_create_process(self, NULL, i, 0,
191 &ltt_time_zero);
192 self->running_process[i]->state->s = LTTV_STATE_RUN;
193 self->running_process[i]->cpu = i;
194 }
195
196 #if 0
197 nb_tracefile = self->parent.tracefiles->len;
198
199 for(i = 0 ; i < nb_tracefile ; i++) {
200 tfcs =
201 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
202 LttvTracefileContext*, i));
203 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
204 // tfcs->saved_position = 0;
205 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
206 tfcs->process->state->s = LTTV_STATE_RUN;
207 tfcs->process->last_cpu = tfcs->cpu_name;
208 tfcs->process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfcs)->tf);
209 }
210 #endif //0
211 }
212
213 //static LttTime time_zero = {0,0};
214
215 static void
216 init(LttvTracesetState *self, LttvTraceset *ts)
217 {
218 guint i, j, nb_trace, nb_tracefile;
219
220 LttvTraceContext *tc;
221
222 LttvTraceState *tcs;
223
224 LttvTracefileState *tfcs;
225
226 LttvAttributeValue v;
227
228 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
229 init((LttvTracesetContext *)self, ts);
230
231 nb_trace = lttv_traceset_number(ts);
232 for(i = 0 ; i < nb_trace ; i++) {
233 tc = self->parent.traces[i];
234 tcs = LTTV_TRACE_STATE(tc);
235 tcs->save_interval = LTTV_STATE_SAVE_INTERVAL;
236 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
237 LTTV_UINT, &v);
238 (*v.v_uint)++;
239
240 if(*(v.v_uint) == 1) {
241 create_name_tables(tcs);
242 create_max_time(tcs);
243 }
244 get_name_tables(tcs);
245 get_max_time(tcs);
246
247 nb_tracefile = tc->tracefiles->len;
248 #if 0
249 for(j = 0 ; j < nb_tracefile ; j++) {
250 tfcs =
251 LTTV_TRACEFILE_STATE(g_array_index(tc->tracefiles,
252 LttvTracefileContext*, j));
253 tfcs->tracefile_name = ltt_tracefile_name(tfcs->parent.tf);
254 }
255 #endif //0
256 tcs->processes = NULL;
257 tcs->running_process = g_new(LttvProcessState*,
258 ltt_trace_get_num_cpu(tc->t));
259 restore_init_state(tcs);
260 }
261 }
262
263
264 static void
265 fini(LttvTracesetState *self)
266 {
267 guint i, nb_trace;
268
269 LttvTraceState *tcs;
270
271 LttvTracefileState *tfcs;
272
273 LttvAttributeValue v;
274
275 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
276 for(i = 0 ; i < nb_trace ; i++) {
277 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
278 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
279 LTTV_UINT, &v);
280
281 g_assert(*(v.v_uint) != 0);
282 (*v.v_uint)--;
283
284 if(*(v.v_uint) == 0) {
285 free_name_tables(tcs);
286 free_max_time(tcs);
287 free_saved_state(tcs);
288 }
289 g_free(tcs->running_process);
290 tcs->running_process = NULL;
291 lttv_state_free_process_table(tcs->processes);
292 tcs->processes = NULL;
293 }
294 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
295 fini((LttvTracesetContext *)self);
296 }
297
298
299 static LttvTracesetContext *
300 new_traceset_context(LttvTracesetContext *self)
301 {
302 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
303 }
304
305
306 static LttvTraceContext *
307 new_trace_context(LttvTracesetContext *self)
308 {
309 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
310 }
311
312
313 static LttvTracefileContext *
314 new_tracefile_context(LttvTracesetContext *self)
315 {
316 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
317 }
318
319
320 /* Write the process state of the trace */
321
322 static void write_process_state(gpointer key, gpointer value,
323 gpointer user_data)
324 {
325 LttvProcessState *process;
326
327 LttvExecutionState *es;
328
329 FILE *fp = (FILE *)user_data;
330
331 guint i;
332
333 process = (LttvProcessState *)value;
334 fprintf(fp,
335 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
336 process, process->pid, process->ppid, process->creation_time.tv_sec,
337 process->creation_time.tv_nsec, g_quark_to_string(process->name),
338 process->cpu);
339
340 for(i = 0 ; i < process->execution_stack->len; i++) {
341 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
342 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
343 g_quark_to_string(es->t), g_quark_to_string(es->n),
344 es->entry.tv_sec, es->entry.tv_nsec);
345 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
346 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
347 }
348 fprintf(fp, " </PROCESS>\n");
349 }
350
351
352 void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
353 {
354 guint i, nb_tracefile, nb_block, offset;
355 guint64 tsc;
356
357 LttvTracefileState *tfcs;
358
359 LttTracefile *tf;
360
361 LttEventPosition *ep;
362
363 guint nb_cpus;
364
365 ep = ltt_event_position_new();
366
367 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
368
369 g_hash_table_foreach(self->processes, write_process_state, fp);
370
371 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
372 for(i=0;i<nb_cpus;i++) {
373 fprintf(fp,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
374 i, self->running_process[i]->pid);
375 }
376
377 nb_tracefile = self->parent.tracefiles->len;
378
379 for(i = 0 ; i < nb_tracefile ; i++) {
380 tfcs =
381 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
382 LttvTracefileContext*, i));
383 fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
384 tfcs->parent.timestamp.tv_sec,
385 tfcs->parent.timestamp.tv_nsec);
386 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
387 if(e == NULL) fprintf(fp,"/>\n");
388 else {
389 ltt_event_position(e, ep);
390 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
391 fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
392 tsc);
393 }
394 }
395 g_free(ep);
396 fprintf(fp,"</PROCESS_STATE>");
397 }
398
399
400 /* Copy each process from an existing hash table to a new one */
401
402 static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
403 {
404 LttvProcessState *process, *new_process;
405
406 GHashTable *new_processes = (GHashTable *)user_data;
407
408 guint i;
409
410 process = (LttvProcessState *)value;
411 new_process = g_new(LttvProcessState, 1);
412 *new_process = *process;
413 new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
414 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
415 new_process->execution_stack =
416 g_array_set_size(new_process->execution_stack,
417 process->execution_stack->len);
418 for(i = 0 ; i < process->execution_stack->len; i++) {
419 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
420 g_array_index(process->execution_stack, LttvExecutionState, i);
421 }
422 new_process->state = &g_array_index(new_process->execution_stack,
423 LttvExecutionState, new_process->execution_stack->len - 1);
424 g_hash_table_insert(new_processes, new_process, new_process);
425 }
426
427
428 static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
429 {
430 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
431
432 g_hash_table_foreach(processes, copy_process_state, new_processes);
433 return new_processes;
434 }
435
436
437 /* The saved state for each trace contains a member "processes", which
438 stores a copy of the process table, and a member "tracefiles" with
439 one entry per tracefile. Each tracefile has a "process" member pointing
440 to the current process and a "position" member storing the tracefile
441 position (needed to seek to the current "next" event. */
442
443 static void state_save(LttvTraceState *self, LttvAttribute *container)
444 {
445 guint i, nb_tracefile, nb_cpus;
446
447 LttvTracefileState *tfcs;
448
449 LttvAttribute *tracefiles_tree, *tracefile_tree;
450
451 guint *running_process;
452
453 LttvAttributeType type;
454
455 LttvAttributeValue value;
456
457 LttvAttributeName name;
458
459 LttEventPosition *ep;
460
461 tracefiles_tree = lttv_attribute_find_subdir(container,
462 LTTV_STATE_TRACEFILES);
463
464 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
465 LTTV_POINTER);
466 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
467
468 /* Add the currently running processes array */
469 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
470 running_process = g_new(guint, nb_cpus);
471 for(i=0;i<nb_cpus;i++) {
472 running_process[i] = self->running_process[i]->pid;
473 }
474 value = lttv_attribute_add(container, LTTV_STATE_RUNNING_PROCESS,
475 LTTV_POINTER);
476 *(value.v_pointer) = running_process;
477
478 g_info("State save");
479
480 nb_tracefile = self->parent.tracefiles->len;
481
482 for(i = 0 ; i < nb_tracefile ; i++) {
483 tfcs =
484 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
485 LttvTracefileContext*, i));
486 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
487 value = lttv_attribute_add(tracefiles_tree, i,
488 LTTV_GOBJECT);
489 *(value.v_gobject) = (GObject *)tracefile_tree;
490 #if 0
491 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
492 LTTV_UINT);
493 *(value.v_uint) = tfcs->process->pid;
494 #endif //0
495 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
496 LTTV_POINTER);
497 /* Only save the position if the tfs has not infinite time. */
498 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
499 // && current_tfcs != tfcs) {
500 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) == 0) {
501 *(value.v_pointer) = NULL;
502 } else {
503 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
504 ep = ltt_event_position_new();
505 ltt_event_position(e, ep);
506 *(value.v_pointer) = ep;
507
508 guint nb_block, offset;
509 guint64 tsc;
510 LttTracefile *tf;
511 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
512 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block, offset,
513 tsc,
514 tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
515 }
516 }
517 }
518
519
520 static void state_restore(LttvTraceState *self, LttvAttribute *container)
521 {
522 guint i, nb_tracefile, pid, nb_cpus;
523
524 LttvTracefileState *tfcs;
525
526 LttvAttribute *tracefiles_tree, *tracefile_tree;
527
528 guint *running_process;
529
530 LttvAttributeType type;
531
532 LttvAttributeValue value;
533
534 LttvAttributeName name;
535
536 LttEventPosition *ep;
537
538 LttvTracesetContext *tsc = self->parent.ts_context;
539
540 tracefiles_tree = lttv_attribute_find_subdir(container,
541 LTTV_STATE_TRACEFILES);
542
543 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
544 &value);
545 g_assert(type == LTTV_POINTER);
546 lttv_state_free_process_table(self->processes);
547 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
548
549 /* Add the currently running processes array */
550 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
551 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
552 &value);
553 g_assert(type == LTTV_POINTER);
554 running_process = *(value.v_pointer);
555 for(i=0;i<nb_cpus;i++) {
556 pid = running_process[i];
557 self->running_process[i] = lttv_state_find_process(self, i, pid);
558 g_assert(self->running_process[i] != NULL);
559 }
560
561
562 nb_tracefile = self->parent.tracefiles->len;
563
564 g_tree_destroy(tsc->pqueue);
565 tsc->pqueue = g_tree_new(compare_tracefile);
566
567 for(i = 0 ; i < nb_tracefile ; i++) {
568 tfcs =
569 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
570 LttvTracefileContext*, i));
571 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
572 g_assert(type == LTTV_GOBJECT);
573 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
574 #if 0
575 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
576 &value);
577 g_assert(type == LTTV_UINT);
578 pid = *(value.v_uint);
579 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
580 #endif //0
581 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
582 &value);
583 g_assert(type == LTTV_POINTER);
584 //g_assert(*(value.v_pointer) != NULL);
585 ep = *(value.v_pointer);
586 g_assert(tfcs->parent.t_context != NULL);
587
588 LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
589
590 if(ep != NULL) {
591 g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
592 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
593 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
594 g_tree_insert(tsc->pqueue, tfc, tfc);
595 g_info("Restoring state for a tf at time %lu.%lu", tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
596 } else {
597 tfc->timestamp = ltt_time_infinite;
598 }
599 }
600 }
601
602
603 static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
604 {
605 guint i, nb_tracefile, nb_cpus;
606
607 LttvTracefileState *tfcs;
608
609 LttvAttribute *tracefiles_tree, *tracefile_tree;
610
611 guint *running_process;
612
613 LttvAttributeType type;
614
615 LttvAttributeValue value;
616
617 LttvAttributeName name;
618
619 LttEventPosition *ep;
620
621 tracefiles_tree = lttv_attribute_find_subdir(container,
622 LTTV_STATE_TRACEFILES);
623 g_object_ref(G_OBJECT(tracefiles_tree));
624 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
625
626 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
627 &value);
628 g_assert(type == LTTV_POINTER);
629 lttv_state_free_process_table(*(value.v_pointer));
630 *(value.v_pointer) = NULL;
631 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
632
633 /* Free running processes array */
634 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
635 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
636 &value);
637 g_assert(type == LTTV_POINTER);
638 running_process = *(value.v_pointer);
639 g_free(running_process);
640
641 nb_tracefile = self->parent.tracefiles->len;
642
643 for(i = 0 ; i < nb_tracefile ; i++) {
644 tfcs =
645 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
646 LttvTracefileContext*, i));
647 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
648 g_assert(type == LTTV_GOBJECT);
649 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
650
651 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
652 &value);
653 g_assert(type == LTTV_POINTER);
654 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
655 }
656 g_object_unref(G_OBJECT(tracefiles_tree));
657 }
658
659
660 static void free_saved_state(LttvTraceState *self)
661 {
662 guint i, nb;
663
664 LttvAttributeType type;
665
666 LttvAttributeValue value;
667
668 LttvAttributeName name;
669
670 LttvAttribute *saved_states;
671
672 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
673 LTTV_STATE_SAVED_STATES);
674
675 nb = lttv_attribute_get_number(saved_states);
676 for(i = 0 ; i < nb ; i++) {
677 type = lttv_attribute_get(saved_states, i, &name, &value);
678 g_assert(type == LTTV_GOBJECT);
679 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
680 }
681
682 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
683 }
684
685
686 static void
687 create_max_time(LttvTraceState *tcs)
688 {
689 LttvAttributeValue v;
690
691 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
692 LTTV_POINTER, &v);
693 g_assert(*(v.v_pointer) == NULL);
694 *(v.v_pointer) = g_new(LttTime,1);
695 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
696 }
697
698
699 static void
700 get_max_time(LttvTraceState *tcs)
701 {
702 LttvAttributeValue v;
703
704 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
705 LTTV_POINTER, &v);
706 g_assert(*(v.v_pointer) != NULL);
707 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
708 }
709
710
711 static void
712 free_max_time(LttvTraceState *tcs)
713 {
714 LttvAttributeValue v;
715
716 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
717 LTTV_POINTER, &v);
718 g_free(*(v.v_pointer));
719 *(v.v_pointer) = NULL;
720 }
721
722
723 typedef struct _LttvNameTables {
724 // FIXME GQuark *eventtype_names;
725 GQuark *syscall_names;
726 GQuark *trap_names;
727 GQuark *irq_names;
728 } LttvNameTables;
729
730
731 static void
732 create_name_tables(LttvTraceState *tcs)
733 {
734 int i, nb;
735
736 GQuark f_name, e_name;
737
738 LttvTraceHook h;
739
740 LttvTraceHookByFacility *thf;
741
742 LttEventType *et;
743
744 LttType *t;
745
746 GString *fe_name = g_string_new("");
747
748 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
749
750 LttvAttributeValue v;
751
752 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
753 LTTV_POINTER, &v);
754 g_assert(*(v.v_pointer) == NULL);
755 *(v.v_pointer) = name_tables;
756 #if 0 // Use iteration over the facilities_by_name and then list all event
757 // types of each facility
758 nb = ltt_trace_eventtype_number(tcs->parent.t);
759 name_tables->eventtype_names = g_new(GQuark, nb);
760 for(i = 0 ; i < nb ; i++) {
761 et = ltt_trace_eventtype_get(tcs->parent.t, i);
762 e_name = ltt_eventtype_name(et);
763 f_name = ltt_facility_name(ltt_eventtype_facility(et));
764 g_string_printf(fe_name, "%s.%s", f_name, e_name);
765 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
766 }
767 #endif //0
768 if(lttv_trace_find_hook(tcs->parent.t,
769 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
770 LTT_FIELD_SYSCALL_ID, 0, 0,
771 NULL, NULL, &h))
772 return;
773
774 thf = lttv_trace_hook_get_first(&h);
775
776 t = ltt_field_type(thf->f1);
777 nb = ltt_type_element_number(t);
778
779 lttv_trace_hook_destroy(&h);
780
781 /* CHECK syscalls should be an enum but currently are not!
782 name_tables->syscall_names = g_new(GQuark, nb);
783
784 for(i = 0 ; i < nb ; i++) {
785 name_tables->syscall_names[i] = g_quark_from_string(
786 ltt_enum_string_get(t, i));
787 }
788 */
789
790 name_tables->syscall_names = g_new(GQuark, 256);
791 for(i = 0 ; i < 256 ; i++) {
792 g_string_printf(fe_name, "syscall %d", i);
793 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
794 }
795
796 if(lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL,
797 LTT_EVENT_TRAP_ENTRY,
798 LTT_FIELD_TRAP_ID, 0, 0,
799 NULL, NULL, &h))
800 return;
801
802 thf = lttv_trace_hook_get_first(&h);
803
804 t = ltt_field_type(thf->f1);
805 nb = ltt_type_element_number(t);
806
807 lttv_trace_hook_destroy(&h);
808
809 /*
810 name_tables->trap_names = g_new(GQuark, nb);
811 for(i = 0 ; i < nb ; i++) {
812 name_tables->trap_names[i] = g_quark_from_string(
813 ltt_enum_string_get(t, i));
814 }
815 */
816
817 name_tables->trap_names = g_new(GQuark, 256);
818 for(i = 0 ; i < 256 ; i++) {
819 g_string_printf(fe_name, "trap %d", i);
820 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
821 }
822
823 if(lttv_trace_find_hook(tcs->parent.t,
824 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
825 LTT_FIELD_IRQ_ID, 0, 0,
826 NULL, NULL, &h))
827 return;
828
829 thf = lttv_trace_hook_get_first(&h);
830
831 t = ltt_field_type(thf->f1);
832 nb = ltt_type_element_number(t);
833
834 lttv_trace_hook_destroy(&h);
835
836 /*
837 name_tables->irq_names = g_new(GQuark, nb);
838 for(i = 0 ; i < nb ; i++) {
839 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
840 }
841 */
842
843 name_tables->irq_names = g_new(GQuark, 256);
844 for(i = 0 ; i < 256 ; i++) {
845 g_string_printf(fe_name, "irq %d", i);
846 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
847 }
848
849 g_string_free(fe_name, TRUE);
850 }
851
852
853 static void
854 get_name_tables(LttvTraceState *tcs)
855 {
856 LttvNameTables *name_tables;
857
858 LttvAttributeValue v;
859
860 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
861 LTTV_POINTER, &v);
862 g_assert(*(v.v_pointer) != NULL);
863 name_tables = (LttvNameTables *)*(v.v_pointer);
864 //tcs->eventtype_names = name_tables->eventtype_names;
865 tcs->syscall_names = name_tables->syscall_names;
866 tcs->trap_names = name_tables->trap_names;
867 tcs->irq_names = name_tables->irq_names;
868 }
869
870
871 static void
872 free_name_tables(LttvTraceState *tcs)
873 {
874 LttvNameTables *name_tables;
875
876 LttvAttributeValue v;
877
878 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
879 LTTV_POINTER, &v);
880 name_tables = (LttvNameTables *)*(v.v_pointer);
881 *(v.v_pointer) = NULL;
882
883 // g_free(name_tables->eventtype_names);
884 g_free(name_tables->syscall_names);
885 g_free(name_tables->trap_names);
886 g_free(name_tables->irq_names);
887 g_free(name_tables);
888 }
889
890 #ifdef HASH_TABLE_DEBUG
891
892 static void test_process(gpointer key, gpointer value, gpointer user_data)
893 {
894 LttvProcessState *process = (LttvProcessState *)value;
895
896 /* Test for process corruption */
897 guint stack_len = process->execution_stack->len;
898 }
899
900 static void hash_table_check(GHashTable *table)
901 {
902 g_hash_table_foreach(table, test_process, NULL);
903 }
904
905
906 #endif
907
908
909 static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
910 guint state_id)
911 {
912 LttvExecutionState *es;
913
914 guint cpu = ltt_tracefile_num(tfs->parent.tf);
915 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
916
917 #ifdef HASH_TABLE_DEBUG
918 hash_table_check(ts->processes);
919 #endif
920 LttvProcessState *process = ts->running_process[cpu];
921
922 guint depth = process->execution_stack->len;
923
924 process->execution_stack =
925 g_array_set_size(process->execution_stack, depth + 1);
926 /* Keep in sync */
927 process->state =
928 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
929
930 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
931 es->t = t;
932 es->n = state_id;
933 es->entry = es->change = tfs->parent.timestamp;
934 es->s = process->state->s;
935 process->state = es;
936 }
937
938
939 static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
940 {
941 guint cpu = ltt_tracefile_num(tfs->parent.tf);
942 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
943 LttvProcessState *process = ts->running_process[cpu];
944
945 guint depth = process->execution_stack->len;
946
947 if(process->state->t != t){
948 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
949 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
950 g_info("process state has %s when pop_int is %s\n",
951 g_quark_to_string(process->state->t),
952 g_quark_to_string(t));
953 g_info("{ %u, %u, %s, %s }\n",
954 process->pid,
955 process->ppid,
956 g_quark_to_string(process->name),
957 g_quark_to_string(process->state->s));
958 return;
959 }
960
961 if(depth == 1){
962 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
963 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
964 return;
965 }
966
967 process->execution_stack =
968 g_array_set_size(process->execution_stack, depth - 1);
969 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
970 depth - 2);
971 process->state->change = tfs->parent.timestamp;
972 }
973
974
975 LttvProcessState *
976 lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
977 guint cpu, guint pid, const LttTime *timestamp)
978 {
979 LttvProcessState *process = g_new(LttvProcessState, 1);
980
981 LttvExecutionState *es;
982
983 LttvTraceContext *tc = (LttvTraceContext*)tcs;
984
985 char buffer[128];
986
987 process->pid = pid;
988 process->cpu = cpu;
989 //process->last_cpu = tfs->cpu_name;
990 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
991 g_info("Process %u, core %p", process->pid, process);
992 g_hash_table_insert(tcs->processes, process, process);
993
994 if(parent) {
995 process->ppid = parent->pid;
996 process->name = parent->name;
997 process->creation_time = *timestamp;
998 }
999
1000 /* No parent. This process exists but we are missing all information about
1001 its creation. The birth time is set to zero but we remember the time of
1002 insertion */
1003
1004 else {
1005 process->ppid = 0;
1006 process->name = LTTV_STATE_UNNAMED;
1007 process->creation_time = ltt_time_zero;
1008 }
1009
1010 process->insertion_time = *timestamp;
1011 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
1012 process->creation_time.tv_nsec);
1013 process->pid_time = g_quark_from_string(buffer);
1014 process->cpu = cpu;
1015 //process->last_cpu = tfs->cpu_name;
1016 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1017 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1018 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
1019 process->execution_stack = g_array_set_size(process->execution_stack, 1);
1020 es = process->state = &g_array_index(process->execution_stack,
1021 LttvExecutionState, 0);
1022 es->t = LTTV_STATE_USER_MODE;
1023 es->n = LTTV_STATE_SUBMODE_NONE;
1024 es->entry = *timestamp;
1025 //g_assert(timestamp->tv_sec != 0);
1026 es->change = *timestamp;
1027 es->s = LTTV_STATE_WAIT_FORK;
1028
1029 return process;
1030 }
1031
1032 LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
1033 guint pid)
1034 {
1035 LttvProcessState key;
1036 LttvProcessState *process;
1037
1038 key.pid = pid;
1039 key.cpu = cpu;
1040 process = g_hash_table_lookup(ts->processes, &key);
1041 return process;
1042 }
1043
1044 LttvProcessState *
1045 lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1046 LttTime *timestamp)
1047 {
1048 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
1049
1050 /* Put ltt_time_zero creation time for unexisting processes */
1051 if(unlikely(process == NULL)) process = lttv_state_create_process(ts,
1052 NULL, cpu, pid, timestamp);
1053 return process;
1054 }
1055
1056 /* FIXME : this function should be called when we receive an event telling that
1057 * release_task has been called in the kernel. In happens generally when
1058 * the parent waits for its child terminaison, but may also happen in special
1059 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1060 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1061 * of a killed thread ground, but isn't the leader.
1062 */
1063 static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
1064 {
1065 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
1066 LttvProcessState key;
1067
1068 key.pid = process->pid;
1069 key.cpu = process->cpu;
1070 g_hash_table_remove(ts->processes, &key);
1071 g_array_free(process->execution_stack, TRUE);
1072 g_free(process);
1073 }
1074
1075
1076 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
1077 {
1078 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
1079 g_free(value);
1080 }
1081
1082
1083 static void lttv_state_free_process_table(GHashTable *processes)
1084 {
1085 g_hash_table_foreach(processes, free_process_state, NULL);
1086 g_hash_table_destroy(processes);
1087 }
1088
1089
1090 static gboolean syscall_entry(void *hook_data, void *call_data)
1091 {
1092 LttvTracefileState *s = (LttvTracefileState *)call_data;
1093 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1094 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1095 LttField *f = thf->f1;
1096
1097 LttvExecutionSubmode submode;
1098
1099 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
1100 ltt_event_get_unsigned(e, f)];
1101 push_state(s, LTTV_STATE_SYSCALL, submode);
1102 return FALSE;
1103 }
1104
1105
1106 static gboolean syscall_exit(void *hook_data, void *call_data)
1107 {
1108 LttvTracefileState *s = (LttvTracefileState *)call_data;
1109
1110 pop_state(s, LTTV_STATE_SYSCALL);
1111 return FALSE;
1112 }
1113
1114
1115 static gboolean trap_entry(void *hook_data, void *call_data)
1116 {
1117 LttvTracefileState *s = (LttvTracefileState *)call_data;
1118 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1119 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1120 LttField *f = thf->f1;
1121
1122 LttvExecutionSubmode submode;
1123
1124 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
1125 ltt_event_get_unsigned(e, f)];
1126 push_state(s, LTTV_STATE_TRAP, submode);
1127 return FALSE;
1128 }
1129
1130
1131 static gboolean trap_exit(void *hook_data, void *call_data)
1132 {
1133 LttvTracefileState *s = (LttvTracefileState *)call_data;
1134
1135 pop_state(s, LTTV_STATE_TRAP);
1136 return FALSE;
1137 }
1138
1139
1140 static gboolean irq_entry(void *hook_data, void *call_data)
1141 {
1142 LttvTracefileState *s = (LttvTracefileState *)call_data;
1143 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1144 guint8 fac_id = ltt_event_facility_id(e);
1145 guint8 ev_id = ltt_event_eventtype_id(e);
1146 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1147 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1148 g_assert(thf->f1 != NULL);
1149 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1150 LttField *f = thf->f1;
1151
1152 LttvExecutionSubmode submode;
1153
1154 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
1155 ltt_event_get_unsigned(e, f)];
1156
1157 /* Do something with the info about being in user or system mode when int? */
1158 push_state(s, LTTV_STATE_IRQ, submode);
1159 return FALSE;
1160 }
1161
1162
1163 static gboolean irq_exit(void *hook_data, void *call_data)
1164 {
1165 LttvTracefileState *s = (LttvTracefileState *)call_data;
1166
1167 pop_state(s, LTTV_STATE_IRQ);
1168 return FALSE;
1169 }
1170
1171
1172 static gboolean schedchange(void *hook_data, void *call_data)
1173 {
1174 LttvTracefileState *s = (LttvTracefileState *)call_data;
1175 guint cpu = ltt_tracefile_num(s->parent.tf);
1176 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1177 LttvProcessState *process = ts->running_process[cpu];
1178
1179 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1180 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1181 guint pid_in, pid_out;
1182 gint state_out;
1183
1184 pid_out = ltt_event_get_unsigned(e, thf->f1);
1185 pid_in = ltt_event_get_unsigned(e, thf->f2);
1186 state_out = ltt_event_get_int(e, thf->f3);
1187
1188 if(likely(process != NULL)) {
1189
1190 /* We could not know but it was not the idle process executing.
1191 This should only happen at the beginning, before the first schedule
1192 event, and when the initial information (current process for each CPU)
1193 is missing. It is not obvious how we could, after the fact, compensate
1194 the wrongly attributed statistics. */
1195
1196 //This test only makes sense once the state is known and if there is no
1197 //missing events.
1198 //if(unlikely(process->pid != pid_out)) {
1199 // g_assert(process->pid == 0);
1200 //}
1201
1202 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
1203 process->state->s = LTTV_STATE_ZOMBIE;
1204 } else {
1205 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
1206 else process->state->s = LTTV_STATE_WAIT;
1207 } /* FIXME : we do not remove process here, because the kernel
1208 * still has them : they may be zombies. We need to know
1209 * exactly when release_task is executed on the PID to
1210 * know when the zombie is destroyed.
1211 */
1212 //else
1213 // exit_process(s, process);
1214
1215 process->state->change = s->parent.timestamp;
1216 }
1217 process = ts->running_process[cpu] =
1218 lttv_state_find_process_or_create(
1219 (LttvTraceState*)s->parent.t_context,
1220 cpu, pid_in,
1221 &s->parent.timestamp);
1222 process->state->s = LTTV_STATE_RUN;
1223 process->cpu = cpu;
1224 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1225 process->state->change = s->parent.timestamp;
1226 return FALSE;
1227 }
1228
1229 static gboolean process_fork(void *hook_data, void *call_data)
1230 {
1231 LttvTracefileState *s = (LttvTracefileState *)call_data;
1232 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1233 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1234 LttField *f;
1235 guint parent_pid;
1236 guint child_pid;
1237 LttvProcessState *zombie_process;
1238 guint cpu = ltt_tracefile_num(s->parent.tf);
1239 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1240 LttvProcessState *process = ts->running_process[cpu];
1241
1242 /* Parent PID */
1243 f = thf->f1;
1244 parent_pid = ltt_event_get_unsigned(e, f);
1245
1246 /* Child PID */
1247 f = thf->f2;
1248 child_pid = ltt_event_get_unsigned(e, f);
1249
1250 /* Mathieu : it seems like the process might have been scheduled in before the
1251 * fork, and, in a rare case, might be the current process. This might happen
1252 * in a SMP case where we don't have enough precision on the clocks */
1253 #if 0
1254 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1255
1256 if(unlikely(zombie_process != NULL)) {
1257 /* Reutilisation of PID. Only now we are sure that the old PID
1258 * has been released. FIXME : should know when release_task happens instead.
1259 */
1260 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1261 guint i;
1262 for(i=0; i< num_cpus; i++) {
1263 g_assert(process != ts->running_process[i]);
1264 }
1265
1266 exit_process(s, zombie_process);
1267 }
1268 #endif //0
1269 g_assert(process->pid != child_pid);
1270 // FIXME : Add this test in the "known state" section
1271 // g_assert(process->pid == parent_pid);
1272 lttv_state_create_process(ts, process, cpu, child_pid, &s->parent.timestamp);
1273
1274 return FALSE;
1275 }
1276
1277
1278 static gboolean process_exit(void *hook_data, void *call_data)
1279 {
1280 LttvTracefileState *s = (LttvTracefileState *)call_data;
1281 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1282 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1283 LttField *f;
1284 guint pid;
1285 guint cpu = ltt_tracefile_num(s->parent.tf);
1286 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1287 LttvProcessState *process = ts->running_process[cpu];
1288
1289 pid = ltt_event_get_unsigned(e, thf->f1);
1290
1291 // FIXME : Add this test in the "known state" section
1292 // g_assert(process->pid == pid);
1293
1294 if(likely(process != NULL)) {
1295 process->state->s = LTTV_STATE_EXIT;
1296 }
1297 return FALSE;
1298 }
1299
1300 static gboolean process_free(void *hook_data, void *call_data)
1301 {
1302 LttvTracefileState *s = (LttvTracefileState *)call_data;
1303 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1304 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1305 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1306 guint release_pid;
1307 LttvProcessState *process;
1308
1309 /* PID of the process to release */
1310 release_pid = ltt_event_get_unsigned(e, thf->f1);
1311
1312 g_assert(release_pid != 0);
1313
1314 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
1315
1316 if(likely(process != NULL)) {
1317 /* release_task is happening at kernel level : we can now safely release
1318 * the data structure of the process */
1319 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1320 guint i;
1321 for(i=0; i< num_cpus; i++) {
1322 g_assert(process != ts->running_process[i]);
1323 }
1324 exit_process(s, process);
1325 }
1326
1327 return FALSE;
1328 }
1329
1330
1331 static gboolean process_exec(void *hook_data, void *call_data)
1332 {
1333 LttvTracefileState *s = (LttvTracefileState *)call_data;
1334 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1335 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1336 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1337 gchar *name;
1338 guint cpu = ltt_tracefile_num(s->parent.tf);
1339 LttvProcessState *process = ts->running_process[cpu];
1340
1341 /* PID of the process to release */
1342 name = ltt_event_get_string(e, thf->f1);
1343
1344 process->name = g_quark_from_string(name);
1345
1346 return FALSE;
1347 }
1348
1349
1350
1351
1352 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1353 {
1354 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1355
1356 lttv_state_add_event_hooks(tss);
1357
1358 return 0;
1359 }
1360
1361 void lttv_state_add_event_hooks(LttvTracesetState *self)
1362 {
1363 LttvTraceset *traceset = self->parent.ts;
1364
1365 guint i, j, k, l, nb_trace, nb_tracefile;
1366
1367 LttvTraceState *ts;
1368
1369 LttvTracefileState *tfs;
1370
1371 GArray *hooks;
1372
1373 LttvTraceHookByFacility *thf;
1374
1375 LttvTraceHook *hook;
1376
1377 LttvAttributeValue val;
1378
1379 gint ret;
1380
1381 nb_trace = lttv_traceset_number(traceset);
1382 for(i = 0 ; i < nb_trace ; i++) {
1383 ts = (LttvTraceState *)self->parent.traces[i];
1384
1385 /* Find the eventtype id for the following events and register the
1386 associated by id hooks. */
1387
1388 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 11);
1389 hooks = g_array_set_size(hooks, 11);
1390
1391 ret = lttv_trace_find_hook(ts->parent.t,
1392 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
1393 LTT_FIELD_SYSCALL_ID, 0, 0,
1394 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
1395 g_assert(!ret);
1396
1397 ret = lttv_trace_find_hook(ts->parent.t,
1398 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_EXIT,
1399 0, 0, 0,
1400 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
1401 g_assert(!ret);
1402
1403 ret = lttv_trace_find_hook(ts->parent.t,
1404 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1405 LTT_FIELD_TRAP_ID, 0, 0,
1406 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, 2));
1407 g_assert(!ret);
1408
1409 ret = lttv_trace_find_hook(ts->parent.t,
1410 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1411 0, 0, 0,
1412 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, 3));
1413 g_assert(!ret);
1414
1415 ret = lttv_trace_find_hook(ts->parent.t,
1416 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1417 LTT_FIELD_IRQ_ID, 0, 0,
1418 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 4));
1419 g_assert(!ret);
1420
1421 ret = lttv_trace_find_hook(ts->parent.t,
1422 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1423 0, 0, 0,
1424 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
1425 g_assert(!ret);
1426
1427 ret = lttv_trace_find_hook(ts->parent.t,
1428 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1429 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
1430 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 6));
1431 g_assert(!ret);
1432
1433 ret = lttv_trace_find_hook(ts->parent.t,
1434 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1435 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
1436 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 7));
1437 g_assert(!ret);
1438
1439 ret = lttv_trace_find_hook(ts->parent.t,
1440 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1441 LTT_FIELD_PID, 0, 0,
1442 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 8));
1443 g_assert(!ret);
1444
1445 ret = lttv_trace_find_hook(ts->parent.t,
1446 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1447 LTT_FIELD_PID, 0, 0,
1448 process_free, NULL, &g_array_index(hooks, LttvTraceHook, 9));
1449 g_assert(!ret);
1450
1451 ret = lttv_trace_find_hook(ts->parent.t,
1452 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1453 LTT_FIELD_FILENAME, 0, 0,
1454 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 10));
1455 g_assert(!ret);
1456
1457
1458
1459 /* Add these hooks to each event_by_id hooks list */
1460
1461 nb_tracefile = ts->parent.tracefiles->len;
1462
1463 for(j = 0 ; j < nb_tracefile ; j++) {
1464 tfs =
1465 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1466 LttvTracefileContext*, j));
1467
1468 for(k = 0 ; k < hooks->len ; k++) {
1469 hook = &g_array_index(hooks, LttvTraceHook, k);
1470 for(l=0;l<hook->fac_list->len;l++) {
1471 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1472 lttv_hooks_add(
1473 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1474 thf->h,
1475 thf,
1476 LTTV_PRIO_STATE);
1477 }
1478 }
1479 }
1480 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1481 *(val.v_pointer) = hooks;
1482 }
1483 }
1484
1485 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1486 {
1487 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1488
1489 lttv_state_remove_event_hooks(tss);
1490
1491 return 0;
1492 }
1493
1494 void lttv_state_remove_event_hooks(LttvTracesetState *self)
1495 {
1496 LttvTraceset *traceset = self->parent.ts;
1497
1498 guint i, j, k, l, nb_trace, nb_tracefile;
1499
1500 LttvTraceState *ts;
1501
1502 LttvTracefileState *tfs;
1503
1504 GArray *hooks;
1505
1506 LttvTraceHook *hook;
1507
1508 LttvTraceHookByFacility *thf;
1509
1510 LttvAttributeValue val;
1511
1512 nb_trace = lttv_traceset_number(traceset);
1513 for(i = 0 ; i < nb_trace ; i++) {
1514 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1515 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1516 hooks = *(val.v_pointer);
1517
1518 /* Remove these hooks from each event_by_id hooks list */
1519
1520 nb_tracefile = ts->parent.tracefiles->len;
1521
1522 for(j = 0 ; j < nb_tracefile ; j++) {
1523 tfs =
1524 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1525 LttvTracefileContext*, j));
1526
1527 for(k = 0 ; k < hooks->len ; k++) {
1528 hook = &g_array_index(hooks, LttvTraceHook, k);
1529 for(l=0;l<hook->fac_list->len;l++) {
1530 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1531
1532 lttv_hooks_remove_data(
1533 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1534 thf->h,
1535 thf);
1536 }
1537 }
1538 }
1539 for(k = 0 ; k < hooks->len ; k++)
1540 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
1541 g_array_free(hooks, TRUE);
1542 }
1543 }
1544
1545 static gboolean state_save_event_hook(void *hook_data, void *call_data)
1546 {
1547 guint *event_count = (guint*)hook_data;
1548
1549 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1550 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
1551 return FALSE;
1552 else
1553 *event_count = 0;
1554
1555 LttvTracefileState *self = (LttvTracefileState *)call_data;
1556
1557 LttvTracefileState *tfcs;
1558
1559 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1560
1561 LttEventPosition *ep;
1562
1563 guint i;
1564
1565 LttTracefile *tf;
1566
1567 LttvAttribute *saved_states_tree, *saved_state_tree;
1568
1569 LttvAttributeValue value;
1570
1571 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1572 LTTV_STATE_SAVED_STATES);
1573 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1574 value = lttv_attribute_add(saved_states_tree,
1575 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1576 *(value.v_gobject) = (GObject *)saved_state_tree;
1577 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1578 *(value.v_time) = self->parent.timestamp;
1579 lttv_state_save(tcs, saved_state_tree);
1580 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1581 self->parent.timestamp.tv_nsec);
1582
1583 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1584
1585 return FALSE;
1586 }
1587
1588 #if 0
1589 static gboolean block_start(void *hook_data, void *call_data)
1590 {
1591 LttvTracefileState *self = (LttvTracefileState *)call_data;
1592
1593 LttvTracefileState *tfcs;
1594
1595 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1596
1597 LttEventPosition *ep;
1598
1599 guint i, nb_block, nb_event, nb_tracefile;
1600
1601 LttTracefile *tf;
1602
1603 LttvAttribute *saved_states_tree, *saved_state_tree;
1604
1605 LttvAttributeValue value;
1606
1607 ep = ltt_event_position_new();
1608
1609 nb_tracefile = tcs->parent.tracefiles->len;
1610
1611 /* Count the number of events added since the last block end in any
1612 tracefile. */
1613
1614 for(i = 0 ; i < nb_tracefile ; i++) {
1615 tfcs =
1616 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
1617 LttvTracefileContext, i));
1618 ltt_event_position(tfcs->parent.e, ep);
1619 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1620 tcs->nb_event += nb_event - tfcs->saved_position;
1621 tfcs->saved_position = nb_event;
1622 }
1623 g_free(ep);
1624
1625 if(tcs->nb_event >= tcs->save_interval) {
1626 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1627 LTTV_STATE_SAVED_STATES);
1628 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1629 value = lttv_attribute_add(saved_states_tree,
1630 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1631 *(value.v_gobject) = (GObject *)saved_state_tree;
1632 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1633 *(value.v_time) = self->parent.timestamp;
1634 lttv_state_save(tcs, saved_state_tree);
1635 tcs->nb_event = 0;
1636 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1637 self->parent.timestamp.tv_nsec);
1638 }
1639 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1640 return FALSE;
1641 }
1642 #endif //0
1643
1644 #if 0
1645 static gboolean block_end(void *hook_data, void *call_data)
1646 {
1647 LttvTracefileState *self = (LttvTracefileState *)call_data;
1648
1649 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1650
1651 LttTracefile *tf;
1652
1653 LttEventPosition *ep;
1654
1655 guint nb_block, nb_event;
1656
1657 ep = ltt_event_position_new();
1658 ltt_event_position(self->parent.e, ep);
1659 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1660 tcs->nb_event += nb_event - self->saved_position + 1;
1661 self->saved_position = 0;
1662 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1663 g_free(ep);
1664
1665 return FALSE;
1666 }
1667 #endif //0
1668 #if 0
1669 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1670 {
1671 LttvTraceset *traceset = self->parent.ts;
1672
1673 guint i, j, nb_trace, nb_tracefile;
1674
1675 LttvTraceState *ts;
1676
1677 LttvTracefileState *tfs;
1678
1679 LttvTraceHook hook_start, hook_end;
1680
1681 nb_trace = lttv_traceset_number(traceset);
1682 for(i = 0 ; i < nb_trace ; i++) {
1683 ts = (LttvTraceState *)self->parent.traces[i];
1684
1685 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1686 NULL, NULL, block_start, &hook_start);
1687 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1688 NULL, NULL, block_end, &hook_end);
1689
1690 nb_tracefile = ts->parent.tracefiles->len;
1691
1692 for(j = 0 ; j < nb_tracefile ; j++) {
1693 tfs =
1694 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1695 LttvTracefileContext, j));
1696 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1697 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1698 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1699 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1700 }
1701 }
1702 }
1703 #endif //0
1704
1705 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1706 {
1707 LttvTraceset *traceset = self->parent.ts;
1708
1709 guint i, j, nb_trace, nb_tracefile;
1710
1711 LttvTraceState *ts;
1712
1713 LttvTracefileState *tfs;
1714
1715
1716 nb_trace = lttv_traceset_number(traceset);
1717 for(i = 0 ; i < nb_trace ; i++) {
1718
1719 ts = (LttvTraceState *)self->parent.traces[i];
1720 nb_tracefile = ts->parent.tracefiles->len;
1721
1722 guint *event_count = g_new(guint, 1);
1723 *event_count = 0;
1724
1725 for(j = 0 ; j < nb_tracefile ; j++) {
1726 tfs =
1727 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1728 LttvTracefileContext*, j));
1729 lttv_hooks_add(tfs->parent.event,
1730 state_save_event_hook,
1731 event_count,
1732 LTTV_PRIO_STATE);
1733
1734 }
1735 }
1736 }
1737
1738 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1739 {
1740 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1741
1742 lttv_state_save_add_event_hooks(tss);
1743
1744 return 0;
1745 }
1746
1747
1748 #if 0
1749 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1750 {
1751 LttvTraceset *traceset = self->parent.ts;
1752
1753 guint i, j, nb_trace, nb_tracefile;
1754
1755 LttvTraceState *ts;
1756
1757 LttvTracefileState *tfs;
1758
1759 LttvTraceHook hook_start, hook_end;
1760
1761 nb_trace = lttv_traceset_number(traceset);
1762 for(i = 0 ; i < nb_trace ; i++) {
1763 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1764
1765 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1766 NULL, NULL, block_start, &hook_start);
1767
1768 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1769 NULL, NULL, block_end, &hook_end);
1770
1771 nb_tracefile = ts->parent.tracefiles->len;
1772
1773 for(j = 0 ; j < nb_tracefile ; j++) {
1774 tfs =
1775 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1776 LttvTracefileContext, j));
1777 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1778 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
1779 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1780 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
1781 }
1782 }
1783 }
1784 #endif //0
1785
1786 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1787 {
1788 LttvTraceset *traceset = self->parent.ts;
1789
1790 guint i, j, nb_trace, nb_tracefile;
1791
1792 LttvTraceState *ts;
1793
1794 LttvTracefileState *tfs;
1795
1796
1797 nb_trace = lttv_traceset_number(traceset);
1798 for(i = 0 ; i < nb_trace ; i++) {
1799
1800 ts = (LttvTraceState *)self->parent.traces[i];
1801 nb_tracefile = ts->parent.tracefiles->len;
1802
1803 guint *event_count;
1804
1805 for(j = 0 ; j < nb_tracefile ; j++) {
1806 tfs =
1807 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1808 LttvTracefileContext*, j));
1809 event_count = lttv_hooks_remove(tfs->parent.event,
1810 state_save_event_hook);
1811
1812 }
1813 g_free(event_count);
1814 }
1815 }
1816
1817 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1818 {
1819 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1820
1821 lttv_state_save_remove_event_hooks(tss);
1822
1823 return 0;
1824 }
1825
1826 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
1827 {
1828 LttvTraceset *traceset = self->parent.ts;
1829
1830 guint i, nb_trace;
1831
1832 int min_pos, mid_pos, max_pos;
1833
1834 guint call_rest = 0;
1835
1836 LttvTraceState *tcs;
1837
1838 LttvAttributeValue value;
1839
1840 LttvAttributeType type;
1841
1842 LttvAttributeName name;
1843
1844 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1845
1846 g_tree_destroy(self->parent.pqueue);
1847 self->parent.pqueue = g_tree_new(compare_tracefile);
1848
1849 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
1850
1851 nb_trace = lttv_traceset_number(traceset);
1852 for(i = 0 ; i < nb_trace ; i++) {
1853 tcs = (LttvTraceState *)self->parent.traces[i];
1854
1855 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1856 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1857 LTTV_STATE_SAVED_STATES);
1858 min_pos = -1;
1859
1860 if(saved_states_tree) {
1861 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1862 mid_pos = max_pos / 2;
1863 while(min_pos < max_pos) {
1864 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1865 g_assert(type == LTTV_GOBJECT);
1866 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1867 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1868 &value);
1869 g_assert(type == LTTV_TIME);
1870 if(ltt_time_compare(*(value.v_time), t) < 0) {
1871 min_pos = mid_pos;
1872 closest_tree = saved_state_tree;
1873 }
1874 else max_pos = mid_pos - 1;
1875
1876 mid_pos = (min_pos + max_pos + 1) / 2;
1877 }
1878 }
1879
1880 /* restore the closest earlier saved state */
1881 if(min_pos != -1) {
1882 lttv_state_restore(tcs, closest_tree);
1883 call_rest = 1;
1884 }
1885
1886 /* There is no saved state, yet we want to have it. Restart at T0 */
1887 else {
1888 restore_init_state(tcs);
1889 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
1890 }
1891 }
1892 /* We want to seek quickly without restoring/updating the state */
1893 else {
1894 restore_init_state(tcs);
1895 lttv_process_trace_seek_time(&(tcs->parent), t);
1896 }
1897 }
1898 if(!call_rest) g_info("NOT Calling restore");
1899 }
1900
1901
1902 static void
1903 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1904 {
1905 }
1906
1907
1908 static void
1909 traceset_state_finalize (LttvTracesetState *self)
1910 {
1911 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1912 finalize(G_OBJECT(self));
1913 }
1914
1915
1916 static void
1917 traceset_state_class_init (LttvTracesetContextClass *klass)
1918 {
1919 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1920
1921 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1922 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1923 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1924 klass->new_traceset_context = new_traceset_context;
1925 klass->new_trace_context = new_trace_context;
1926 klass->new_tracefile_context = new_tracefile_context;
1927 }
1928
1929
1930 GType
1931 lttv_traceset_state_get_type(void)
1932 {
1933 static GType type = 0;
1934 if (type == 0) {
1935 static const GTypeInfo info = {
1936 sizeof (LttvTracesetStateClass),
1937 NULL, /* base_init */
1938 NULL, /* base_finalize */
1939 (GClassInitFunc) traceset_state_class_init, /* class_init */
1940 NULL, /* class_finalize */
1941 NULL, /* class_data */
1942 sizeof (LttvTracesetState),
1943 0, /* n_preallocs */
1944 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
1945 NULL /* value handling */
1946 };
1947
1948 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1949 &info, 0);
1950 }
1951 return type;
1952 }
1953
1954
1955 static void
1956 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1957 {
1958 }
1959
1960
1961 static void
1962 trace_state_finalize (LttvTraceState *self)
1963 {
1964 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
1965 finalize(G_OBJECT(self));
1966 }
1967
1968
1969 static void
1970 trace_state_class_init (LttvTraceStateClass *klass)
1971 {
1972 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1973
1974 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
1975 klass->state_save = state_save;
1976 klass->state_restore = state_restore;
1977 klass->state_saved_free = state_saved_free;
1978 }
1979
1980
1981 GType
1982 lttv_trace_state_get_type(void)
1983 {
1984 static GType type = 0;
1985 if (type == 0) {
1986 static const GTypeInfo info = {
1987 sizeof (LttvTraceStateClass),
1988 NULL, /* base_init */
1989 NULL, /* base_finalize */
1990 (GClassInitFunc) trace_state_class_init, /* class_init */
1991 NULL, /* class_finalize */
1992 NULL, /* class_data */
1993 sizeof (LttvTraceState),
1994 0, /* n_preallocs */
1995 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
1996 NULL /* value handling */
1997 };
1998
1999 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2000 "LttvTraceStateType", &info, 0);
2001 }
2002 return type;
2003 }
2004
2005
2006 static void
2007 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2008 {
2009 }
2010
2011
2012 static void
2013 tracefile_state_finalize (LttvTracefileState *self)
2014 {
2015 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2016 finalize(G_OBJECT(self));
2017 }
2018
2019
2020 static void
2021 tracefile_state_class_init (LttvTracefileStateClass *klass)
2022 {
2023 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2024
2025 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2026 }
2027
2028
2029 GType
2030 lttv_tracefile_state_get_type(void)
2031 {
2032 static GType type = 0;
2033 if (type == 0) {
2034 static const GTypeInfo info = {
2035 sizeof (LttvTracefileStateClass),
2036 NULL, /* base_init */
2037 NULL, /* base_finalize */
2038 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2039 NULL, /* class_finalize */
2040 NULL, /* class_data */
2041 sizeof (LttvTracefileState),
2042 0, /* n_preallocs */
2043 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2044 NULL /* value handling */
2045 };
2046
2047 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2048 "LttvTracefileStateType", &info, 0);
2049 }
2050 return type;
2051 }
2052
2053
2054 static void module_init()
2055 {
2056 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
2057 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
2058 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
2059 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
2060 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
2061 LTTV_STATE_TRAP = g_quark_from_string("trap");
2062 LTTV_STATE_IRQ = g_quark_from_string("irq");
2063 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
2064 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
2065 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
2066 LTTV_STATE_EXIT = g_quark_from_string("exiting");
2067 LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
2068 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
2069 LTTV_STATE_RUN = g_quark_from_string("running");
2070 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2071 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2072 LTTV_STATE_PROCESS = g_quark_from_string("process");
2073 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
2074 LTTV_STATE_EVENT = g_quark_from_string("event");
2075 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
2076 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
2077 LTTV_STATE_TIME = g_quark_from_string("time");
2078 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
2079 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2080 LTTV_STATE_TRACE_STATE_USE_COUNT =
2081 g_quark_from_string("trace_state_use_count");
2082
2083
2084 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2085 LTT_FACILITY_PROCESS = g_quark_from_string("process");
2086 LTT_FACILITY_FS = g_quark_from_string("fs");
2087
2088
2089 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2090 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2091 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2092 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2093 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2094 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2095 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2096 LTT_EVENT_FORK = g_quark_from_string("fork");
2097 LTT_EVENT_EXIT = g_quark_from_string("exit");
2098 LTT_EVENT_FREE = g_quark_from_string("free");
2099 LTT_EVENT_EXEC = g_quark_from_string("exec");
2100
2101
2102 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2103 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2104 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2105 LTT_FIELD_OUT = g_quark_from_string("out");
2106 LTT_FIELD_IN = g_quark_from_string("in");
2107 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2108 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2109 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2110 LTT_FIELD_PID = g_quark_from_string("pid");
2111 LTT_FIELD_FILENAME = g_quark_from_string("filename");
2112
2113 }
2114
2115 static void module_destroy()
2116 {
2117 }
2118
2119
2120 LTTV_MODULE("state", "State computation", \
2121 "Update the system state, possibly saving it at intervals", \
2122 module_init, module_destroy)
2123
2124
2125
This page took 0.071912 seconds and 4 git commands to generate.