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