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