Add config.h support : will fix the LARGEFILE problem
[lttv.git] / ltt / branches / poly / lttv / lttv / hook.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <lttv/hook.h>
24 #include <ltt/compiler.h>
25
26 typedef struct _LttvHookClosure {
27 LttvHook hook;
28 void *hook_data;
29 LttvHookPrio prio;
30 guint ref_count;
31 } LttvHookClosure;
32
33 gint lttv_hooks_prio_compare(LttvHookClosure *a, LttvHookClosure *b)
34 {
35 gint ret=0;
36 if(a->prio < b->prio) ret = -1;
37 else if(a->prio > b->prio) ret = 1;
38 return ret;
39 }
40
41
42 LttvHooks *lttv_hooks_new()
43 {
44 return g_array_new(FALSE, FALSE, sizeof(LttvHookClosure));
45 }
46
47
48 void lttv_hooks_destroy(LttvHooks *h)
49 {
50 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "lttv_hooks_destroy()");
51 g_array_free(h, TRUE);
52 }
53
54
55 void lttv_hooks_add(LttvHooks *h, LttvHook f, void *hook_data, LttvHookPrio p)
56 {
57 LttvHookClosure *c, new_c;
58 guint i;
59
60 if(unlikely(h == NULL))g_error("Null hook added");
61
62 new_c.hook = f;
63 new_c.hook_data = hook_data;
64 new_c.prio = p;
65 new_c.ref_count = 1;
66
67 /* Preliminary check for duplication */
68 /* only hook and hook data is checked */
69 for(i = 0; i < h->len; i++) {
70 c = &g_array_index(h, LttvHookClosure, i);
71 if(new_c.hook == c->hook && new_c.hook_data == c->hook_data) {
72 g_assert(new_c.prio == c->prio);
73 c->ref_count++;
74 return;
75 }
76 }
77
78
79 for(i = 0; i < h->len; i++) {
80 c = &g_array_index(h, LttvHookClosure, i);
81 if(new_c.prio < c->prio) {
82 g_array_insert_val(h,i,new_c);
83 return;
84 }
85 }
86 if(i == h->len)
87 g_array_append_val(h,new_c);
88 }
89
90 /* lttv_hooks_add_list
91 *
92 * Adds a sorted list into another sorted list.
93 *
94 * Note : h->len is modified, but only incremented. This assures
95 * its coherence through the function.
96 *
97 * j is an index to the element following the last one added in the
98 * destination array.
99 */
100 void lttv_hooks_add_list(LttvHooks *h, const LttvHooks *list)
101 {
102 guint i,j,k;
103 LttvHookClosure *c;
104 const LttvHookClosure *new_c;
105
106 if(unlikely(list == NULL)) return;
107
108 for(i = 0, j = 0 ; i < list->len; i++) {
109 new_c = &g_array_index(list, LttvHookClosure, i);
110 gboolean found=FALSE;
111
112 /* Preliminary check for duplication */
113 /* only hook and hook data is checked, not priority */
114 for(k = 0; k < h->len; k++) {
115 c = &g_array_index(h, LttvHookClosure, k);
116 if(new_c->hook == c->hook && new_c->hook_data == c->hook_data) {
117 /* Found another identical entry : increment its ref_count and
118 * jump over the source index */
119 g_assert(new_c->prio == c->prio);
120 found=TRUE;
121 c->ref_count++;
122 break;
123 }
124 }
125
126 if(!found) {
127 /* If not found, add it to the destination array */
128 while(j < h->len) {
129 c = &g_array_index(h, LttvHookClosure, j);
130 if(new_c->prio < c->prio) {
131 g_array_insert_val(h,j,*new_c);
132 j++;
133 break;
134 }
135 else j++;
136 }
137 if(j == h->len) {
138 g_array_append_val(h,*new_c);
139 j++;
140 }
141 }
142 }
143 }
144
145
146 void *lttv_hooks_remove(LttvHooks *h, LttvHook f)
147 {
148 unsigned i;
149
150 void *hook_data;
151
152 LttvHookClosure *c;
153
154 for(i = 0 ; i < h->len ; i++) {
155 c = &g_array_index(h, LttvHookClosure, i);
156 if(c->hook == f) {
157 if(c->ref_count == 1) {
158 hook_data = c->hook_data;
159 lttv_hooks_remove_by_position(h, i);
160 return hook_data;
161 } else {
162 g_assert(c->ref_count != 0);
163 c->ref_count--;
164 return NULL; /* We do not want anyone to free a hook_data
165 still referenced */
166 }
167 }
168 }
169 return NULL;
170 }
171
172
173 void lttv_hooks_remove_data(LttvHooks *h, LttvHook f, void *hook_data)
174 {
175 unsigned i;
176
177 LttvHookClosure *c;
178
179 for(i = 0 ; i < h->len ; i++) {
180 c = &g_array_index(h, LttvHookClosure, i);
181 if(c->hook == f && c->hook_data == hook_data) {
182 if(c->ref_count == 1) {
183 lttv_hooks_remove_by_position(h, i);
184 return;
185 } else {
186 g_assert(c->ref_count != 0);
187 c->ref_count--;
188 return;
189 }
190 }
191 }
192 }
193
194
195 void lttv_hooks_remove_list(LttvHooks *h, LttvHooks *list)
196 {
197 guint i, j;
198
199 LttvHookClosure *c, *c_list;
200
201 if(list == NULL) return;
202 for(i = 0, j = 0 ; i < h->len && j < list->len ;) {
203 c = &g_array_index(h, LttvHookClosure, i);
204 c_list = &g_array_index(list, LttvHookClosure, j);
205 if(c->hook == c_list->hook && c->hook_data == c_list->hook_data) {
206 if(c->ref_count == 1) {
207 lttv_hooks_remove_by_position(h, i);
208 } else {
209 g_assert(c->ref_count != 0);
210 c->ref_count--;
211 }
212 j++;
213 }
214 else i++;
215 }
216
217 /* Normally the hooks in h are ordered as in list. If this is not the case,
218 try harder here. */
219
220 if(unlikely(j < list->len)) {
221 for(; j < list->len ; j++) {
222 c_list = &g_array_index(list, LttvHookClosure, j);
223 lttv_hooks_remove_data(h, c_list->hook, c_list->hook_data);
224 }
225 }
226 }
227
228
229 unsigned lttv_hooks_number(LttvHooks *h)
230 {
231 return h->len;
232 }
233
234
235 void lttv_hooks_get(LttvHooks *h, unsigned i, LttvHook *f, void **hook_data,
236 LttvHookPrio *p)
237 {
238 LttvHookClosure *c;
239
240 if(unlikely(i >= h->len))
241 {
242 *f = NULL;
243 *hook_data = NULL;
244 *p = 0;
245 return;
246 }
247
248 c = &g_array_index(h, LttvHookClosure, i);
249 *f = c->hook;
250 *hook_data = c->hook_data;
251 *p = c->prio;
252 }
253
254
255 void lttv_hooks_remove_by_position(LttvHooks *h, unsigned i)
256 {
257 g_array_remove_index(h, i);
258 }
259
260 gboolean lttv_hooks_call(LttvHooks *h, void *call_data)
261 {
262 gboolean ret, sum_ret = FALSE;
263
264 LttvHookClosure *c;
265
266 guint i;
267
268 if(likely(h != NULL)) {
269 for(i = 0 ; i < h->len ; i++) {
270 c = &g_array_index(h, LttvHookClosure, i);
271 ret = c->hook(c->hook_data,call_data);
272 sum_ret = sum_ret || ret;
273 }
274 }
275 return sum_ret;
276 }
277
278
279 gboolean lttv_hooks_call_check(LttvHooks *h, void *call_data)
280 {
281 LttvHookClosure *c;
282
283 guint i;
284
285 for(i = 0 ; i < h->len ; i++) {
286 c = &g_array_index(h, LttvHookClosure, i);
287 if(unlikely(c->hook(c->hook_data,call_data))) return TRUE;
288 }
289 return FALSE;
290 }
291
292 /* Optimised for h1 == NULL, h2 != NULL. This is the case
293 * for optimised computation (with specific by id hooks, but
294 * no main hooks).
295 *
296 * The second case that should occur the most often is
297 * h1 != NULL , h2 == NULL.
298 */
299 gboolean lttv_hooks_call_merge(LttvHooks *h1, void *call_data1,
300 LttvHooks *h2, void *call_data2)
301 {
302 gboolean ret, sum_ret = FALSE;
303
304 LttvHookClosure *c1, *c2;
305
306 guint i, j;
307
308 if(unlikely(h1 != NULL)) {
309 if(unlikely(h2 != NULL)) {
310 for(i = 0, j = 0 ; i < h1->len && j < h2->len ;) {
311 c1 = &g_array_index(h1, LttvHookClosure, i);
312 c2 = &g_array_index(h2, LttvHookClosure, j);
313 if(c1->prio <= c2->prio) {
314 ret = c1->hook(c1->hook_data,call_data1);
315 sum_ret = sum_ret || ret;
316 i++;
317 }
318 else {
319 ret = c2->hook(c2->hook_data,call_data2);
320 sum_ret = sum_ret || ret;
321 j++;
322 }
323 }
324 /* Finish the last list with hooks left */
325 for(;i < h1->len; i++) {
326 c1 = &g_array_index(h1, LttvHookClosure, i);
327 ret = c1->hook(c1->hook_data,call_data1);
328 sum_ret = sum_ret || ret;
329 }
330 for(;j < h2->len; j++) {
331 c2 = &g_array_index(h2, LttvHookClosure, j);
332 ret = c2->hook(c2->hook_data,call_data2);
333 sum_ret = sum_ret || ret;
334 }
335 } else { /* h1 != NULL && h2 == NULL */
336 for(i = 0 ; i < h1->len ; i++) {
337 c1 = &g_array_index(h1, LttvHookClosure, i);
338 ret = c1->hook(c1->hook_data,call_data1);
339 sum_ret = sum_ret || ret;
340 }
341 }
342 } else if(likely(h2 != NULL)) { /* h1 == NULL && h2 != NULL */
343 for(j = 0 ; j < h2->len ; j++) {
344 c2 = &g_array_index(h2, LttvHookClosure, j);
345 ret = c2->hook(c2->hook_data,call_data2);
346 sum_ret = sum_ret || ret;
347 }
348 }
349
350 return sum_ret;
351 }
352
353 gboolean lttv_hooks_call_check_merge(LttvHooks *h1, void *call_data1,
354 LttvHooks *h2, void *call_data2)
355 {
356 LttvHookClosure *c1, *c2;
357
358 guint i, j;
359
360 if(unlikely(h1 != NULL)) {
361 if(unlikely(h2 != NULL)) {
362 for(i = 0, j = 0 ; i < h1->len && j < h2->len ;) {
363 c1 = &g_array_index(h1, LttvHookClosure, i);
364 c2 = &g_array_index(h2, LttvHookClosure, j);
365 if(c1->prio <= c2->prio) {
366 if(c1->hook(c1->hook_data,call_data1)) return TRUE;
367 i++;
368 }
369 else {
370 if(c2->hook(c2->hook_data,call_data2)) return TRUE;
371 j++;
372 }
373 }
374 /* Finish the last list with hooks left */
375 for(;i < h1->len; i++) {
376 c1 = &g_array_index(h1, LttvHookClosure, i);
377 if(c1->hook(c1->hook_data,call_data1)) return TRUE;
378 }
379 for(;j < h2->len; j++) {
380 c2 = &g_array_index(h2, LttvHookClosure, j);
381 if(c2->hook(c2->hook_data,call_data2)) return TRUE;
382 }
383 } else { /* h2 == NULL && h1 != NULL */
384 for(i = 0 ; i < h1->len ; i++) {
385 c1 = &g_array_index(h1, LttvHookClosure, i);
386 if(c1->hook(c1->hook_data,call_data1)) return TRUE;
387 }
388 }
389 } else if(likely(h2 != NULL)) { /* h1 == NULL && h2 != NULL */
390 for(j = 0 ; j < h2->len ; j++) {
391 c2 = &g_array_index(h2, LttvHookClosure, j);
392 if(c2->hook(c2->hook_data,call_data2)) return TRUE;
393 }
394 }
395
396 return FALSE;
397
398 }
399
400
401 LttvHooksById *lttv_hooks_by_id_new()
402 {
403 return g_ptr_array_new();
404 }
405
406
407 void lttv_hooks_by_id_destroy(LttvHooksById *h)
408 {
409 guint i;
410
411 for(i = 0 ; i < h->len ; i++) {
412 if(h->pdata[i] != NULL) lttv_hooks_destroy((LttvHooks *)(h->pdata[i]));
413 }
414 g_ptr_array_free(h, TRUE);
415 }
416
417 /* Optimised for searching an existing hook */
418 LttvHooks *lttv_hooks_by_id_find(LttvHooksById *h, unsigned id)
419 {
420 if(unlikely(h->len <= id)) g_ptr_array_set_size(h, id + 1);
421 if(unlikely(h->pdata[id] == NULL)) h->pdata[id] = lttv_hooks_new();
422 return h->pdata[id];
423 }
424
425
426 unsigned lttv_hooks_by_id_max_id(LttvHooksById *h)
427 {
428 return h->len;
429 }
430
431 void lttv_hooks_by_id_remove(LttvHooksById *h, unsigned id)
432 {
433 if(likely(id < h->len && h->pdata[id] != NULL)) {
434 lttv_hooks_destroy((LttvHooks *)h->pdata[id]);
435 h->pdata[id] = NULL;
436 }
437 }
438
This page took 0.038793 seconds and 4 git commands to generate.