likely/unlikely branch prediction
[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 #include <ltt/compiler.h>
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 gint ret=0;
33 if(a->prio < b->prio) ret = -1;
34 else if(a->prio > b->prio) ret = 1;
35 return ret;
36 }
37
38
39 LttvHooks *lttv_hooks_new()
40 {
41 return g_array_new(FALSE, FALSE, sizeof(LttvHookClosure));
42 }
43
44
45 void lttv_hooks_destroy(LttvHooks *h)
46 {
47 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "lttv_hooks_destroy()");
48 g_array_free(h, TRUE);
49 }
50
51
52 void lttv_hooks_add(LttvHooks *h, LttvHook f, void *hook_data, LttvHookPrio p)
53 {
54 LttvHookClosure *c, new_c;
55 guint i;
56
57 if(unlikely(h == NULL))g_error("Null hook added");
58
59 new_c.hook = f;
60 new_c.hook_data = hook_data;
61 new_c.prio = p;
62 new_c.ref_count = 1;
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
76 for(i = 0; i < h->len; i++) {
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);
85 }
86
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 */
97 void lttv_hooks_add_list(LttvHooks *h, const LttvHooks *list)
98 {
99 guint i,j,k;
100 LttvHookClosure *c;
101 const LttvHookClosure *new_c;
102
103 if(unlikely(list == NULL)) return;
104
105 for(i = 0, j = 0 ; i < list->len; i++) {
106 new_c = &g_array_index(list, LttvHookClosure, i);
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++;
119 break;
120 }
121 }
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 }
138 }
139 }
140 }
141
142
143 void *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) {
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 }
164 }
165 }
166 return NULL;
167 }
168
169
170 void lttv_hooks_remove_data(LttvHooks *h, LttvHook f, void *hook_data)
171 {
172 unsigned i;
173
174 LttvHookClosure *c;
175
176 for(i = 0 ; i < h->len ; i++) {
177 c = &g_array_index(h, LttvHookClosure, i);
178 if(c->hook == f && c->hook_data == hook_data) {
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 }
187 }
188 }
189 }
190
191
192 void lttv_hooks_remove_list(LttvHooks *h, LttvHooks *list)
193 {
194 guint i, j;
195
196 LttvHookClosure *c, *c_list;
197
198 if(list == NULL) return;
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) {
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 }
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
217 if(unlikely(j < list->len)) {
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 }
222 }
223 }
224
225
226 unsigned lttv_hooks_number(LttvHooks *h)
227 {
228 return h->len;
229 }
230
231
232 void lttv_hooks_get(LttvHooks *h, unsigned i, LttvHook *f, void **hook_data,
233 LttvHookPrio *p)
234 {
235 LttvHookClosure *c;
236
237 if(unlikely(i >= h->len))
238 {
239 *f = NULL;
240 *hook_data = NULL;
241 *p = 0;
242 return;
243 }
244
245 c = &g_array_index(h, LttvHookClosure, i);
246 *f = c->hook;
247 *hook_data = c->hook_data;
248 *p = c->prio;
249 }
250
251
252 void lttv_hooks_remove_by_position(LttvHooks *h, unsigned i)
253 {
254 g_array_remove_index(h, i);
255 }
256
257 gboolean lttv_hooks_call(LttvHooks *h, void *call_data)
258 {
259 gboolean ret, sum_ret = FALSE;
260
261 LttvHookClosure *c;
262
263 guint i;
264
265 if(likely(h != NULL)) {
266 for(i = 0 ; i < h->len ; i++) {
267 c = &g_array_index(h, LttvHookClosure, i);
268 ret = c->hook(c->hook_data,call_data);
269 sum_ret = sum_ret || ret;
270 }
271 }
272 return sum_ret;
273 }
274
275
276 gboolean lttv_hooks_call_check(LttvHooks *h, void *call_data)
277 {
278 LttvHookClosure *c;
279
280 guint i;
281
282 for(i = 0 ; i < h->len ; i++) {
283 c = &g_array_index(h, LttvHookClosure, i);
284 if(unlikely(c->hook(c->hook_data,call_data))) return TRUE;
285 }
286 return FALSE;
287 }
288
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 */
296 gboolean 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
305 if(unlikely(h1 != NULL)) {
306 if(unlikely(h2 != NULL)) {
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);
324 ret = c1->hook(c1->hook_data,call_data1);
325 sum_ret = sum_ret || ret;
326 }
327 for(;j < h2->len; j++) {
328 c2 = &g_array_index(h2, LttvHookClosure, j);
329 ret = c2->hook(c2->hook_data,call_data2);
330 sum_ret = sum_ret || ret;
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;
337 }
338 }
339 } else if(likely(h2 != NULL)) { /* h1 == NULL && h2 != NULL */
340 for(j = 0 ; j < h2->len ; j++) {
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
350 gboolean 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
357 if(unlikely(h1 != NULL)) {
358 if(unlikely(h2 != NULL)) {
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);
374 if(c1->hook(c1->hook_data,call_data1)) return TRUE;
375 }
376 for(;j < h2->len; j++) {
377 c2 = &g_array_index(h2, LttvHookClosure, j);
378 if(c2->hook(c2->hook_data,call_data2)) return TRUE;
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;
384 }
385 }
386 } else if(likely(h2 != NULL)) { /* h1 == NULL && h2 != NULL */
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 }
392
393 return FALSE;
394
395 }
396
397
398 LttvHooksById *lttv_hooks_by_id_new()
399 {
400 return g_ptr_array_new();
401 }
402
403
404 void 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 }
411 g_ptr_array_free(h, TRUE);
412 }
413
414 /* Optimised for searching an existing hook */
415 LttvHooks *lttv_hooks_by_id_find(LttvHooksById *h, unsigned id)
416 {
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();
419 return h->pdata[id];
420 }
421
422
423 unsigned lttv_hooks_by_id_max_id(LttvHooksById *h)
424 {
425 return h->len;
426 }
427
428 void lttv_hooks_by_id_remove(LttvHooksById *h, unsigned id)
429 {
430 if(likely(id < h->len && h->pdata[id] != NULL)) {
431 lttv_hooks_destroy((LttvHooks *)h->pdata[id]);
432 h->pdata[id] = NULL;
433 }
434 }
435
This page took 0.037104 seconds and 4 git commands to generate.