Fix warnings and timespan_end
[lttv.git] / lttv / modules / gui / controlflow / eventhooks.c
CommitLineData
ce0214a6 1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Mathieu Desnoyers
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
f0d936c0 20/*****************************************************************************
21 * Hooks to be called by the main window *
22 *****************************************************************************/
23
f0d936c0 24
b9a010a2 25/* Event hooks are the drawing hooks called during traceset read. They draw the
26 * icons, text, lines and background color corresponding to the events read.
27 *
e92eabaf 28 * Two hooks are used for drawing : before_schedchange and after_schedchange hooks. The
29 * before_schedchange is called before the state update that occurs with an event and
30 * the after_schedchange hook is called after this state update.
b9a010a2 31 *
e92eabaf 32 * The before_schedchange hooks fulfill the task of drawing the visible objects that
33 * corresponds to the data accumulated by the after_schedchange hook.
b9a010a2 34 *
e92eabaf 35 * The after_schedchange hook accumulates the data that need to be shown on the screen
36 * (items) into a queue. Then, the next before_schedchange hook will draw what that
b9a010a2 37 * queue contains. That's the Right Way (TM) of drawing items on the screen,
38 * because we need to draw the background first (and then add icons, text, ...
39 * over it), but we only know the length of a background region once the state
e92eabaf 40 * corresponding to it is over, which happens to be at the next before_schedchange
b9a010a2 41 * hook.
42 *
43 * We also have a hook called at the end of a chunk to draw the information left
44 * undrawn in each process queue. We use the current time as end of
45 * line/background.
46 */
47
4e4d11b3 48#ifdef HAVE_CONFIG_H
49#include <config.h>
50#endif
b9a010a2 51
cf6cb7e0 52//#define PANGO_ENABLE_BACKEND
558aa013 53#include <gtk/gtk.h>
54#include <gdk/gdk.h>
5f16133f 55#include <glib.h>
80a52ff8 56#include <assert.h>
50439712 57#include <string.h>
319e9d81 58#include <stdio.h>
5f16133f 59
cf6cb7e0 60//#include <pango/pango.h>
61
80a52ff8 62#include <ltt/event.h>
4ba42155 63#include <ltt/time.h>
2c82c4dc 64#include <ltt/trace.h>
80a52ff8 65
2a2fa4f0 66#include <lttv/lttv.h>
558aa013 67#include <lttv/hook.h>
80a52ff8 68#include <lttv/state.h>
2d262115 69#include <lttvwindow/lttvwindow.h>
6395d57c 70#include <lttvwindow/lttvwindowtraces.h>
0de51231 71#include <lttvwindow/support.h>
80a52ff8 72
f0d936c0 73
a117e3f7 74#include "eventhooks.h"
75#include "cfv.h"
76#include "processlist.h"
77#include "drawing.h"
5f16133f 78
80a52ff8 79
1a31868c 80#define MAX_PATH_LEN 256
3d27be8a 81#define STATE_LINE_WIDTH 6
5bb606ce 82#define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
1a31868c 83
0de51231 84extern GSList *g_legend_list;
85
b9a010a2 86
6395d57c 87/* Action to do when background computation completed.
88 *
e800cf84 89 * Wait for all the awaited computations to be over.
6395d57c 90 */
91
703b25fa 92static gint background_ready(void *hook_data, void *call_data)
6395d57c 93{
94 ControlFlowData *control_flow_data = (ControlFlowData *)hook_data;
6395d57c 95
e800cf84 96 control_flow_data->background_info_waiting--;
97
98 if(control_flow_data->background_info_waiting == 0) {
4a24fa1f 99 g_message("control flow viewer : background computation data ready.");
6395d57c 100
e800cf84 101 drawing_clear(control_flow_data->drawing);
102 processlist_clear(control_flow_data->process_list);
07390ec1 103 gtk_widget_set_size_request(
104 control_flow_data->drawing->drawing_area,
105 -1, processlist_get_height(control_flow_data->process_list));
e800cf84 106 redraw_notify(control_flow_data, NULL);
b9a010a2 107 }
6395d57c 108
109 return 0;
110}
111
112
113/* Request background computation. Verify if it is in progress or ready first.
e800cf84 114 * Only for each trace in the tab's traceset.
6395d57c 115 */
88bf15f0 116
3f7f592e 117static void request_background_data(ControlFlowData *control_flow_data)
6395d57c 118{
88bf15f0
FD
119
120 LttvTraceset *ts = lttvwindow_get_traceset(control_flow_data->tab);
121 gint num_traces = lttv_traceset_number(ts);
6395d57c 122 gint i;
123 LttvTrace *trace;
7df20ca4 124 LttvTraceState *tstate;
6395d57c 125
88bf15f0 126 LttvHooks *background_ready_hook = lttv_hooks_new();
6395d57c 127 lttv_hooks_add(background_ready_hook, background_ready, control_flow_data,
128 LTTV_PRIO_DEFAULT);
e800cf84 129 control_flow_data->background_info_waiting = 0;
6395d57c 130
131 for(i=0;i<num_traces;i++) {
88bf15f0
FD
132 trace = lttv_traceset_get(ts, i);
133 tstate = trace->state;
6395d57c 134
7df20ca4 135 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace)==FALSE
88bf15f0 136 && !ts->has_precomputed_states) {
6395d57c 137
138 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
139 trace) == FALSE) {
140 /* We first remove requests that could have been done for the same
141 * information. Happens when two viewers ask for it before servicing
142 * starts.
143 */
93ac601b 144 if(!lttvwindowtraces_background_request_find(trace, "state"))
b5e17af5 145 lttvwindowtraces_background_request_queue(
146 main_window_get_widget(control_flow_data->tab), trace, "state");
6395d57c 147 lttvwindowtraces_background_notify_queue(control_flow_data,
148 trace,
149 ltt_time_infinite,
150 NULL,
151 background_ready_hook);
e800cf84 152 control_flow_data->background_info_waiting++;
6395d57c 153 } else { /* in progress */
154
155 lttvwindowtraces_background_notify_current(control_flow_data,
156 trace,
157 ltt_time_infinite,
158 NULL,
159 background_ready_hook);
e800cf84 160 control_flow_data->background_info_waiting++;
6395d57c 161 }
4368b993 162 } else {
7df20ca4 163 /* Data ready. By its nature, this viewer doesn't need to have
618fbcc1 164 * its data ready hook called there, because a background
4368b993 165 * request is always linked with a redraw.
166 */
6395d57c 167 }
4368b993 168
6395d57c 169 }
170
171 lttv_hooks_destroy(background_ready_hook);
172}
173
174
175
176
f0d936c0 177/**
178 * Event Viewer's constructor hook
179 *
180 * This constructor is given as a parameter to the menuitem and toolbar button
181 * registration. It creates the list.
ca0f8a8e 182 * @param tab A pointer to the parent tab.
f0d936c0 183 * @return The widget created.
184 */
185GtkWidget *
e433e6d6 186h_guicontrolflow(LttvPlugin *plugin)
f0d936c0 187{
e433e6d6 188 LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin);
189 Tab *tab = ptab->tab;
d47b33d2 190 g_info("h_guicontrolflow, %p", tab);
e433e6d6 191 ControlFlowData *control_flow_data = guicontrolflow(ptab);
a56a1ba4 192
ca0f8a8e 193 control_flow_data->tab = tab;
a56a1ba4 194
a56a1ba4 195 // Unreg done in the GuiControlFlow_Destructor
6395d57c 196 lttvwindow_register_traceset_notify(tab,
197 traceset_notify,
198 control_flow_data);
199
ca0f8a8e 200 lttvwindow_register_time_window_notify(tab,
224446ce 201 update_time_window_hook,
202 control_flow_data);
ca0f8a8e 203 lttvwindow_register_current_time_notify(tab,
224446ce 204 update_current_time_hook,
205 control_flow_data);
ca0f8a8e 206 lttvwindow_register_redraw_notify(tab,
207 redraw_notify,
208 control_flow_data);
209 lttvwindow_register_continue_notify(tab,
210 continue_notify,
211 control_flow_data);
667ca2a0 212 request_background_data(control_flow_data);
6395d57c 213
ca0f8a8e 214
68997a22 215 return guicontrolflow_get_widget(control_flow_data) ;
a56a1ba4 216
f0d936c0 217}
218
3cff8cc1 219int event_selected_hook(void *hook_data, void *call_data)
f0d936c0 220{
14963be0 221 guint *event_number = (guint*) call_data;
f0d936c0 222
2a2fa4f0 223 g_debug("DEBUG : event selected by main window : %u", *event_number);
a56a1ba4 224
2eef04b5 225 return 0;
f0d936c0 226}
227
9a1ec01b 228/* Function that selects the color of status&exemode line */
6550d711 229static inline PropertiesLine prepare_s_e_line(LttvProcessState *process)
9a1ec01b 230{
231 PropertiesLine prop_line;
5bb606ce 232 prop_line.line_width = STATE_LINE_WIDTH;
9a1ec01b 233 prop_line.style = GDK_LINE_SOLID;
234 prop_line.y = MIDDLE;
235 //GdkColormap *colormap = gdk_colormap_get_system();
236
9a1ec01b 237 if(process->state->s == LTTV_STATE_RUN) {
238 if(process->state->t == LTTV_STATE_USER_MODE)
239 prop_line.color = drawing_colors[COL_RUN_USER_MODE];
240 else if(process->state->t == LTTV_STATE_SYSCALL)
241 prop_line.color = drawing_colors[COL_RUN_SYSCALL];
242 else if(process->state->t == LTTV_STATE_TRAP)
243 prop_line.color = drawing_colors[COL_RUN_TRAP];
244 else if(process->state->t == LTTV_STATE_IRQ)
245 prop_line.color = drawing_colors[COL_RUN_IRQ];
faf074a3 246 else if(process->state->t == LTTV_STATE_SOFT_IRQ)
247 prop_line.color = drawing_colors[COL_RUN_SOFT_IRQ];
f044974e
MD
248 else if(process->state->t == LTTV_STATE_MAYBE_SYSCALL)
249 prop_line.color = drawing_colors[COL_MODE_UNKNOWN];
250 else if(process->state->t == LTTV_STATE_MAYBE_USER_MODE)
251 prop_line.color = drawing_colors[COL_MODE_UNKNOWN];
252 else if(process->state->t == LTTV_STATE_MAYBE_TRAP)
253 prop_line.color = drawing_colors[COL_MODE_UNKNOWN];
9a1ec01b 254 else if(process->state->t == LTTV_STATE_MODE_UNKNOWN)
255 prop_line.color = drawing_colors[COL_MODE_UNKNOWN];
256 else
257 g_assert(FALSE); /* RUNNING MODE UNKNOWN */
258 } else if(process->state->s == LTTV_STATE_WAIT) {
259 /* We don't show if we wait while in user mode, trap, irq or syscall */
260 prop_line.color = drawing_colors[COL_WAIT];
261 } else if(process->state->s == LTTV_STATE_WAIT_CPU) {
262 /* We don't show if we wait for CPU while in user mode, trap, irq
263 * or syscall */
264 prop_line.color = drawing_colors[COL_WAIT_CPU];
265 } else if(process->state->s == LTTV_STATE_ZOMBIE) {
266 prop_line.color = drawing_colors[COL_ZOMBIE];
267 } else if(process->state->s == LTTV_STATE_WAIT_FORK) {
268 prop_line.color = drawing_colors[COL_WAIT_FORK];
269 } else if(process->state->s == LTTV_STATE_EXIT) {
270 prop_line.color = drawing_colors[COL_EXIT];
271 } else if(process->state->s == LTTV_STATE_UNNAMED) {
272 prop_line.color = drawing_colors[COL_UNNAMED];
c7620c79 273 } else if(process->state->s == LTTV_STATE_DEAD) {
274 prop_line.color = drawing_colors[COL_DEAD];
b3fd4c02 275 } else {
276 g_critical("unknown state : %s", g_quark_to_string(process->state->s));
9a1ec01b 277 g_assert(FALSE); /* UNKNOWN STATE */
b3fd4c02 278 }
9a1ec01b 279
280 return prop_line;
281
282}
283
068572ab
CS
284/* Before try-wake-up hook. A process is being woken; we need to draw its line up to this point in time
285 in that colour. This is basically like exec-state, but the change applies to a process other than that
286 which is currently running. */
287
288int before_trywakeup_hook(void *hook_data, void *call_data)
289{
88bf15f0 290#ifdef BABEL_CLEANUP
068572ab
CS
291 LttvTraceHook *th = (LttvTraceHook*)hook_data;
292 EventsRequest *events_request = (EventsRequest*)th->hook_data;
88bf15f0 293
068572ab
CS
294 ControlFlowData *control_flow_data = events_request->viewer_data;
295
296 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
297
068572ab
CS
298 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
299
300 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
301 gint target_pid_saved = tfc->target_pid;
302
303 LttTime evtime = ltt_event_time(e);
304 LttvFilter *filter = control_flow_data->filter;
305
306 guint woken_pid;
307 gint woken_cpu;
308
309 woken_pid = ltt_event_get_int(e, lttv_trace_get_hook_field(th, 0));
310 woken_cpu = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
311
312 tfc->target_pid = woken_pid;
313 if(!filter || !filter->head ||
314 lttv_filter_tree_parse(filter->head,e,tfc->tf,
315 tfc->t_context->t,tfc,NULL,NULL)) {
316
317 /* First, check if the woken process is in the state computation
318 * process list. If it is there, that means we must add it right now and
319 * draw items from the beginning of the read for it. If it is not
320 * present, it's a new process and it was not present : it will
321 * be added after the state update. TOCHECK: What does that last para mean? */
068572ab
CS
322 guint trace_num = ts->parent.index;
323 LttvProcessState *process = lttv_state_find_process(ts, woken_cpu, woken_pid);
324
325 if(process != NULL) {
326 /* Well, the woken process existed : we must get it in the process hash
327 * or add it, and draw its items.
328 */
329 /* Add process to process list (if not present) */
330 guint pl_height = 0;
331 HashedProcessData *hashed_process_data = NULL;
332 ProcessList *process_list = control_flow_data->process_list;
333 LttTime birth = process->creation_time;
334
335 hashed_process_data = processlist_get_process_data(process_list,
336 woken_pid,
337 process->cpu,
338 &birth,
339 trace_num);
340 if(hashed_process_data == NULL)
341 {
342 g_assert(woken_pid != process->ppid);
343 /* Process not present */
344 ProcessInfo *process_info;
345 Drawing_t *drawing = control_flow_data->drawing;
346 processlist_add(process_list,
347 drawing,
348 woken_pid,
349 process->tgid,
350 process->cpu,
351 process->ppid,
352 &birth,
353 trace_num,
354 process->name,
355 process->brand,
356 &pl_height,
357 &process_info,
358 &hashed_process_data);
359 gtk_widget_set_size_request(drawing->drawing_area,
360 -1,
361 pl_height);
362 gtk_widget_queue_draw(drawing->drawing_area);
363
364 }
365
366 /* Now, the process is in the state hash and our own process hash.
367 * We definitely can draw the items related to the ending state.
368 */
369
370 if(ltt_time_compare(hashed_process_data->next_good_time,
371 evtime) > 0)
372 {
373 if(hashed_process_data->x.middle_marked == FALSE) {
374
375 TimeWindow time_window =
376 lttvwindow_get_time_window(control_flow_data->tab);
377#ifdef EXTRA_CHECK
378 if(ltt_time_compare(evtime, time_window.start_time) == -1
379 || ltt_time_compare(evtime, time_window.end_time) == 1)
380 return FALSE;
381#endif //EXTRA_CHECK
382 Drawing_t *drawing = control_flow_data->drawing;
383 guint width = drawing->width;
384 guint x;
385 convert_time_to_pixels(
386 time_window,
387 evtime,
388 width,
389 &x);
390
391 /* Draw collision indicator */
392 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
393 gdk_draw_point(hashed_process_data->pixmap,
394 drawing->gc,
395 x,
396 COLLISION_POSITION(hashed_process_data->height));
397 hashed_process_data->x.middle_marked = TRUE;
398 }
399 } else {
400 TimeWindow time_window =
401 lttvwindow_get_time_window(control_flow_data->tab);
402#ifdef EXTRA_CHECK
403 if(ltt_time_compare(evtime, time_window.start_time) == -1
404 || ltt_time_compare(evtime, time_window.end_time) == 1)
405 return FALSE;
406#endif //EXTRA_CHECK
407 Drawing_t *drawing = control_flow_data->drawing;
408 guint width = drawing->width;
409 guint x;
410 convert_time_to_pixels(
411 time_window,
412 evtime,
413 width,
414 &x);
415
416
417 /* Jump over draw if we are at the same x position */
418 if(x == hashed_process_data->x.middle &&
419 hashed_process_data->x.middle_used)
420 {
421 if(hashed_process_data->x.middle_marked == FALSE) {
422 /* Draw collision indicator */
423 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
424 gdk_draw_point(hashed_process_data->pixmap,
425 drawing->gc,
426 x,
427 COLLISION_POSITION(hashed_process_data->height));
428 hashed_process_data->x.middle_marked = TRUE;
429 }
430 /* jump */
431 } else {
432 DrawContext draw_context;
433
434 /* Now create the drawing context that will be used to draw
435 * items related to the last state. */
436 draw_context.drawable = hashed_process_data->pixmap;
437 draw_context.gc = drawing->gc;
438 draw_context.pango_layout = drawing->pango_layout;
439 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
440 draw_context.drawinfo.end.x = x;
441
442 draw_context.drawinfo.y.over = 1;
443 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
444 draw_context.drawinfo.y.under = hashed_process_data->height;
445
446 draw_context.drawinfo.start.offset.over = 0;
447 draw_context.drawinfo.start.offset.middle = 0;
448 draw_context.drawinfo.start.offset.under = 0;
449 draw_context.drawinfo.end.offset.over = 0;
450 draw_context.drawinfo.end.offset.middle = 0;
451 draw_context.drawinfo.end.offset.under = 0;
452
453 {
454 /* Draw the line */
455 PropertiesLine prop_line = prepare_s_e_line(process);
456 draw_line((void*)&prop_line, (void*)&draw_context);
457
458 }
459 /* become the last x position */
460 hashed_process_data->x.middle = x;
461 hashed_process_data->x.middle_used = TRUE;
462 hashed_process_data->x.middle_marked = FALSE;
463
464 /* Calculate the next good time */
465 convert_pixels_to_time(width, x+1, time_window,
466 &hashed_process_data->next_good_time);
467 }
468 }
469 }
470 }
471
472 tfc->target_pid = target_pid_saved;
473
88bf15f0 474#endif //babel_cleanup
10599fb9 475 return 0;
068572ab
CS
476
477}
c8bba5fa 478
e92eabaf 479/* before_schedchange_hook
b9a010a2 480 *
f0d936c0 481 * This function basically draw lines and icons. Two types of lines are drawn :
482 * one small (3 pixels?) representing the state of the process and the second
483 * type is thicker (10 pixels?) representing on which CPU a process is running
484 * (and this only in running state).
485 *
486 * Extremums of the lines :
487 * x_min : time of the last event context for this process kept in memory.
488 * x_max : time of the current event.
489 * y : middle of the process in the process list. The process is found in the
490 * list, therefore is it's position in pixels.
491 *
492 * The choice of lines'color is defined by the context of the last event for this
493 * process.
494 */
b9a010a2 495
496
e92eabaf 497int before_schedchange_hook(void *hook_data, void *call_data)
f0d936c0 498{
88bf15f0
FD
499 LttvEvent *event;
500 guint cpu;
501 LttvTraceState *ts;
502 LttvProcessState *process;
503
504 //LttvProcessState *old_process = ts->running_process[cpu];
505
506 guint pid_in, pid_out;
507 gint64 state_out;
508 LttTime timestamp;
509 event = (LttvEvent *) call_data;
8924e3e4
FD
510 if (strcmp(lttv_traceset_get_name_from_event(event),"sched_switch") != 0)
511 return FALSE;
512
88bf15f0 513 ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
b9a010a2 514
fd22065b 515
10a1069a 516 /* we are in a schedchange, before the state update. We must draw the
517 * items corresponding to the state before it changes : now is the right
518 * time to do it.
519 */
88bf15f0
FD
520 cpu = lttv_traceset_get_cpuid_from_event(event);
521 ts = event->state;
8924e3e4 522
88bf15f0
FD
523 pid_out = lttv_event_get_long(event, "prev_tid");
524 pid_in = lttv_event_get_long(event, "next_tid");
525 state_out = lttv_event_get_long(event, "prev_state");
8924e3e4 526 guint trace_number = 0;//TODO fdeslauriers 2012-07-17: // Use trace handle to know trace number
88bf15f0 527
8924e3e4 528 process = lttv_state_find_process(ts,cpu,pid_out);
88bf15f0 529 timestamp = lttv_event_get_timestamp(event);
10a1069a 530 /* For the pid_out */
531 /* First, check if the current process is in the state computation
532 * process list. If it is there, that means we must add it right now and
533 * draw items from the beginning of the read for it. If it is not
534 * present, it's a new process and it was not present : it will
535 * be added after the state update. */
b9a010a2 536
88bf15f0
FD
537 /* unknown state, bad current pid */
538
10a1069a 539 if(process != NULL) {
540 /* Well, the process_out existed : we must get it in the process hash
541 * or add it, and draw its items.
542 */
543 /* Add process to process list (if not present) */
1c736ed5 544 guint pl_height = 0;
10a1069a 545 HashedProcessData *hashed_process_data = NULL;
5c230fc4 546 ProcessList *process_list = control_flow_data->process_list;
10a1069a 547 LttTime birth = process->creation_time;
b9a010a2 548
ac4e21cf 549 hashed_process_data = processlist_get_process_data(process_list,
10a1069a 550 pid_out,
348c6ba8 551 process->cpu,
10a1069a 552 &birth,
8924e3e4 553 trace_number);
ac4e21cf 554 if(hashed_process_data == NULL)
10a1069a 555 {
556 g_assert(pid_out == 0 || pid_out != process->ppid);
557 /* Process not present */
4e86ae2e 558 ProcessInfo *process_info;
1c736ed5 559 Drawing_t *drawing = control_flow_data->drawing;
10a1069a 560 processlist_add(process_list,
1c736ed5 561 drawing,
10a1069a 562 pid_out,
fcc08e1e 563 process->tgid,
348c6ba8 564 process->cpu,
10a1069a 565 process->ppid,
566 &birth,
8924e3e4 567 trace_number,
f4b88a7d 568 process->name,
7b5f6cf1 569 process->brand,
10a1069a 570 &pl_height,
4e86ae2e 571 &process_info,
10a1069a 572 &hashed_process_data);
1c736ed5 573 gtk_widget_set_size_request(drawing->drawing_area,
574 -1,
575 pl_height);
576 gtk_widget_queue_draw(drawing->drawing_area);
577
10a1069a 578 }
10a1069a 579 /* Now, the process is in the state hash and our own process hash.
580 * We definitely can draw the items related to the ending state.
581 */
e800cf84 582
b2743953 583 if(ltt_time_compare(hashed_process_data->next_good_time,
88bf15f0 584 timestamp) > 0)
10a1069a 585 {
b2743953 586 if(hashed_process_data->x.middle_marked == FALSE) {
ac4e21cf 587
fd22065b 588 TimeWindow time_window =
589 lttvwindow_get_time_window(control_flow_data->tab);
590#ifdef EXTRA_CHECK
591 if(ltt_time_compare(evtime, time_window.start_time) == -1
592 || ltt_time_compare(evtime, time_window.end_time) == 1)
3311444c 593 return FALSE;
fd22065b 594#endif //EXTRA_CHECK
d6fef890 595 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 596 guint width = drawing->width;
b2743953 597 guint x;
598 convert_time_to_pixels(
599 time_window,
88bf15f0 600 timestamp,
b2743953 601 width,
602 &x);
603
604 /* Draw collision indicator */
605 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 606 gdk_draw_point(hashed_process_data->pixmap,
b2743953 607 drawing->gc,
608 x,
5bb606ce 609 COLLISION_POSITION(hashed_process_data->height));
b2743953 610 hashed_process_data->x.middle_marked = TRUE;
611 }
612 } else {
ac4e21cf 613 TimeWindow time_window =
614 lttvwindow_get_time_window(control_flow_data->tab);
fd22065b 615#ifdef EXTRA_CHECK
ac4e21cf 616 if(ltt_time_compare(evtime, time_window.start_time) == -1
617 || ltt_time_compare(evtime, time_window.end_time) == 1)
3311444c 618 return FALSE;
fd22065b 619#endif //EXTRA_CHECK
d6fef890 620 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 621 guint width = drawing->width;
10a1069a 622 guint x;
10a1069a 623 convert_time_to_pixels(
a18124ff 624 time_window,
88bf15f0 625 timestamp,
4b7dc462 626 width,
627 &x);
10a1069a 628
10a1069a 629
4b7dc462 630 /* Jump over draw if we are at the same x position */
e72908ed 631 if(x == hashed_process_data->x.middle &&
632 hashed_process_data->x.middle_used)
e800cf84 633 {
e72908ed 634 if(hashed_process_data->x.middle_marked == FALSE) {
635 /* Draw collision indicator */
636 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 637 gdk_draw_point(hashed_process_data->pixmap,
e72908ed 638 drawing->gc,
639 x,
5bb606ce 640 COLLISION_POSITION(hashed_process_data->height));
de4ea1ad 641 hashed_process_data->x.middle_marked = TRUE;
e72908ed 642 }
4b7dc462 643 /* jump */
644 } else {
645 DrawContext draw_context;
10a1069a 646
4b7dc462 647 /* Now create the drawing context that will be used to draw
648 * items related to the last state. */
1c736ed5 649 draw_context.drawable = hashed_process_data->pixmap;
4b7dc462 650 draw_context.gc = drawing->gc;
651 draw_context.pango_layout = drawing->pango_layout;
652 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
653 draw_context.drawinfo.end.x = x;
654
1c736ed5 655 draw_context.drawinfo.y.over = 1;
656 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
657 draw_context.drawinfo.y.under = hashed_process_data->height;
4b7dc462 658
659 draw_context.drawinfo.start.offset.over = 0;
660 draw_context.drawinfo.start.offset.middle = 0;
661 draw_context.drawinfo.start.offset.under = 0;
662 draw_context.drawinfo.end.offset.over = 0;
663 draw_context.drawinfo.end.offset.middle = 0;
664 draw_context.drawinfo.end.offset.under = 0;
665
666 {
667 /* Draw the line */
9a1ec01b 668 PropertiesLine prop_line = prepare_s_e_line(process);
4b7dc462 669 draw_line((void*)&prop_line, (void*)&draw_context);
670
671 }
672 /* become the last x position */
673 hashed_process_data->x.middle = x;
e72908ed 674 hashed_process_data->x.middle_used = TRUE;
675 hashed_process_data->x.middle_marked = FALSE;
b2743953 676
677 /* Calculate the next good time */
678 convert_pixels_to_time(width, x+1, time_window,
679 &hashed_process_data->next_good_time);
e800cf84 680 }
681 }
682 }
683
10a1069a 684 /* For the pid_in */
685 /* First, check if the current process is in the state computation
686 * process list. If it is there, that means we must add it right now and
687 * draw items from the beginning of the read for it. If it is not
688 * present, it's a new process and it was not present : it will
689 * be added after the state update. */
8924e3e4 690 process = lttv_state_find_process(ts,cpu,pid_in);
10a1069a 691
692 if(process != NULL) {
800aa029 693 /* Well, the process existed : we must get it in the process hash
10a1069a 694 * or add it, and draw its items.
695 */
696 /* Add process to process list (if not present) */
1c736ed5 697 guint pl_height = 0;
10a1069a 698 HashedProcessData *hashed_process_data = NULL;
5c230fc4 699 ProcessList *process_list = control_flow_data->process_list;
10a1069a 700 LttTime birth = process->creation_time;
e800cf84 701
ac4e21cf 702 hashed_process_data = processlist_get_process_data(process_list,
10a1069a 703 pid_in,
88bf15f0 704 cpu,
10a1069a 705 &birth,
8924e3e4 706 trace_number);//TODO "use the right value or delete"
ac4e21cf 707 if(hashed_process_data == NULL)
10a1069a 708 {
709 g_assert(pid_in == 0 || pid_in != process->ppid);
710 /* Process not present */
4e86ae2e 711 ProcessInfo *process_info;
1c736ed5 712 Drawing_t *drawing = control_flow_data->drawing;
10a1069a 713 processlist_add(process_list,
1c736ed5 714 drawing,
10a1069a 715 pid_in,
fcc08e1e 716 process->tgid,
88bf15f0 717 cpu,
10a1069a 718 process->ppid,
719 &birth,
8924e3e4 720 trace_number,
f4b88a7d 721 process->name,
7b5f6cf1 722 process->brand,
10a1069a 723 &pl_height,
4e86ae2e 724 &process_info,
10a1069a 725 &hashed_process_data);
1c736ed5 726 gtk_widget_set_size_request(drawing->drawing_area,
727 -1,
728 pl_height);
729 gtk_widget_queue_draw(drawing->drawing_area);
730
10a1069a 731 }
40debf7b 732 //We could set the current process and hash here, but will be done
733 //by after schedchange hook
10a1069a 734
735 /* Now, the process is in the state hash and our own process hash.
736 * We definitely can draw the items related to the ending state.
737 */
b9a010a2 738
b2743953 739 if(ltt_time_compare(hashed_process_data->next_good_time,
88bf15f0 740 timestamp) > 0)
10a1069a 741 {
b2743953 742 if(hashed_process_data->x.middle_marked == FALSE) {
ac4e21cf 743
fd22065b 744 TimeWindow time_window =
745 lttvwindow_get_time_window(control_flow_data->tab);
746#ifdef EXTRA_CHECK
747 if(ltt_time_compare(evtime, time_window.start_time) == -1
748 || ltt_time_compare(evtime, time_window.end_time) == 1)
3311444c 749 return FALSE;
fd22065b 750#endif //EXTRA_CHECK
d6fef890 751 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 752 guint width = drawing->width;
b2743953 753 guint x;
754 convert_time_to_pixels(
755 time_window,
88bf15f0 756 timestamp,
b2743953 757 width,
758 &x);
759
760 /* Draw collision indicator */
761 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 762 gdk_draw_point(hashed_process_data->pixmap,
b2743953 763 drawing->gc,
764 x,
5bb606ce 765 COLLISION_POSITION(hashed_process_data->height));
b2743953 766 hashed_process_data->x.middle_marked = TRUE;
767 }
768 } else {
fd22065b 769 TimeWindow time_window =
770 lttvwindow_get_time_window(control_flow_data->tab);
771#ifdef EXTRA_CHECK
772 if(ltt_time_compare(evtime, time_window.start_time) == -1
773 || ltt_time_compare(evtime, time_window.end_time) == 1)
3311444c 774 return FALSE;
fd22065b 775#endif //EXTRA_CHECK
d6fef890 776 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 777 guint width = drawing->width;
10a1069a 778 guint x;
10a1069a 779
780 convert_time_to_pixels(
a18124ff 781 time_window,
88bf15f0 782 timestamp,
4b7dc462 783 width,
784 &x);
10a1069a 785
10a1069a 786
4b7dc462 787 /* Jump over draw if we are at the same x position */
e72908ed 788 if(x == hashed_process_data->x.middle &&
789 hashed_process_data->x.middle_used)
4b7dc462 790 {
e72908ed 791 if(hashed_process_data->x.middle_marked == FALSE) {
792 /* Draw collision indicator */
793 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 794 gdk_draw_point(hashed_process_data->pixmap,
e72908ed 795 drawing->gc,
796 x,
5bb606ce 797 COLLISION_POSITION(hashed_process_data->height));
de4ea1ad 798 hashed_process_data->x.middle_marked = TRUE;
e72908ed 799 }
4b7dc462 800 /* jump */
801 } else {
802 DrawContext draw_context;
10a1069a 803
4b7dc462 804 /* Now create the drawing context that will be used to draw
805 * items related to the last state. */
1c736ed5 806 draw_context.drawable = hashed_process_data->pixmap;
4b7dc462 807 draw_context.gc = drawing->gc;
808 draw_context.pango_layout = drawing->pango_layout;
809 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
810 draw_context.drawinfo.end.x = x;
10a1069a 811
1c736ed5 812 draw_context.drawinfo.y.over = 1;
813 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
814 draw_context.drawinfo.y.under = hashed_process_data->height;
10a1069a 815
4b7dc462 816 draw_context.drawinfo.start.offset.over = 0;
817 draw_context.drawinfo.start.offset.middle = 0;
818 draw_context.drawinfo.start.offset.under = 0;
819 draw_context.drawinfo.end.offset.over = 0;
820 draw_context.drawinfo.end.offset.middle = 0;
821 draw_context.drawinfo.end.offset.under = 0;
822
823 {
824 /* Draw the line */
9a1ec01b 825 PropertiesLine prop_line = prepare_s_e_line(process);
4b7dc462 826 draw_line((void*)&prop_line, (void*)&draw_context);
827 }
828
829
830 /* become the last x position */
831 hashed_process_data->x.middle = x;
e72908ed 832 hashed_process_data->x.middle_used = TRUE;
833 hashed_process_data->x.middle_marked = FALSE;
b2743953 834
835 /* Calculate the next good time */
836 convert_pixels_to_time(width, x+1, time_window,
837 &hashed_process_data->next_good_time);
4b7dc462 838 }
c8bba5fa 839 }
8e680509 840 } else
841 g_warning("Cannot find pin_in in schedchange %u", pid_in);
88bf15f0 842#ifdef BABEL_CLEANUP
e38d9ea0 843 tfc->target_pid = target_pid_saved;
88bf15f0 844#endif //babel_cleanup
b9a010a2 845 return 0;
846
847
b9a010a2 848
a56a1ba4 849
51705146 850 /* Text dump */
80a52ff8 851#ifdef DONTSHOW
a56a1ba4 852 GString *string = g_string_new("");;
853 gboolean field_names = TRUE, state = TRUE;
80a52ff8 854
e9a9c513 855 lttv_event_to_string(e, tfc->tf, string, TRUE, field_names, tfs);
856 g_string_append_printf(string,"\n");
857
858 if(state) {
859 g_string_append_printf(string, " %s",
860 g_quark_to_string(tfs->process->state->s));
861 }
862
863 g_info("%s",string->str);
864
a56a1ba4 865 g_string_free(string, TRUE);
866
867 /* End of text dump */
80a52ff8 868#endif //DONTSHOW
50439712 869
f0d936c0 870}
871
e92eabaf 872/* after_schedchange_hook
b9a010a2 873 *
874 * The draw after hook is called by the reading API to have a
875 * particular event drawn on the screen.
876 * @param hook_data ControlFlowData structure of the viewer.
877 * @param call_data Event context.
878 *
879 * This function adds items to be drawn in a queue for each process.
880 *
881 */
e92eabaf 882int after_schedchange_hook(void *hook_data, void *call_data)
f0d936c0 883{
88bf15f0 884#ifdef BABEL_CLEANUP
dd455fb8 885 LttvTraceHook *th = (LttvTraceHook*)hook_data;
886 EventsRequest *events_request = (EventsRequest*)th->hook_data;
ca0f8a8e 887 ControlFlowData *control_flow_data = events_request->viewer_data;
50439712 888
a56a1ba4 889 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
50439712 890
891 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
892
348c6ba8 893 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
894
b9a010a2 895 LttEvent *e;
2c82c4dc 896 e = ltt_tracefile_get_event(tfc->tf);
b9a010a2 897
e38d9ea0 898 LttvFilter *filter = control_flow_data->filter;
b9a010a2 899 LttTime evtime = ltt_event_time(e);
b9a010a2 900
10a1069a 901 /* Add process to process list (if not present) */
2eef04b5 902 LttvProcessState *process_in;
10a1069a 903 LttTime birth;
1c736ed5 904 guint pl_height = 0;
10a1069a 905 HashedProcessData *hashed_process_data_in = NULL;
b9a010a2 906
5c230fc4 907 ProcessList *process_list = control_flow_data->process_list;
10a1069a 908
909 guint pid_in;
910 {
04348950 911 pid_in = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
10a1069a 912 }
b9a010a2 913
c7620c79 914 tfc->target_pid = pid_in;
915 if(!filter || !filter->head ||
916 lttv_filter_tree_parse(filter->head,e,tfc->tf,
917 tfc->t_context->t,tfc,NULL,NULL)) {
918 /* Find process pid_in in the list... */
919 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
920 //process_in = tfs->process;
921 guint cpu = tfs->cpu;
922 guint trace_num = ts->parent.index;
923 process_in = ts->running_process[cpu];
924 /* It should exist, because we are after the state update. */
96947fcf 925#ifdef EXTRA_CHECK
c7620c79 926 g_assert(process_in != NULL);
96947fcf 927#endif //EXTRA_CHECK
c7620c79 928 birth = process_in->creation_time;
929
930 hashed_process_data_in = processlist_get_process_data(process_list,
931 pid_in,
932 process_in->cpu,
933 &birth,
934 trace_num);
935 if(hashed_process_data_in == NULL)
936 {
937 g_assert(pid_in == 0 || pid_in != process_in->ppid);
938 ProcessInfo *process_info;
939 Drawing_t *drawing = control_flow_data->drawing;
940 /* Process not present */
941 processlist_add(process_list,
942 drawing,
10a1069a 943 pid_in,
c7620c79 944 process_in->tgid,
348c6ba8 945 process_in->cpu,
c7620c79 946 process_in->ppid,
10a1069a 947 &birth,
c7620c79 948 trace_num,
949 process_in->name,
950 process_in->brand,
951 &pl_height,
952 &process_info,
953 &hashed_process_data_in);
954 gtk_widget_set_size_request(drawing->drawing_area,
955 -1,
956 pl_height);
957 gtk_widget_queue_draw(drawing->drawing_area);
958 }
959 /* Set the current process */
960 process_list->current_hash_data[trace_num][process_in->cpu] =
961 hashed_process_data_in;
962
963 if(ltt_time_compare(hashed_process_data_in->next_good_time,
964 evtime) <= 0)
965 {
966 TimeWindow time_window =
967 lttvwindow_get_time_window(control_flow_data->tab);
968
fd22065b 969#ifdef EXTRA_CHECK
c7620c79 970 if(ltt_time_compare(evtime, time_window.start_time) == -1
971 || ltt_time_compare(evtime, time_window.end_time) == 1)
972 return FALSE;
fd22065b 973#endif //EXTRA_CHECK
c7620c79 974 Drawing_t *drawing = control_flow_data->drawing;
975 guint width = drawing->width;
976 guint new_x;
977
978 convert_time_to_pixels(
979 time_window,
980 evtime,
981 width,
982 &new_x);
983
984 if(hashed_process_data_in->x.middle != new_x) {
985 hashed_process_data_in->x.middle = new_x;
986 hashed_process_data_in->x.middle_used = FALSE;
987 hashed_process_data_in->x.middle_marked = FALSE;
988 }
b2743953 989 }
990 }
c7620c79 991
88bf15f0 992#endif //babel_cleanup
10599fb9 993 return 0;
4a24fa1f 994}
b9a010a2 995
996
997
e72908ed 998
4a24fa1f 999/* before_execmode_hook
1000 *
1001 * This function basically draw lines and icons. Two types of lines are drawn :
1002 * one small (3 pixels?) representing the state of the process and the second
1003 * type is thicker (10 pixels?) representing on which CPU a process is running
1004 * (and this only in running state).
1005 *
1006 * Extremums of the lines :
1007 * x_min : time of the last event context for this process kept in memory.
1008 * x_max : time of the current event.
1009 * y : middle of the process in the process list. The process is found in the
1010 * list, therefore is it's position in pixels.
1011 *
1012 * The choice of lines'color is defined by the context of the last event for this
1013 * process.
1014 */
1015
e72908ed 1016
4a24fa1f 1017int before_execmode_hook(void *hook_data, void *call_data)
1018{
88bf15f0
FD
1019 LttvEvent *event;
1020 guint cpu;
10599fb9 1021 guint pid = 0;
88bf15f0
FD
1022 LttvTraceState *ts;
1023 LttvProcessState *process;
1024
4a24fa1f 1025 /* we are in a execmode, before the state update. We must draw the
1026 * items corresponding to the state before it changes : now is the right
1027 * time to do it.
1028 */
88bf15f0
FD
1029
1030 event = (LttvEvent *) call_data;
8924e3e4
FD
1031 if ((strncmp(lttv_traceset_get_name_from_event(event),"sys_", sizeof("sys_") - 1) == 0)
1032 ||(strcmp(lttv_traceset_get_name_from_event(event),"exit_syscall") == 0)
1033 ||(strncmp(lttv_traceset_get_name_from_event(event),"irq_handler_",sizeof("irq_handler_")) == 0)
1034 ||(strncmp(lttv_traceset_get_name_from_event(event),"softirq_", sizeof("softirq_")) == 0)){
1035
88bf15f0
FD
1036 LttTime evtime = lttv_event_get_timestamp(event);
1037 ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
4a24fa1f 1038 /* For the pid */
88bf15f0
FD
1039 LttvTraceset *traceSet = lttvwindow_get_traceset(control_flow_data->tab);
1040
1041 cpu = lttv_traceset_get_cpuid_from_event(event);
1042 ts = event->state;
1043
1044 guint trace_number = 0;//TODO fdeslauriers 2012-07-17: // Use trace handle to know trace number
8924e3e4 1045 process = lttv_state_find_process(ts ,cpu ,pid);
4a24fa1f 1046 g_assert(process != NULL);
23093869 1047
10a1069a 1048 guint pid = process->pid;
23093869 1049
10a1069a 1050 /* Well, the process_out existed : we must get it in the process hash
1051 * or add it, and draw its items.
1052 */
1053 /* Add process to process list (if not present) */
1c736ed5 1054 guint pl_height = 0;
10a1069a 1055 HashedProcessData *hashed_process_data = NULL;
5c230fc4 1056 ProcessList *process_list = control_flow_data->process_list;
88bf15f0
FD
1057 if(process_list->current_hash_data == NULL){//TODO fdeslauriers 2012-07-17 : should not be necessary
1058 return 0;
1059 }
1060
10a1069a 1061 LttTime birth = process->creation_time;
40debf7b 1062
88bf15f0
FD
1063 if(likely(process_list->current_hash_data[trace_number][cpu] != NULL)) {
1064 hashed_process_data = process_list->current_hash_data[trace_number][cpu];
40debf7b 1065 } else {
ac4e21cf 1066 hashed_process_data = processlist_get_process_data(process_list,
40debf7b 1067 pid,
348c6ba8 1068 process->cpu,
40debf7b 1069 &birth,
88bf15f0 1070 trace_number);
1d1df11d 1071 if(unlikely(hashed_process_data == NULL))
40debf7b 1072 {
1073 g_assert(pid == 0 || pid != process->ppid);
1074 ProcessInfo *process_info;
1075 /* Process not present */
1c736ed5 1076 Drawing_t *drawing = control_flow_data->drawing;
40debf7b 1077 processlist_add(process_list,
1c736ed5 1078 drawing,
40debf7b 1079 pid,
fcc08e1e 1080 process->tgid,
348c6ba8 1081 process->cpu,
40debf7b 1082 process->ppid,
1083 &birth,
88bf15f0 1084 trace_number,
f4b88a7d 1085 process->name,
7b5f6cf1 1086 process->brand,
40debf7b 1087 &pl_height,
1088 &process_info,
1089 &hashed_process_data);
1c736ed5 1090 gtk_widget_set_size_request(drawing->drawing_area,
1091 -1,
1092 pl_height);
1093 gtk_widget_queue_draw(drawing->drawing_area);
40debf7b 1094 }
1095 /* Set the current process */
88bf15f0 1096 process_list->current_hash_data[trace_number][process->cpu] =
40debf7b 1097 hashed_process_data;
10a1069a 1098 }
23093869 1099
10a1069a 1100 /* Now, the process is in the state hash and our own process hash.
1101 * We definitely can draw the items related to the ending state.
1102 */
b2743953 1103
1d1df11d 1104 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1105 evtime) > 0))
10a1069a 1106 {
1d1df11d 1107 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
fd22065b 1108 TimeWindow time_window =
1109 lttvwindow_get_time_window(control_flow_data->tab);
1110
1111#ifdef EXTRA_CHECK
1112 if(ltt_time_compare(evtime, time_window.start_time) == -1
1113 || ltt_time_compare(evtime, time_window.end_time) == 1)
3311444c 1114 return FALSE;
fd22065b 1115#endif //EXTRA_CHECK
d6fef890 1116 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 1117 guint width = drawing->width;
b2743953 1118 guint x;
1119 convert_time_to_pixels(
1120 time_window,
1121 evtime,
1122 width,
1123 &x);
1124
1125 /* Draw collision indicator */
1126 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 1127 gdk_draw_point(hashed_process_data->pixmap,
b2743953 1128 drawing->gc,
1129 x,
5bb606ce 1130 COLLISION_POSITION(hashed_process_data->height));
b2743953 1131 hashed_process_data->x.middle_marked = TRUE;
1132 }
1133 } else {
fd22065b 1134 TimeWindow time_window =
1135 lttvwindow_get_time_window(control_flow_data->tab);
1136
1137#ifdef EXTRA_CHECK
1138 if(ltt_time_compare(evtime, time_window.start_time) == -1
1139 || ltt_time_compare(evtime, time_window.end_time) == 1)
3311444c 1140 return FALSE;
fd22065b 1141#endif //EXTRA_CHECK
d6fef890 1142 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 1143 guint width = drawing->width;
10a1069a 1144 guint x;
dbd243b1 1145
10a1069a 1146 convert_time_to_pixels(
a18124ff 1147 time_window,
10a1069a 1148 evtime,
1149 width,
1150 &x);
dbd243b1 1151
23093869 1152
4b7dc462 1153 /* Jump over draw if we are at the same x position */
1d1df11d 1154 if(unlikely(x == hashed_process_data->x.middle &&
1155 hashed_process_data->x.middle_used))
10a1069a 1156 {
1d1df11d 1157 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
e72908ed 1158 /* Draw collision indicator */
1159 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 1160 gdk_draw_point(hashed_process_data->pixmap,
e72908ed 1161 drawing->gc,
1162 x,
5bb606ce 1163 COLLISION_POSITION(hashed_process_data->height));
de4ea1ad 1164 hashed_process_data->x.middle_marked = TRUE;
e72908ed 1165 }
4b7dc462 1166 /* jump */
1167 } else {
1168
1169 DrawContext draw_context;
1170 /* Now create the drawing context that will be used to draw
1171 * items related to the last state. */
1c736ed5 1172 draw_context.drawable = hashed_process_data->pixmap;
4b7dc462 1173 draw_context.gc = drawing->gc;
1174 draw_context.pango_layout = drawing->pango_layout;
9a1ec01b 1175 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
4b7dc462 1176 draw_context.drawinfo.end.x = x;
1177
1c736ed5 1178 draw_context.drawinfo.y.over = 1;
1179 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1180 draw_context.drawinfo.y.under = hashed_process_data->height;
4b7dc462 1181
1182 draw_context.drawinfo.start.offset.over = 0;
1183 draw_context.drawinfo.start.offset.middle = 0;
1184 draw_context.drawinfo.start.offset.under = 0;
1185 draw_context.drawinfo.end.offset.over = 0;
1186 draw_context.drawinfo.end.offset.middle = 0;
1187 draw_context.drawinfo.end.offset.under = 0;
1188
1189 {
1190 /* Draw the line */
9a1ec01b 1191 PropertiesLine prop_line = prepare_s_e_line(process);
4b7dc462 1192 draw_line((void*)&prop_line, (void*)&draw_context);
23093869 1193
4b7dc462 1194 }
1195 /* become the last x position */
9a1ec01b 1196 hashed_process_data->x.middle = x;
e72908ed 1197 hashed_process_data->x.middle_used = TRUE;
1198 hashed_process_data->x.middle_marked = FALSE;
b2743953 1199
1200 /* Calculate the next good time */
1201 convert_pixels_to_time(width, x+1, time_window,
1202 &hashed_process_data->next_good_time);
23093869 1203 }
1204 }
8924e3e4 1205 }
23093869 1206 return 0;
1207}
1208
4a24fa1f 1209/* before_process_exit_hook
23093869 1210 *
4a24fa1f 1211 * Draw lines for process event.
1212 *
23093869 1213 * @param hook_data ControlFlowData structure of the viewer.
1214 * @param call_data Event context.
1215 *
1216 * This function adds items to be drawn in a queue for each process.
1217 *
1218 */
8869ac08 1219
1220
4a24fa1f 1221int before_process_exit_hook(void *hook_data, void *call_data)
1222{
88bf15f0 1223#ifdef BABEL_CLEANUP
dd455fb8 1224 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1225 EventsRequest *events_request = (EventsRequest*)th->hook_data;
4a24fa1f 1226
23093869 1227 ControlFlowData *control_flow_data = events_request->viewer_data;
1228
1229 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1230
1231 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
23093869 1232
4a24fa1f 1233 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1234
23093869 1235 LttEvent *e;
2c82c4dc 1236 e = ltt_tracefile_get_event(tfc->tf);
23093869 1237
e38d9ea0 1238 LttvFilter *filter = control_flow_data->filter;
1239 if(filter != NULL && filter->head != NULL)
1240 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
b6ef18af 1241 tfc->t_context->t,tfc,NULL,NULL))
e38d9ea0 1242 return FALSE;
1243
23093869 1244 LttTime evtime = ltt_event_time(e);
23093869 1245
10a1069a 1246 /* Add process to process list (if not present) */
4a24fa1f 1247 //LttvProcessState *process = tfs->process;
ae3d0f50 1248 guint cpu = tfs->cpu;
0f090e21 1249 guint trace_num = ts->parent.index;
4a24fa1f 1250 LttvProcessState *process = ts->running_process[cpu];
1251 guint pid = process->pid;
10a1069a 1252 LttTime birth;
1c736ed5 1253 guint pl_height = 0;
10a1069a 1254 HashedProcessData *hashed_process_data = NULL;
23093869 1255
5c230fc4 1256 ProcessList *process_list = control_flow_data->process_list;
4a24fa1f 1257
10a1069a 1258 g_assert(process != NULL);
23093869 1259
10a1069a 1260 birth = process->creation_time;
23093869 1261
0f090e21 1262 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1263 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
40debf7b 1264 } else {
ac4e21cf 1265 hashed_process_data = processlist_get_process_data(process_list,
4a24fa1f 1266 pid,
1267 process->cpu,
1268 &birth,
0f090e21 1269 trace_num);
1d1df11d 1270 if(unlikely(hashed_process_data == NULL))
40debf7b 1271 {
1272 g_assert(pid == 0 || pid != process->ppid);
1273 /* Process not present */
1c736ed5 1274 Drawing_t *drawing = control_flow_data->drawing;
40debf7b 1275 ProcessInfo *process_info;
1276 processlist_add(process_list,
1c736ed5 1277 drawing,
40debf7b 1278 pid,
fcc08e1e 1279 process->tgid,
4a24fa1f 1280 process->cpu,
40debf7b 1281 process->ppid,
1282 &birth,
0f090e21 1283 trace_num,
4a24fa1f 1284 process->name,
7b5f6cf1 1285 process->brand,
40debf7b 1286 &pl_height,
1287 &process_info,
1288 &hashed_process_data);
4a24fa1f 1289 gtk_widget_set_size_request(drawing->drawing_area,
1290 -1,
1291 pl_height);
1292 gtk_widget_queue_draw(drawing->drawing_area);
40debf7b 1293 }
23093869 1294 }
40debf7b 1295
4a24fa1f 1296 /* Now, the process is in the state hash and our own process hash.
1297 * We definitely can draw the items related to the ending state.
1298 */
1299
1300 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1301 evtime) > 0))
b2743953 1302 {
4a24fa1f 1303 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1304 TimeWindow time_window =
1305 lttvwindow_get_time_window(control_flow_data->tab);
1306
1307#ifdef EXTRA_CHECK
1308 if(ltt_time_compare(evtime, time_window.start_time) == -1
1309 || ltt_time_compare(evtime, time_window.end_time) == 1)
3311444c 1310 return FALSE;
4a24fa1f 1311#endif //EXTRA_CHECK
1312 Drawing_t *drawing = control_flow_data->drawing;
1313 guint width = drawing->width;
1314 guint x;
1315 convert_time_to_pixels(
1316 time_window,
1317 evtime,
1318 width,
1319 &x);
1320
1321 /* Draw collision indicator */
1322 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1323 gdk_draw_point(hashed_process_data->pixmap,
1324 drawing->gc,
1325 x,
5bb606ce 1326 COLLISION_POSITION(hashed_process_data->height));
4a24fa1f 1327 hashed_process_data->x.middle_marked = TRUE;
1328 }
1329 } else {
fd22065b 1330 TimeWindow time_window =
1331 lttvwindow_get_time_window(control_flow_data->tab);
1332
1333#ifdef EXTRA_CHECK
1334 if(ltt_time_compare(evtime, time_window.start_time) == -1
1335 || ltt_time_compare(evtime, time_window.end_time) == 1)
3311444c 1336 return FALSE;
fd22065b 1337#endif //EXTRA_CHECK
d6fef890 1338 Drawing_t *drawing = control_flow_data->drawing;
1339 guint width = drawing->width;
4a24fa1f 1340 guint x;
1341
2c82c4dc 1342 convert_time_to_pixels(
1343 time_window,
1344 evtime,
1345 width,
1346 &x);
1347
b2743953 1348
2c82c4dc 1349 /* Jump over draw if we are at the same x position */
1350 if(unlikely(x == hashed_process_data->x.middle &&
1351 hashed_process_data->x.middle_used))
1352 {
1353 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
b2743953 1354 /* Draw collision indicator */
1355 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 1356 gdk_draw_point(hashed_process_data->pixmap,
b2743953 1357 drawing->gc,
1358 x,
5bb606ce 1359 COLLISION_POSITION(hashed_process_data->height));
b2743953 1360 hashed_process_data->x.middle_marked = TRUE;
1361 }
2c82c4dc 1362 /* jump */
b2743953 1363 } else {
2c82c4dc 1364 DrawContext draw_context;
fd22065b 1365
2c82c4dc 1366 /* Now create the drawing context that will be used to draw
1367 * items related to the last state. */
1368 draw_context.drawable = hashed_process_data->pixmap;
1369 draw_context.gc = drawing->gc;
1370 draw_context.pango_layout = drawing->pango_layout;
1371 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1372 draw_context.drawinfo.end.x = x;
dbd243b1 1373
2c82c4dc 1374 draw_context.drawinfo.y.over = 1;
1375 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1376 draw_context.drawinfo.y.under = hashed_process_data->height;
dbd243b1 1377
2c82c4dc 1378 draw_context.drawinfo.start.offset.over = 0;
1379 draw_context.drawinfo.start.offset.middle = 0;
1380 draw_context.drawinfo.start.offset.under = 0;
1381 draw_context.drawinfo.end.offset.over = 0;
1382 draw_context.drawinfo.end.offset.middle = 0;
1383 draw_context.drawinfo.end.offset.under = 0;
dbd243b1 1384
2c82c4dc 1385 {
1386 /* Draw the line */
1387 PropertiesLine prop_line = prepare_s_e_line(process);
1388 draw_line((void*)&prop_line, (void*)&draw_context);
dbd243b1 1389
2c82c4dc 1390 }
1391 /* become the last x position */
1392 hashed_process_data->x.middle = x;
1393 hashed_process_data->x.middle_used = TRUE;
1394 hashed_process_data->x.middle_marked = FALSE;
dbd243b1 1395
2c82c4dc 1396 /* Calculate the next good time */
1397 convert_pixels_to_time(width, x+1, time_window,
1398 &hashed_process_data->next_good_time);
1399 }
1400 }
1401
88bf15f0 1402#endif //babel_cleanup
10599fb9 1403 return 0;
2c82c4dc 1404
1405}
1406
1407
1408
1409/* before_process_release_hook
1410 *
1411 * Draw lines for process event.
1412 *
1413 * @param hook_data ControlFlowData structure of the viewer.
1414 * @param call_data Event context.
1415 *
1416 * This function adds items to be drawn in a queue for each process.
1417 *
1418 */
1419
1420
1421int before_process_release_hook(void *hook_data, void *call_data)
1422{
88bf15f0 1423#ifdef BABEL_CLEANUP
dd455fb8 1424 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1425 EventsRequest *events_request = (EventsRequest*)th->hook_data;
2c82c4dc 1426
1427 ControlFlowData *control_flow_data = events_request->viewer_data;
1428
1429 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1430
348c6ba8 1431 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1432
2c82c4dc 1433 LttEvent *e;
1434 e = ltt_tracefile_get_event(tfc->tf);
1435
e38d9ea0 1436 LttvFilter *filter = control_flow_data->filter;
1437 if(filter != NULL && filter->head != NULL)
1438 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
b6ef18af 1439 tfc->t_context->t,tfc,NULL,NULL))
e38d9ea0 1440 return FALSE;
1441
2c82c4dc 1442 LttTime evtime = ltt_event_time(e);
1443
0f090e21 1444 guint trace_num = ts->parent.index;
2c82c4dc 1445
1446 guint pid;
1447 {
04348950 1448 pid = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
2c82c4dc 1449 }
1450
1451 /* Add process to process list (if not present) */
1452 /* Don't care about the process if it's not in the state hash already :
1453 * that means a process that has never done anything in the trace and
1454 * unknown suddently gets destroyed : no state meaningful to show. */
348c6ba8 1455 LttvProcessState *process = lttv_state_find_process(ts, ANY_CPU, pid);
2c82c4dc 1456
1457 if(process != NULL) {
1458 LttTime birth;
2c82c4dc 1459 HashedProcessData *hashed_process_data = NULL;
1460
1461 ProcessList *process_list = control_flow_data->process_list;
1462
1463 birth = process->creation_time;
1464
1465 /* Cannot use current process : this event happens on another process,
1466 * action done by the parent. */
1467 hashed_process_data = processlist_get_process_data(process_list,
1468 pid,
348c6ba8 1469 process->cpu,
2c82c4dc 1470 &birth,
0f090e21 1471 trace_num);
2c82c4dc 1472 if(unlikely(hashed_process_data == NULL))
3311444c 1473 /*
1474 * Process already been scheduled out EXIT_DEAD, not in the process list
1475 * anymore. Just return.
1476 */
1477 return FALSE;
2c82c4dc 1478
1479 /* Now, the process is in the state hash and our own process hash.
1480 * We definitely can draw the items related to the ending state.
1481 */
1482
1483 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1484 evtime) > 0))
1485 {
1486 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1487 TimeWindow time_window =
1488 lttvwindow_get_time_window(control_flow_data->tab);
1489
1490#ifdef EXTRA_CHECK
1491 if(ltt_time_compare(evtime, time_window.start_time) == -1
1492 || ltt_time_compare(evtime, time_window.end_time) == 1)
3311444c 1493 return FALSE;
2c82c4dc 1494#endif //EXTRA_CHECK
1495 Drawing_t *drawing = control_flow_data->drawing;
1496 guint width = drawing->width;
1497 guint x;
1498 convert_time_to_pixels(
1499 time_window,
1500 evtime,
1501 width,
1502 &x);
1503
1504 /* Draw collision indicator */
1505 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1506 gdk_draw_point(hashed_process_data->pixmap,
1507 drawing->gc,
1508 x,
5bb606ce 1509 COLLISION_POSITION(hashed_process_data->height));
2c82c4dc 1510 hashed_process_data->x.middle_marked = TRUE;
1511 }
1512 } else {
1513 TimeWindow time_window =
1514 lttvwindow_get_time_window(control_flow_data->tab);
1515
1516#ifdef EXTRA_CHECK
1517 if(ltt_time_compare(evtime, time_window.start_time) == -1
4a24fa1f 1518 || ltt_time_compare(evtime, time_window.end_time) == 1)
3311444c 1519 return FALSE;
2da61677 1520#endif //EXTRA_CHECK
4a24fa1f 1521 Drawing_t *drawing = control_flow_data->drawing;
1522 guint width = drawing->width;
1523 guint x;
1524
1525 convert_time_to_pixels(
1526 time_window,
1527 evtime,
1528 width,
1529 &x);
1530
2da61677 1531
4a24fa1f 1532 /* Jump over draw if we are at the same x position */
1533 if(unlikely(x == hashed_process_data->x.middle &&
1534 hashed_process_data->x.middle_used))
1535 {
1536 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
2da61677 1537 /* Draw collision indicator */
1538 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1539 gdk_draw_point(hashed_process_data->pixmap,
1540 drawing->gc,
1541 x,
5bb606ce 1542 COLLISION_POSITION(hashed_process_data->height));
2da61677 1543 hashed_process_data->x.middle_marked = TRUE;
1544 }
4a24fa1f 1545 /* jump */
2da61677 1546 } else {
4a24fa1f 1547 DrawContext draw_context;
2da61677 1548
4a24fa1f 1549 /* Now create the drawing context that will be used to draw
1550 * items related to the last state. */
1551 draw_context.drawable = hashed_process_data->pixmap;
1552 draw_context.gc = drawing->gc;
1553 draw_context.pango_layout = drawing->pango_layout;
1554 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1555 draw_context.drawinfo.end.x = x;
2da61677 1556
4a24fa1f 1557 draw_context.drawinfo.y.over = 1;
1558 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1559 draw_context.drawinfo.y.under = hashed_process_data->height;
2da61677 1560
4a24fa1f 1561 draw_context.drawinfo.start.offset.over = 0;
1562 draw_context.drawinfo.start.offset.middle = 0;
1563 draw_context.drawinfo.start.offset.under = 0;
1564 draw_context.drawinfo.end.offset.over = 0;
1565 draw_context.drawinfo.end.offset.middle = 0;
1566 draw_context.drawinfo.end.offset.under = 0;
2da61677 1567
4a24fa1f 1568 {
1569 /* Draw the line */
1570 PropertiesLine prop_line = prepare_s_e_line(process);
1571 draw_line((void*)&prop_line, (void*)&draw_context);
2da61677 1572
2da61677 1573 }
4a24fa1f 1574 /* become the last x position */
1575 hashed_process_data->x.middle = x;
1576 hashed_process_data->x.middle_used = TRUE;
1577 hashed_process_data->x.middle_marked = FALSE;
1578
1579 /* Calculate the next good time */
1580 convert_pixels_to_time(width, x+1, time_window,
1581 &hashed_process_data->next_good_time);
2da61677 1582 }
1583 }
dbd243b1 1584 }
dbd243b1 1585
88bf15f0 1586#endif //babel_cleanup
10599fb9 1587 return 0;
dbd243b1 1588}
1589
4a24fa1f 1590
2c82c4dc 1591
1592
1593
1594/* after_process_fork_hook
1595 *
1596 * Create the processlist entry for the child process. Put the last
1597 * position in x at the current time value.
1598 *
1599 * @param hook_data ControlFlowData structure of the viewer.
1600 * @param call_data Event context.
1601 *
1602 * This function adds items to be drawn in a queue for each process.
1603 *
1604 */
1605int after_process_fork_hook(void *hook_data, void *call_data)
1606{
88bf15f0 1607#ifdef BABEL_CLEANUP
dd455fb8 1608 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1609 EventsRequest *events_request = (EventsRequest*)th->hook_data;
2c82c4dc 1610 ControlFlowData *control_flow_data = events_request->viewer_data;
1611
1612 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1613
348c6ba8 1614 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1615
2c82c4dc 1616 LttEvent *e;
1617 e = ltt_tracefile_get_event(tfc->tf);
1618
e38d9ea0 1619 LttvFilter *filter = control_flow_data->filter;
1620 if(filter != NULL && filter->head != NULL)
1621 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
b6ef18af 1622 tfc->t_context->t,tfc,NULL,NULL))
e38d9ea0 1623 return FALSE;
1624
2c82c4dc 1625 LttTime evtime = ltt_event_time(e);
1626
1627 guint child_pid;
1628 {
04348950 1629 child_pid = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
2c82c4dc 1630 }
1631
1632 /* Add process to process list (if not present) */
1633 LttvProcessState *process_child;
1634 LttTime birth;
1635 guint pl_height = 0;
1636 HashedProcessData *hashed_process_data_child = NULL;
1637
1638 ProcessList *process_list = control_flow_data->process_list;
1639
1640 /* Find child in the list... */
348c6ba8 1641 process_child = lttv_state_find_process(ts, ANY_CPU, child_pid);
2c82c4dc 1642 /* It should exist, because we are after the state update. */
1643 g_assert(process_child != NULL);
1644
1645 birth = process_child->creation_time;
0f090e21 1646 guint trace_num = ts->parent.index;
2c82c4dc 1647
1648 /* Cannot use current process, because this action is done by the parent
1649 * on its child. */
1650 hashed_process_data_child = processlist_get_process_data(process_list,
1651 child_pid,
348c6ba8 1652 process_child->cpu,
2c82c4dc 1653 &birth,
0f090e21 1654 trace_num);
2c82c4dc 1655 if(likely(hashed_process_data_child == NULL))
1656 {
1657 g_assert(child_pid == 0 || child_pid != process_child->ppid);
1658 /* Process not present */
1659 Drawing_t *drawing = control_flow_data->drawing;
2c82c4dc 1660 ProcessInfo *process_info;
1661 processlist_add(process_list,
1662 drawing,
1663 child_pid,
fcc08e1e 1664 process_child->tgid,
348c6ba8 1665 process_child->cpu,
2c82c4dc 1666 process_child->ppid,
1667 &birth,
0f090e21 1668 trace_num,
f4b88a7d 1669 process_child->name,
7b5f6cf1 1670 process_child->brand,
2c82c4dc 1671 &pl_height,
1672 &process_info,
1673 &hashed_process_data_child);
1674 gtk_widget_set_size_request(drawing->drawing_area,
1675 -1,
1676 pl_height);
1677 gtk_widget_queue_draw(drawing->drawing_area);
fcc08e1e 1678 } else {
1679 processlist_set_ppid(process_list, process_child->ppid,
1680 hashed_process_data_child);
1681 processlist_set_tgid(process_list, process_child->tgid,
1682 hashed_process_data_child);
2c82c4dc 1683 }
1684
1685
1686 if(likely(ltt_time_compare(hashed_process_data_child->next_good_time,
1687 evtime) <= 0))
1688 {
1689 TimeWindow time_window =
1690 lttvwindow_get_time_window(control_flow_data->tab);
1691
1692#ifdef EXTRA_CHECK
1693 if(ltt_time_compare(evtime, time_window.start_time) == -1
1694 || ltt_time_compare(evtime, time_window.end_time) == 1)
3311444c 1695 return FALSE;
2c82c4dc 1696#endif //EXTRA_CHECK
1697 Drawing_t *drawing = control_flow_data->drawing;
1698 guint width = drawing->width;
1699 guint new_x;
1700 convert_time_to_pixels(
1701 time_window,
1702 evtime,
1703 width,
1704 &new_x);
1705
1706 if(likely(hashed_process_data_child->x.over != new_x)) {
1707 hashed_process_data_child->x.over = new_x;
1708 hashed_process_data_child->x.over_used = FALSE;
1709 hashed_process_data_child->x.over_marked = FALSE;
1710 }
1711 if(likely(hashed_process_data_child->x.middle != new_x)) {
1712 hashed_process_data_child->x.middle = new_x;
1713 hashed_process_data_child->x.middle_used = FALSE;
1714 hashed_process_data_child->x.middle_marked = FALSE;
1715 }
1716 if(likely(hashed_process_data_child->x.under != new_x)) {
1717 hashed_process_data_child->x.under = new_x;
1718 hashed_process_data_child->x.under_used = FALSE;
1719 hashed_process_data_child->x.under_marked = FALSE;
1720 }
1721 }
88bf15f0 1722#endif //babel_cleanup
10599fb9 1723 return FALSE;
2c82c4dc 1724}
1725
1726
1727
1728/* after_process_exit_hook
1729 *
1730 * Create the processlist entry for the child process. Put the last
1731 * position in x at the current time value.
1732 *
1733 * @param hook_data ControlFlowData structure of the viewer.
1734 * @param call_data Event context.
1735 *
1736 * This function adds items to be drawn in a queue for each process.
1737 *
1738 */
1739int after_process_exit_hook(void *hook_data, void *call_data)
1740{
88bf15f0 1741#ifdef BABEL_CLEANUP
dd455fb8 1742 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1743 EventsRequest *events_request = (EventsRequest*)th->hook_data;
2c82c4dc 1744 ControlFlowData *control_flow_data = events_request->viewer_data;
1745
1746 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1747
1748 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1749
348c6ba8 1750 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1751
2c82c4dc 1752 LttEvent *e;
1753 e = ltt_tracefile_get_event(tfc->tf);
1754
e38d9ea0 1755 LttvFilter *filter = control_flow_data->filter;
1756 if(filter != NULL && filter->head != NULL)
1757 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
b6ef18af 1758 tfc->t_context->t,tfc,NULL,NULL))
e38d9ea0 1759 return FALSE;
1760
2c82c4dc 1761 LttTime evtime = ltt_event_time(e);
1762
1763 /* Add process to process list (if not present) */
348c6ba8 1764 //LttvProcessState *process = tfs->process;
ae3d0f50 1765 guint cpu = tfs->cpu;
0f090e21 1766 guint trace_num = ts->parent.index;
348c6ba8 1767 LttvProcessState *process = ts->running_process[cpu];
1768
1769 /* It should exist, because we are after the state update. */
1770 g_assert(process != NULL);
1771
2c82c4dc 1772 guint pid = process->pid;
1773 LttTime birth;
1774 guint pl_height = 0;
1775 HashedProcessData *hashed_process_data = NULL;
1776
1777 ProcessList *process_list = control_flow_data->process_list;
1778
2c82c4dc 1779 birth = process->creation_time;
1780
0f090e21 1781 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL) ){
1782 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
2c82c4dc 1783 } else {
1784 hashed_process_data = processlist_get_process_data(process_list,
1785 pid,
348c6ba8 1786 process->cpu,
2c82c4dc 1787 &birth,
0f090e21 1788 trace_num);
2c82c4dc 1789 if(unlikely(hashed_process_data == NULL))
1790 {
1791 g_assert(pid == 0 || pid != process->ppid);
1792 /* Process not present */
1793 Drawing_t *drawing = control_flow_data->drawing;
2c82c4dc 1794 ProcessInfo *process_info;
1795 processlist_add(process_list,
1796 drawing,
1797 pid,
fcc08e1e 1798 process->tgid,
348c6ba8 1799 process->cpu,
2c82c4dc 1800 process->ppid,
1801 &birth,
0f090e21 1802 trace_num,
f4b88a7d 1803 process->name,
7b5f6cf1 1804 process->brand,
2c82c4dc 1805 &pl_height,
1806 &process_info,
1807 &hashed_process_data);
1808 gtk_widget_set_size_request(drawing->drawing_area,
1809 -1,
1810 pl_height);
1811 gtk_widget_queue_draw(drawing->drawing_area);
1812 }
1813
1814 /* Set the current process */
0f090e21 1815 process_list->current_hash_data[trace_num][process->cpu] =
2c82c4dc 1816 hashed_process_data;
1817 }
1818
1819 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
1820 evtime) <= 0))
1821 {
1822 TimeWindow time_window =
1823 lttvwindow_get_time_window(control_flow_data->tab);
dbd243b1 1824
2c82c4dc 1825#ifdef EXTRA_CHECK
1826 if(ltt_time_compare(evtime, time_window.start_time) == -1
1827 || ltt_time_compare(evtime, time_window.end_time) == 1)
3311444c 1828 return FALSE;
2c82c4dc 1829#endif //EXTRA_CHECK
1830 Drawing_t *drawing = control_flow_data->drawing;
1831 guint width = drawing->width;
1832 guint new_x;
1833 convert_time_to_pixels(
1834 time_window,
1835 evtime,
1836 width,
1837 &new_x);
1838 if(unlikely(hashed_process_data->x.middle != new_x)) {
1839 hashed_process_data->x.middle = new_x;
1840 hashed_process_data->x.middle_used = FALSE;
1841 hashed_process_data->x.middle_marked = FALSE;
1842 }
1843 }
dbd243b1 1844
88bf15f0 1845#endif //babel_cleanup
10599fb9 1846 return FALSE;
2c82c4dc 1847}
dbd243b1 1848
1849
f4b88a7d 1850/* Get the filename of the process to print */
1851int after_fs_exec_hook(void *hook_data, void *call_data)
1852{
88bf15f0 1853#ifdef BABEL_CLEANUP
dd455fb8 1854 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1855 EventsRequest *events_request = (EventsRequest*)th->hook_data;
f4b88a7d 1856 ControlFlowData *control_flow_data = events_request->viewer_data;
1857
1858 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1859
1860 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1861
1862 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1863
e38d9ea0 1864 LttEvent *e;
1865 e = ltt_tracefile_get_event(tfc->tf);
1866
1867 LttvFilter *filter = control_flow_data->filter;
1868 if(filter != NULL && filter->head != NULL)
1869 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
b6ef18af 1870 tfc->t_context->t,tfc,NULL,NULL))
e38d9ea0 1871 return FALSE;
1872
ae3d0f50 1873 guint cpu = tfs->cpu;
0f090e21 1874 guint trace_num = ts->parent.index;
f4b88a7d 1875 LttvProcessState *process = ts->running_process[cpu];
1876 g_assert(process != NULL);
1877
1878 guint pid = process->pid;
1879
1880 /* Well, the process_out existed : we must get it in the process hash
1881 * or add it, and draw its items.
1882 */
1883 /* Add process to process list (if not present) */
1884 guint pl_height = 0;
1885 HashedProcessData *hashed_process_data = NULL;
1886 ProcessList *process_list = control_flow_data->process_list;
1887 LttTime birth = process->creation_time;
1888
0f090e21 1889 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1890 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
f4b88a7d 1891 } else {
1892 hashed_process_data = processlist_get_process_data(process_list,
1893 pid,
1894 process->cpu,
1895 &birth,
0f090e21 1896 trace_num);
f4b88a7d 1897 if(unlikely(hashed_process_data == NULL))
1898 {
1899 g_assert(pid == 0 || pid != process->ppid);
1900 ProcessInfo *process_info;
1901 /* Process not present */
1902 Drawing_t *drawing = control_flow_data->drawing;
1903 processlist_add(process_list,
1904 drawing,
1905 pid,
fcc08e1e 1906 process->tgid,
f4b88a7d 1907 process->cpu,
1908 process->ppid,
1909 &birth,
0f090e21 1910 trace_num,
f4b88a7d 1911 process->name,
7b5f6cf1 1912 process->brand,
f4b88a7d 1913 &pl_height,
1914 &process_info,
1915 &hashed_process_data);
1916 gtk_widget_set_size_request(drawing->drawing_area,
1917 -1,
1918 pl_height);
1919 gtk_widget_queue_draw(drawing->drawing_area);
1920 }
1921 /* Set the current process */
0f090e21 1922 process_list->current_hash_data[trace_num][process->cpu] =
f4b88a7d 1923 hashed_process_data;
1924 }
1925
1926 processlist_set_name(process_list, process->name, hashed_process_data);
1927
88bf15f0 1928#endif //babel_cleanup
10599fb9 1929 return 0;
f4b88a7d 1930
1931}
1932
7b5f6cf1 1933/* Get the filename of the process to print */
1934int after_user_generic_thread_brand_hook(void *hook_data, void *call_data)
1935{
88bf15f0 1936#ifdef BABEL_CLEANUP
dd455fb8 1937 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1938 EventsRequest *events_request = (EventsRequest*)th->hook_data;
7b5f6cf1 1939 ControlFlowData *control_flow_data = events_request->viewer_data;
1940
1941 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1942
1943 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1944
1945 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1946
e38d9ea0 1947 LttEvent *e;
1948 e = ltt_tracefile_get_event(tfc->tf);
1949
1950 LttvFilter *filter = control_flow_data->filter;
1951 if(filter != NULL && filter->head != NULL)
1952 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
b6ef18af 1953 tfc->t_context->t,tfc,NULL,NULL))
e38d9ea0 1954 return FALSE;
1955
7b5f6cf1 1956 guint cpu = tfs->cpu;
0f090e21 1957 guint trace_num = ts->parent.index;
7b5f6cf1 1958 LttvProcessState *process = ts->running_process[cpu];
1959 g_assert(process != NULL);
1960
1961 guint pid = process->pid;
1962
1963 /* Well, the process_out existed : we must get it in the process hash
1964 * or add it, and draw its items.
1965 */
1966 /* Add process to process list (if not present) */
1967 guint pl_height = 0;
1968 HashedProcessData *hashed_process_data = NULL;
1969 ProcessList *process_list = control_flow_data->process_list;
1970 LttTime birth = process->creation_time;
1971
0f090e21 1972 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1973 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
7b5f6cf1 1974 } else {
1975 hashed_process_data = processlist_get_process_data(process_list,
1976 pid,
1977 process->cpu,
1978 &birth,
0f090e21 1979 trace_num);
7b5f6cf1 1980 if(unlikely(hashed_process_data == NULL))
1981 {
1982 g_assert(pid == 0 || pid != process->ppid);
1983 ProcessInfo *process_info;
1984 /* Process not present */
1985 Drawing_t *drawing = control_flow_data->drawing;
1986 processlist_add(process_list,
1987 drawing,
1988 pid,
fcc08e1e 1989 process->tgid,
7b5f6cf1 1990 process->cpu,
1991 process->ppid,
1992 &birth,
0f090e21 1993 trace_num,
7b5f6cf1 1994 process->name,
1995 process->brand,
1996 &pl_height,
1997 &process_info,
1998 &hashed_process_data);
1999 gtk_widget_set_size_request(drawing->drawing_area,
2000 -1,
2001 pl_height);
2002 gtk_widget_queue_draw(drawing->drawing_area);
2003 }
2004 /* Set the current process */
0f090e21 2005 process_list->current_hash_data[trace_num][process->cpu] =
7b5f6cf1 2006 hashed_process_data;
2007 }
2008
2009 processlist_set_brand(process_list, process->brand, hashed_process_data);
2010
88bf15f0 2011#endif //babel_cleanup
10599fb9 2012 return 0;
7b5f6cf1 2013}
2014
2015
b3fd4c02 2016/* after_event_enum_process_hook
2017 *
b3fd4c02 2018 * Create the processlist entry for the child process. Put the last
2019 * position in x at the current time value.
2020 *
2021 * @param hook_data ControlFlowData structure of the viewer.
2022 * @param call_data Event context.
2023 *
2024 * This function adds items to be drawn in a queue for each process.
2025 *
2026 */
2027int after_event_enum_process_hook(void *hook_data, void *call_data)
2028{
88bf15f0 2029#ifdef BABEL_CLEANUP
dd455fb8 2030 LttvTraceHook *th = (LttvTraceHook*)hook_data;
2031 EventsRequest *events_request = (EventsRequest*)th->hook_data;
b3fd4c02 2032 ControlFlowData *control_flow_data = events_request->viewer_data;
2033
2034 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
2035
b3fd4c02 2036 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
2037
c4a72569 2038 guint first_cpu, nb_cpus, cpu;
2039
b3fd4c02 2040 LttEvent *e;
2041 e = ltt_tracefile_get_event(tfc->tf);
2042
e38d9ea0 2043 LttvFilter *filter = control_flow_data->filter;
2044 if(filter != NULL && filter->head != NULL)
2045 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
b6ef18af 2046 tfc->t_context->t,tfc,NULL,NULL))
e38d9ea0 2047 return FALSE;
2048
b3fd4c02 2049 /* Add process to process list (if not present) */
2050 LttvProcessState *process_in;
2051 LttTime birth;
2052 guint pl_height = 0;
2053 HashedProcessData *hashed_process_data_in = NULL;
2054
2055 ProcessList *process_list = control_flow_data->process_list;
0f090e21 2056 guint trace_num = ts->parent.index;
b3fd4c02 2057
2058 guint pid_in;
2059 {
04348950 2060 pid_in = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
b3fd4c02 2061 }
c4a72569 2062
2063 if(pid_in == 0) {
2064 first_cpu = 0;
2065 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2066 } else {
2067 first_cpu = ANY_CPU;
2068 nb_cpus = ANY_CPU+1;
2069 }
b3fd4c02 2070
c4a72569 2071 for(cpu = first_cpu; cpu < nb_cpus; cpu++) {
2072 /* Find process pid_in in the list... */
2073 process_in = lttv_state_find_process(ts, cpu, pid_in);
2074 //process_in = tfs->process;
2075 //guint cpu = tfs->cpu;
2076 //guint trace_num = ts->parent.index;
2077 //process_in = ts->running_process[cpu];
2078 /* It should exist, because we are after the state update. */
2079 #ifdef EXTRA_CHECK
2080 //g_assert(process_in != NULL);
2081 #endif //EXTRA_CHECK
2082 birth = process_in->creation_time;
2083
2084 hashed_process_data_in = processlist_get_process_data(process_list,
2085 pid_in,
2086 process_in->cpu,
2087 &birth,
2088 trace_num);
2089 if(hashed_process_data_in == NULL)
2090 {
2091 if(pid_in != 0 && pid_in == process_in->ppid)
2092 g_critical("TEST %u , %u", pid_in, process_in->ppid);
2093 g_assert(pid_in == 0 || pid_in != process_in->ppid);
2094 ProcessInfo *process_info;
2095 Drawing_t *drawing = control_flow_data->drawing;
2096 /* Process not present */
2097 processlist_add(process_list,
2098 drawing,
b3fd4c02 2099 pid_in,
c4a72569 2100 process_in->tgid,
b3fd4c02 2101 process_in->cpu,
c4a72569 2102 process_in->ppid,
b3fd4c02 2103 &birth,
c4a72569 2104 trace_num,
2105 process_in->name,
2106 process_in->brand,
2107 &pl_height,
2108 &process_info,
2109 &hashed_process_data_in);
2110 gtk_widget_set_size_request(drawing->drawing_area,
2111 -1,
2112 pl_height);
2113 gtk_widget_queue_draw(drawing->drawing_area);
2114 } else {
2115 processlist_set_name(process_list, process_in->name,
2116 hashed_process_data_in);
2117 processlist_set_ppid(process_list, process_in->ppid,
2118 hashed_process_data_in);
2119 processlist_set_tgid(process_list, process_in->tgid,
2120 hashed_process_data_in);
2121 }
2122 }
88bf15f0 2123#endif //babel_cleanup
10599fb9 2124 return 0;
b3fd4c02 2125}
f4b88a7d 2126
2127
1b238973 2128gint update_time_window_hook(void *hook_data, void *call_data)
f7afe191 2129{
a56a1ba4 2130 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
a43d67ba 2131 Drawing_t *drawing = control_flow_data->drawing;
1c736ed5 2132 ProcessList *process_list = control_flow_data->process_list;
a43d67ba 2133
224446ce 2134 const TimeWindowNotifyData *time_window_nofify_data =
2135 ((const TimeWindowNotifyData *)call_data);
2136
14963be0 2137 TimeWindow *old_time_window =
224446ce 2138 time_window_nofify_data->old_time_window;
2139 TimeWindow *new_time_window =
2140 time_window_nofify_data->new_time_window;
a56a1ba4 2141
3cb8b205 2142 /* Update the ruler */
2143 drawing_update_ruler(control_flow_data->drawing,
2144 new_time_window);
2145
2146
a56a1ba4 2147 /* Two cases : zoom in/out or scrolling */
2148
2149 /* In order to make sure we can reuse the old drawing, the scale must
2150 * be the same and the new time interval being partly located in the
2151 * currently shown time interval. (reuse is only for scrolling)
2152 */
2153
2eef04b5 2154 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
14963be0 2155 old_time_window->start_time.tv_sec,
2156 old_time_window->start_time.tv_nsec,
2157 old_time_window->time_width.tv_sec,
2158 old_time_window->time_width.tv_nsec);
a56a1ba4 2159
2eef04b5 2160 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
14963be0 2161 new_time_window->start_time.tv_sec,
2162 new_time_window->start_time.tv_nsec,
2163 new_time_window->time_width.tv_sec,
2164 new_time_window->time_width.tv_nsec);
a56a1ba4 2165
14963be0 2166 if( new_time_window->time_width.tv_sec == old_time_window->time_width.tv_sec
2167 && new_time_window->time_width.tv_nsec == old_time_window->time_width.tv_nsec)
a56a1ba4 2168 {
2169 /* Same scale (scrolling) */
2170 g_info("scrolling");
14963be0 2171 LttTime *ns = &new_time_window->start_time;
2172 LttTime *os = &old_time_window->start_time;
6f26fc38 2173 LttTime old_end = old_time_window->end_time;
2174 LttTime new_end = new_time_window->end_time;
a56a1ba4 2175 //if(ns<os+w<ns+w)
2176 //if(ns<os+w && os+w<ns+w)
2177 //if(ns<old_end && os<ns)
2178 if(ltt_time_compare(*ns, old_end) == -1
2179 && ltt_time_compare(*os, *ns) == -1)
2180 {
2181 g_info("scrolling near right");
2182 /* Scroll right, keep right part of the screen */
2183 guint x = 0;
51705146 2184 guint width = control_flow_data->drawing->width;
a56a1ba4 2185 convert_time_to_pixels(
a18124ff 2186 *old_time_window,
a56a1ba4 2187 *ns,
2188 width,
2189 &x);
2190
2191 /* Copy old data to new location */
1c736ed5 2192 copy_pixmap_region(process_list,
2193 NULL,
2194 control_flow_data->drawing->drawing_area->style->black_gc,
2195 NULL,
2196 x, 0,
2197 0, 0,
2198 control_flow_data->drawing->width-x+SAFETY, -1);
2199
6395d57c 2200 if(drawing->damage_begin == drawing->damage_end)
2201 drawing->damage_begin = control_flow_data->drawing->width-x;
2202 else
2203 drawing->damage_begin = 0;
2204
2205 drawing->damage_end = control_flow_data->drawing->width;
2206
a56a1ba4 2207 /* Clear the data request background, but not SAFETY */
1c736ed5 2208 rectangle_pixmap(process_list,
cfe526b1 2209 control_flow_data->drawing->drawing_area->style->black_gc,
a56a1ba4 2210 TRUE,
6395d57c 2211 drawing->damage_begin+SAFETY, 0,
2212 drawing->damage_end - drawing->damage_begin, // do not overlap
1c736ed5 2213 -1);
7abb23ad 2214 gtk_widget_queue_draw(drawing->drawing_area);
2215 //gtk_widget_queue_draw_area (drawing->drawing_area,
2216 // 0,0,
2217 // control_flow_data->drawing->width,
2218 // control_flow_data->drawing->height);
a43d67ba 2219
a56a1ba4 2220 /* Get new data for the rest. */
501d5405 2221 drawing_data_request(control_flow_data->drawing,
6395d57c 2222 drawing->damage_begin, 0,
2223 drawing->damage_end - drawing->damage_begin,
501d5405 2224 control_flow_data->drawing->height);
a56a1ba4 2225 } else {
2226 //if(ns<os<ns+w)
2227 //if(ns<os && os<ns+w)
2228 //if(ns<os && os<new_end)
2229 if(ltt_time_compare(*ns,*os) == -1
2230 && ltt_time_compare(*os,new_end) == -1)
2231 {
2232 g_info("scrolling near left");
2233 /* Scroll left, keep left part of the screen */
2234 guint x = 0;
51705146 2235 guint width = control_flow_data->drawing->width;
a56a1ba4 2236 convert_time_to_pixels(
a18124ff 2237 *new_time_window,
a56a1ba4 2238 *os,
2239 width,
2240 &x);
6395d57c 2241
a56a1ba4 2242 /* Copy old data to new location */
1c736ed5 2243 copy_pixmap_region (process_list,
2244 NULL,
cfe526b1 2245 control_flow_data->drawing->drawing_area->style->black_gc,
1c736ed5 2246 NULL,
a56a1ba4 2247 0, 0,
2248 x, 0,
2249 -1, -1);
2250
6395d57c 2251 if(drawing->damage_begin == drawing->damage_end)
2252 drawing->damage_end = x;
2253 else
2254 drawing->damage_end =
51705146 2255 control_flow_data->drawing->width;
6395d57c 2256
2257 drawing->damage_begin = 0;
2258
1c736ed5 2259 rectangle_pixmap (process_list,
cfe526b1 2260 control_flow_data->drawing->drawing_area->style->black_gc,
a56a1ba4 2261 TRUE,
6395d57c 2262 drawing->damage_begin, 0,
2263 drawing->damage_end - drawing->damage_begin, // do not overlap
1c736ed5 2264 -1);
a43d67ba 2265
7abb23ad 2266 gtk_widget_queue_draw(drawing->drawing_area);
2267 //gtk_widget_queue_draw_area (drawing->drawing_area,
2268 // 0,0,
2269 // control_flow_data->drawing->width,
2270 // control_flow_data->drawing->height);
a43d67ba 2271
6395d57c 2272
a56a1ba4 2273 /* Get new data for the rest. */
501d5405 2274 drawing_data_request(control_flow_data->drawing,
6395d57c 2275 drawing->damage_begin, 0,
2276 drawing->damage_end - drawing->damage_begin,
501d5405 2277 control_flow_data->drawing->height);
a56a1ba4 2278
a56a1ba4 2279 } else {
a43d67ba 2280 if(ltt_time_compare(*ns,*os) == 0)
2281 {
2282 g_info("not scrolling");
2283 } else {
2284 g_info("scrolling far");
2285 /* Cannot reuse any part of the screen : far jump */
2286
2287
1c736ed5 2288 rectangle_pixmap (process_list,
a43d67ba 2289 control_flow_data->drawing->drawing_area->style->black_gc,
2290 TRUE,
a56a1ba4 2291 0, 0,
a43d67ba 2292 control_flow_data->drawing->width+SAFETY, // do not overlap
1c736ed5 2293 -1);
a43d67ba 2294
7abb23ad 2295 //gtk_widget_queue_draw_area (drawing->drawing_area,
2296 // 0,0,
2297 // control_flow_data->drawing->width,
2298 // control_flow_data->drawing->height);
2299 gtk_widget_queue_draw(drawing->drawing_area);
a43d67ba 2300
6395d57c 2301 drawing->damage_begin = 0;
2302 drawing->damage_end = control_flow_data->drawing->width;
2303
a43d67ba 2304 drawing_data_request(control_flow_data->drawing,
a43d67ba 2305 0, 0,
2306 control_flow_data->drawing->width,
2307 control_flow_data->drawing->height);
2308
2309 }
a56a1ba4 2310 }
2311 }
2312 } else {
2313 /* Different scale (zoom) */
2314 g_info("zoom");
2315
1c736ed5 2316 rectangle_pixmap (process_list,
cfe526b1 2317 control_flow_data->drawing->drawing_area->style->black_gc,
a56a1ba4 2318 TRUE,
2319 0, 0,
501d5405 2320 control_flow_data->drawing->width+SAFETY, // do not overlap
1c736ed5 2321 -1);
a56a1ba4 2322
7abb23ad 2323 //gtk_widget_queue_draw_area (drawing->drawing_area,
2324 // 0,0,
2325 // control_flow_data->drawing->width,
2326 // control_flow_data->drawing->height);
2327 gtk_widget_queue_draw(drawing->drawing_area);
a56a1ba4 2328
6395d57c 2329 drawing->damage_begin = 0;
2330 drawing->damage_end = control_flow_data->drawing->width;
2331
501d5405 2332 drawing_data_request(control_flow_data->drawing,
a56a1ba4 2333 0, 0,
501d5405 2334 control_flow_data->drawing->width,
2335 control_flow_data->drawing->height);
a56a1ba4 2336 }
2337
15f77e3b 2338 /* Update directly when scrolling */
2339 gdk_window_process_updates(control_flow_data->drawing->drawing_area->window,
2340 TRUE);
3cb8b205 2341
a56a1ba4 2342 return 0;
f7afe191 2343}
2344
6395d57c 2345gint traceset_notify(void *hook_data, void *call_data)
2346{
2347 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
2348 Drawing_t *drawing = control_flow_data->drawing;
6395d57c 2349
6cec4cd2 2350 if(unlikely(drawing->gc == NULL)) {
2351 return FALSE;
2352 }
2353 if(drawing->dotted_gc == NULL) {
2354 return FALSE;
2355 }
6395d57c 2356
b9a010a2 2357 drawing_clear(control_flow_data->drawing);
2358 processlist_clear(control_flow_data->process_list);
07390ec1 2359 gtk_widget_set_size_request(
2360 control_flow_data->drawing->drawing_area,
2361 -1, processlist_get_height(control_flow_data->process_list));
d9267eec 2362 redraw_notify(control_flow_data, NULL);
6395d57c 2363
d9267eec 2364 request_background_data(control_flow_data);
6395d57c 2365
2366 return FALSE;
2367}
2368
ca0f8a8e 2369gint redraw_notify(void *hook_data, void *call_data)
2370{
2371 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
2372 Drawing_t *drawing = control_flow_data->drawing;
2373 GtkWidget *widget = drawing->drawing_area;
2374
2375 drawing->damage_begin = 0;
51705146 2376 drawing->damage_end = drawing->width;
ca0f8a8e 2377
49217bd4 2378 /* fun feature, to be separated someday... */
2379 drawing_clear(control_flow_data->drawing);
2380 processlist_clear(control_flow_data->process_list);
07390ec1 2381 gtk_widget_set_size_request(
2382 control_flow_data->drawing->drawing_area,
2383 -1, processlist_get_height(control_flow_data->process_list));
1c736ed5 2384 // Clear the images
2385 rectangle_pixmap (control_flow_data->process_list,
ca0f8a8e 2386 widget->style->black_gc,
2387 TRUE,
2388 0, 0,
f3b7430d 2389 drawing->alloc_width,
1c736ed5 2390 -1);
ca0f8a8e 2391
f3b7430d 2392 gtk_widget_queue_draw(drawing->drawing_area);
4a24fa1f 2393
ca0f8a8e 2394 if(drawing->damage_begin < drawing->damage_end)
2395 {
2396 drawing_data_request(drawing,
ca0f8a8e 2397 drawing->damage_begin,
2398 0,
2399 drawing->damage_end-drawing->damage_begin,
51705146 2400 drawing->height);
ca0f8a8e 2401 }
2402
7abb23ad 2403 //gtk_widget_queue_draw_area(drawing->drawing_area,
2404 // 0,0,
2405 // drawing->width,
2406 // drawing->height);
ca0f8a8e 2407 return FALSE;
2408
2409}
2410
2411
2412gint continue_notify(void *hook_data, void *call_data)
a43d67ba 2413{
2414 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
ca0f8a8e 2415 Drawing_t *drawing = control_flow_data->drawing;
a43d67ba 2416
6395d57c 2417 //g_assert(widget->allocation.width == drawing->damage_end);
ca0f8a8e 2418
2419 if(drawing->damage_begin < drawing->damage_end)
2420 {
2421 drawing_data_request(drawing,
ca0f8a8e 2422 drawing->damage_begin,
2423 0,
2424 drawing->damage_end-drawing->damage_begin,
51705146 2425 drawing->height);
ca0f8a8e 2426 }
2427
2428 return FALSE;
2429}
2430
2431
1b238973 2432gint update_current_time_hook(void *hook_data, void *call_data)
f7afe191 2433{
88bf15f0 2434
14963be0 2435 ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
a56a1ba4 2436
224446ce 2437 LttTime current_time = *((LttTime*)call_data);
88bf15f0 2438
ca0f8a8e 2439 TimeWindow time_window =
2440 lttvwindow_get_time_window(control_flow_data->tab);
a56a1ba4 2441
ca0f8a8e 2442 LttTime time_begin = time_window.start_time;
2443 LttTime width = time_window.time_width;
90ef7e4a 2444 LttTime half_width;
2445 {
2446 guint64 time_ll = ltt_time_to_uint64(width);
2447 time_ll = time_ll >> 1; /* divide by two */
2448 half_width = ltt_time_from_uint64(time_ll);
2449 }
a56a1ba4 2450 LttTime time_end = ltt_time_add(time_begin, width);
2451
88bf15f0 2452 LttvTraceset * ts = lttvwindow_get_traceset(control_flow_data->tab);
a56a1ba4 2453
88bf15f0
FD
2454 TimeInterval time_span = lttv_traceset_get_time_span_real(ts);
2455 LttTime trace_start = time_span.start_time;
2456 LttTime trace_end = time_span.end_time;
a56a1ba4 2457
2eef04b5 2458 g_info("New current time HOOK : %lu, %lu", current_time.tv_sec,
224446ce 2459 current_time.tv_nsec);
a56a1ba4 2460
2461
2462
2463 /* If current time is inside time interval, just move the highlight
2464 * bar */
2465
2466 /* Else, we have to change the time interval. We have to tell it
2467 * to the main window. */
2468 /* The time interval change will take care of placing the current
2469 * time at the center of the visible area, or nearest possible if we are
2470 * at one end of the trace. */
2471
2472
dbc0ef8a 2473 if(ltt_time_compare(current_time, time_begin) < 0)
a56a1ba4 2474 {
224446ce 2475 TimeWindow new_time_window;
2476
2477 if(ltt_time_compare(current_time,
dbc0ef8a 2478 ltt_time_add(trace_start,half_width)) < 0)
a56a1ba4 2479 time_begin = trace_start;
2480 else
224446ce 2481 time_begin = ltt_time_sub(current_time,half_width);
a56a1ba4 2482
224446ce 2483 new_time_window.start_time = time_begin;
2484 new_time_window.time_width = width;
a18124ff 2485 new_time_window.time_width_double = ltt_time_to_double(width);
6f26fc38 2486 new_time_window.end_time = ltt_time_add(time_begin, width);
a56a1ba4 2487
e800cf84 2488 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
a56a1ba4 2489 }
dbc0ef8a 2490 else if(ltt_time_compare(current_time, time_end) > 0)
a56a1ba4 2491 {
224446ce 2492 TimeWindow new_time_window;
2493
dbc0ef8a 2494 if(ltt_time_compare(current_time, ltt_time_sub(trace_end, half_width)) > 0)
a56a1ba4 2495 time_begin = ltt_time_sub(trace_end,width);
2496 else
224446ce 2497 time_begin = ltt_time_sub(current_time,half_width);
a56a1ba4 2498
224446ce 2499 new_time_window.start_time = time_begin;
2500 new_time_window.time_width = width;
a18124ff 2501 new_time_window.time_width_double = ltt_time_to_double(width);
6f26fc38 2502 new_time_window.end_time = ltt_time_add(time_begin, width);
a56a1ba4 2503
e800cf84 2504 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
a56a1ba4 2505
2506 }
7abb23ad 2507 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
a56a1ba4 2508
15f77e3b 2509 /* Update directly when scrolling */
2510 gdk_window_process_updates(control_flow_data->drawing->drawing_area->window,
2511 TRUE);
2512
a56a1ba4 2513 return 0;
88bf15f0 2514
f7afe191 2515}
2516
8b90e648 2517typedef struct _ClosureData {
ca0f8a8e 2518 EventsRequest *events_request;
b9a010a2 2519 LttTime end_time;
bc8d270b 2520 guint x_end;
8b90e648 2521} ClosureData;
a56a1ba4 2522
8b90e648 2523
e800cf84 2524void draw_closure(gpointer key, gpointer value, gpointer user_data)
2525{
88bf15f0 2526
a56a1ba4 2527 ProcessInfo *process_info = (ProcessInfo*)key;
2528 HashedProcessData *hashed_process_data = (HashedProcessData*)value;
2529 ClosureData *closure_data = (ClosureData*)user_data;
88bf15f0 2530
e800cf84 2531 EventsRequest *events_request = closure_data->events_request;
2532 ControlFlowData *control_flow_data = events_request->viewer_data;
88bf15f0 2533 LttvTraceset *ts = lttvwindow_get_traceset(control_flow_data->tab);
a56a1ba4 2534
a56a1ba4 2535
e800cf84 2536 LttTime evtime = closure_data->end_time;
d0cd7f09 2537
e3162168 2538 gboolean dodraw = TRUE;
2539
e800cf84 2540 {
2541 /* For the process */
2542 /* First, check if the current process is in the state computation
2543 * process list. If it is there, that means we must add it right now and
2544 * draw items from the beginning of the read for it. If it is not
2545 * present, it's a new process and it was not present : it will
2546 * be added after the state update. */
31b6868d 2547#ifdef EXTRA_CHECK
e800cf84 2548 g_assert(lttv_traceset_number(tsc->ts) > 0);
31b6868d 2549#endif //EXTRA_CHECK
88bf15f0
FD
2550 //TODO Fdeslauriers 2012-07-17: adapt for multiple traces
2551 LttvTrace *trace = lttv_traceset_get(ts,0);
2552 LttvTraceState *trace_state = trace->state;
2c82c4dc 2553
348c6ba8 2554#if 0
2c82c4dc 2555 //FIXME : optimize data structures.
2556 LttvTracefileState *tfs;
2557 LttvTracefileContext *tfc;
2558 guint i;
2559 for(i=0;i<tc->tracefiles->len;i++) {
2560 tfc = g_array_index(tc->tracefiles, LttvTracefileContext*, i);
2561 if(ltt_tracefile_name(tfc->tf) == LTT_NAME_CPU
ae3d0f50 2562 && tfs->cpu == process_info->cpu)
2c82c4dc 2563 break;
2564
2565 }
2566 g_assert(i<tc->tracefiles->len);
2567 tfs = LTTV_TRACEFILE_STATE(tfc);
348c6ba8 2568#endif //0
88bf15f0 2569 // LttvTracefileState *tfs =ts
2c82c4dc 2570 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2571 // tracefiles[process_info->cpu];
2da61677 2572
e800cf84 2573 LttvProcessState *process;
88bf15f0 2574 process = lttv_state_find_process(trace_state, process_info->cpu,
e025a729 2575 process_info->pid);
a56a1ba4 2576
1d1df11d 2577 if(unlikely(process != NULL)) {
88bf15f0 2578#ifdef BABEL_CLEANUP
b6ef18af 2579 LttvFilter *filter = control_flow_data->filter;
2580 if(filter != NULL && filter->head != NULL)
2581 if(!lttv_filter_tree_parse(filter->head,NULL,NULL,
2582 tc->t,NULL,process,tc))
e3162168 2583 dodraw = FALSE;
88bf15f0 2584#endif //babel_cleanup
e800cf84 2585 /* Only draw for processes that are currently in the trace states */
ad2e83ba 2586
1d1df11d 2587#ifdef EXTRA_CHECK
e800cf84 2588 /* Should be alike when background info is ready */
2589 if(control_flow_data->background_info_waiting==0)
2590 g_assert(ltt_time_compare(process->creation_time,
2591 process_info->birth) == 0);
1d1df11d 2592#endif //EXTRA_CHECK
e800cf84 2593
2594 /* Now, the process is in the state hash and our own process hash.
2595 * We definitely can draw the items related to the ending state.
2596 */
2597
1d1df11d 2598 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
2599 evtime) <= 0))
e800cf84 2600 {
fd22065b 2601 TimeWindow time_window =
2602 lttvwindow_get_time_window(control_flow_data->tab);
2603
2604#ifdef EXTRA_CHECK
2605 if(ltt_time_compare(evtime, time_window.start_time) == -1
2606 || ltt_time_compare(evtime, time_window.end_time) == 1)
2607 return;
2608#endif //EXTRA_CHECK
d6fef890 2609 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 2610 guint width = drawing->width;
a56a1ba4 2611
bc8d270b 2612 guint x = closure_data->x_end;
8b90e648 2613
4b7dc462 2614 DrawContext draw_context;
2615
e800cf84 2616 /* Now create the drawing context that will be used to draw
2617 * items related to the last state. */
1c736ed5 2618 draw_context.drawable = hashed_process_data->pixmap;
e800cf84 2619 draw_context.gc = drawing->gc;
2620 draw_context.pango_layout = drawing->pango_layout;
e800cf84 2621 draw_context.drawinfo.end.x = x;
2622
1c736ed5 2623 draw_context.drawinfo.y.over = 1;
2624 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
2625 draw_context.drawinfo.y.under = hashed_process_data->height;
e800cf84 2626
2627 draw_context.drawinfo.start.offset.over = 0;
2628 draw_context.drawinfo.start.offset.middle = 0;
2629 draw_context.drawinfo.start.offset.under = 0;
2630 draw_context.drawinfo.end.offset.over = 0;
2631 draw_context.drawinfo.end.offset.middle = 0;
2632 draw_context.drawinfo.end.offset.under = 0;
9a1ec01b 2633#if 0
4b7dc462 2634 /* Jump over draw if we are at the same x position */
2635 if(x == hashed_process_data->x.over)
e800cf84 2636 {
4b7dc462 2637 /* jump */
2638 } else {
23093869 2639 draw_context.drawinfo.start.x = hashed_process_data->x.over;
2640 /* Draw the line */
2641 PropertiesLine prop_line = prepare_execmode_line(process);
2642 draw_line((void*)&prop_line, (void*)&draw_context);
2643
4b7dc462 2644 hashed_process_data->x.over = x;
23093869 2645 }
9a1ec01b 2646#endif //0
4b7dc462 2647
1d1df11d 2648 if(unlikely(x == hashed_process_data->x.middle &&
2649 hashed_process_data->x.middle_used)) {
b2743953 2650#if 0 /* do not mark closure : not missing information */
e72908ed 2651 if(hashed_process_data->x.middle_marked == FALSE) {
2652 /* Draw collision indicator */
2653 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
2654 gdk_draw_point(drawing->pixmap,
2655 drawing->gc,
2656 x,
2c6618bc 2657 y+(height/2)-3);
de4ea1ad 2658 hashed_process_data->x.middle_marked = TRUE;
e72908ed 2659 }
b2743953 2660#endif //0
4b7dc462 2661 /* Jump */
2662 } else {
23093869 2663 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
e800cf84 2664 /* Draw the line */
c4a72569 2665 if(dodraw) {
2666 PropertiesLine prop_line = prepare_s_e_line(process);
2667 draw_line((void*)&prop_line, (void*)&draw_context);
2668 }
e800cf84 2669
4b7dc462 2670 /* become the last x position */
1d1df11d 2671 if(likely(x != hashed_process_data->x.middle)) {
e72908ed 2672 hashed_process_data->x.middle = x;
2673 /* but don't use the pixel */
2674 hashed_process_data->x.middle_used = FALSE;
b2743953 2675
2676 /* Calculate the next good time */
2677 convert_pixels_to_time(width, x+1, time_window,
2678 &hashed_process_data->next_good_time);
e72908ed 2679 }
e800cf84 2680 }
e800cf84 2681 }
2682 }
2683 }
2684 return;
8b90e648 2685}
2686
b9a010a2 2687int before_chunk(void *hook_data, void *call_data)
2688{
88bf15f0 2689
b9a010a2 2690 EventsRequest *events_request = (EventsRequest*)hook_data;
88bf15f0 2691 LttvTraceset *ts = (LttvTraceset*)call_data;
cd3892fe 2692#if 0
7c0125e0 2693 /* Desactivate sort */
2694 gtk_tree_sortable_set_sort_column_id(
2695 GTK_TREE_SORTABLE(cfd->process_list->list_store),
2696 TRACE_COLUMN,
2697 GTK_SORT_ASCENDING);
cd3892fe 2698#endif //0
88bf15f0 2699 drawing_chunk_begin(events_request, ts);
b9a010a2 2700
2701 return 0;
2702}
2703
2704int before_request(void *hook_data, void *call_data)
ca0f8a8e 2705{
88bf15f0 2706
ca0f8a8e 2707 EventsRequest *events_request = (EventsRequest*)hook_data;
7c0125e0 2708
88bf15f0 2709 drawing_data_request_begin(events_request);
ca0f8a8e 2710
2711 return 0;
88bf15f0 2712
ca0f8a8e 2713}
2714
2715
8b90e648 2716/*
b9a010a2 2717 * after request is necessary in addition of after chunk in order to draw
2718 * lines until the end of the screen. after chunk just draws lines until
2719 * the last event.
2720 *
8b90e648 2721 * for each process
a56a1ba4 2722 * draw closing line
b9a010a2 2723 * expose
8b90e648 2724 */
b9a010a2 2725int after_request(void *hook_data, void *call_data)
8b90e648 2726{
88bf15f0 2727
ca0f8a8e 2728 EventsRequest *events_request = (EventsRequest*)hook_data;
2729 ControlFlowData *control_flow_data = events_request->viewer_data;
a56a1ba4 2730
5c230fc4 2731 ProcessList *process_list = control_flow_data->process_list;
b9a010a2 2732 LttTime end_time = events_request->end_time;
2733
2734 ClosureData closure_data;
2735 closure_data.events_request = (EventsRequest*)hook_data;
b9a010a2 2736 closure_data.end_time = end_time;
2737
bc8d270b 2738 TimeWindow time_window =
2739 lttvwindow_get_time_window(control_flow_data->tab);
2740 guint width = control_flow_data->drawing->width;
2741 convert_time_to_pixels(
2742 time_window,
2743 end_time,
2744 width,
2745 &closure_data.x_end);
2746
2747
b9a010a2 2748 /* Draw last items */
2749 g_hash_table_foreach(process_list->process_hash, draw_closure,
2750 (void*)&closure_data);
7c0125e0 2751
b9a010a2 2752
2753 /* Request expose */
88bf15f0 2754 drawing_request_expose(events_request, end_time);
b9a010a2 2755 return 0;
2756}
2757
2758/*
2759 * for each process
2760 * draw closing line
e800cf84 2761 * expose
b9a010a2 2762 */
2763int after_chunk(void *hook_data, void *call_data)
2764{
88bf15f0 2765
b9a010a2 2766 EventsRequest *events_request = (EventsRequest*)hook_data;
2767 ControlFlowData *control_flow_data = events_request->viewer_data;
88bf15f0
FD
2768 LttvTraceset *ts = (LttvTraceset*)call_data;
2769
b9a010a2 2770 LttTime end_time;
2771
5c230fc4 2772 ProcessList *process_list = control_flow_data->process_list;
0f090e21 2773 guint i;
88bf15f0 2774 guint nb_trace = lttv_traceset_number(ts);
b9a010a2 2775
0f090e21 2776 /* Only execute when called for the first trace's events request */
43ed82b5 2777 if(!process_list->current_hash_data)
2778 return 0;
0f090e21 2779
2780 for(i = 0 ; i < nb_trace ; i++) {
2781 g_free(process_list->current_hash_data[i]);
2782 }
40debf7b 2783 g_free(process_list->current_hash_data);
2784 process_list->current_hash_data = NULL;
0f090e21 2785
0c5dbe3b 2786 end_time = events_request->end_time;
2787
a56a1ba4 2788 ClosureData closure_data;
ca0f8a8e 2789 closure_data.events_request = (EventsRequest*)hook_data;
b9a010a2 2790 closure_data.end_time = end_time;
a56a1ba4 2791
bc8d270b 2792 TimeWindow time_window =
2793 lttvwindow_get_time_window(control_flow_data->tab);
2794 guint width = control_flow_data->drawing->width;
2795 convert_time_to_pixels(
2796 time_window,
2797 end_time,
2798 width,
2799 &closure_data.x_end);
2800
b9a010a2 2801 /* Draw last items */
14963be0 2802 g_hash_table_foreach(process_list->process_hash, draw_closure,
a56a1ba4 2803 (void*)&closure_data);
cd3892fe 2804#if 0
7c0125e0 2805 /* Reactivate sort */
2806 gtk_tree_sortable_set_sort_column_id(
2807 GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
2808 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
2809 GTK_SORT_ASCENDING);
2810
2811 update_index_to_pixmap(control_flow_data->process_list);
cd3892fe 2812 /* Request a full expose : drawing scrambled */
2813 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2814#endif //0
2815 /* Request expose (updates damages zone also) */
ca0f8a8e 2816
88bf15f0 2817 drawing_request_expose(events_request, end_time);
ca0f8a8e 2818 return 0;
8b90e648 2819}
2820
b70ceef8 2821/* after_statedump_end
2822 *
2823 * @param hook_data ControlFlowData structure of the viewer.
2824 * @param call_data Event context.
2825 *
2826 * This function adds items to be drawn in a queue for each process.
2827 *
2828 */
2829int before_statedump_end(void *hook_data, void *call_data)
2830{
88bf15f0 2831#ifdef BABEL_CLEANUP
dd455fb8 2832 LttvTraceHook *th = (LttvTraceHook*)hook_data;
2833 EventsRequest *events_request = (EventsRequest*)th->hook_data;
b70ceef8 2834 ControlFlowData *control_flow_data = events_request->viewer_data;
2835
2836 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
2837
b70ceef8 2838 LttvTracesetState *tss = (LttvTracesetState*)tfc->t_context->ts_context;
2839 ProcessList *process_list = control_flow_data->process_list;
2840
2841 LttEvent *e;
2842 e = ltt_tracefile_get_event(tfc->tf);
2843
2844 LttvFilter *filter = control_flow_data->filter;
2845 if(filter != NULL && filter->head != NULL)
2846 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
b6ef18af 2847 tfc->t_context->t,tfc,NULL,NULL))
b70ceef8 2848 return FALSE;
2849
2850 LttTime evtime = ltt_event_time(e);
2851
2852 ClosureData closure_data;
2853 closure_data.events_request = events_request;
2854 closure_data.tss = tss;
2855 closure_data.end_time = evtime;
2856
2857 TimeWindow time_window =
2858 lttvwindow_get_time_window(control_flow_data->tab);
2859 guint width = control_flow_data->drawing->width;
2860 convert_time_to_pixels(
2861 time_window,
2862 evtime,
2863 width,
2864 &closure_data.x_end);
2865
2866 /* Draw last items */
2867 g_hash_table_foreach(process_list->process_hash, draw_closure,
2868 (void*)&closure_data);
2869#if 0
2870 /* Reactivate sort */
2871 gtk_tree_sortable_set_sort_column_id(
2872 GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
2873 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
2874 GTK_SORT_ASCENDING);
2875
2876 update_index_to_pixmap(control_flow_data->process_list);
2877 /* Request a full expose : drawing scrambled */
2878 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2879#endif //0
2880 /* Request expose (updates damages zone also) */
2881 drawing_request_expose(events_request, tss, evtime);
2882
88bf15f0 2883#endif //babel_cleanup
10599fb9 2884 return 0;
b70ceef8 2885}
This page took 0.255528 seconds and 4 git commands to generate.