fix process end of life
[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 #define _GNU_SOURCE
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <glib.h>
25 #include <lttv/lttv.h>
26 #include <lttv/module.h>
27 #include <lttv/state.h>
28 #include <ltt/trace.h>
29 #include <ltt/event.h>
30 #include <ltt/ltt.h>
31 #include <ltt/marker-desc.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 /* Comment :
36 * Mathieu Desnoyers
37 * usertrace is there only to be able to update the current CPU of the
38 * usertraces when there is a schedchange. it is a way to link the ProcessState
39 * to the associated usertrace. Link only created upon thread creation.
40 *
41 * The cpu id is necessary : it gives us back the current ProcessState when we
42 * are considering data from the usertrace.
43 */
44
45 #define PREALLOCATED_EXECUTION_STACK 10
46
47 /* Facilities Quarks */
48
49 GQuark
50 LTT_FACILITY_KERNEL,
51 LTT_FACILITY_KERNEL_ARCH,
52 LTT_FACILITY_LIST,
53 LTT_FACILITY_FS,
54 LTT_FACILITY_USER_GENERIC,
55 LTT_FACILITY_BLOCK;
56
57 /* Events Quarks */
58
59 GQuark
60 LTT_EVENT_SYSCALL_ENTRY,
61 LTT_EVENT_SYSCALL_EXIT,
62 LTT_EVENT_TRAP_ENTRY,
63 LTT_EVENT_TRAP_EXIT,
64 LTT_EVENT_IRQ_ENTRY,
65 LTT_EVENT_IRQ_EXIT,
66 LTT_EVENT_SOFT_IRQ_ENTRY,
67 LTT_EVENT_SOFT_IRQ_EXIT,
68 LTT_EVENT_SCHED_SCHEDULE,
69 LTT_EVENT_PROCESS_FORK,
70 LTT_EVENT_KTHREAD_CREATE,
71 LTT_EVENT_PROCESS_EXIT,
72 LTT_EVENT_PROCESS_FREE,
73 LTT_EVENT_EXEC,
74 LTT_EVENT_PROCESS_STATE,
75 LTT_EVENT_STATEDUMP_END,
76 LTT_EVENT_FUNCTION_ENTRY,
77 LTT_EVENT_FUNCTION_EXIT,
78 LTT_EVENT_THREAD_BRAND,
79 LTT_EVENT_REQUEST_ISSUE,
80 LTT_EVENT_REQUEST_COMPLETE,
81 LTT_EVENT_LIST_INTERRUPT;
82
83 /* Fields Quarks */
84
85 GQuark
86 LTT_FIELD_SYSCALL_ID,
87 LTT_FIELD_TRAP_ID,
88 LTT_FIELD_IRQ_ID,
89 LTT_FIELD_SOFT_IRQ_ID,
90 LTT_FIELD_PREV_PID,
91 LTT_FIELD_NEXT_PID,
92 LTT_FIELD_PREV_STATE,
93 LTT_FIELD_PARENT_PID,
94 LTT_FIELD_CHILD_PID,
95 LTT_FIELD_PID,
96 LTT_FIELD_TGID,
97 LTT_FIELD_CHILD_TGID,
98 LTT_FIELD_FILENAME,
99 LTT_FIELD_NAME,
100 LTT_FIELD_TYPE,
101 LTT_FIELD_MODE,
102 LTT_FIELD_SUBMODE,
103 LTT_FIELD_STATUS,
104 LTT_FIELD_THIS_FN,
105 LTT_FIELD_CALL_SITE,
106 LTT_FIELD_MINOR,
107 LTT_FIELD_MAJOR,
108 LTT_FIELD_OPERATION,
109 LTT_FIELD_ACTION;
110
111 LttvExecutionMode
112 LTTV_STATE_MODE_UNKNOWN,
113 LTTV_STATE_USER_MODE,
114 LTTV_STATE_SYSCALL,
115 LTTV_STATE_TRAP,
116 LTTV_STATE_IRQ,
117 LTTV_STATE_SOFT_IRQ;
118
119 LttvExecutionSubmode
120 LTTV_STATE_SUBMODE_UNKNOWN,
121 LTTV_STATE_SUBMODE_NONE;
122
123 LttvProcessStatus
124 LTTV_STATE_UNNAMED,
125 LTTV_STATE_WAIT_FORK,
126 LTTV_STATE_WAIT_CPU,
127 LTTV_STATE_EXIT,
128 LTTV_STATE_ZOMBIE,
129 LTTV_STATE_WAIT,
130 LTTV_STATE_RUN,
131 LTTV_STATE_DEAD;
132
133 GQuark
134 LTTV_STATE_UNBRANDED;
135
136 LttvProcessType
137 LTTV_STATE_USER_THREAD,
138 LTTV_STATE_KERNEL_THREAD;
139
140 LttvCPUMode
141 LTTV_CPU_UNKNOWN,
142 LTTV_CPU_IDLE,
143 LTTV_CPU_BUSY,
144 LTTV_CPU_IRQ,
145 LTTV_CPU_SOFT_IRQ,
146 LTTV_CPU_TRAP;
147
148 LttvIRQMode
149 LTTV_IRQ_UNKNOWN,
150 LTTV_IRQ_IDLE,
151 LTTV_IRQ_BUSY;
152
153 LttvBdevMode
154 LTTV_BDEV_UNKNOWN,
155 LTTV_BDEV_IDLE,
156 LTTV_BDEV_BUSY_READING,
157 LTTV_BDEV_BUSY_WRITING;
158
159 static GQuark
160 LTTV_STATE_TRACEFILES,
161 LTTV_STATE_PROCESSES,
162 LTTV_STATE_PROCESS,
163 LTTV_STATE_RUNNING_PROCESS,
164 LTTV_STATE_EVENT,
165 LTTV_STATE_SAVED_STATES,
166 LTTV_STATE_SAVED_STATES_TIME,
167 LTTV_STATE_TIME,
168 LTTV_STATE_HOOKS,
169 LTTV_STATE_NAME_TABLES,
170 LTTV_STATE_TRACE_STATE_USE_COUNT,
171 LTTV_STATE_RESOURCE_CPUS,
172 LTTV_STATE_RESOURCE_CPUS_COUNT,
173 LTTV_STATE_RESOURCE_IRQS,
174 LTTV_STATE_RESOURCE_SOFT_IRQS,
175 LTTV_STATE_RESOURCE_TRAPS,
176 LTTV_STATE_RESOURCE_BLKDEVS;
177
178 static void create_max_time(LttvTraceState *tcs);
179
180 static void get_max_time(LttvTraceState *tcs);
181
182 static void free_max_time(LttvTraceState *tcs);
183
184 static void create_name_tables(LttvTraceState *tcs);
185
186 static void get_name_tables(LttvTraceState *tcs);
187
188 static void free_name_tables(LttvTraceState *tcs);
189
190 static void free_saved_state(LttvTraceState *tcs);
191
192 static void lttv_state_free_process_table(GHashTable *processes);
193
194 static void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
195 GPtrArray *quarktable);
196
197 /* Resource function prototypes */
198 static LttvBdevState *get_hashed_bdevstate(LttvTraceState *ts, guint16 devcode);
199 static LttvBdevState *bdevstate_new(void);
200 static void bdevstate_free(LttvBdevState *);
201 static void bdevstate_free_cb(gpointer key, gpointer value, gpointer user_data);
202 static LttvBdevState *bdevstate_copy(LttvBdevState *bds);
203
204
205 void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
206 {
207 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
208 }
209
210
211 void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
212 {
213 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
214 }
215
216
217 void lttv_state_state_saved_free(LttvTraceState *self,
218 LttvAttribute *container)
219 {
220 LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
221 }
222
223
224 guint process_hash(gconstpointer key)
225 {
226 guint pid = ((const LttvProcessState *)key)->pid;
227 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
228 }
229
230
231 /* If the hash table hash function is well distributed,
232 * the process_equal should compare different pid */
233 gboolean process_equal(gconstpointer a, gconstpointer b)
234 {
235 const LttvProcessState *process_a, *process_b;
236 gboolean ret = TRUE;
237
238 process_a = (const LttvProcessState *)a;
239 process_b = (const LttvProcessState *)b;
240
241 if(likely(process_a->pid != process_b->pid)) ret = FALSE;
242 else if(likely(process_a->pid == 0 &&
243 process_a->cpu != process_b->cpu)) ret = FALSE;
244
245 return ret;
246 }
247
248 static void delete_usertrace(gpointer key, gpointer value, gpointer user_data)
249 {
250 g_tree_destroy((GTree*)value);
251 }
252
253 static void lttv_state_free_usertraces(GHashTable *usertraces)
254 {
255 g_hash_table_foreach(usertraces, delete_usertrace, NULL);
256 g_hash_table_destroy(usertraces);
257 }
258
259 gboolean rettrue(gpointer key, gpointer value, gpointer user_data)
260 {
261 return TRUE;
262 }
263
264 static void
265 restore_init_state(LttvTraceState *self)
266 {
267 guint i, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps;
268
269 //LttvTracefileState *tfcs;
270
271 LttTime start_time, end_time;
272
273 /* Free the process tables */
274 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
275 if(self->usertraces != NULL) lttv_state_free_usertraces(self->usertraces);
276 self->processes = g_hash_table_new(process_hash, process_equal);
277 self->usertraces = g_hash_table_new(g_direct_hash, g_direct_equal);
278 self->nb_event = 0;
279
280 /* Seek time to beginning */
281 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
282 // closest. It's the tracecontext job to seek the trace to the beginning
283 // anyway : the init state might be used at the middle of the trace as well...
284 //g_tree_destroy(self->parent.ts_context->pqueue);
285 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
286
287 ltt_trace_time_span_get(self->parent.t, &start_time, &end_time);
288
289 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
290
291 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
292 nb_irqs = self->nb_irqs;
293 nb_soft_irqs = self->nb_soft_irqs;
294 nb_traps = self->nb_traps;
295
296 /* Put the per cpu running_process to beginning state : process 0. */
297 for(i=0; i< nb_cpus; i++) {
298 LttvExecutionState *es;
299 self->running_process[i] = lttv_state_create_process(self, NULL, i, 0, 0,
300 LTTV_STATE_UNNAMED, &start_time);
301 /* We are not sure is it's a kernel thread or normal thread, put the
302 * bottom stack state to unknown */
303 self->running_process[i]->execution_stack =
304 g_array_set_size(self->running_process[i]->execution_stack, 1);
305 es = self->running_process[i]->state =
306 &g_array_index(self->running_process[i]->execution_stack,
307 LttvExecutionState, 0);
308 es->t = LTTV_STATE_MODE_UNKNOWN;
309 es->s = LTTV_STATE_UNNAMED;
310
311 //self->running_process[i]->state->s = LTTV_STATE_RUN;
312 self->running_process[i]->cpu = i;
313
314 /* reset cpu states */
315 if(self->cpu_states[i].mode_stack->len > 0)
316 g_array_remove_range(self->cpu_states[i].mode_stack, 0, self->cpu_states[i].mode_stack->len);
317 }
318
319 /* reset irq states */
320 for(i=0; i<nb_irqs; i++) {
321 if(self->irq_states[i].mode_stack->len > 0)
322 g_array_remove_range(self->irq_states[i].mode_stack, 0, self->irq_states[i].mode_stack->len);
323 }
324
325 /* reset softirq states */
326 for(i=0; i<nb_soft_irqs; i++) {
327 self->soft_irq_states[i].running = 0;
328 }
329
330 /* reset trap states */
331 for(i=0; i<nb_traps; i++) {
332 self->trap_states[i].running = 0;
333 }
334
335 /* reset bdev states */
336 g_hash_table_foreach(self->bdev_states, bdevstate_free_cb, NULL);
337 //g_hash_table_steal_all(self->bdev_states);
338 g_hash_table_foreach_steal(self->bdev_states, rettrue, NULL);
339
340 #if 0
341 nb_tracefile = self->parent.tracefiles->len;
342
343 for(i = 0 ; i < nb_tracefile ; i++) {
344 tfcs =
345 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
346 LttvTracefileContext*, i));
347 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
348 // tfcs->saved_position = 0;
349 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
350 tfcs->process->state->s = LTTV_STATE_RUN;
351 tfcs->process->last_cpu = tfcs->cpu_name;
352 tfcs->process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfcs)->tf);
353 }
354 #endif //0
355 }
356
357 //static LttTime time_zero = {0,0};
358
359 static gint compare_usertraces(gconstpointer a, gconstpointer b,
360 gpointer user_data)
361 {
362 const LttTime *t1 = (const LttTime *)a;
363 const LttTime *t2 = (const LttTime *)b;
364
365 return ltt_time_compare(*t1, *t2);
366 }
367
368 static void free_usertrace_key(gpointer data)
369 {
370 g_free(data);
371 }
372
373 #define MAX_STRING_LEN 4096
374
375 static void
376 state_load_saved_states(LttvTraceState *tcs)
377 {
378 FILE *fp;
379 GPtrArray *quarktable;
380 const char *trace_path;
381 char path[PATH_MAX];
382 guint count;
383 guint i;
384 tcs->has_precomputed_states = FALSE;
385 GQuark q;
386 gchar *string;
387 gint hdr;
388 gchar buf[MAX_STRING_LEN];
389 guint len;
390
391 trace_path = g_quark_to_string(ltt_trace_name(tcs->parent.t));
392 strncpy(path, trace_path, PATH_MAX-1);
393 count = strnlen(trace_path, PATH_MAX-1);
394 // quarktable : open, test
395 strncat(path, "/precomputed/quarktable", PATH_MAX-count-1);
396 fp = fopen(path, "r");
397 if(!fp) return;
398 quarktable = g_ptr_array_sized_new(4096);
399
400 /* Index 0 is null */
401 hdr = fgetc(fp);
402 if(hdr == EOF) return;
403 g_assert(hdr == HDR_QUARKS);
404 q = 1;
405 do {
406 hdr = fgetc(fp);
407 if(hdr == EOF) break;
408 g_assert(hdr == HDR_QUARK);
409 g_ptr_array_set_size(quarktable, q+1);
410 i=0;
411 while(1) {
412 fread(&buf[i], sizeof(gchar), 1, fp);
413 if(buf[i] == '\0' || feof(fp)) break;
414 i++;
415 }
416 len = strnlen(buf, MAX_STRING_LEN-1);
417 g_ptr_array_index (quarktable, q) = g_new(gchar, len+1);
418 strncpy(g_ptr_array_index (quarktable, q), buf, len+1);
419 q++;
420 } while(1);
421
422 fclose(fp);
423
424 // saved_states : open, test
425 strncpy(path, trace_path, PATH_MAX-1);
426 count = strnlen(trace_path, PATH_MAX-1);
427 strncat(path, "/precomputed/states", PATH_MAX-count-1);
428 fp = fopen(path, "r");
429 if(!fp) return;
430
431 hdr = fgetc(fp);
432 if(hdr != HDR_TRACE) goto end;
433
434 lttv_trace_states_read_raw(tcs, fp, quarktable);
435
436 tcs->has_precomputed_states = TRUE;
437
438 end:
439 fclose(fp);
440
441 /* Free the quarktable */
442 for(i=0; i<quarktable->len; i++) {
443 string = g_ptr_array_index (quarktable, i);
444 g_free(string);
445 }
446 g_ptr_array_free(quarktable, TRUE);
447 return;
448 }
449
450 static void
451 init(LttvTracesetState *self, LttvTraceset *ts)
452 {
453 guint i, j, nb_trace, nb_tracefile, nb_cpu;
454 guint64 nb_irq;
455
456 LttvTraceContext *tc;
457
458 LttvTraceState *tcs;
459
460 LttvTracefileState *tfcs;
461
462 LttvAttributeValue v;
463
464 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
465 init((LttvTracesetContext *)self, ts);
466
467 nb_trace = lttv_traceset_number(ts);
468 for(i = 0 ; i < nb_trace ; i++) {
469 tc = self->parent.traces[i];
470 tcs = LTTV_TRACE_STATE(tc);
471 tcs->save_interval = LTTV_STATE_SAVE_INTERVAL;
472 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
473 LTTV_UINT, &v);
474 (*v.v_uint)++;
475
476 if(*(v.v_uint) == 1) {
477 create_name_tables(tcs);
478 create_max_time(tcs);
479 }
480 get_name_tables(tcs);
481 get_max_time(tcs);
482
483 nb_tracefile = tc->tracefiles->len;
484 nb_cpu = ltt_trace_get_num_cpu(tc->t);
485 nb_irq = tcs->nb_irqs;
486 tcs->processes = NULL;
487 tcs->usertraces = NULL;
488 tcs->running_process = g_new(LttvProcessState*, nb_cpu);
489
490 /* init cpu resource stuff */
491 tcs->cpu_states = g_new(LttvCPUState, nb_cpu);
492 for(j = 0; j<nb_cpu; j++) {
493 tcs->cpu_states[j].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvCPUMode));
494 g_assert(tcs->cpu_states[j].mode_stack != NULL);
495 }
496
497 /* init irq resource stuff */
498 tcs->irq_states = g_new(LttvIRQState, nb_irq);
499 for(j = 0; j<nb_irq; j++) {
500 tcs->irq_states[j].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvIRQMode));
501 g_assert(tcs->irq_states[j].mode_stack != NULL);
502 }
503
504 /* init soft irq stuff */
505 /* the kernel has a statically fixed max of 32 softirqs */
506 tcs->soft_irq_states = g_new(LttvSoftIRQState, tcs->nb_soft_irqs);
507
508 /* init trap stuff */
509 tcs->trap_states = g_new(LttvTrapState, tcs->nb_traps);
510
511 /* init bdev resource stuff */
512 tcs->bdev_states = g_hash_table_new(g_int_hash, g_int_equal);
513
514 restore_init_state(tcs);
515 for(j = 0 ; j < nb_tracefile ; j++) {
516 tfcs =
517 LTTV_TRACEFILE_STATE(g_array_index(tc->tracefiles,
518 LttvTracefileContext*, j));
519 tfcs->tracefile_name = ltt_tracefile_name(tfcs->parent.tf);
520 tfcs->cpu = ltt_tracefile_cpu(tfcs->parent.tf);
521 tfcs->cpu_state = &(tcs->cpu_states[tfcs->cpu]);
522 if(ltt_tracefile_tid(tfcs->parent.tf) != 0) {
523 /* It's a Usertrace */
524 guint tid = ltt_tracefile_tid(tfcs->parent.tf);
525 GTree *usertrace_tree = (GTree*)g_hash_table_lookup(tcs->usertraces,
526 (gconstpointer)tid);
527 if(!usertrace_tree) {
528 usertrace_tree = g_tree_new_full(compare_usertraces,
529 NULL, free_usertrace_key, NULL);
530 g_hash_table_insert(tcs->usertraces,
531 (gpointer)tid, usertrace_tree);
532 }
533 LttTime *timestamp = g_new(LttTime, 1);
534 *timestamp = ltt_interpolate_time_from_tsc(tfcs->parent.tf,
535 ltt_tracefile_creation(tfcs->parent.tf));
536 g_tree_insert(usertrace_tree, timestamp, tfcs);
537 }
538 }
539
540 /* See if the trace has saved states */
541 state_load_saved_states(tcs);
542 }
543 }
544
545 static void
546 fini(LttvTracesetState *self)
547 {
548 guint i, nb_trace;
549
550 LttvTraceState *tcs;
551
552 //LttvTracefileState *tfcs;
553
554 LttvAttributeValue v;
555
556 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
557 for(i = 0 ; i < nb_trace ; i++) {
558 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
559 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
560 LTTV_UINT, &v);
561
562 g_assert(*(v.v_uint) != 0);
563 (*v.v_uint)--;
564
565 if(*(v.v_uint) == 0) {
566 free_name_tables(tcs);
567 free_max_time(tcs);
568 free_saved_state(tcs);
569 }
570 g_free(tcs->running_process);
571 tcs->running_process = NULL;
572 lttv_state_free_process_table(tcs->processes);
573 lttv_state_free_usertraces(tcs->usertraces);
574 tcs->processes = NULL;
575 tcs->usertraces = NULL;
576 }
577 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
578 fini((LttvTracesetContext *)self);
579 }
580
581
582 static LttvTracesetContext *
583 new_traceset_context(LttvTracesetContext *self)
584 {
585 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
586 }
587
588
589 static LttvTraceContext *
590 new_trace_context(LttvTracesetContext *self)
591 {
592 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
593 }
594
595
596 static LttvTracefileContext *
597 new_tracefile_context(LttvTracesetContext *self)
598 {
599 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
600 }
601
602
603 /* Write the process state of the trace */
604
605 static void write_process_state(gpointer key, gpointer value,
606 gpointer user_data)
607 {
608 LttvProcessState *process;
609
610 LttvExecutionState *es;
611
612 FILE *fp = (FILE *)user_data;
613
614 guint i;
615 guint64 address;
616
617 process = (LttvProcessState *)value;
618 fprintf(fp,
619 " <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" FREE_EVENTS=\"%u\">\n",
620 process, process->pid, process->tgid, process->ppid,
621 g_quark_to_string(process->type),
622 process->creation_time.tv_sec,
623 process->creation_time.tv_nsec,
624 process->insertion_time.tv_sec,
625 process->insertion_time.tv_nsec,
626 g_quark_to_string(process->name),
627 g_quark_to_string(process->brand),
628 process->cpu, process->free_events);
629
630 for(i = 0 ; i < process->execution_stack->len; i++) {
631 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
632 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
633 g_quark_to_string(es->t), g_quark_to_string(es->n),
634 es->entry.tv_sec, es->entry.tv_nsec);
635 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
636 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
637 }
638
639 for(i = 0 ; i < process->user_stack->len; i++) {
640 address = g_array_index(process->user_stack, guint64, i);
641 fprintf(fp, " <USER_STACK ADDRESS=\"%llu\"/>\n",
642 address);
643 }
644
645 if(process->usertrace) {
646 fprintf(fp, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
647 g_quark_to_string(process->usertrace->tracefile_name),
648 process->usertrace->cpu);
649 }
650
651
652 fprintf(fp, " </PROCESS>\n");
653 }
654
655
656 void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
657 {
658 guint i, nb_tracefile, nb_block, offset;
659 guint64 tsc;
660
661 LttvTracefileState *tfcs;
662
663 LttTracefile *tf;
664
665 LttEventPosition *ep;
666
667 guint nb_cpus;
668
669 ep = ltt_event_position_new();
670
671 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
672
673 g_hash_table_foreach(self->processes, write_process_state, fp);
674
675 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
676 for(i=0;i<nb_cpus;i++) {
677 fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
678 i, self->running_process[i]->pid);
679 }
680
681 nb_tracefile = self->parent.tracefiles->len;
682
683 for(i = 0 ; i < nb_tracefile ; i++) {
684 tfcs =
685 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
686 LttvTracefileContext*, i));
687 fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
688 tfcs->parent.timestamp.tv_sec,
689 tfcs->parent.timestamp.tv_nsec);
690 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
691 if(e == NULL) fprintf(fp,"/>\n");
692 else {
693 ltt_event_position(e, ep);
694 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
695 fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
696 tsc);
697 }
698 }
699 g_free(ep);
700 fprintf(fp,"</PROCESS_STATE>\n");
701 }
702
703
704 static void write_process_state_raw(gpointer key, gpointer value,
705 gpointer user_data)
706 {
707 LttvProcessState *process;
708
709 LttvExecutionState *es;
710
711 FILE *fp = (FILE *)user_data;
712
713 guint i;
714 guint64 address;
715
716 process = (LttvProcessState *)value;
717 fputc(HDR_PROCESS, fp);
718 //fwrite(&header, sizeof(header), 1, fp);
719 //fprintf(fp, "%s", g_quark_to_string(process->type));
720 //fputc('\0', fp);
721 fwrite(&process->type, sizeof(process->type), 1, fp);
722 //fprintf(fp, "%s", g_quark_to_string(process->name));
723 //fputc('\0', fp);
724 fwrite(&process->name, sizeof(process->name), 1, fp);
725 //fprintf(fp, "%s", g_quark_to_string(process->brand));
726 //fputc('\0', fp);
727 fwrite(&process->brand, sizeof(process->brand), 1, fp);
728 fwrite(&process->pid, sizeof(process->pid), 1, fp);
729 fwrite(&process->free_events, sizeof(process->free_events), 1, fp);
730 fwrite(&process->tgid, sizeof(process->tgid), 1, fp);
731 fwrite(&process->ppid, sizeof(process->ppid), 1, fp);
732 fwrite(&process->cpu, sizeof(process->cpu), 1, fp);
733 fwrite(&process->creation_time, sizeof(process->creation_time), 1, fp);
734 fwrite(&process->insertion_time, sizeof(process->insertion_time), 1, fp);
735
736 #if 0
737 fprintf(fp,
738 " <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" PROCESS_TYPE=%u>\n",
739 process, process->pid, process->tgid, process->ppid,
740 g_quark_to_string(process->type),
741 process->creation_time.tv_sec,
742 process->creation_time.tv_nsec,
743 process->insertion_time.tv_sec,
744 process->insertion_time.tv_nsec,
745 g_quark_to_string(process->name),
746 g_quark_to_string(process->brand),
747 process->cpu);
748 #endif //0
749
750 for(i = 0 ; i < process->execution_stack->len; i++) {
751 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
752
753 fputc(HDR_ES, fp);
754 //fprintf(fp, "%s", g_quark_to_string(es->t));
755 //fputc('\0', fp);
756 fwrite(&es->t, sizeof(es->t), 1, fp);
757 //fprintf(fp, "%s", g_quark_to_string(es->n));
758 //fputc('\0', fp);
759 fwrite(&es->n, sizeof(es->n), 1, fp);
760 //fprintf(fp, "%s", g_quark_to_string(es->s));
761 //fputc('\0', fp);
762 fwrite(&es->s, sizeof(es->s), 1, fp);
763 fwrite(&es->entry, sizeof(es->entry), 1, fp);
764 fwrite(&es->change, sizeof(es->change), 1, fp);
765 fwrite(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
766 #if 0
767 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
768 g_quark_to_string(es->t), g_quark_to_string(es->n),
769 es->entry.tv_sec, es->entry.tv_nsec);
770 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
771 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
772 #endif //0
773 }
774
775 for(i = 0 ; i < process->user_stack->len; i++) {
776 address = g_array_index(process->user_stack, guint64, i);
777 fputc(HDR_USER_STACK, fp);
778 fwrite(&address, sizeof(address), 1, fp);
779 #if 0
780 fprintf(fp, " <USER_STACK ADDRESS=\"%llu\"/>\n",
781 address);
782 #endif //0
783 }
784
785 if(process->usertrace) {
786 fputc(HDR_USERTRACE, fp);
787 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
788 //fputc('\0', fp);
789 fwrite(&process->usertrace->tracefile_name,
790 sizeof(process->usertrace->tracefile_name), 1, fp);
791 fwrite(&process->usertrace->cpu, sizeof(process->usertrace->cpu), 1, fp);
792 #if 0
793 fprintf(fp, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
794 g_quark_to_string(process->usertrace->tracefile_name),
795 process->usertrace->cpu);
796 #endif //0
797 }
798
799 }
800
801
802 void lttv_state_write_raw(LttvTraceState *self, LttTime t, FILE *fp)
803 {
804 guint i, nb_tracefile, nb_block, offset;
805 guint64 tsc;
806
807 LttvTracefileState *tfcs;
808
809 LttTracefile *tf;
810
811 LttEventPosition *ep;
812
813 guint nb_cpus;
814
815 ep = ltt_event_position_new();
816
817 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
818 fputc(HDR_PROCESS_STATE, fp);
819 fwrite(&t, sizeof(t), 1, fp);
820
821 g_hash_table_foreach(self->processes, write_process_state_raw, fp);
822
823 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
824 for(i=0;i<nb_cpus;i++) {
825 fputc(HDR_CPU, fp);
826 fwrite(&i, sizeof(i), 1, fp); /* cpu number */
827 fwrite(&self->running_process[i]->pid,
828 sizeof(self->running_process[i]->pid), 1, fp);
829 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
830 // i, self->running_process[i]->pid);
831 }
832
833 nb_tracefile = self->parent.tracefiles->len;
834
835 for(i = 0 ; i < nb_tracefile ; i++) {
836 tfcs =
837 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
838 LttvTracefileContext*, i));
839 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
840 // tfcs->parent.timestamp.tv_sec,
841 // tfcs->parent.timestamp.tv_nsec);
842 fputc(HDR_TRACEFILE, fp);
843 fwrite(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
844 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
845 * position following : end of trace */
846 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
847 if(e != NULL) {
848 ltt_event_position(e, ep);
849 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
850 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
851 // tsc);
852 fwrite(&nb_block, sizeof(nb_block), 1, fp);
853 fwrite(&offset, sizeof(offset), 1, fp);
854 fwrite(&tsc, sizeof(tsc), 1, fp);
855 }
856 }
857 g_free(ep);
858 }
859
860
861 /* Read process state from a file */
862
863 /* Called because a HDR_PROCESS was found */
864 static void read_process_state_raw(LttvTraceState *self, FILE *fp,
865 GPtrArray *quarktable)
866 {
867 LttvExecutionState *es;
868 LttvProcessState *process, *parent_process;
869 LttvProcessState tmp;
870 GQuark tmpq;
871
872 guint64 *address;
873
874 /* TODO : check return value */
875 fread(&tmp.type, sizeof(tmp.type), 1, fp);
876 fread(&tmp.name, sizeof(tmp.name), 1, fp);
877 fread(&tmp.brand, sizeof(tmp.brand), 1, fp);
878 fread(&tmp.pid, sizeof(tmp.pid), 1, fp);
879 fread(&tmp.free_events, sizeof(tmp.free_events), 1, fp);
880 fread(&tmp.tgid, sizeof(tmp.tgid), 1, fp);
881 fread(&tmp.ppid, sizeof(tmp.ppid), 1, fp);
882 fread(&tmp.cpu, sizeof(tmp.cpu), 1, fp);
883 fread(&tmp.creation_time, sizeof(tmp.creation_time), 1, fp);
884 fread(&tmp.insertion_time, sizeof(tmp.insertion_time), 1, fp);
885
886 if(tmp.pid == 0) {
887 process = lttv_state_find_process(self, tmp.cpu, tmp.pid);
888 } else {
889 /* We must link to the parent */
890 parent_process = lttv_state_find_process_or_create(self, ANY_CPU, tmp.ppid,
891 &ltt_time_zero);
892 process = lttv_state_find_process(self, ANY_CPU, tmp.pid);
893 if(process == NULL) {
894 process = lttv_state_create_process(self, parent_process, tmp.cpu,
895 tmp.pid, tmp.tgid,
896 g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name)),
897 &tmp.creation_time);
898 }
899 }
900 process->insertion_time = tmp.insertion_time;
901 process->creation_time = tmp.creation_time;
902 process->type = g_quark_from_string(
903 (gchar*)g_ptr_array_index(quarktable, tmp.type));
904 process->tgid = tmp.tgid;
905 process->ppid = tmp.ppid;
906 process->brand = g_quark_from_string(
907 (gchar*)g_ptr_array_index(quarktable, tmp.brand));
908 process->name =
909 g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name));
910 process->free_events = tmp.free_events;
911
912 do {
913 if(feof(fp) || ferror(fp)) goto end_loop;
914
915 gint hdr = fgetc(fp);
916 if(hdr == EOF) goto end_loop;
917
918 switch(hdr) {
919 case HDR_ES:
920 process->execution_stack =
921 g_array_set_size(process->execution_stack,
922 process->execution_stack->len + 1);
923 es = &g_array_index(process->execution_stack, LttvExecutionState,
924 process->execution_stack->len-1);
925 process->state = es;
926
927 fread(&es->t, sizeof(es->t), 1, fp);
928 es->t = g_quark_from_string(
929 (gchar*)g_ptr_array_index(quarktable, es->t));
930 fread(&es->n, sizeof(es->n), 1, fp);
931 es->n = g_quark_from_string(
932 (gchar*)g_ptr_array_index(quarktable, es->n));
933 fread(&es->s, sizeof(es->s), 1, fp);
934 es->s = g_quark_from_string(
935 (gchar*)g_ptr_array_index(quarktable, es->s));
936 fread(&es->entry, sizeof(es->entry), 1, fp);
937 fread(&es->change, sizeof(es->change), 1, fp);
938 fread(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
939 break;
940 case HDR_USER_STACK:
941 process->user_stack = g_array_set_size(process->user_stack,
942 process->user_stack->len + 1);
943 address = &g_array_index(process->user_stack, guint64,
944 process->user_stack->len-1);
945 fread(address, sizeof(address), 1, fp);
946 process->current_function = *address;
947 break;
948 case HDR_USERTRACE:
949 fread(&tmpq, sizeof(tmpq), 1, fp);
950 fread(&process->usertrace->cpu, sizeof(process->usertrace->cpu), 1, fp);
951 break;
952 default:
953 ungetc(hdr, fp);
954 goto end_loop;
955 };
956 } while(1);
957 end_loop:
958 return;
959 }
960
961
962 /* Called because a HDR_PROCESS_STATE was found */
963 /* Append a saved state to the trace states */
964 void lttv_state_read_raw(LttvTraceState *self, FILE *fp, GPtrArray *quarktable)
965 {
966 guint i, nb_tracefile, nb_block, offset;
967 guint64 tsc;
968 LttvTracefileState *tfcs;
969
970 LttEventPosition *ep;
971
972 guint nb_cpus;
973
974 int hdr;
975
976 LttTime t;
977
978 LttvAttribute *saved_states_tree, *saved_state_tree;
979
980 LttvAttributeValue value;
981 GTree *pqueue = self->parent.ts_context->pqueue;
982 ep = ltt_event_position_new();
983
984 restore_init_state(self);
985
986 fread(&t, sizeof(t), 1, fp);
987
988 do {
989 if(feof(fp) || ferror(fp)) goto end_loop;
990 hdr = fgetc(fp);
991 if(hdr == EOF) goto end_loop;
992
993 switch(hdr) {
994 case HDR_PROCESS:
995 /* Call read_process_state_raw */
996 read_process_state_raw(self, fp, quarktable);
997 break;
998 case HDR_TRACEFILE:
999 case HDR_TRACESET:
1000 case HDR_TRACE:
1001 case HDR_QUARKS:
1002 case HDR_QUARK:
1003 case HDR_ES:
1004 case HDR_USER_STACK:
1005 case HDR_USERTRACE:
1006 case HDR_PROCESS_STATE:
1007 case HDR_CPU:
1008 ungetc(hdr, fp);
1009 goto end_loop;
1010 break;
1011 default:
1012 g_error("Error while parsing saved state file : unknown data header %d",
1013 hdr);
1014 };
1015 } while(1);
1016 end_loop:
1017
1018 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1019 for(i=0;i<nb_cpus;i++) {
1020 int cpu_num;
1021 hdr = fgetc(fp);
1022 g_assert(hdr == HDR_CPU);
1023 fread(&cpu_num, sizeof(cpu_num), 1, fp); /* cpu number */
1024 g_assert(i == cpu_num);
1025 fread(&self->running_process[i]->pid,
1026 sizeof(self->running_process[i]->pid), 1, fp);
1027 }
1028
1029 nb_tracefile = self->parent.tracefiles->len;
1030
1031 for(i = 0 ; i < nb_tracefile ; i++) {
1032 tfcs =
1033 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1034 LttvTracefileContext*, i));
1035 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1036 // tfcs->parent.timestamp.tv_sec,
1037 // tfcs->parent.timestamp.tv_nsec);
1038 g_tree_remove(pqueue, &tfcs->parent);
1039 hdr = fgetc(fp);
1040 g_assert(hdr == HDR_TRACEFILE);
1041 fread(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
1042 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1043 * position following : end of trace */
1044 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) != 0) {
1045 fread(&nb_block, sizeof(nb_block), 1, fp);
1046 fread(&offset, sizeof(offset), 1, fp);
1047 fread(&tsc, sizeof(tsc), 1, fp);
1048 ltt_event_position_set(ep, tfcs->parent.tf, nb_block, offset, tsc);
1049 gint ret = ltt_tracefile_seek_position(tfcs->parent.tf, ep);
1050 g_assert(ret == 0);
1051 g_tree_insert(pqueue, &tfcs->parent, &tfcs->parent);
1052 }
1053 }
1054 g_free(ep);
1055
1056 saved_states_tree = lttv_attribute_find_subdir(self->parent.t_a,
1057 LTTV_STATE_SAVED_STATES);
1058 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1059 value = lttv_attribute_add(saved_states_tree,
1060 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1061 *(value.v_gobject) = (GObject *)saved_state_tree;
1062 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1063 *(value.v_time) = t;
1064 lttv_state_save(self, saved_state_tree);
1065 g_debug("Saving state at time %lu.%lu", t.tv_sec,
1066 t.tv_nsec);
1067
1068 *(self->max_time_state_recomputed_in_seek) = t;
1069
1070 }
1071
1072 /* Called when a HDR_TRACE is found */
1073 void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
1074 GPtrArray *quarktable)
1075 {
1076 int hdr;
1077
1078 do {
1079 if(feof(fp) || ferror(fp)) goto end_loop;
1080 hdr = fgetc(fp);
1081 if(hdr == EOF) goto end_loop;
1082
1083 switch(hdr) {
1084 case HDR_PROCESS_STATE:
1085 /* Call read_process_state_raw */
1086 lttv_state_read_raw(tcs, fp, quarktable);
1087 break;
1088 case HDR_TRACEFILE:
1089 case HDR_TRACESET:
1090 case HDR_TRACE:
1091 case HDR_QUARKS:
1092 case HDR_QUARK:
1093 case HDR_ES:
1094 case HDR_USER_STACK:
1095 case HDR_USERTRACE:
1096 case HDR_PROCESS:
1097 case HDR_CPU:
1098 g_error("Error while parsing saved state file :"
1099 " unexpected data header %d",
1100 hdr);
1101 break;
1102 default:
1103 g_error("Error while parsing saved state file : unknown data header %d",
1104 hdr);
1105 };
1106 } while(1);
1107 end_loop:
1108 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1109 restore_init_state(tcs);
1110 lttv_process_trace_seek_time(&tcs->parent, ltt_time_zero);
1111 return;
1112 }
1113
1114
1115
1116 /* Copy each process from an existing hash table to a new one */
1117
1118 static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
1119 {
1120 LttvProcessState *process, *new_process;
1121
1122 GHashTable *new_processes = (GHashTable *)user_data;
1123
1124 guint i;
1125
1126 process = (LttvProcessState *)value;
1127 new_process = g_new(LttvProcessState, 1);
1128 *new_process = *process;
1129 new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
1130 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
1131 new_process->execution_stack =
1132 g_array_set_size(new_process->execution_stack,
1133 process->execution_stack->len);
1134 for(i = 0 ; i < process->execution_stack->len; i++) {
1135 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
1136 g_array_index(process->execution_stack, LttvExecutionState, i);
1137 }
1138 new_process->state = &g_array_index(new_process->execution_stack,
1139 LttvExecutionState, new_process->execution_stack->len - 1);
1140 new_process->user_stack = g_array_sized_new(FALSE, FALSE,
1141 sizeof(guint64), 0);
1142 new_process->user_stack =
1143 g_array_set_size(new_process->user_stack,
1144 process->user_stack->len);
1145 for(i = 0 ; i < process->user_stack->len; i++) {
1146 g_array_index(new_process->user_stack, guint64, i) =
1147 g_array_index(process->user_stack, guint64, i);
1148 }
1149 new_process->current_function = process->current_function;
1150 g_hash_table_insert(new_processes, new_process, new_process);
1151 }
1152
1153
1154 static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
1155 {
1156 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
1157
1158 g_hash_table_foreach(processes, copy_process_state, new_processes);
1159 return new_processes;
1160 }
1161
1162 static LttvCPUState *lttv_state_copy_cpu_states(LttvCPUState *states, guint n)
1163 {
1164 guint i,j;
1165 LttvCPUState *retval;
1166
1167 retval = g_malloc(n*sizeof(LttvCPUState));
1168
1169 for(i=0; i<n; i++) {
1170 retval[i].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvCPUMode));
1171 retval[i].last_irq = states[i].last_irq;
1172 g_array_set_size(retval[i].mode_stack, states[i].mode_stack->len);
1173 for(j=0; j<states[i].mode_stack->len; j++) {
1174 g_array_index(retval[i].mode_stack, GQuark, j) = g_array_index(states[i].mode_stack, GQuark, j);
1175 }
1176 }
1177
1178 return retval;
1179 }
1180
1181 static void lttv_state_free_cpu_states(LttvCPUState *states, guint n)
1182 {
1183 guint i;
1184
1185 for(i=0; i<n; i++) {
1186 g_array_free(states[i].mode_stack, TRUE);
1187 }
1188
1189 g_free(states);
1190 }
1191
1192 static LttvIRQState *lttv_state_copy_irq_states(LttvIRQState *states, guint n)
1193 {
1194 guint i,j;
1195 LttvIRQState *retval;
1196
1197 retval = g_malloc(n*sizeof(LttvIRQState));
1198
1199 for(i=0; i<n; i++) {
1200 retval[i].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvIRQMode));
1201 g_array_set_size(retval[i].mode_stack, states[i].mode_stack->len);
1202 for(j=0; j<states[i].mode_stack->len; j++) {
1203 g_array_index(retval[i].mode_stack, GQuark, j) = g_array_index(states[i].mode_stack, GQuark, j);
1204 }
1205 }
1206
1207 return retval;
1208 }
1209
1210 static void lttv_state_free_irq_states(LttvIRQState *states, guint n)
1211 {
1212 guint i;
1213
1214 for(i=0; i<n; i++) {
1215 g_array_free(states[i].mode_stack, TRUE);
1216 }
1217
1218 g_free(states);
1219 }
1220
1221 static LttvSoftIRQState *lttv_state_copy_soft_irq_states(LttvSoftIRQState *states, guint n)
1222 {
1223 guint i;
1224 LttvSoftIRQState *retval;
1225
1226 retval = g_malloc(n*sizeof(LttvSoftIRQState));
1227
1228 for(i=0; i<n; i++) {
1229 retval[i].running = states[i].running;
1230 }
1231
1232 return retval;
1233 }
1234
1235 static void lttv_state_free_soft_irq_states(LttvSoftIRQState *states, guint n)
1236 {
1237 g_free(states);
1238 }
1239
1240 static LttvTrapState *lttv_state_copy_trap_states(LttvTrapState *states, guint n)
1241 {
1242 guint i;
1243 LttvTrapState *retval;
1244
1245 retval = g_malloc(n*sizeof(LttvTrapState));
1246
1247 for(i=0; i<n; i++) {
1248 retval[i].running = states[i].running;
1249 }
1250
1251 return retval;
1252 }
1253
1254 static void lttv_state_free_trap_states(LttvTrapState *states, guint n)
1255 {
1256 g_free(states);
1257 }
1258
1259 /* bdevstate stuff */
1260
1261 static LttvBdevState *get_hashed_bdevstate(LttvTraceState *ts, guint16 devcode)
1262 {
1263 gint devcode_gint = devcode;
1264 gpointer bdev = g_hash_table_lookup(ts->bdev_states, &devcode_gint);
1265 if(bdev == NULL) {
1266 LttvBdevState *bdevstate = g_malloc(sizeof(LttvBdevState));
1267 bdevstate->mode_stack = g_array_new(FALSE, FALSE, sizeof(GQuark));
1268
1269 gint * key = g_malloc(sizeof(gint));
1270 *key = devcode;
1271 g_hash_table_insert(ts->bdev_states, key, bdevstate);
1272
1273 bdev = bdevstate;
1274 }
1275
1276 return bdev;
1277 }
1278
1279 static LttvBdevState *bdevstate_new(void)
1280 {
1281 LttvBdevState *retval;
1282 retval = g_malloc(sizeof(LttvBdevState));
1283 retval->mode_stack = g_array_new(FALSE, FALSE, sizeof(GQuark));
1284
1285 return retval;
1286 }
1287
1288 static void bdevstate_free(LttvBdevState *bds)
1289 {
1290 g_array_free(bds->mode_stack, TRUE);
1291 g_free(bds);
1292 }
1293
1294 static void bdevstate_free_cb(gpointer key, gpointer value, gpointer user_data)
1295 {
1296 LttvBdevState *bds = (LttvBdevState *) value;
1297
1298 bdevstate_free(bds);
1299 }
1300
1301 static LttvBdevState *bdevstate_copy(LttvBdevState *bds)
1302 {
1303 LttvBdevState *retval;
1304
1305 retval = bdevstate_new();
1306 g_array_insert_vals(retval->mode_stack, 0, bds->mode_stack->data, bds->mode_stack->len);
1307
1308 return retval;
1309 }
1310
1311 static void insert_and_copy_bdev_state(gpointer k, gpointer v, gpointer u)
1312 {
1313 //GHashTable *ht = (GHashTable *)u;
1314 LttvBdevState *bds = (LttvBdevState *)v;
1315 LttvBdevState *newbds;
1316
1317 newbds = bdevstate_copy(bds);
1318
1319 g_hash_table_insert(u, k, newbds);
1320 }
1321
1322 static GHashTable *lttv_state_copy_blkdev_hashtable(GHashTable *ht)
1323 {
1324 GHashTable *retval;
1325
1326 retval = g_hash_table_new(g_int_hash, g_int_equal);
1327
1328 g_hash_table_foreach(ht, insert_and_copy_bdev_state, retval);
1329
1330 return retval;
1331 }
1332
1333 /* Free a hashtable and the LttvBdevState structures its values
1334 * point to. */
1335
1336 static void lttv_state_free_blkdev_hashtable(GHashTable *ht)
1337 {
1338 g_hash_table_foreach(ht, bdevstate_free_cb, NULL);
1339 g_hash_table_destroy(ht);
1340 }
1341
1342 /* The saved state for each trace contains a member "processes", which
1343 stores a copy of the process table, and a member "tracefiles" with
1344 one entry per tracefile. Each tracefile has a "process" member pointing
1345 to the current process and a "position" member storing the tracefile
1346 position (needed to seek to the current "next" event. */
1347
1348 static void state_save(LttvTraceState *self, LttvAttribute *container)
1349 {
1350 guint i, nb_tracefile, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps;
1351
1352 LttvTracefileState *tfcs;
1353
1354 LttvAttribute *tracefiles_tree, *tracefile_tree;
1355
1356 guint *running_process;
1357
1358 LttvAttributeValue value;
1359
1360 LttEventPosition *ep;
1361
1362 tracefiles_tree = lttv_attribute_find_subdir(container,
1363 LTTV_STATE_TRACEFILES);
1364
1365 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
1366 LTTV_POINTER);
1367 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
1368
1369 /* Add the currently running processes array */
1370 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1371 running_process = g_new(guint, nb_cpus);
1372 for(i=0;i<nb_cpus;i++) {
1373 running_process[i] = self->running_process[i]->pid;
1374 }
1375 value = lttv_attribute_add(container, LTTV_STATE_RUNNING_PROCESS,
1376 LTTV_POINTER);
1377 *(value.v_pointer) = running_process;
1378
1379 g_info("State save");
1380
1381 nb_tracefile = self->parent.tracefiles->len;
1382
1383 for(i = 0 ; i < nb_tracefile ; i++) {
1384 tfcs =
1385 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1386 LttvTracefileContext*, i));
1387 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1388 value = lttv_attribute_add(tracefiles_tree, i,
1389 LTTV_GOBJECT);
1390 *(value.v_gobject) = (GObject *)tracefile_tree;
1391 #if 0
1392 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
1393 LTTV_UINT);
1394 *(value.v_uint) = tfcs->process->pid;
1395 #endif //0
1396 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
1397 LTTV_POINTER);
1398 /* Only save the position if the tfs has not infinite time. */
1399 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1400 // && current_tfcs != tfcs) {
1401 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) == 0) {
1402 *(value.v_pointer) = NULL;
1403 } else {
1404 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
1405 ep = ltt_event_position_new();
1406 ltt_event_position(e, ep);
1407 *(value.v_pointer) = ep;
1408
1409 guint nb_block, offset;
1410 guint64 tsc;
1411 LttTracefile *tf;
1412 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
1413 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block, offset,
1414 tsc,
1415 tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
1416 }
1417 }
1418
1419 /* save the cpu state */
1420 {
1421 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_CPUS_COUNT,
1422 LTTV_UINT);
1423 *(value.v_uint) = nb_cpus;
1424
1425 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_CPUS,
1426 LTTV_POINTER);
1427 *(value.v_pointer) = lttv_state_copy_cpu_states(self->cpu_states, nb_cpus);
1428 }
1429
1430 /* save the irq state */
1431 nb_irqs = self->nb_irqs;
1432 {
1433 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_IRQS,
1434 LTTV_POINTER);
1435 *(value.v_pointer) = lttv_state_copy_irq_states(self->irq_states, nb_irqs);
1436 }
1437
1438 /* save the soft irq state */
1439 nb_soft_irqs = self->nb_soft_irqs;
1440 {
1441 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_SOFT_IRQS,
1442 LTTV_POINTER);
1443 *(value.v_pointer) = lttv_state_copy_soft_irq_states(self->soft_irq_states, nb_soft_irqs);
1444 }
1445
1446 /* save the trap state */
1447 nb_traps = self->nb_traps;
1448 {
1449 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_TRAPS,
1450 LTTV_POINTER);
1451 *(value.v_pointer) = lttv_state_copy_trap_states(self->trap_states, nb_traps);
1452 }
1453
1454 /* save the blkdev states */
1455 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_BLKDEVS,
1456 LTTV_POINTER);
1457 *(value.v_pointer) = lttv_state_copy_blkdev_hashtable(self->bdev_states);
1458 }
1459
1460
1461 static void state_restore(LttvTraceState *self, LttvAttribute *container)
1462 {
1463 guint i, nb_tracefile, pid, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps;
1464
1465 LttvTracefileState *tfcs;
1466
1467 LttvAttribute *tracefiles_tree, *tracefile_tree;
1468
1469 guint *running_process;
1470
1471 LttvAttributeType type;
1472
1473 LttvAttributeValue value;
1474
1475 LttvAttributeName name;
1476
1477 gboolean is_named;
1478
1479 LttEventPosition *ep;
1480
1481 LttvTracesetContext *tsc = self->parent.ts_context;
1482
1483 tracefiles_tree = lttv_attribute_find_subdir(container,
1484 LTTV_STATE_TRACEFILES);
1485
1486 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1487 &value);
1488 g_assert(type == LTTV_POINTER);
1489 lttv_state_free_process_table(self->processes);
1490 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
1491
1492 /* Add the currently running processes array */
1493 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1494 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
1495 &value);
1496 g_assert(type == LTTV_POINTER);
1497 running_process = *(value.v_pointer);
1498 for(i=0;i<nb_cpus;i++) {
1499 pid = running_process[i];
1500 self->running_process[i] = lttv_state_find_process(self, i, pid);
1501 g_assert(self->running_process[i] != NULL);
1502 }
1503
1504 nb_tracefile = self->parent.tracefiles->len;
1505
1506 //g_tree_destroy(tsc->pqueue);
1507 //tsc->pqueue = g_tree_new(compare_tracefile);
1508
1509 /* restore cpu resource states */
1510 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS, &value);
1511 g_assert(type == LTTV_POINTER);
1512 lttv_state_free_cpu_states(self->cpu_states, nb_cpus);
1513 self->cpu_states = lttv_state_copy_cpu_states(*(value.v_pointer), nb_cpus);
1514
1515 /* restore irq resource states */
1516 nb_irqs = self->nb_irqs;
1517 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_IRQS, &value);
1518 g_assert(type == LTTV_POINTER);
1519 lttv_state_free_irq_states(self->irq_states, nb_irqs);
1520 self->irq_states = lttv_state_copy_irq_states(*(value.v_pointer), nb_irqs);
1521
1522 /* restore soft irq resource states */
1523 nb_soft_irqs = self->nb_soft_irqs;
1524 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_SOFT_IRQS, &value);
1525 g_assert(type == LTTV_POINTER);
1526 lttv_state_free_soft_irq_states(self->soft_irq_states, nb_soft_irqs);
1527 self->soft_irq_states = lttv_state_copy_soft_irq_states(*(value.v_pointer), nb_soft_irqs);
1528
1529 /* restore trap resource states */
1530 nb_traps = self->nb_traps;
1531 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_TRAPS, &value);
1532 g_assert(type == LTTV_POINTER);
1533 lttv_state_free_trap_states(self->trap_states, nb_traps);
1534 self->trap_states = lttv_state_copy_trap_states(*(value.v_pointer), nb_traps);
1535
1536 /* restore the blkdev states */
1537 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_BLKDEVS, &value);
1538 g_assert(type == LTTV_POINTER);
1539 lttv_state_free_blkdev_hashtable(self->bdev_states);
1540 self->bdev_states = lttv_state_copy_blkdev_hashtable(*(value.v_pointer));
1541
1542 for(i = 0 ; i < nb_tracefile ; i++) {
1543 tfcs =
1544 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1545 LttvTracefileContext*, i));
1546 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
1547 g_assert(type == LTTV_GOBJECT);
1548 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
1549 #if 0
1550 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
1551 &value);
1552 g_assert(type == LTTV_UINT);
1553 pid = *(value.v_uint);
1554 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
1555 #endif //0
1556 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1557 &value);
1558 g_assert(type == LTTV_POINTER);
1559 //g_assert(*(value.v_pointer) != NULL);
1560 ep = *(value.v_pointer);
1561 g_assert(tfcs->parent.t_context != NULL);
1562
1563 tfcs->cpu_state = &self->cpu_states[tfcs->cpu];
1564
1565 LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
1566 g_tree_remove(tsc->pqueue, tfc);
1567
1568 if(ep != NULL) {
1569 g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
1570 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
1571 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
1572 g_tree_insert(tsc->pqueue, tfc, tfc);
1573 g_info("Restoring state for a tf at time %lu.%lu", tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
1574 } else {
1575 tfc->timestamp = ltt_time_infinite;
1576 }
1577 }
1578 }
1579
1580
1581 static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
1582 {
1583 guint i, nb_tracefile, nb_cpus, nb_irqs;
1584
1585 LttvTracefileState *tfcs;
1586
1587 LttvAttribute *tracefiles_tree, *tracefile_tree;
1588
1589 guint *running_process;
1590
1591 LttvAttributeType type;
1592
1593 LttvAttributeValue value;
1594
1595 LttvAttributeName name;
1596
1597 gboolean is_named;
1598
1599 tracefiles_tree = lttv_attribute_find_subdir(container,
1600 LTTV_STATE_TRACEFILES);
1601 g_object_ref(G_OBJECT(tracefiles_tree));
1602 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
1603
1604 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1605 &value);
1606 g_assert(type == LTTV_POINTER);
1607 lttv_state_free_process_table(*(value.v_pointer));
1608 *(value.v_pointer) = NULL;
1609 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
1610
1611 /* Free running processes array */
1612 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
1613 &value);
1614 g_assert(type == LTTV_POINTER);
1615 running_process = *(value.v_pointer);
1616 g_free(running_process);
1617
1618 /* free cpu resource states */
1619 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS_COUNT, &value);
1620 g_assert(type == LTTV_UINT);
1621 nb_cpus = *value.v_uint;
1622 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS, &value);
1623 g_assert(type == LTTV_POINTER);
1624 lttv_state_free_cpu_states(*(value.v_pointer), nb_cpus);
1625
1626 /* free irq resource states */
1627 nb_irqs = self->nb_irqs;
1628 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_IRQS, &value);
1629 g_assert(type == LTTV_POINTER);
1630 lttv_state_free_irq_states(*(value.v_pointer), nb_irqs);
1631
1632 /* free the blkdev states */
1633 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_BLKDEVS, &value);
1634 g_assert(type == LTTV_POINTER);
1635 lttv_state_free_blkdev_hashtable(*(value.v_pointer));
1636
1637 nb_tracefile = self->parent.tracefiles->len;
1638
1639 for(i = 0 ; i < nb_tracefile ; i++) {
1640 tfcs =
1641 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1642 LttvTracefileContext*, i));
1643 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
1644 g_assert(type == LTTV_GOBJECT);
1645 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
1646
1647 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1648 &value);
1649 g_assert(type == LTTV_POINTER);
1650 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
1651 }
1652 g_object_unref(G_OBJECT(tracefiles_tree));
1653 }
1654
1655
1656 static void free_saved_state(LttvTraceState *self)
1657 {
1658 guint i, nb;
1659
1660 LttvAttributeType type;
1661
1662 LttvAttributeValue value;
1663
1664 LttvAttributeName name;
1665
1666 gboolean is_named;
1667
1668 LttvAttribute *saved_states;
1669
1670 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
1671 LTTV_STATE_SAVED_STATES);
1672
1673 nb = lttv_attribute_get_number(saved_states);
1674 for(i = 0 ; i < nb ; i++) {
1675 type = lttv_attribute_get(saved_states, i, &name, &value, &is_named);
1676 g_assert(type == LTTV_GOBJECT);
1677 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
1678 }
1679
1680 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
1681 }
1682
1683
1684 static void
1685 create_max_time(LttvTraceState *tcs)
1686 {
1687 LttvAttributeValue v;
1688
1689 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1690 LTTV_POINTER, &v);
1691 g_assert(*(v.v_pointer) == NULL);
1692 *(v.v_pointer) = g_new(LttTime,1);
1693 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
1694 }
1695
1696
1697 static void
1698 get_max_time(LttvTraceState *tcs)
1699 {
1700 LttvAttributeValue v;
1701
1702 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1703 LTTV_POINTER, &v);
1704 g_assert(*(v.v_pointer) != NULL);
1705 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
1706 }
1707
1708
1709 static void
1710 free_max_time(LttvTraceState *tcs)
1711 {
1712 LttvAttributeValue v;
1713
1714 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1715 LTTV_POINTER, &v);
1716 g_free(*(v.v_pointer));
1717 *(v.v_pointer) = NULL;
1718 }
1719
1720
1721 typedef struct _LttvNameTables {
1722 // FIXME GQuark *eventtype_names;
1723 GQuark *syscall_names;
1724 guint nb_syscalls;
1725 GQuark *trap_names;
1726 guint nb_traps;
1727 GQuark *irq_names;
1728 guint nb_irqs;
1729 GQuark *soft_irq_names;
1730 guint nb_softirqs;
1731 } LttvNameTables;
1732
1733
1734 static void
1735 create_name_tables(LttvTraceState *tcs)
1736 {
1737 int i;
1738
1739 GString *fe_name = g_string_new("");
1740
1741 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
1742
1743 LttvAttributeValue v;
1744
1745 GArray *hooks;
1746
1747 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1748 LTTV_POINTER, &v);
1749 g_assert(*(v.v_pointer) == NULL);
1750 *(v.v_pointer) = name_tables;
1751
1752 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 1);
1753
1754 if(!lttv_trace_find_hook(tcs->parent.t,
1755 LTT_FACILITY_KERNEL_ARCH,
1756 LTT_EVENT_SYSCALL_ENTRY,
1757 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
1758 NULL, NULL, &hooks)) {
1759
1760 // th = lttv_trace_hook_get_first(&th);
1761 //
1762 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1763 // nb = ltt_type_element_number(t);
1764 //
1765 // name_tables->syscall_names = g_new(GQuark, nb);
1766 // name_tables->nb_syscalls = nb;
1767 //
1768 // for(i = 0 ; i < nb ; i++) {
1769 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1770 // if(!name_tables->syscall_names[i]) {
1771 // GString *string = g_string_new("");
1772 // g_string_printf(string, "syscall %u", i);
1773 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1774 // g_string_free(string, TRUE);
1775 // }
1776 // }
1777
1778 name_tables->nb_syscalls = 256;
1779 name_tables->syscall_names = g_new(GQuark, 256);
1780 for(i = 0 ; i < 256 ; i++) {
1781 g_string_printf(fe_name, "syscall %d", i);
1782 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1783 }
1784 } else {
1785 name_tables->syscall_names = NULL;
1786 name_tables->nb_syscalls = 0;
1787 }
1788 lttv_trace_hook_remove_all(&hooks);
1789
1790 if(!lttv_trace_find_hook(tcs->parent.t,
1791 LTT_FACILITY_KERNEL_ARCH,
1792 LTT_EVENT_TRAP_ENTRY,
1793 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
1794 NULL, NULL, &hooks)) {
1795
1796 // th = lttv_trace_hook_get_first(&th);
1797 //
1798 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1799 // //nb = ltt_type_element_number(t);
1800 //
1801 // name_tables->trap_names = g_new(GQuark, nb);
1802 // for(i = 0 ; i < nb ; i++) {
1803 // name_tables->trap_names[i] = g_quark_from_string(
1804 // ltt_enum_string_get(t, i));
1805 // }
1806
1807 name_tables->nb_traps = 256;
1808 name_tables->trap_names = g_new(GQuark, 256);
1809 for(i = 0 ; i < 256 ; i++) {
1810 g_string_printf(fe_name, "trap %d", i);
1811 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
1812 }
1813 } else {
1814 name_tables->trap_names = NULL;
1815 name_tables->nb_traps = 0;
1816 }
1817 lttv_trace_hook_remove_all(&hooks);
1818
1819 if(!lttv_trace_find_hook(tcs->parent.t,
1820 LTT_FACILITY_KERNEL,
1821 LTT_EVENT_IRQ_ENTRY,
1822 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
1823 NULL, NULL, &hooks)) {
1824
1825 /*
1826 name_tables->irq_names = g_new(GQuark, nb);
1827 for(i = 0 ; i < nb ; i++) {
1828 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1829 }
1830 */
1831
1832 name_tables->nb_irqs = 256;
1833 name_tables->irq_names = g_new(GQuark, 256);
1834 for(i = 0 ; i < 256 ; i++) {
1835 g_string_printf(fe_name, "irq %d", i);
1836 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
1837 }
1838 } else {
1839 name_tables->nb_irqs = 0;
1840 name_tables->irq_names = NULL;
1841 }
1842 lttv_trace_hook_remove_all(&hooks);
1843 /*
1844 name_tables->soft_irq_names = g_new(GQuark, nb);
1845 for(i = 0 ; i < nb ; i++) {
1846 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1847 }
1848 */
1849
1850 /* the kernel is limited to 32 statically defined softirqs */
1851 name_tables->nb_softirqs = 32;
1852 name_tables->soft_irq_names = g_new(GQuark, name_tables->nb_softirqs);
1853 for(i = 0 ; i < name_tables->nb_softirqs ; i++) {
1854 g_string_printf(fe_name, "softirq %d", i);
1855 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
1856 }
1857 g_array_free(hooks, TRUE);
1858
1859 g_string_free(fe_name, TRUE);
1860 }
1861
1862
1863 static void
1864 get_name_tables(LttvTraceState *tcs)
1865 {
1866 LttvNameTables *name_tables;
1867
1868 LttvAttributeValue v;
1869
1870 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1871 LTTV_POINTER, &v);
1872 g_assert(*(v.v_pointer) != NULL);
1873 name_tables = (LttvNameTables *)*(v.v_pointer);
1874 //tcs->eventtype_names = name_tables->eventtype_names;
1875 tcs->syscall_names = name_tables->syscall_names;
1876 tcs->nb_syscalls = name_tables->nb_syscalls;
1877 tcs->trap_names = name_tables->trap_names;
1878 tcs->nb_traps = name_tables->nb_traps;
1879 tcs->irq_names = name_tables->irq_names;
1880 tcs->soft_irq_names = name_tables->soft_irq_names;
1881 tcs->nb_irqs = name_tables->nb_irqs;
1882 tcs->nb_soft_irqs = name_tables->nb_softirqs;
1883 }
1884
1885
1886 static void
1887 free_name_tables(LttvTraceState *tcs)
1888 {
1889 LttvNameTables *name_tables;
1890
1891 LttvAttributeValue v;
1892
1893 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1894 LTTV_POINTER, &v);
1895 name_tables = (LttvNameTables *)*(v.v_pointer);
1896 *(v.v_pointer) = NULL;
1897
1898 // g_free(name_tables->eventtype_names);
1899 if(name_tables->syscall_names) g_free(name_tables->syscall_names);
1900 if(name_tables->trap_names) g_free(name_tables->trap_names);
1901 if(name_tables->irq_names) g_free(name_tables->irq_names);
1902 if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
1903 if(name_tables) g_free(name_tables);
1904 }
1905
1906 #ifdef HASH_TABLE_DEBUG
1907
1908 static void test_process(gpointer key, gpointer value, gpointer user_data)
1909 {
1910 LttvProcessState *process = (LttvProcessState *)value;
1911
1912 /* Test for process corruption */
1913 guint stack_len = process->execution_stack->len;
1914 }
1915
1916 static void hash_table_check(GHashTable *table)
1917 {
1918 g_hash_table_foreach(table, test_process, NULL);
1919 }
1920
1921
1922 #endif
1923
1924 /* clears the stack and sets the state passed as argument */
1925 static void cpu_set_base_mode(LttvCPUState *cpust, LttvCPUMode state)
1926 {
1927 g_array_set_size(cpust->mode_stack, 1);
1928 ((GQuark *)cpust->mode_stack->data)[0] = state;
1929 }
1930
1931 static void cpu_push_mode(LttvCPUState *cpust, LttvCPUMode state)
1932 {
1933 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len + 1);
1934 ((GQuark *)cpust->mode_stack->data)[cpust->mode_stack->len - 1] = state;
1935 }
1936
1937 static void cpu_pop_mode(LttvCPUState *cpust)
1938 {
1939 if(cpust->mode_stack->len <= 1)
1940 cpu_set_base_mode(cpust, LTTV_CPU_UNKNOWN);
1941 else
1942 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len - 1);
1943 }
1944
1945 /* clears the stack and sets the state passed as argument */
1946 static void bdev_set_base_mode(LttvBdevState *bdevst, LttvBdevMode state)
1947 {
1948 g_array_set_size(bdevst->mode_stack, 1);
1949 ((GQuark *)bdevst->mode_stack->data)[0] = state;
1950 }
1951
1952 static void bdev_push_mode(LttvBdevState *bdevst, LttvBdevMode state)
1953 {
1954 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len + 1);
1955 ((GQuark *)bdevst->mode_stack->data)[bdevst->mode_stack->len - 1] = state;
1956 }
1957
1958 static void bdev_pop_mode(LttvBdevState *bdevst)
1959 {
1960 if(bdevst->mode_stack->len <= 1)
1961 bdev_set_base_mode(bdevst, LTTV_BDEV_UNKNOWN);
1962 else
1963 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len - 1);
1964 }
1965
1966 static void irq_set_base_mode(LttvIRQState *irqst, LttvIRQMode state)
1967 {
1968 g_array_set_size(irqst->mode_stack, 1);
1969 ((GQuark *)irqst->mode_stack->data)[0] = state;
1970 }
1971
1972 static void irq_push_mode(LttvIRQState *irqst, LttvIRQMode state)
1973 {
1974 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len + 1);
1975 ((GQuark *)irqst->mode_stack->data)[irqst->mode_stack->len - 1] = state;
1976 }
1977
1978 static void irq_pop_mode(LttvIRQState *irqst)
1979 {
1980 if(irqst->mode_stack->len <= 1)
1981 irq_set_base_mode(irqst, LTTV_IRQ_UNKNOWN);
1982 else
1983 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len - 1);
1984 }
1985
1986 static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
1987 guint state_id)
1988 {
1989 LttvExecutionState *es;
1990
1991 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1992 guint cpu = tfs->cpu;
1993
1994 #ifdef HASH_TABLE_DEBUG
1995 hash_table_check(ts->processes);
1996 #endif
1997 LttvProcessState *process = ts->running_process[cpu];
1998
1999 guint depth = process->execution_stack->len;
2000
2001 process->execution_stack =
2002 g_array_set_size(process->execution_stack, depth + 1);
2003 /* Keep in sync */
2004 process->state =
2005 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
2006
2007 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
2008 es->t = t;
2009 es->n = state_id;
2010 es->entry = es->change = tfs->parent.timestamp;
2011 es->cum_cpu_time = ltt_time_zero;
2012 es->s = process->state->s;
2013 process->state = es;
2014 }
2015
2016 /* pop state
2017 * return 1 when empty, else 0 */
2018 int lttv_state_pop_state_cleanup(LttvProcessState *process,
2019 LttvTracefileState *tfs)
2020 {
2021 guint depth = process->execution_stack->len;
2022
2023 if(depth == 1){
2024 return 1;
2025 }
2026
2027 process->execution_stack =
2028 g_array_set_size(process->execution_stack, depth - 1);
2029 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
2030 depth - 2);
2031 process->state->change = tfs->parent.timestamp;
2032
2033 return 0;
2034 }
2035
2036 static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
2037 {
2038 guint cpu = tfs->cpu;
2039 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2040 LttvProcessState *process = ts->running_process[cpu];
2041
2042 guint depth = process->execution_stack->len;
2043
2044 if(process->state->t != t){
2045 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2046 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2047 g_info("process state has %s when pop_int is %s\n",
2048 g_quark_to_string(process->state->t),
2049 g_quark_to_string(t));
2050 g_info("{ %u, %u, %s, %s, %s }\n",
2051 process->pid,
2052 process->ppid,
2053 g_quark_to_string(process->name),
2054 g_quark_to_string(process->brand),
2055 g_quark_to_string(process->state->s));
2056 return;
2057 }
2058
2059 if(depth == 1){
2060 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2061 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2062 return;
2063 }
2064
2065 process->execution_stack =
2066 g_array_set_size(process->execution_stack, depth - 1);
2067 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
2068 depth - 2);
2069 process->state->change = tfs->parent.timestamp;
2070 }
2071
2072 struct search_result {
2073 const LttTime *time; /* Requested time */
2074 LttTime *best; /* Best result */
2075 };
2076
2077 static gint search_usertrace(gconstpointer a, gconstpointer b)
2078 {
2079 const LttTime *elem_time = (const LttTime*)a;
2080 /* Explicit non const cast */
2081 struct search_result *res = (struct search_result *)b;
2082
2083 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
2084 /* The usertrace was created before the schedchange */
2085 /* Get larger keys */
2086 return 1;
2087 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
2088 /* The usertrace was created after the schedchange time */
2089 /* Get smaller keys */
2090 if(res->best) {
2091 if(ltt_time_compare(*elem_time, *res->best) < 0) {
2092 res->best = (LttTime *)elem_time;
2093 }
2094 } else {
2095 res->best = (LttTime *)elem_time;
2096 }
2097 return -1;
2098 }
2099 return 0;
2100 }
2101
2102 static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
2103 guint pid, const LttTime *timestamp)
2104 {
2105 LttvTracefileState *tfs = NULL;
2106 struct search_result res;
2107 /* Find the usertrace associated with a pid and time interval.
2108 * Search in the usertraces by PID (within a hash) and then, for each
2109 * corresponding element of the array, find the first one with creation
2110 * timestamp the lowest, but higher or equal to "timestamp". */
2111 res.time = timestamp;
2112 res.best = NULL;
2113 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
2114 if(usertrace_tree) {
2115 g_tree_search(usertrace_tree, search_usertrace, &res);
2116 if(res.best)
2117 tfs = g_tree_lookup(usertrace_tree, res.best);
2118 }
2119
2120 return tfs;
2121 }
2122
2123
2124 LttvProcessState *
2125 lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
2126 guint cpu, guint pid, guint tgid, GQuark name, const LttTime *timestamp)
2127 {
2128 LttvProcessState *process = g_new(LttvProcessState, 1);
2129
2130 LttvExecutionState *es;
2131
2132 char buffer[128];
2133
2134 process->pid = pid;
2135 process->tgid = tgid;
2136 process->cpu = cpu;
2137 process->name = name;
2138 process->brand = LTTV_STATE_UNBRANDED;
2139 //process->last_cpu = tfs->cpu_name;
2140 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2141 process->type = LTTV_STATE_USER_THREAD;
2142 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
2143 process->current_function = 0; //function 0x0 by default.
2144
2145 g_info("Process %u, core %p", process->pid, process);
2146 g_hash_table_insert(tcs->processes, process, process);
2147
2148 if(parent) {
2149 process->ppid = parent->pid;
2150 process->creation_time = *timestamp;
2151 }
2152
2153 /* No parent. This process exists but we are missing all information about
2154 its creation. The birth time is set to zero but we remember the time of
2155 insertion */
2156
2157 else {
2158 process->ppid = 0;
2159 process->creation_time = ltt_time_zero;
2160 }
2161
2162 process->insertion_time = *timestamp;
2163 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
2164 process->creation_time.tv_nsec);
2165 process->pid_time = g_quark_from_string(buffer);
2166 process->cpu = cpu;
2167 process->free_events = 0;
2168 //process->last_cpu = tfs->cpu_name;
2169 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2170 process->execution_stack = g_array_sized_new(FALSE, FALSE,
2171 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
2172 process->execution_stack = g_array_set_size(process->execution_stack, 2);
2173 es = process->state = &g_array_index(process->execution_stack,
2174 LttvExecutionState, 0);
2175 es->t = LTTV_STATE_USER_MODE;
2176 es->n = LTTV_STATE_SUBMODE_NONE;
2177 es->entry = *timestamp;
2178 //g_assert(timestamp->tv_sec != 0);
2179 es->change = *timestamp;
2180 es->cum_cpu_time = ltt_time_zero;
2181 es->s = LTTV_STATE_RUN;
2182
2183 es = process->state = &g_array_index(process->execution_stack,
2184 LttvExecutionState, 1);
2185 es->t = LTTV_STATE_SYSCALL;
2186 es->n = LTTV_STATE_SUBMODE_NONE;
2187 es->entry = *timestamp;
2188 //g_assert(timestamp->tv_sec != 0);
2189 es->change = *timestamp;
2190 es->cum_cpu_time = ltt_time_zero;
2191 es->s = LTTV_STATE_WAIT_FORK;
2192
2193 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2194 process->user_stack = g_array_sized_new(FALSE, FALSE,
2195 sizeof(guint64), 0);
2196
2197 return process;
2198 }
2199
2200 LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
2201 guint pid)
2202 {
2203 LttvProcessState key;
2204 LttvProcessState *process;
2205
2206 key.pid = pid;
2207 key.cpu = cpu;
2208 process = g_hash_table_lookup(ts->processes, &key);
2209 return process;
2210 }
2211
2212 LttvProcessState *
2213 lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
2214 const LttTime *timestamp)
2215 {
2216 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
2217 LttvExecutionState *es;
2218
2219 /* Put ltt_time_zero creation time for unexisting processes */
2220 if(unlikely(process == NULL)) {
2221 process = lttv_state_create_process(ts,
2222 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
2223 /* We are not sure is it's a kernel thread or normal thread, put the
2224 * bottom stack state to unknown */
2225 process->execution_stack =
2226 g_array_set_size(process->execution_stack, 1);
2227 process->state = es =
2228 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2229 es->t = LTTV_STATE_MODE_UNKNOWN;
2230 es->s = LTTV_STATE_UNNAMED;
2231 }
2232 return process;
2233 }
2234
2235 /* FIXME : this function should be called when we receive an event telling that
2236 * release_task has been called in the kernel. In happens generally when
2237 * the parent waits for its child terminaison, but may also happen in special
2238 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2239 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2240 * of a killed thread group, but isn't the leader.
2241 */
2242 static int exit_process(LttvTracefileState *tfs, LttvProcessState *process)
2243 {
2244 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2245 LttvProcessState key;
2246
2247 /* Wait for both schedule with exit dead and process free to happen.
2248 * They can happen in any order. */
2249 if (++(process->free_events) < 2)
2250 return 0;
2251
2252 key.pid = process->pid;
2253 key.cpu = process->cpu;
2254 g_hash_table_remove(ts->processes, &key);
2255 g_array_free(process->execution_stack, TRUE);
2256 g_array_free(process->user_stack, TRUE);
2257 g_free(process);
2258 return 1;
2259 }
2260
2261
2262 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
2263 {
2264 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
2265 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
2266 g_free(value);
2267 }
2268
2269
2270 static void lttv_state_free_process_table(GHashTable *processes)
2271 {
2272 g_hash_table_foreach(processes, free_process_state, NULL);
2273 g_hash_table_destroy(processes);
2274 }
2275
2276
2277 static gboolean syscall_entry(void *hook_data, void *call_data)
2278 {
2279 LttvTracefileState *s = (LttvTracefileState *)call_data;
2280 guint cpu = s->cpu;
2281 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2282 LttvProcessState *process = ts->running_process[cpu];
2283 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2284 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2285 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2286
2287 LttvExecutionSubmode submode;
2288
2289 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
2290 guint syscall = ltt_event_get_unsigned(e, f);
2291
2292 if(syscall < nb_syscalls) {
2293 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
2294 syscall];
2295 } else {
2296 /* Fixup an incomplete syscall table */
2297 GString *string = g_string_new("");
2298 g_string_printf(string, "syscall %u", syscall);
2299 submode = g_quark_from_string(string->str);
2300 g_string_free(string, TRUE);
2301 }
2302 /* There can be no system call from PID 0 : unknown state */
2303 if(process->pid != 0)
2304 push_state(s, LTTV_STATE_SYSCALL, submode);
2305 return FALSE;
2306 }
2307
2308
2309 static gboolean syscall_exit(void *hook_data, void *call_data)
2310 {
2311 LttvTracefileState *s = (LttvTracefileState *)call_data;
2312 guint cpu = s->cpu;
2313 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2314 LttvProcessState *process = ts->running_process[cpu];
2315
2316 /* There can be no system call from PID 0 : unknown state */
2317 if(process->pid != 0)
2318 pop_state(s, LTTV_STATE_SYSCALL);
2319 return FALSE;
2320 }
2321
2322
2323 static gboolean trap_entry(void *hook_data, void *call_data)
2324 {
2325 LttvTracefileState *s = (LttvTracefileState *)call_data;
2326 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2327 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2328 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2329 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2330
2331 LttvExecutionSubmode submode;
2332
2333 guint64 nb_traps = ((LttvTraceState *)(s->parent.t_context))->nb_traps;
2334 guint64 trap = ltt_event_get_long_unsigned(e, f);
2335
2336 if(trap < nb_traps) {
2337 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap];
2338 } else {
2339 /* Fixup an incomplete trap table */
2340 GString *string = g_string_new("");
2341 g_string_printf(string, "trap %llu", trap);
2342 submode = g_quark_from_string(string->str);
2343 g_string_free(string, TRUE);
2344 }
2345
2346 push_state(s, LTTV_STATE_TRAP, submode);
2347
2348 /* update cpu status */
2349 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
2350
2351 /* update trap status */
2352 s->cpu_state->last_trap = trap;
2353 ts->trap_states[trap].running++;
2354
2355 return FALSE;
2356 }
2357
2358 static gboolean trap_exit(void *hook_data, void *call_data)
2359 {
2360 LttvTracefileState *s = (LttvTracefileState *)call_data;
2361 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2362 guint trap = s->cpu_state->last_trap;
2363
2364 pop_state(s, LTTV_STATE_TRAP);
2365
2366 /* update cpu status */
2367 cpu_pop_mode(s->cpu_state);
2368
2369 /* update trap status */
2370 if(ts->trap_states[trap].running)
2371 ts->trap_states[trap].running--;
2372
2373 return FALSE;
2374 }
2375
2376 static gboolean irq_entry(void *hook_data, void *call_data)
2377 {
2378 LttvTracefileState *s = (LttvTracefileState *)call_data;
2379 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2380 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2381 //guint8 ev_id = ltt_event_eventtype_id(e);
2382 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2383 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2384
2385 LttvExecutionSubmode submode;
2386 guint64 irq = ltt_event_get_long_unsigned(e, f);
2387 guint64 nb_irqs = ((LttvTraceState *)(s->parent.t_context))->nb_irqs;
2388
2389 if(irq < nb_irqs) {
2390 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[irq];
2391 } else {
2392 /* Fixup an incomplete irq table */
2393 GString *string = g_string_new("");
2394 g_string_printf(string, "irq %llu", irq);
2395 submode = g_quark_from_string(string->str);
2396 g_string_free(string, TRUE);
2397 }
2398
2399 /* Do something with the info about being in user or system mode when int? */
2400 push_state(s, LTTV_STATE_IRQ, submode);
2401
2402 /* update cpu status */
2403 cpu_push_mode(s->cpu_state, LTTV_CPU_IRQ);
2404
2405 /* update irq status */
2406 s->cpu_state->last_irq = irq;
2407 irq_push_mode(&ts->irq_states[irq], LTTV_IRQ_BUSY);
2408
2409 return FALSE;
2410 }
2411
2412 static gboolean soft_irq_exit(void *hook_data, void *call_data)
2413 {
2414 LttvTracefileState *s = (LttvTracefileState *)call_data;
2415 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2416 guint softirq = s->cpu_state->last_soft_irq;
2417
2418 pop_state(s, LTTV_STATE_SOFT_IRQ);
2419
2420 /* update softirq status */
2421 if(ts->soft_irq_states[softirq].running)
2422 ts->soft_irq_states[softirq].running--;
2423
2424 /* update cpu status */
2425 cpu_pop_mode(s->cpu_state);
2426
2427 return FALSE;
2428 }
2429
2430 static gboolean irq_exit(void *hook_data, void *call_data)
2431 {
2432 LttvTracefileState *s = (LttvTracefileState *)call_data;
2433 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2434
2435 pop_state(s, LTTV_STATE_IRQ);
2436
2437 /* update cpu status */
2438 cpu_pop_mode(s->cpu_state);
2439
2440 /* update irq status */
2441 irq_pop_mode(&ts->irq_states[s->cpu_state->last_irq]);
2442
2443 return FALSE;
2444 }
2445
2446 static gboolean soft_irq_entry(void *hook_data, void *call_data)
2447 {
2448 LttvTracefileState *s = (LttvTracefileState *)call_data;
2449 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2450 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2451 //guint8 ev_id = ltt_event_eventtype_id(e);
2452 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2453 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2454
2455 LttvExecutionSubmode submode;
2456 guint64 softirq = ltt_event_get_long_unsigned(e, f);
2457 guint64 nb_softirqs = ((LttvTraceState *)(s->parent.t_context))->nb_soft_irqs;
2458
2459 if(softirq < nb_softirqs) {
2460 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[softirq];
2461 } else {
2462 /* Fixup an incomplete irq table */
2463 GString *string = g_string_new("");
2464 g_string_printf(string, "softirq %llu", softirq);
2465 submode = g_quark_from_string(string->str);
2466 g_string_free(string, TRUE);
2467 }
2468
2469 /* Do something with the info about being in user or system mode when int? */
2470 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
2471
2472 /* update cpu status */
2473 cpu_push_mode(s->cpu_state, LTTV_CPU_SOFT_IRQ);
2474
2475 /* update softirq status */
2476 s->cpu_state->last_soft_irq = softirq;
2477 ts->soft_irq_states[softirq].running++;
2478
2479 return FALSE;
2480 }
2481
2482 static gboolean enum_interrupt(void *hook_data, void *call_data)
2483 {
2484 LttvTracefileState *s = (LttvTracefileState *)call_data;
2485 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2486 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2487 //guint8 ev_id = ltt_event_eventtype_id(e);
2488 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2489
2490 GQuark action = g_quark_from_string(ltt_event_get_string(e,
2491 lttv_trace_get_hook_field(th, 0)));
2492 guint irq = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
2493
2494 ts->irq_names[irq] = action;
2495
2496 return FALSE;
2497 }
2498
2499
2500 static gboolean bdev_request_issue(void *hook_data, void *call_data)
2501 {
2502 LttvTracefileState *s = (LttvTracefileState *)call_data;
2503 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2504 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2505 //guint8 ev_id = ltt_event_eventtype_id(e);
2506 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2507
2508 guint major = ltt_event_get_long_unsigned(e,
2509 lttv_trace_get_hook_field(th, 0));
2510 guint minor = ltt_event_get_long_unsigned(e,
2511 lttv_trace_get_hook_field(th, 1));
2512 guint oper = ltt_event_get_long_unsigned(e,
2513 lttv_trace_get_hook_field(th, 2));
2514 guint16 devcode = MKDEV(major,minor);
2515
2516 /* have we seen this block device before? */
2517 gpointer bdev = get_hashed_bdevstate(ts, devcode);
2518
2519 if(oper == 0)
2520 bdev_push_mode(bdev, LTTV_BDEV_BUSY_READING);
2521 else
2522 bdev_push_mode(bdev, LTTV_BDEV_BUSY_WRITING);
2523
2524 return FALSE;
2525 }
2526
2527 static gboolean bdev_request_complete(void *hook_data, void *call_data)
2528 {
2529 LttvTracefileState *s = (LttvTracefileState *)call_data;
2530 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2531 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2532 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2533
2534 guint major = ltt_event_get_long_unsigned(e,
2535 lttv_trace_get_hook_field(th, 0));
2536 guint minor = ltt_event_get_long_unsigned(e,
2537 lttv_trace_get_hook_field(th, 1));
2538 //guint oper = ltt_event_get_long_unsigned(e,
2539 // lttv_trace_get_hook_field(th, 2));
2540 guint16 devcode = MKDEV(major,minor);
2541
2542 /* have we seen this block device before? */
2543 gpointer bdev = get_hashed_bdevstate(ts, devcode);
2544
2545 /* update block device */
2546 bdev_pop_mode(bdev);
2547
2548 return FALSE;
2549 }
2550
2551 static void push_function(LttvTracefileState *tfs, guint64 funcptr)
2552 {
2553 guint64 *new_func;
2554
2555 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2556 guint cpu = tfs->cpu;
2557 LttvProcessState *process = ts->running_process[cpu];
2558
2559 guint depth = process->user_stack->len;
2560
2561 process->user_stack =
2562 g_array_set_size(process->user_stack, depth + 1);
2563
2564 new_func = &g_array_index(process->user_stack, guint64, depth);
2565 *new_func = funcptr;
2566 process->current_function = funcptr;
2567 }
2568
2569 static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
2570 {
2571 guint cpu = tfs->cpu;
2572 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2573 LttvProcessState *process = ts->running_process[cpu];
2574
2575 if(process->current_function != funcptr){
2576 g_info("Different functions (%lu.%09lu): ignore it\n",
2577 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2578 g_info("process state has %llu when pop_function is %llu\n",
2579 process->current_function, funcptr);
2580 g_info("{ %u, %u, %s, %s, %s }\n",
2581 process->pid,
2582 process->ppid,
2583 g_quark_to_string(process->name),
2584 g_quark_to_string(process->brand),
2585 g_quark_to_string(process->state->s));
2586 return;
2587 }
2588 guint depth = process->user_stack->len;
2589
2590 if(depth == 0){
2591 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2592 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2593 return;
2594 }
2595
2596 process->user_stack =
2597 g_array_set_size(process->user_stack, depth - 1);
2598 process->current_function =
2599 g_array_index(process->user_stack, guint64, depth - 2);
2600 }
2601
2602
2603 static gboolean function_entry(void *hook_data, void *call_data)
2604 {
2605 LttvTracefileState *s = (LttvTracefileState *)call_data;
2606 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2607 //guint8 ev_id = ltt_event_eventtype_id(e);
2608 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2609 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2610 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2611
2612 push_function(s, funcptr);
2613 return FALSE;
2614 }
2615
2616 static gboolean function_exit(void *hook_data, void *call_data)
2617 {
2618 LttvTracefileState *s = (LttvTracefileState *)call_data;
2619 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2620 //guint8 ev_id = ltt_event_eventtype_id(e);
2621 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2622 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2623 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2624
2625 pop_function(s, funcptr);
2626 return FALSE;
2627 }
2628
2629 static gboolean schedchange(void *hook_data, void *call_data)
2630 {
2631 LttvTracefileState *s = (LttvTracefileState *)call_data;
2632 guint cpu = s->cpu;
2633 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2634 LttvProcessState *process = ts->running_process[cpu];
2635 //LttvProcessState *old_process = ts->running_process[cpu];
2636
2637 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2638 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2639 guint pid_in, pid_out;
2640 gint64 state_out;
2641
2642 pid_out = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2643 pid_in = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
2644 state_out = ltt_event_get_long_int(e, lttv_trace_get_hook_field(th, 2));
2645
2646 if(likely(process != NULL)) {
2647
2648 /* We could not know but it was not the idle process executing.
2649 This should only happen at the beginning, before the first schedule
2650 event, and when the initial information (current process for each CPU)
2651 is missing. It is not obvious how we could, after the fact, compensate
2652 the wrongly attributed statistics. */
2653
2654 //This test only makes sense once the state is known and if there is no
2655 //missing events. We need to silently ignore schedchange coming after a
2656 //process_free, or it causes glitches. (FIXME)
2657 //if(unlikely(process->pid != pid_out)) {
2658 // g_assert(process->pid == 0);
2659 //}
2660 if(process->pid == 0
2661 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
2662 if(pid_out == 0) {
2663 /* Scheduling out of pid 0 at beginning of the trace :
2664 * we know for sure it is in syscall mode at this point. */
2665 g_assert(process->execution_stack->len == 1);
2666 process->state->t = LTTV_STATE_SYSCALL;
2667 process->state->s = LTTV_STATE_WAIT;
2668 process->state->change = s->parent.timestamp;
2669 process->state->entry = s->parent.timestamp;
2670 }
2671 } else {
2672 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
2673 process->state->s = LTTV_STATE_ZOMBIE;
2674 process->state->change = s->parent.timestamp;
2675 } else {
2676 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
2677 else process->state->s = LTTV_STATE_WAIT;
2678 process->state->change = s->parent.timestamp;
2679 }
2680
2681 if(state_out == 32 || state_out == 64) { /* EXIT_DEAD || TASK_DEAD */
2682 /* see sched.h for states */
2683 if (!exit_process(s, process)) {
2684 process->state->s = LTTV_STATE_DEAD;
2685 process->state->change = s->parent.timestamp;
2686 }
2687 }
2688 }
2689 }
2690 process = ts->running_process[cpu] =
2691 lttv_state_find_process_or_create(
2692 (LttvTraceState*)s->parent.t_context,
2693 cpu, pid_in,
2694 &s->parent.timestamp);
2695 process->state->s = LTTV_STATE_RUN;
2696 process->cpu = cpu;
2697 if(process->usertrace)
2698 process->usertrace->cpu = cpu;
2699 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2700 process->state->change = s->parent.timestamp;
2701
2702 /* update cpu status */
2703 if(pid_in == 0)
2704 /* going to idle task */
2705 cpu_set_base_mode(s->cpu_state, LTTV_CPU_IDLE);
2706 else {
2707 /* scheduling a real task.
2708 * we must be careful here:
2709 * if we just schedule()'ed to a process that is
2710 * in a trap, we must put the cpu in trap mode
2711 */
2712 cpu_set_base_mode(s->cpu_state, LTTV_CPU_BUSY);
2713 if(process->state->t == LTTV_STATE_TRAP)
2714 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
2715 }
2716
2717 return FALSE;
2718 }
2719
2720 static gboolean process_fork(void *hook_data, void *call_data)
2721 {
2722 LttvTracefileState *s = (LttvTracefileState *)call_data;
2723 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2724 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2725 guint parent_pid;
2726 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
2727 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
2728 //LttvProcessState *zombie_process;
2729 guint cpu = s->cpu;
2730 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2731 LttvProcessState *process = ts->running_process[cpu];
2732 LttvProcessState *child_process;
2733 struct marker_field *f;
2734
2735 /* Parent PID */
2736 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2737
2738 /* Child PID */
2739 child_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
2740 s->parent.target_pid = child_pid;
2741
2742 /* Child TGID */
2743 f = lttv_trace_get_hook_field(th, 2);
2744 if (likely(f))
2745 child_tgid = ltt_event_get_unsigned(e, f);
2746 else
2747 child_tgid = 0;
2748
2749 /* Mathieu : it seems like the process might have been scheduled in before the
2750 * fork, and, in a rare case, might be the current process. This might happen
2751 * in a SMP case where we don't have enough precision on the clocks.
2752 *
2753 * Test reenabled after precision fixes on time. (Mathieu) */
2754 #if 0
2755 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2756
2757 if(unlikely(zombie_process != NULL)) {
2758 /* Reutilisation of PID. Only now we are sure that the old PID
2759 * has been released. FIXME : should know when release_task happens instead.
2760 */
2761 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2762 guint i;
2763 for(i=0; i< num_cpus; i++) {
2764 g_assert(zombie_process != ts->running_process[i]);
2765 }
2766
2767 exit_process(s, zombie_process);
2768 }
2769 #endif //0
2770 g_assert(process->pid != child_pid);
2771 // FIXME : Add this test in the "known state" section
2772 // g_assert(process->pid == parent_pid);
2773 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2774 if(child_process == NULL) {
2775 child_process = lttv_state_create_process(ts, process, cpu,
2776 child_pid, child_tgid,
2777 LTTV_STATE_UNNAMED, &s->parent.timestamp);
2778 } else {
2779 /* The process has already been created : due to time imprecision between
2780 * multiple CPUs : it has been scheduled in before creation. Note that we
2781 * shouldn't have this kind of imprecision.
2782 *
2783 * Simply put a correct parent.
2784 */
2785 g_error("Process %u has been created before fork on cpu %u. Probably an unsynchronized TSC problem on the traced machine.", child_pid, cpu);
2786 //g_assert(0); /* This is a problematic case : the process has been created
2787 // before the fork event */
2788 child_process->ppid = process->pid;
2789 child_process->tgid = child_tgid;
2790 }
2791 g_assert(child_process->name == LTTV_STATE_UNNAMED);
2792 child_process->name = process->name;
2793 child_process->brand = process->brand;
2794
2795 return FALSE;
2796 }
2797
2798 /* We stamp a newly created process as kernel_thread.
2799 * The thread should not be running yet. */
2800 static gboolean process_kernel_thread(void *hook_data, void *call_data)
2801 {
2802 LttvTracefileState *s = (LttvTracefileState *)call_data;
2803 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2804 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2805 guint pid;
2806 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2807 LttvProcessState *process;
2808 LttvExecutionState *es;
2809
2810 /* PID */
2811 pid = (guint)ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
2812 s->parent.target_pid = pid;
2813
2814 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
2815 &ltt_time_zero);
2816 if (process->state->s != LTTV_STATE_DEAD) {
2817 process->execution_stack =
2818 g_array_set_size(process->execution_stack, 1);
2819 es = process->state =
2820 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2821 es->t = LTTV_STATE_SYSCALL;
2822 }
2823 process->type = LTTV_STATE_KERNEL_THREAD;
2824
2825 return FALSE;
2826 }
2827
2828 static gboolean process_exit(void *hook_data, void *call_data)
2829 {
2830 LttvTracefileState *s = (LttvTracefileState *)call_data;
2831 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2832 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2833 guint pid;
2834 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2835 LttvProcessState *process; // = ts->running_process[cpu];
2836
2837 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2838 s->parent.target_pid = pid;
2839
2840 // FIXME : Add this test in the "known state" section
2841 // g_assert(process->pid == pid);
2842
2843 process = lttv_state_find_process(ts, ANY_CPU, pid);
2844 if(likely(process != NULL)) {
2845 process->state->s = LTTV_STATE_EXIT;
2846 }
2847 return FALSE;
2848 }
2849
2850 static gboolean process_free(void *hook_data, void *call_data)
2851 {
2852 LttvTracefileState *s = (LttvTracefileState *)call_data;
2853 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2854 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2855 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2856 guint release_pid;
2857 LttvProcessState *process;
2858
2859 /* PID of the process to release */
2860 release_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2861 s->parent.target_pid = release_pid;
2862
2863 g_assert(release_pid != 0);
2864
2865 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2866 if(likely(process != NULL))
2867 exit_process(s, process);
2868 return FALSE;
2869 //DISABLED
2870 if(likely(process != NULL)) {
2871 /* release_task is happening at kernel level : we can now safely release
2872 * the data structure of the process */
2873 //This test is fun, though, as it may happen that
2874 //at time t : CPU 0 : process_free
2875 //at time t+150ns : CPU 1 : schedule out
2876 //Clearly due to time imprecision, we disable it. (Mathieu)
2877 //If this weird case happen, we have no choice but to put the
2878 //Currently running process on the cpu to 0.
2879 //I re-enable it following time precision fixes. (Mathieu)
2880 //Well, in the case where an process is freed by a process on another CPU
2881 //and still scheduled, it happens that this is the schedchange that will
2882 //drop the last reference count. Do not free it here!
2883 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2884 guint i;
2885 for(i=0; i< num_cpus; i++) {
2886 //g_assert(process != ts->running_process[i]);
2887 if(process == ts->running_process[i]) {
2888 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2889 break;
2890 }
2891 }
2892 if(i == num_cpus) /* process is not scheduled */
2893 exit_process(s, process);
2894 }
2895
2896 return FALSE;
2897 }
2898
2899
2900 static gboolean process_exec(void *hook_data, void *call_data)
2901 {
2902 LttvTracefileState *s = (LttvTracefileState *)call_data;
2903 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2904 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2905 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2906 //gchar *name;
2907 guint cpu = s->cpu;
2908 LttvProcessState *process = ts->running_process[cpu];
2909
2910 #if 0//how to use a sequence that must be transformed in a string
2911 /* PID of the process to release */
2912 guint64 name_len = ltt_event_field_element_number(e,
2913 lttv_trace_get_hook_field(th, 0));
2914 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2915 LttField *child = ltt_event_field_element_select(e,
2916 lttv_trace_get_hook_field(th, 0), 0);
2917 gchar *name_begin =
2918 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
2919 gchar *null_term_name = g_new(gchar, name_len+1);
2920 memcpy(null_term_name, name_begin, name_len);
2921 null_term_name[name_len] = '\0';
2922 process->name = g_quark_from_string(null_term_name);
2923 #endif //0
2924
2925 process->name = g_quark_from_string(ltt_event_get_string(e,
2926 lttv_trace_get_hook_field(th, 0)));
2927 process->brand = LTTV_STATE_UNBRANDED;
2928 //g_free(null_term_name);
2929 return FALSE;
2930 }
2931
2932 static gboolean thread_brand(void *hook_data, void *call_data)
2933 {
2934 LttvTracefileState *s = (LttvTracefileState *)call_data;
2935 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2936 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2937 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2938 gchar *name;
2939 guint cpu = s->cpu;
2940 LttvProcessState *process = ts->running_process[cpu];
2941
2942 name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2943 process->brand = g_quark_from_string(name);
2944
2945 return FALSE;
2946 }
2947
2948 static void fix_process(gpointer key, gpointer value,
2949 gpointer user_data)
2950 {
2951 LttvProcessState *process;
2952 LttvExecutionState *es;
2953 process = (LttvProcessState *)value;
2954 LttTime *timestamp = (LttTime*)user_data;
2955
2956 if(process->type == LTTV_STATE_KERNEL_THREAD) {
2957 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2958 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2959 es->t = LTTV_STATE_SYSCALL;
2960 es->n = LTTV_STATE_SUBMODE_NONE;
2961 es->entry = *timestamp;
2962 es->change = *timestamp;
2963 es->cum_cpu_time = ltt_time_zero;
2964 if(es->s == LTTV_STATE_UNNAMED)
2965 es->s = LTTV_STATE_WAIT;
2966 }
2967 } else {
2968 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2969 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2970 es->t = LTTV_STATE_USER_MODE;
2971 es->n = LTTV_STATE_SUBMODE_NONE;
2972 es->entry = *timestamp;
2973 //g_assert(timestamp->tv_sec != 0);
2974 es->change = *timestamp;
2975 es->cum_cpu_time = ltt_time_zero;
2976 if(es->s == LTTV_STATE_UNNAMED)
2977 es->s = LTTV_STATE_RUN;
2978
2979 if(process->execution_stack->len == 1) {
2980 /* Still in bottom unknown mode, means never did a system call
2981 * May be either in user mode, syscall mode, running or waiting.*/
2982 /* FIXME : we may be tagging syscall mode when being user mode */
2983 process->execution_stack =
2984 g_array_set_size(process->execution_stack, 2);
2985 es = process->state = &g_array_index(process->execution_stack,
2986 LttvExecutionState, 1);
2987 es->t = LTTV_STATE_SYSCALL;
2988 es->n = LTTV_STATE_SUBMODE_NONE;
2989 es->entry = *timestamp;
2990 //g_assert(timestamp->tv_sec != 0);
2991 es->change = *timestamp;
2992 es->cum_cpu_time = ltt_time_zero;
2993 if(es->s == LTTV_STATE_WAIT_FORK)
2994 es->s = LTTV_STATE_WAIT;
2995 }
2996 }
2997 }
2998 }
2999
3000 static gboolean statedump_end(void *hook_data, void *call_data)
3001 {
3002 LttvTracefileState *s = (LttvTracefileState *)call_data;
3003 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3004 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
3005 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3006 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3007
3008 /* For all processes */
3009 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3010 /* else, if stack[0] is unknown, set to user mode, running */
3011
3012 g_hash_table_foreach(ts->processes, fix_process, &tfc->timestamp);
3013
3014 return FALSE;
3015 }
3016
3017 static gboolean enum_process_state(void *hook_data, void *call_data)
3018 {
3019 LttvTracefileState *s = (LttvTracefileState *)call_data;
3020 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3021 //It's slow : optimise later by doing this before reading trace.
3022 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3023 guint parent_pid;
3024 guint pid;
3025 guint tgid;
3026 gchar * command;
3027 guint cpu = s->cpu;
3028 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3029 LttvProcessState *process = ts->running_process[cpu];
3030 LttvProcessState *parent_process;
3031 struct marker_field *f;
3032 GQuark type, mode, submode, status;
3033 LttvExecutionState *es;
3034 guint i, nb_cpus;
3035
3036 /* PID */
3037 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
3038 s->parent.target_pid = pid;
3039
3040 /* Parent PID */
3041 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
3042
3043 /* Command name */
3044 command = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
3045
3046 /* type */
3047 f = lttv_trace_get_hook_field(th, 3);
3048 type = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
3049
3050 //FIXME: type is rarely used, enum must match possible types.
3051
3052 /* mode */
3053 f = lttv_trace_get_hook_field(th, 4);
3054 mode = ltt_enum_string_get(f,ltt_event_get_unsigned(e, f));
3055
3056 /* submode */
3057 f = lttv_trace_get_hook_field(th, 5);
3058 submode = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
3059
3060 /* status */
3061 f = lttv_trace_get_hook_field(th, 6);
3062 status = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
3063
3064 /* TGID */
3065 f = lttv_trace_get_hook_field(th, 7);
3066 if(f)
3067 tgid = ltt_event_get_unsigned(e, f);
3068 else
3069 tgid = 0;
3070
3071 if(pid == 0) {
3072 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
3073 for(i=0; i<nb_cpus; i++) {
3074 process = lttv_state_find_process(ts, i, pid);
3075 g_assert(process != NULL);
3076
3077 process->ppid = parent_pid;
3078 process->tgid = tgid;
3079 process->name = g_quark_from_string(command);
3080 es =
3081 &g_array_index(process->execution_stack, LttvExecutionState, 0);
3082 process->type = LTTV_STATE_KERNEL_THREAD;
3083 }
3084
3085 } else {
3086 /* The process might exist if a process was forked while performing the
3087 * state dump. */
3088 process = lttv_state_find_process(ts, ANY_CPU, pid);
3089 if(process == NULL) {
3090 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
3091 process = lttv_state_create_process(ts, parent_process, cpu,
3092 pid, tgid, g_quark_from_string(command),
3093 &s->parent.timestamp);
3094
3095 /* Keep the stack bottom : a running user mode */
3096 /* Disabled because of inconsistencies in the current statedump states. */
3097 if(type == LTTV_STATE_KERNEL_THREAD) {
3098 /* Only keep the bottom
3099 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3100 /* Will cause expected trap when in fact being syscall (even after end of
3101 * statedump event)
3102 * Will cause expected interrupt when being syscall. (only before end of
3103 * statedump event) */
3104 // This will cause a "popping last state on stack, ignoring it."
3105 process->execution_stack = g_array_set_size(process->execution_stack, 1);
3106 es = process->state = &g_array_index(process->execution_stack,
3107 LttvExecutionState, 0);
3108 process->type = LTTV_STATE_KERNEL_THREAD;
3109 es->t = LTTV_STATE_MODE_UNKNOWN;
3110 es->s = LTTV_STATE_UNNAMED;
3111 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3112 #if 0
3113 es->t = LTTV_STATE_SYSCALL;
3114 es->s = status;
3115 es->n = submode;
3116 #endif //0
3117 } else {
3118 /* User space process :
3119 * bottom : user mode
3120 * either currently running or scheduled out.
3121 * can be scheduled out because interrupted in (user mode or in syscall)
3122 * or because of an explicit call to the scheduler in syscall. Note that
3123 * the scheduler call comes after the irq_exit, so never in interrupt
3124 * context. */
3125 // temp workaround : set size to 1 : only have user mode bottom of stack.
3126 // will cause g_info message of expected syscall mode when in fact being
3127 // in user mode. Can also cause expected trap when in fact being user
3128 // mode in the event of a page fault reenabling interrupts in the handler.
3129 // Expected syscall and trap can also happen after the end of statedump
3130 // This will cause a "popping last state on stack, ignoring it."
3131 process->execution_stack = g_array_set_size(process->execution_stack, 1);
3132 es = process->state = &g_array_index(process->execution_stack,
3133 LttvExecutionState, 0);
3134 es->t = LTTV_STATE_MODE_UNKNOWN;
3135 es->s = LTTV_STATE_UNNAMED;
3136 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3137 #if 0
3138 es->t = LTTV_STATE_USER_MODE;
3139 es->s = status;
3140 es->n = submode;
3141 #endif //0
3142 }
3143 #if 0
3144 /* UNKNOWN STATE */
3145 {
3146 es = process->state = &g_array_index(process->execution_stack,
3147 LttvExecutionState, 1);
3148 es->t = LTTV_STATE_MODE_UNKNOWN;
3149 es->s = LTTV_STATE_UNNAMED;
3150 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3151 }
3152 #endif //0
3153 } else {
3154 /* The process has already been created :
3155 * Probably was forked while dumping the process state or
3156 * was simply scheduled in prior to get the state dump event.
3157 */
3158 process->ppid = parent_pid;
3159 process->tgid = tgid;
3160 process->name = g_quark_from_string(command);
3161 process->type = type;
3162 es =
3163 &g_array_index(process->execution_stack, LttvExecutionState, 0);
3164 #if 0
3165 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
3166 if(type == LTTV_STATE_KERNEL_THREAD)
3167 es->t = LTTV_STATE_SYSCALL;
3168 else
3169 es->t = LTTV_STATE_USER_MODE;
3170 }
3171 #endif //0
3172 /* Don't mess around with the stack, it will eventually become
3173 * ok after the end of state dump. */
3174 }
3175 }
3176
3177 return FALSE;
3178 }
3179
3180 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
3181 {
3182 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3183
3184 lttv_state_add_event_hooks(tss);
3185
3186 return 0;
3187 }
3188
3189 void lttv_state_add_event_hooks(LttvTracesetState *self)
3190 {
3191 LttvTraceset *traceset = self->parent.ts;
3192
3193 guint i, j, k, nb_trace, nb_tracefile;
3194
3195 LttvTraceState *ts;
3196
3197 LttvTracefileState *tfs;
3198
3199 GArray *hooks;
3200
3201 LttvTraceHook *th;
3202
3203 LttvAttributeValue val;
3204
3205 nb_trace = lttv_traceset_number(traceset);
3206 for(i = 0 ; i < nb_trace ; i++) {
3207 ts = (LttvTraceState *)self->parent.traces[i];
3208
3209 /* Find the eventtype id for the following events and register the
3210 associated by id hooks. */
3211
3212 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 19);
3213 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3214 //hn = 0;
3215
3216 lttv_trace_find_hook(ts->parent.t,
3217 LTT_FACILITY_KERNEL_ARCH,
3218 LTT_EVENT_SYSCALL_ENTRY,
3219 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
3220 syscall_entry, NULL, &hooks);
3221
3222 lttv_trace_find_hook(ts->parent.t,
3223 LTT_FACILITY_KERNEL_ARCH,
3224 LTT_EVENT_SYSCALL_EXIT,
3225 NULL,
3226 syscall_exit, NULL, &hooks);
3227
3228 lttv_trace_find_hook(ts->parent.t,
3229 LTT_FACILITY_KERNEL_ARCH,
3230 LTT_EVENT_TRAP_ENTRY,
3231 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3232 trap_entry, NULL, &hooks);
3233
3234 lttv_trace_find_hook(ts->parent.t,
3235 LTT_FACILITY_KERNEL_ARCH,
3236 LTT_EVENT_TRAP_EXIT,
3237 NULL,
3238 trap_exit, NULL, &hooks);
3239
3240 lttv_trace_find_hook(ts->parent.t,
3241 LTT_FACILITY_KERNEL,
3242 LTT_EVENT_IRQ_ENTRY,
3243 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
3244 irq_entry, NULL, &hooks);
3245
3246 lttv_trace_find_hook(ts->parent.t,
3247 LTT_FACILITY_KERNEL,
3248 LTT_EVENT_IRQ_EXIT,
3249 NULL,
3250 irq_exit, NULL, &hooks);
3251
3252 lttv_trace_find_hook(ts->parent.t,
3253 LTT_FACILITY_KERNEL,
3254 LTT_EVENT_SOFT_IRQ_ENTRY,
3255 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3256 soft_irq_entry, NULL, &hooks);
3257
3258 lttv_trace_find_hook(ts->parent.t,
3259 LTT_FACILITY_KERNEL,
3260 LTT_EVENT_SOFT_IRQ_EXIT,
3261 NULL,
3262 soft_irq_exit, NULL, &hooks);
3263
3264 lttv_trace_find_hook(ts->parent.t,
3265 LTT_FACILITY_KERNEL,
3266 LTT_EVENT_SCHED_SCHEDULE,
3267 FIELD_ARRAY(LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID,
3268 LTT_FIELD_PREV_STATE),
3269 schedchange, NULL, &hooks);
3270
3271 lttv_trace_find_hook(ts->parent.t,
3272 LTT_FACILITY_KERNEL,
3273 LTT_EVENT_PROCESS_FORK,
3274 FIELD_ARRAY(LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID,
3275 LTT_FIELD_CHILD_TGID),
3276 process_fork, NULL, &hooks);
3277
3278 lttv_trace_find_hook(ts->parent.t,
3279 LTT_FACILITY_KERNEL_ARCH,
3280 LTT_EVENT_KTHREAD_CREATE,
3281 FIELD_ARRAY(LTT_FIELD_PID),
3282 process_kernel_thread, NULL, &hooks);
3283
3284 lttv_trace_find_hook(ts->parent.t,
3285 LTT_FACILITY_KERNEL,
3286 LTT_EVENT_PROCESS_EXIT,
3287 FIELD_ARRAY(LTT_FIELD_PID),
3288 process_exit, NULL, &hooks);
3289
3290 lttv_trace_find_hook(ts->parent.t,
3291 LTT_FACILITY_KERNEL,
3292 LTT_EVENT_PROCESS_FREE,
3293 FIELD_ARRAY(LTT_FIELD_PID),
3294 process_free, NULL, &hooks);
3295
3296 lttv_trace_find_hook(ts->parent.t,
3297 LTT_FACILITY_FS,
3298 LTT_EVENT_EXEC,
3299 FIELD_ARRAY(LTT_FIELD_FILENAME),
3300 process_exec, NULL, &hooks);
3301
3302 lttv_trace_find_hook(ts->parent.t,
3303 LTT_FACILITY_USER_GENERIC,
3304 LTT_EVENT_THREAD_BRAND,
3305 FIELD_ARRAY(LTT_FIELD_NAME),
3306 thread_brand, NULL, &hooks);
3307
3308 /* statedump-related hooks */
3309 lttv_trace_find_hook(ts->parent.t,
3310 LTT_FACILITY_LIST,
3311 LTT_EVENT_PROCESS_STATE,
3312 FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
3313 LTT_FIELD_TYPE, LTT_FIELD_MODE, LTT_FIELD_SUBMODE,
3314 LTT_FIELD_STATUS, LTT_FIELD_TGID),
3315 enum_process_state, NULL, &hooks);
3316
3317 lttv_trace_find_hook(ts->parent.t,
3318 LTT_FACILITY_LIST,
3319 LTT_EVENT_STATEDUMP_END,
3320 NULL,
3321 statedump_end, NULL, &hooks);
3322
3323 lttv_trace_find_hook(ts->parent.t,
3324 LTT_FACILITY_LIST,
3325 LTT_EVENT_LIST_INTERRUPT,
3326 FIELD_ARRAY(LTT_FIELD_ACTION, LTT_FIELD_IRQ_ID),
3327 enum_interrupt, NULL, &hooks);
3328
3329 lttv_trace_find_hook(ts->parent.t,
3330 LTT_FACILITY_BLOCK,
3331 LTT_EVENT_REQUEST_ISSUE,
3332 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3333 bdev_request_issue, NULL, &hooks);
3334
3335 lttv_trace_find_hook(ts->parent.t,
3336 LTT_FACILITY_BLOCK,
3337 LTT_EVENT_REQUEST_COMPLETE,
3338 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3339 bdev_request_complete, NULL, &hooks);
3340
3341 lttv_trace_find_hook(ts->parent.t,
3342 LTT_FACILITY_USER_GENERIC,
3343 LTT_EVENT_FUNCTION_ENTRY,
3344 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3345 function_entry, NULL, &hooks);
3346
3347 lttv_trace_find_hook(ts->parent.t,
3348 LTT_FACILITY_USER_GENERIC,
3349 LTT_EVENT_FUNCTION_EXIT,
3350 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3351 function_exit, NULL, &hooks);
3352
3353 /* Add these hooks to each event_by_id hooks list */
3354
3355 nb_tracefile = ts->parent.tracefiles->len;
3356
3357 for(j = 0 ; j < nb_tracefile ; j++) {
3358 tfs =
3359 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3360 LttvTracefileContext*, j));
3361
3362 for(k = 0 ; k < hooks->len ; k++) {
3363 th = &g_array_index(hooks, LttvTraceHook, k);
3364 lttv_hooks_add(
3365 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3366 th->h,
3367 th,
3368 LTTV_PRIO_STATE);
3369 }
3370 }
3371 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3372 *(val.v_pointer) = hooks;
3373 }
3374 }
3375
3376 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
3377 {
3378 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3379
3380 lttv_state_remove_event_hooks(tss);
3381
3382 return 0;
3383 }
3384
3385 void lttv_state_remove_event_hooks(LttvTracesetState *self)
3386 {
3387 LttvTraceset *traceset = self->parent.ts;
3388
3389 guint i, j, k, nb_trace, nb_tracefile;
3390
3391 LttvTraceState *ts;
3392
3393 LttvTracefileState *tfs;
3394
3395 GArray *hooks;
3396
3397 LttvTraceHook *th;
3398
3399 LttvAttributeValue val;
3400
3401 nb_trace = lttv_traceset_number(traceset);
3402 for(i = 0 ; i < nb_trace ; i++) {
3403 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
3404
3405 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3406 hooks = *(val.v_pointer);
3407
3408 /* Remove these hooks from each event_by_id hooks list */
3409
3410 nb_tracefile = ts->parent.tracefiles->len;
3411
3412 for(j = 0 ; j < nb_tracefile ; j++) {
3413 tfs =
3414 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3415 LttvTracefileContext*, j));
3416
3417 for(k = 0 ; k < hooks->len ; k++) {
3418 th = &g_array_index(hooks, LttvTraceHook, k);
3419 lttv_hooks_remove_data(
3420 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3421 th->h,
3422 th);
3423 }
3424 }
3425 lttv_trace_hook_remove_all(&hooks);
3426 g_array_free(hooks, TRUE);
3427 }
3428 }
3429
3430 static gboolean state_save_event_hook(void *hook_data, void *call_data)
3431 {
3432 guint *event_count = (guint*)hook_data;
3433
3434 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3435 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
3436 return FALSE;
3437 else
3438 *event_count = 0;
3439
3440 LttvTracefileState *self = (LttvTracefileState *)call_data;
3441
3442 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3443
3444 LttvAttribute *saved_states_tree, *saved_state_tree;
3445
3446 LttvAttributeValue value;
3447
3448 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3449 LTTV_STATE_SAVED_STATES);
3450 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3451 value = lttv_attribute_add(saved_states_tree,
3452 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3453 *(value.v_gobject) = (GObject *)saved_state_tree;
3454 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3455 *(value.v_time) = self->parent.timestamp;
3456 lttv_state_save(tcs, saved_state_tree);
3457 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3458 self->parent.timestamp.tv_nsec);
3459
3460 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3461
3462 return FALSE;
3463 }
3464
3465 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
3466 {
3467 LttvTraceState *tcs = (LttvTraceState *)(call_data);
3468
3469 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
3470
3471 return FALSE;
3472 }
3473
3474 guint lttv_state_current_cpu(LttvTracefileState *tfs)
3475 {
3476 return tfs->cpu;
3477 }
3478
3479
3480
3481 #if 0
3482 static gboolean block_start(void *hook_data, void *call_data)
3483 {
3484 LttvTracefileState *self = (LttvTracefileState *)call_data;
3485
3486 LttvTracefileState *tfcs;
3487
3488 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3489
3490 LttEventPosition *ep;
3491
3492 guint i, nb_block, nb_event, nb_tracefile;
3493
3494 LttTracefile *tf;
3495
3496 LttvAttribute *saved_states_tree, *saved_state_tree;
3497
3498 LttvAttributeValue value;
3499
3500 ep = ltt_event_position_new();
3501
3502 nb_tracefile = tcs->parent.tracefiles->len;
3503
3504 /* Count the number of events added since the last block end in any
3505 tracefile. */
3506
3507 for(i = 0 ; i < nb_tracefile ; i++) {
3508 tfcs =
3509 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
3510 LttvTracefileContext, i));
3511 ltt_event_position(tfcs->parent.e, ep);
3512 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3513 tcs->nb_event += nb_event - tfcs->saved_position;
3514 tfcs->saved_position = nb_event;
3515 }
3516 g_free(ep);
3517
3518 if(tcs->nb_event >= tcs->save_interval) {
3519 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3520 LTTV_STATE_SAVED_STATES);
3521 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3522 value = lttv_attribute_add(saved_states_tree,
3523 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3524 *(value.v_gobject) = (GObject *)saved_state_tree;
3525 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3526 *(value.v_time) = self->parent.timestamp;
3527 lttv_state_save(tcs, saved_state_tree);
3528 tcs->nb_event = 0;
3529 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3530 self->parent.timestamp.tv_nsec);
3531 }
3532 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3533 return FALSE;
3534 }
3535 #endif //0
3536
3537 #if 0
3538 static gboolean block_end(void *hook_data, void *call_data)
3539 {
3540 LttvTracefileState *self = (LttvTracefileState *)call_data;
3541
3542 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3543
3544 LttTracefile *tf;
3545
3546 LttEventPosition *ep;
3547
3548 guint nb_block, nb_event;
3549
3550 ep = ltt_event_position_new();
3551 ltt_event_position(self->parent.e, ep);
3552 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3553 tcs->nb_event += nb_event - self->saved_position + 1;
3554 self->saved_position = 0;
3555 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3556 g_free(ep);
3557
3558 return FALSE;
3559 }
3560 #endif //0
3561 #if 0
3562 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3563 {
3564 LttvTraceset *traceset = self->parent.ts;
3565
3566 guint i, j, nb_trace, nb_tracefile;
3567
3568 LttvTraceState *ts;
3569
3570 LttvTracefileState *tfs;
3571
3572 LttvTraceHook hook_start, hook_end;
3573
3574 nb_trace = lttv_traceset_number(traceset);
3575 for(i = 0 ; i < nb_trace ; i++) {
3576 ts = (LttvTraceState *)self->parent.traces[i];
3577
3578 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
3579 NULL, NULL, block_start, &hook_start);
3580 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
3581 NULL, NULL, block_end, &hook_end);
3582
3583 nb_tracefile = ts->parent.tracefiles->len;
3584
3585 for(j = 0 ; j < nb_tracefile ; j++) {
3586 tfs =
3587 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3588 LttvTracefileContext, j));
3589 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3590 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
3591 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3592 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
3593 }
3594 }
3595 }
3596 #endif //0
3597
3598 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3599 {
3600 LttvTraceset *traceset = self->parent.ts;
3601
3602 guint i, j, nb_trace, nb_tracefile;
3603
3604 LttvTraceState *ts;
3605
3606 LttvTracefileState *tfs;
3607
3608
3609 nb_trace = lttv_traceset_number(traceset);
3610 for(i = 0 ; i < nb_trace ; i++) {
3611
3612 ts = (LttvTraceState *)self->parent.traces[i];
3613 nb_tracefile = ts->parent.tracefiles->len;
3614
3615 if(ts->has_precomputed_states) continue;
3616
3617 guint *event_count = g_new(guint, 1);
3618 *event_count = 0;
3619
3620 for(j = 0 ; j < nb_tracefile ; j++) {
3621 tfs =
3622 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3623 LttvTracefileContext*, j));
3624 lttv_hooks_add(tfs->parent.event,
3625 state_save_event_hook,
3626 event_count,
3627 LTTV_PRIO_STATE);
3628
3629 }
3630 }
3631
3632 lttv_process_traceset_begin(&self->parent,
3633 NULL, NULL, NULL, NULL, NULL);
3634
3635 }
3636
3637 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
3638 {
3639 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3640
3641 lttv_state_save_add_event_hooks(tss);
3642
3643 return 0;
3644 }
3645
3646
3647 #if 0
3648 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3649 {
3650 LttvTraceset *traceset = self->parent.ts;
3651
3652 guint i, j, nb_trace, nb_tracefile;
3653
3654 LttvTraceState *ts;
3655
3656 LttvTracefileState *tfs;
3657
3658 LttvTraceHook hook_start, hook_end;
3659
3660 nb_trace = lttv_traceset_number(traceset);
3661 for(i = 0 ; i < nb_trace ; i++) {
3662 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
3663
3664 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
3665 NULL, NULL, block_start, &hook_start);
3666
3667 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
3668 NULL, NULL, block_end, &hook_end);
3669
3670 nb_tracefile = ts->parent.tracefiles->len;
3671
3672 for(j = 0 ; j < nb_tracefile ; j++) {
3673 tfs =
3674 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3675 LttvTracefileContext, j));
3676 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3677 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
3678 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3679 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
3680 }
3681 }
3682 }
3683 #endif //0
3684
3685 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3686 {
3687 LttvTraceset *traceset = self->parent.ts;
3688
3689 guint i, j, nb_trace, nb_tracefile;
3690
3691 LttvTraceState *ts;
3692
3693 LttvTracefileState *tfs;
3694
3695 LttvHooks *after_trace = lttv_hooks_new();
3696
3697 lttv_hooks_add(after_trace,
3698 state_save_after_trace_hook,
3699 NULL,
3700 LTTV_PRIO_STATE);
3701
3702
3703 lttv_process_traceset_end(&self->parent,
3704 NULL, after_trace, NULL, NULL, NULL);
3705
3706 lttv_hooks_destroy(after_trace);
3707
3708 nb_trace = lttv_traceset_number(traceset);
3709 for(i = 0 ; i < nb_trace ; i++) {
3710
3711 ts = (LttvTraceState *)self->parent.traces[i];
3712 nb_tracefile = ts->parent.tracefiles->len;
3713
3714 if(ts->has_precomputed_states) continue;
3715
3716 guint *event_count = NULL;
3717
3718 for(j = 0 ; j < nb_tracefile ; j++) {
3719 tfs =
3720 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3721 LttvTracefileContext*, j));
3722 event_count = lttv_hooks_remove(tfs->parent.event,
3723 state_save_event_hook);
3724 }
3725 if(event_count) g_free(event_count);
3726 }
3727 }
3728
3729 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
3730 {
3731 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3732
3733 lttv_state_save_remove_event_hooks(tss);
3734
3735 return 0;
3736 }
3737
3738 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
3739 {
3740 LttvTraceset *traceset = self->parent.ts;
3741
3742 guint i, nb_trace;
3743
3744 int min_pos, mid_pos, max_pos;
3745
3746 guint call_rest = 0;
3747
3748 LttvTraceState *tcs;
3749
3750 LttvAttributeValue value;
3751
3752 LttvAttributeType type;
3753
3754 LttvAttributeName name;
3755
3756 gboolean is_named;
3757
3758 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
3759
3760 //g_tree_destroy(self->parent.pqueue);
3761 //self->parent.pqueue = g_tree_new(compare_tracefile);
3762
3763 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
3764
3765 nb_trace = lttv_traceset_number(traceset);
3766 for(i = 0 ; i < nb_trace ; i++) {
3767 tcs = (LttvTraceState *)self->parent.traces[i];
3768
3769 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
3770 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3771 LTTV_STATE_SAVED_STATES);
3772 min_pos = -1;
3773
3774 if(saved_states_tree) {
3775 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
3776 mid_pos = max_pos / 2;
3777 while(min_pos < max_pos) {
3778 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
3779 &is_named);
3780 g_assert(type == LTTV_GOBJECT);
3781 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
3782 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
3783 &value);
3784 g_assert(type == LTTV_TIME);
3785 if(ltt_time_compare(*(value.v_time), t) < 0) {
3786 min_pos = mid_pos;
3787 closest_tree = saved_state_tree;
3788 }
3789 else max_pos = mid_pos - 1;
3790
3791 mid_pos = (min_pos + max_pos + 1) / 2;
3792 }
3793 }
3794
3795 /* restore the closest earlier saved state */
3796 if(min_pos != -1) {
3797 lttv_state_restore(tcs, closest_tree);
3798 call_rest = 1;
3799 }
3800
3801 /* There is no saved state, yet we want to have it. Restart at T0 */
3802 else {
3803 restore_init_state(tcs);
3804 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
3805 }
3806 }
3807 /* We want to seek quickly without restoring/updating the state */
3808 else {
3809 restore_init_state(tcs);
3810 lttv_process_trace_seek_time(&(tcs->parent), t);
3811 }
3812 }
3813 if(!call_rest) g_info("NOT Calling restore");
3814 }
3815
3816
3817 static void
3818 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
3819 {
3820 }
3821
3822
3823 static void
3824 traceset_state_finalize (LttvTracesetState *self)
3825 {
3826 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
3827 finalize(G_OBJECT(self));
3828 }
3829
3830
3831 static void
3832 traceset_state_class_init (LttvTracesetContextClass *klass)
3833 {
3834 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3835
3836 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
3837 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
3838 klass->fini = (void (*)(LttvTracesetContext *self))fini;
3839 klass->new_traceset_context = new_traceset_context;
3840 klass->new_trace_context = new_trace_context;
3841 klass->new_tracefile_context = new_tracefile_context;
3842 }
3843
3844
3845 GType
3846 lttv_traceset_state_get_type(void)
3847 {
3848 static GType type = 0;
3849 if (type == 0) {
3850 static const GTypeInfo info = {
3851 sizeof (LttvTracesetStateClass),
3852 NULL, /* base_init */
3853 NULL, /* base_finalize */
3854 (GClassInitFunc) traceset_state_class_init, /* class_init */
3855 NULL, /* class_finalize */
3856 NULL, /* class_data */
3857 sizeof (LttvTracesetState),
3858 0, /* n_preallocs */
3859 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
3860 NULL /* value handling */
3861 };
3862
3863 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
3864 &info, 0);
3865 }
3866 return type;
3867 }
3868
3869
3870 static void
3871 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
3872 {
3873 }
3874
3875
3876 static void
3877 trace_state_finalize (LttvTraceState *self)
3878 {
3879 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
3880 finalize(G_OBJECT(self));
3881 }
3882
3883
3884 static void
3885 trace_state_class_init (LttvTraceStateClass *klass)
3886 {
3887 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3888
3889 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
3890 klass->state_save = state_save;
3891 klass->state_restore = state_restore;
3892 klass->state_saved_free = state_saved_free;
3893 }
3894
3895
3896 GType
3897 lttv_trace_state_get_type(void)
3898 {
3899 static GType type = 0;
3900 if (type == 0) {
3901 static const GTypeInfo info = {
3902 sizeof (LttvTraceStateClass),
3903 NULL, /* base_init */
3904 NULL, /* base_finalize */
3905 (GClassInitFunc) trace_state_class_init, /* class_init */
3906 NULL, /* class_finalize */
3907 NULL, /* class_data */
3908 sizeof (LttvTraceState),
3909 0, /* n_preallocs */
3910 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
3911 NULL /* value handling */
3912 };
3913
3914 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
3915 "LttvTraceStateType", &info, 0);
3916 }
3917 return type;
3918 }
3919
3920
3921 static void
3922 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
3923 {
3924 }
3925
3926
3927 static void
3928 tracefile_state_finalize (LttvTracefileState *self)
3929 {
3930 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
3931 finalize(G_OBJECT(self));
3932 }
3933
3934
3935 static void
3936 tracefile_state_class_init (LttvTracefileStateClass *klass)
3937 {
3938 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3939
3940 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
3941 }
3942
3943
3944 GType
3945 lttv_tracefile_state_get_type(void)
3946 {
3947 static GType type = 0;
3948 if (type == 0) {
3949 static const GTypeInfo info = {
3950 sizeof (LttvTracefileStateClass),
3951 NULL, /* base_init */
3952 NULL, /* base_finalize */
3953 (GClassInitFunc) tracefile_state_class_init, /* class_init */
3954 NULL, /* class_finalize */
3955 NULL, /* class_data */
3956 sizeof (LttvTracefileState),
3957 0, /* n_preallocs */
3958 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
3959 NULL /* value handling */
3960 };
3961
3962 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
3963 "LttvTracefileStateType", &info, 0);
3964 }
3965 return type;
3966 }
3967
3968
3969 static void module_init()
3970 {
3971 LTTV_STATE_UNNAMED = g_quark_from_string("");
3972 LTTV_STATE_UNBRANDED = g_quark_from_string("");
3973 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
3974 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
3975 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
3976 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
3977 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
3978 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
3979 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
3980 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
3981 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
3982 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
3983 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
3984 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
3985 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
3986 LTTV_STATE_RUN = g_quark_from_string("RUN");
3987 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
3988 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
3989 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
3990 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
3991 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
3992 LTTV_STATE_PROCESS = g_quark_from_string("process");
3993 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
3994 LTTV_STATE_EVENT = g_quark_from_string("event");
3995 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
3996 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
3997 LTTV_STATE_TIME = g_quark_from_string("time");
3998 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
3999 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
4000 LTTV_STATE_TRACE_STATE_USE_COUNT =
4001 g_quark_from_string("trace_state_use_count");
4002 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu resource states");
4003 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu count");
4004 LTTV_STATE_RESOURCE_IRQS = g_quark_from_string("irq resource states");
4005 LTTV_STATE_RESOURCE_SOFT_IRQS = g_quark_from_string("soft irq resource states");
4006 LTTV_STATE_RESOURCE_TRAPS = g_quark_from_string("trap resource states");
4007 LTTV_STATE_RESOURCE_BLKDEVS = g_quark_from_string("blkdevs resource states");
4008
4009
4010 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
4011 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
4012 LTT_FACILITY_FS = g_quark_from_string("fs");
4013 LTT_FACILITY_LIST = g_quark_from_string("list");
4014 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
4015 LTT_FACILITY_BLOCK = g_quark_from_string("block");
4016
4017
4018 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
4019 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
4020 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
4021 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
4022 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
4023 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
4024 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("softirq_entry");
4025 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("softirq_exit");
4026 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
4027 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
4028 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
4029 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
4030 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
4031 LTT_EVENT_EXEC = g_quark_from_string("exec");
4032 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
4033 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
4034 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
4035 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
4036 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
4037 LTT_EVENT_REQUEST_ISSUE = g_quark_from_string("_blk_request_issue");
4038 LTT_EVENT_REQUEST_COMPLETE = g_quark_from_string("_blk_request_complete");
4039 LTT_EVENT_LIST_INTERRUPT = g_quark_from_string("interrupt");;
4040
4041
4042 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
4043 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
4044 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
4045 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
4046 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
4047 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
4048 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
4049 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
4050 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
4051 LTT_FIELD_PID = g_quark_from_string("pid");
4052 LTT_FIELD_TGID = g_quark_from_string("tgid");
4053 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
4054 LTT_FIELD_FILENAME = g_quark_from_string("filename");
4055 LTT_FIELD_NAME = g_quark_from_string("name");
4056 LTT_FIELD_TYPE = g_quark_from_string("type");
4057 LTT_FIELD_MODE = g_quark_from_string("mode");
4058 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
4059 LTT_FIELD_STATUS = g_quark_from_string("status");
4060 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
4061 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
4062 LTT_FIELD_MAJOR = g_quark_from_string("major");
4063 LTT_FIELD_MINOR = g_quark_from_string("minor");
4064 LTT_FIELD_OPERATION = g_quark_from_string("direction");
4065 LTT_FIELD_ACTION = g_quark_from_string("action");
4066
4067 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
4068 LTTV_CPU_IDLE = g_quark_from_string("idle");
4069 LTTV_CPU_BUSY = g_quark_from_string("busy");
4070 LTTV_CPU_IRQ = g_quark_from_string("irq");
4071 LTTV_CPU_SOFT_IRQ = g_quark_from_string("softirq");
4072 LTTV_CPU_TRAP = g_quark_from_string("trap");
4073
4074 LTTV_IRQ_UNKNOWN = g_quark_from_string("unknown");
4075 LTTV_IRQ_IDLE = g_quark_from_string("idle");
4076 LTTV_IRQ_BUSY = g_quark_from_string("busy");
4077
4078 LTTV_BDEV_UNKNOWN = g_quark_from_string("unknown");
4079 LTTV_BDEV_IDLE = g_quark_from_string("idle");
4080 LTTV_BDEV_BUSY_READING = g_quark_from_string("busy_reading");
4081 LTTV_BDEV_BUSY_WRITING = g_quark_from_string("busy_writing");
4082 }
4083
4084 static void module_destroy()
4085 {
4086 }
4087
4088
4089 LTTV_MODULE("state", "State computation", \
4090 "Update the system state, possibly saving it at intervals", \
4091 module_init, module_destroy)
4092
4093
4094
This page took 0.116094 seconds and 4 git commands to generate.