Update FSF address
[lttv.git] / 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
b9ce0bad
YB
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16 * MA 02110-1301, USA.
9c312311 17 */
18
4e4d11b3 19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
ffd54a90 22
3d218f2a 23#include <lttv/hook.h>
d04fa838 24#include <stdio.h>
eccb5352 25
dc877563 26typedef struct _LttvHookClosure {
90e19f82
AM
27 LttvHook hook;
28 void *hook_data;
29 LttvHookPrio prio;
30 guint ref_count;
dc877563 31} LttvHookClosure;
eccb5352 32
47e76340 33gint lttv_hooks_prio_compare(LttvHookClosure *a, LttvHookClosure *b)
34{
90e19f82
AM
35 gint ret=0;
36 if(a->prio < b->prio) ret = -1;
37 else if(a->prio > b->prio) ret = 1;
38 return ret;
47e76340 39}
40
eccb5352 41
7a4bdb54 42LttvHooks *lttv_hooks_new(void)
dc877563 43{
90e19f82 44 return g_array_new(FALSE, FALSE, sizeof(LttvHookClosure));
eccb5352 45}
46
dc877563 47
48void lttv_hooks_destroy(LttvHooks *h)
49{
90e19f82
AM
50 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "lttv_hooks_destroy()");
51 g_array_free(h, TRUE);
eccb5352 52}
53
eccb5352 54
47e76340 55void lttv_hooks_add(LttvHooks *h, LttvHook f, void *hook_data, LttvHookPrio p)
dc877563 56{
90e19f82
AM
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);
eccb5352 88}
89
bb545b3c 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 */
100void lttv_hooks_add_list(LttvHooks *h, const LttvHooks *list)
dc877563 101{
90e19f82
AM
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 }
dc877563 143}
144
145
146void *lttv_hooks_remove(LttvHooks *h, LttvHook f)
147{
90e19f82
AM
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;
dc877563 170}
171
172
173void lttv_hooks_remove_data(LttvHooks *h, LttvHook f, void *hook_data)
eccb5352 174{
90e19f82
AM
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 }
dc877563 192}
193
194
27fb4fd2 195void lttv_hooks_remove_list(LttvHooks *h, const LttvHooks *list)
dc877563 196{
90e19f82
AM
197 guint i, j;
198
199 LttvHookClosure *c, *c_list;
200
201 if(list == NULL) return;
27fb4fd2
YB
202 g_assert(h != list);
203 /* This iteration assume that both list are in the same order */
90e19f82
AM
204 for(i = 0, j = 0 ; i < h->len && j < list->len ;) {
205 c = &g_array_index(h, LttvHookClosure, i);
206 c_list = &g_array_index(list, LttvHookClosure, j);
207 if(c->hook == c_list->hook && c->hook_data == c_list->hook_data) {
208 if(c->ref_count == 1) {
27fb4fd2 209 int count = h->len;
90e19f82 210 lttv_hooks_remove_by_position(h, i);
27fb4fd2 211 g_assert((count-1) == h->len);
90e19f82
AM
212 } else {
213 g_assert(c->ref_count != 0);
214 c->ref_count--;
215 }
216 j++;
217 }
218 else i++;
219 }
220
221 /* Normally the hooks in h are ordered as in list. If this is not the case,
222 try harder here. */
223
224 if(unlikely(j < list->len)) {
225 for(; j < list->len ; j++) {
226 c_list = &g_array_index(list, LttvHookClosure, j);
227 lttv_hooks_remove_data(h, c_list->hook, c_list->hook_data);
228 }
229 }
eccb5352 230}
231
232
dc877563 233unsigned lttv_hooks_number(LttvHooks *h)
234{
90e19f82 235 return h->len;
dc877563 236}
eccb5352 237
dc877563 238
47e76340 239void lttv_hooks_get(LttvHooks *h, unsigned i, LttvHook *f, void **hook_data,
90e19f82 240 LttvHookPrio *p)
dc877563 241{
90e19f82
AM
242 LttvHookClosure *c;
243
244 if(unlikely(i >= h->len))
245 {
246 *f = NULL;
247 *hook_data = NULL;
248 *p = 0;
249 return;
250 }
251
252 c = &g_array_index(h, LttvHookClosure, i);
253 *f = c->hook;
254 *hook_data = c->hook_data;
255 *p = c->prio;
dc877563 256}
257
258
ffd54a90 259void lttv_hooks_remove_by_position(LttvHooks *h, unsigned i)
dc877563 260{
90e19f82 261 g_array_remove_index(h, i);
dc877563 262}
263
dc877563 264gboolean lttv_hooks_call(LttvHooks *h, void *call_data)
265{
90e19f82 266 gboolean ret, sum_ret = FALSE;
dc877563 267
90e19f82 268 LttvHookClosure *c;
dc877563 269
90e19f82 270 guint i;
ffd54a90 271
90e19f82
AM
272 if(likely(h != NULL)) {
273 for(i = 0 ; i < h->len ; i++) {
274 c = &g_array_index(h, LttvHookClosure, i);
275 ret = c->hook(c->hook_data,call_data);
276 sum_ret = sum_ret || ret;
277 }
278 }
279 return sum_ret;
dc877563 280}
281
282
283gboolean lttv_hooks_call_check(LttvHooks *h, void *call_data)
284{
90e19f82 285 LttvHookClosure *c;
dc877563 286
90e19f82 287 guint i;
ffd54a90 288
90e19f82
AM
289 for(i = 0 ; i < h->len ; i++) {
290 c = &g_array_index(h, LttvHookClosure, i);
291 if(unlikely(c->hook(c->hook_data,call_data))) return TRUE;
292 }
293 return FALSE;
dc877563 294}
295
1d1df11d 296/* Optimised for h1 == NULL, h2 != NULL. This is the case
297 * for optimised computation (with specific by id hooks, but
298 * no main hooks).
299 *
300 * The second case that should occur the most often is
301 * h1 != NULL , h2 == NULL.
302 */
78b82ded 303gint lttv_hooks_call_merge(LttvHooks *h1, void *call_data1,
90e19f82 304 LttvHooks *h2, void *call_data2)
47e76340 305{
90e19f82
AM
306 gint ret, sum_ret = 0;
307
308 LttvHookClosure *c1, *c2;
309
310 guint i, j;
311
312 if(unlikely(h1 != NULL)) {
313 if(unlikely(h2 != NULL)) {
314 for(i = 0, j = 0 ; i < h1->len && j < h2->len ;) {
315 c1 = &g_array_index(h1, LttvHookClosure, i);
316 c2 = &g_array_index(h2, LttvHookClosure, j);
317 if(c1->prio <= c2->prio) {
318 ret = c1->hook(c1->hook_data,call_data1);
319 sum_ret = sum_ret | ret;
320 i++;
321 } else {
322 ret = c2->hook(c2->hook_data,call_data2);
323 sum_ret = sum_ret | ret;
324 j++;
325 }
326 }
327 /* Finish the last list with hooks left */
328 for(;i < h1->len; i++) {
329 c1 = &g_array_index(h1, LttvHookClosure, i);
330 ret = c1->hook(c1->hook_data,call_data1);
331 sum_ret = sum_ret | ret;
332 }
333 for(;j < h2->len; j++) {
334 c2 = &g_array_index(h2, LttvHookClosure, j);
335 ret = c2->hook(c2->hook_data,call_data2);
336 sum_ret = sum_ret | ret;
337 }
338 } else { /* h1 != NULL && h2 == NULL */
339 for(i = 0 ; i < h1->len ; i++) {
340 c1 = &g_array_index(h1, LttvHookClosure, i);
341 ret = c1->hook(c1->hook_data,call_data1);
342 sum_ret = sum_ret | ret;
343 }
344 }
345 } else if(likely(h2 != NULL)) { /* h1 == NULL && h2 != NULL */
346 for(j = 0 ; j < h2->len ; j++) {
347 c2 = &g_array_index(h2, LttvHookClosure, j);
348 ret = c2->hook(c2->hook_data,call_data2);
349 sum_ret = sum_ret | ret;
350 }
351 }
352
353 return sum_ret;
47e76340 354}
355
356gboolean lttv_hooks_call_check_merge(LttvHooks *h1, void *call_data1,
90e19f82 357 LttvHooks *h2, void *call_data2)
47e76340 358{
90e19f82
AM
359 LttvHookClosure *c1, *c2;
360
361 guint i, j;
362
363 if(unlikely(h1 != NULL)) {
364 if(unlikely(h2 != NULL)) {
365 for(i = 0, j = 0 ; i < h1->len && j < h2->len ;) {
366 c1 = &g_array_index(h1, LttvHookClosure, i);
367 c2 = &g_array_index(h2, LttvHookClosure, j);
368 if(c1->prio <= c2->prio) {
369 if(c1->hook(c1->hook_data,call_data1)) return TRUE;
370 i++;
371 } else {
372 if(c2->hook(c2->hook_data,call_data2)) return TRUE;
373 j++;
374 }
375 }
376 /* Finish the last list with hooks left */
377 for(;i < h1->len; i++) {
378 c1 = &g_array_index(h1, LttvHookClosure, i);
379 if(c1->hook(c1->hook_data,call_data1)) return TRUE;
380 }
381 for(;j < h2->len; j++) {
382 c2 = &g_array_index(h2, LttvHookClosure, j);
383 if(c2->hook(c2->hook_data,call_data2)) return TRUE;
384 }
385 } else { /* h2 == NULL && h1 != NULL */
386 for(i = 0 ; i < h1->len ; i++) {
387 c1 = &g_array_index(h1, LttvHookClosure, i);
388 if(c1->hook(c1->hook_data,call_data1)) return TRUE;
389 }
390 }
391 } else if(likely(h2 != NULL)) { /* h1 == NULL && h2 != NULL */
392 for(j = 0 ; j < h2->len ; j++) {
393 c2 = &g_array_index(h2, LttvHookClosure, j);
394 if(c2->hook(c2->hook_data,call_data2)) return TRUE;
395 }
396 }
397
398 return FALSE;
750eb11a 399}
27fb4fd2
YB
400
401
402void lttv_hooks_print(const LttvHooks *h)
403{
27fb4fd2
YB
404 LttvHookClosure *c;
405
406 guint i;
407
408 if(likely(h != NULL)) {
409 for(i = 0 ; i < h->len ; i++) {
410 c = &g_array_index(h, LttvHookClosure, i);
411 printf("%p:%i:%i,", c->hook, c->ref_count, c->prio);
412 }
413 printf("\n");
414 }
415
416}
This page took 0.088051 seconds and 4 git commands to generate.