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