a1a2b649 |
1 | /* This file is part of the Linux Trace Toolkit Graphic User Interface |
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 | /* This file is the API used to launch any background computation on a trace */ |
20 | |
21 | /* Here is the implementation of the API */ |
22 | |
0fdb8bb0 |
23 | #include <sys/types.h> |
24 | #include <sys/stat.h> |
25 | #include <unistd.h> |
26 | |
a1a2b649 |
27 | #include <ltt/time.h> |
28 | #include <ltt/trace.h> |
29 | #include <glib.h> |
30 | #include <lttv/lttv.h> |
31 | #include <lttv/traceset.h> |
32 | #include <lttv/attribute.h> |
33 | #include <lttv/tracecontext.h> |
34 | #include <lttvwindow/lttvwindowtraces.h> |
35 | |
36 | |
37 | typedef struct _BackgroundRequest { |
38 | LttvAttributeName module_name; /* Hook path in global attributes, |
39 | where all standard hooks under computation/. |
40 | i.e. modulename */ |
41 | LttvTrace *trace; /* trace concerned */ |
42 | } BackgroundRequest; |
43 | |
44 | typedef struct _BackgroundNotify { |
45 | gpointer owner; |
46 | LttvTrace *trace; /* trace */ |
47 | LttTime notify_time; |
48 | LttvTracesetContextPosition *notify_position; |
49 | LttvHooks *notify; /* Hook to call when the notify is |
50 | passed, or at the end of trace */ |
51 | } BackgroundNotify; |
52 | |
53 | |
54 | |
55 | /* Get a trace by its path name. |
56 | * |
57 | * @param path path of the trace on the virtual file system. |
58 | * @return Pointer to trace if found |
59 | * NULL is returned if the trace is not present |
60 | */ |
61 | |
62 | LttvTrace *lttvwindowtraces_get_trace_by_name(gchar *path) |
63 | { |
64 | LttvAttribute *attribute = lttv_global_attributes(); |
65 | guint i; |
66 | |
67 | for(i=0;i<lttvwindowtraces_get_number();i++) { |
68 | LttvTrace *trace_v = lttvwindowtraces_get_trace(i); |
69 | LttTrace *trace; |
70 | gchar *name; |
71 | |
72 | g_assert(trace_v != NULL); |
73 | |
74 | trace = lttv_trace(trace_v); |
75 | g_assert(trace != NULL); |
76 | name = ltt_trace_name(trace); |
77 | |
78 | if(strcmp(name, path) == 0) { |
79 | /* Found */ |
80 | return trace_v; |
81 | } |
82 | } |
83 | |
84 | return NULL; |
85 | } |
86 | |
87 | /* Get a trace by its number identifier */ |
88 | |
89 | LttvTrace *lttvwindowtraces_get_trace(guint num) |
90 | { |
91 | LttvAttribute *g_attribute = lttv_global_attributes(); |
92 | LttvAttribute *attribute; |
93 | LttvAttributeType type; |
94 | LttvAttributeName name; |
95 | LttvAttributeValue value; |
96 | |
97 | g_assert(attribute = |
98 | LTTV_ATTRIBUTE(lttv_iattribute_find_subdir(LTTV_IATTRIBUTE(g_attribute), |
99 | LTTV_TRACES))); |
100 | |
101 | type = lttv_iattribute_get(LTTV_IATTRIBUTE(attribute), num, &name, &value); |
102 | |
103 | if(type == LTTV_POINTER) { |
104 | return (LttvTrace *)*(value.v_pointer); |
105 | } |
106 | |
107 | return NULL; |
108 | } |
109 | |
110 | /* Total number of traces */ |
111 | |
112 | guint lttvwindowtraces_get_number() |
113 | { |
114 | LttvAttribute *g_attribute = lttv_global_attributes(); |
115 | LttvAttribute *attribute; |
116 | LttvAttributeValue value; |
117 | |
118 | g_assert(attribute = |
119 | LTTV_ATTRIBUTE(lttv_iattribute_find_subdir(LTTV_IATTRIBUTE(g_attribute), |
120 | LTTV_TRACES))); |
121 | |
122 | return ( lttv_iattribute_get_number(LTTV_IATTRIBUTE(attribute)) ); |
123 | } |
124 | |
125 | /* Add a trace to the global attributes */ |
126 | |
127 | void lttvwindowtraces_add_trace(LttvTrace *trace) |
128 | { |
129 | LttvAttribute *g_attribute = lttv_global_attributes(); |
130 | LttvAttribute *attribute; |
131 | LttvAttributeValue value; |
132 | guint num; |
0fdb8bb0 |
133 | struct stat buf; |
134 | gchar attribute_path[PATH_MAX]; |
a1a2b649 |
135 | |
0fdb8bb0 |
136 | if(stat(ltt_trace_name(lttv_trace(trace)), &buf)) { |
137 | g_warning("lttvwindowtraces_add_trace: Trace %s not found", |
138 | ltt_trace_name(lttv_trace(trace))); |
139 | return; |
140 | } |
141 | g_assert( |
142 | snprintf(attribute_path, PATH_MAX, "%lu:%lu", buf.st_dev, buf.st_ino) >= 0); |
143 | |
a1a2b649 |
144 | g_assert(attribute = |
145 | LTTV_ATTRIBUTE(lttv_iattribute_find_subdir(LTTV_IATTRIBUTE(g_attribute), |
146 | LTTV_TRACES))); |
0fdb8bb0 |
147 | |
a1a2b649 |
148 | value = lttv_attribute_add(attribute, |
0fdb8bb0 |
149 | g_quark_from_string(attribute_path), |
a1a2b649 |
150 | LTTV_POINTER); |
151 | |
152 | *(value.v_pointer) = (gpointer)trace; |
153 | } |
154 | |
155 | /* Remove a trace from the global attributes */ |
156 | |
157 | void lttvwindowtraces_remove_trace(LttvTrace *trace) |
158 | { |
159 | LttvAttribute *g_attribute = lttv_global_attributes(); |
160 | LttvAttribute *attribute; |
161 | LttvAttributeValue value; |
162 | guint i; |
163 | |
164 | g_assert(attribute = |
165 | LTTV_ATTRIBUTE(lttv_iattribute_find_subdir(LTTV_IATTRIBUTE(g_attribute), |
166 | LTTV_TRACES))); |
167 | |
168 | for(i=0;i<lttvwindowtraces_get_number();i++) { |
169 | LttvTrace *trace_v = lttvwindowtraces_get_trace(i); |
170 | |
171 | g_assert(trace_v != NULL); |
172 | |
173 | if(trace_v == trace) { |
174 | /* Found */ |
175 | lttv_attribute_remove(attribute, i); |
176 | return; |
177 | } |
178 | } |
179 | } |
180 | |
181 | |
182 | /** |
183 | * Function to request data from a specific trace |
184 | * |
185 | * The memory allocated for the request will be managed by the API. |
186 | * |
187 | * @param trace the trace to compute |
188 | * @param module_name the name of the module which registered global computation |
189 | * hooks. |
190 | */ |
191 | |
192 | void lttvwindowtraces_background_request_queue |
193 | (LttvTrace *trace, gchar *module_name) |
194 | { |
195 | BackgroundRequest *bg_req; |
196 | LttvAttribute *attribute = lttv_trace_attribute(trace); |
197 | LttvAttributeValue value; |
198 | GSList **slist; |
199 | guint num; |
200 | |
201 | g_assert(lttv_iattribute_find(LTTV_IATTRIBUTE(attribute), |
202 | LTTV_REQUESTS_QUEUE, |
203 | LTTV_POINTER, |
204 | &value)); |
205 | slist = (GSList**)(value.v_pointer); |
206 | |
207 | bg_req = g_new(BackgroundRequest,1); |
208 | bg_req->module_name = g_quark_from_string(module_name); |
209 | bg_req->trace = trace; |
210 | |
211 | *slist = g_slist_append(*slist, bg_req); |
212 | } |
213 | |
214 | /** |
215 | * Remove a background request from a trace. |
216 | * |
217 | * This should ONLY be used by the modules which registered the global hooks |
218 | * (module_name). If this is called by the viewers, it may lead to incomplete |
219 | * and incoherent background processing information. |
220 | * |
221 | * Even if the module which deals with the hooks removes the background |
222 | * requests, it may cause a problem if the module gets loaded again in the |
223 | * session : the data will be partially calculated. The calculation function |
224 | * must deal with this case correctly. |
225 | * |
226 | * @param trace the trace to compute |
227 | * @param module_name the name of the module which registered global computation |
228 | * hooks. |
229 | */ |
230 | |
231 | void lttvwindowtraces_background_request_remove |
232 | (LttvTrace *trace, gchar *module_name) |
233 | { |
234 | LttvAttribute *attribute = lttv_trace_attribute(trace); |
235 | LttvAttributeValue value; |
236 | GSList *iter = NULL; |
237 | GSList **slist; |
238 | |
239 | g_assert(lttv_iattribute_find(LTTV_IATTRIBUTE(attribute), |
240 | LTTV_REQUESTS_QUEUE, |
241 | LTTV_POINTER, |
242 | &value)); |
243 | slist = (GSList**)(value.v_pointer); |
244 | |
245 | for(iter=*slist;iter!=NULL;) { |
246 | BackgroundRequest *bg_req = |
247 | (BackgroundRequest *)iter->data; |
248 | |
249 | if(bg_req->module_name == g_quark_from_string(module_name)) { |
250 | GSList *rem_iter = iter; |
251 | iter=g_slist_next(iter); |
252 | g_free(bg_req); |
253 | *slist = g_slist_delete_link(*slist, rem_iter); |
254 | } else { |
255 | iter=g_slist_next(iter); |
256 | } |
257 | } |
258 | } |
259 | |
260 | |
261 | /** |
262 | * Register a callback to be called when requested data is passed in the next |
263 | * queued background processing. |
264 | * |
265 | * @param owner owner of the background notification |
266 | * @param trace the trace computed |
267 | * @param notify_time time when notification hooks must be called |
268 | * @param notify_position position when notification hooks must be called |
269 | * @param notify Hook to call when the notify position is passed |
270 | */ |
271 | |
272 | void lttvwindowtraces_background_notify_queue |
273 | (gpointer owner, |
274 | LttvTrace *trace, |
275 | LttTime notify_time, |
276 | const LttvTracesetContextPosition *notify_position, |
277 | const LttvHooks *notify) |
278 | { |
279 | BackgroundNotify *bg_notify; |
280 | LttvAttribute *attribute = lttv_trace_attribute(trace); |
281 | LttvAttributeValue value; |
282 | GSList **slist; |
283 | |
284 | g_assert(lttv_iattribute_find(LTTV_IATTRIBUTE(attribute), |
285 | LTTV_NOTIFY_QUEUE, |
286 | LTTV_POINTER, |
287 | &value)); |
288 | slist = (GSList**)(value.v_pointer); |
289 | |
290 | |
291 | bg_notify = g_new(BackgroundNotify,1); |
292 | |
293 | bg_notify->owner = owner; |
294 | bg_notify->trace = trace; |
295 | bg_notify->notify_time = notify_time; |
296 | bg_notify->notify_position = ltt_traceset_context_position_new(); |
297 | lttv_traceset_context_position_copy(bg_notify->notify_position, |
298 | notify_position); |
299 | bg_notify->notify = lttv_hooks_new(); |
300 | lttv_hooks_add_list(bg_notify->notify, notify); |
301 | |
302 | *slist = g_slist_append(*slist, bg_notify); |
303 | } |
304 | |
305 | /** |
306 | * Register a callback to be called when requested data is passed in the current |
307 | * background processing. |
308 | * |
309 | * @param owner owner of the background notification |
310 | * @param trace the trace computed |
311 | * @param notify_time time when notification hooks must be called |
312 | * @param notify_position position when notification hooks must be called |
313 | * @param notify Hook to call when the notify position is passed |
314 | */ |
315 | |
316 | void lttvwindowtraces_background_notify_current |
317 | (gpointer owner, |
318 | LttvTrace *trace, |
319 | LttTime notify_time, |
320 | const LttvTracesetContextPosition *notify_position, |
321 | const LttvHooks *notify) |
322 | { |
323 | BackgroundNotify *bg_notify; |
324 | LttvAttribute *attribute = lttv_trace_attribute(trace); |
325 | LttvAttributeValue value; |
326 | GSList **slist; |
327 | |
328 | g_assert(lttv_iattribute_find(LTTV_IATTRIBUTE(attribute), |
329 | LTTV_NOTIFY_CURRENT, |
330 | LTTV_POINTER, |
331 | &value)); |
332 | slist = (GSList**)(value.v_pointer); |
333 | |
334 | bg_notify = g_new(BackgroundNotify,1); |
335 | |
336 | bg_notify->owner = owner; |
337 | bg_notify->trace = trace; |
338 | bg_notify->notify_time = notify_time; |
339 | bg_notify->notify_position = ltt_traceset_context_position_new(); |
340 | lttv_traceset_context_position_copy(bg_notify->notify_position, |
341 | notify_position); |
342 | bg_notify->notify = lttv_hooks_new(); |
343 | lttv_hooks_add_list(bg_notify->notify, notify); |
344 | |
345 | *slist = g_slist_append(*slist, bg_notify); |
346 | } |
347 | |
348 | /** |
349 | * Removes all the notifications requests from a specific viewer. |
350 | * |
351 | * @param owner owner of the background notification |
352 | */ |
353 | |
354 | void lttvwindowtraces_background_notify_remove(gpointer owner) |
355 | { |
356 | guint i; |
357 | |
358 | for(i=0;i<lttvwindowtraces_get_number();i++) { |
359 | LttvAttribute *attribute; |
360 | LttvAttributeValue value; |
361 | LttvTrace *trace_v = lttvwindowtraces_get_trace(i); |
362 | GSList **slist; |
363 | GSList *iter = NULL; |
364 | |
365 | g_assert(trace_v != NULL); |
366 | |
367 | LttvAttribute *t_a = lttv_trace_attribute(trace_v); |
368 | |
369 | g_assert(lttv_iattribute_find(LTTV_IATTRIBUTE(attribute), |
370 | LTTV_NOTIFY_QUEUE, |
371 | LTTV_POINTER, |
372 | &value)); |
373 | slist = (GSList**)(value.v_pointer); |
374 | |
375 | for(iter=*slist;iter!=NULL;) { |
376 | |
377 | BackgroundNotify *bg_notify = (BackgroundNotify*)iter->data; |
378 | |
379 | if(bg_notify->owner == owner) { |
380 | GSList *rem_iter = iter; |
381 | iter=g_slist_next(iter); |
382 | lttv_traceset_context_position_destroy( |
383 | bg_notify->notify_position); |
384 | lttv_hooks_destroy(bg_notify->notify); |
385 | g_free(bg_notify); |
386 | g_slist_remove_link(*slist, rem_iter); |
387 | } else { |
388 | iter=g_slist_next(iter); |
389 | } |
390 | } |
391 | |
392 | g_assert(lttv_iattribute_find(LTTV_IATTRIBUTE(attribute), |
393 | LTTV_NOTIFY_CURRENT, |
394 | LTTV_POINTER, |
395 | &value)); |
396 | slist = (GSList**)(value.v_pointer); |
397 | |
398 | for(iter=*slist;iter!=NULL;) { |
399 | |
400 | BackgroundNotify *bg_notify = (BackgroundNotify*)iter->data; |
401 | |
402 | if(bg_notify->owner == owner) { |
403 | GSList *rem_iter = iter; |
404 | iter=g_slist_next(iter); |
405 | lttv_traceset_context_position_destroy( |
406 | bg_notify->notify_position); |
407 | lttv_hooks_destroy(bg_notify->notify); |
408 | g_free(bg_notify); |
409 | g_slist_remove_link(*slist, rem_iter); |
410 | } else { |
411 | iter=g_slist_next(iter); |
412 | } |
413 | } |
414 | } |
415 | } |
416 | |