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