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