X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=ltt%2Fbranches%2Fpoly%2Flttv%2Flttv%2Fhook.c;h=f0e535d9e6823c9b83bd3971b72fc0dce4f8b61a;hb=8436038a4e160b8916eee165b2a897d05d4bca2f;hp=a7f0960db27f9bd1b5f018c6cabb3ee8aaa9c840;hpb=d8f124de0295aea546b6debf5945bfeea2bbeb2a;p=lttv.git diff --git a/ltt/branches/poly/lttv/lttv/hook.c b/ltt/branches/poly/lttv/lttv/hook.c index a7f0960d..f0e535d9 100644 --- a/ltt/branches/poly/lttv/lttv/hook.c +++ b/ltt/branches/poly/lttv/lttv/hook.c @@ -21,10 +21,19 @@ typedef struct _LttvHookClosure { - LttvHook hook; - void *hook_data; + LttvHook hook; + void *hook_data; + LttvHookPrio prio; + guint ref_count; } LttvHookClosure; +gint lttv_hooks_prio_compare(LttvHookClosure *a, LttvHookClosure *b) +{ + if(a->prio < b->prio) return -1; + if(a->prio > b->prio) return 1; + return 0; +} + LttvHooks *lttv_hooks_new() { @@ -39,25 +48,91 @@ void lttv_hooks_destroy(LttvHooks *h) } -void lttv_hooks_add(LttvHooks *h, LttvHook f, void *hook_data) +void lttv_hooks_add(LttvHooks *h, LttvHook f, void *hook_data, LttvHookPrio p) { - LttvHookClosure c; - + LttvHookClosure *c, new_c; + guint i; + if(h == NULL)g_error("Null hook added"); - c.hook = f; - c.hook_data = hook_data; - g_array_append_val(h,c); -} + new_c.hook = f; + new_c.hook_data = hook_data; + new_c.prio = p; + /* Preliminary check for duplication */ + /* only hook and hook data is checked */ + for(i = 0; i < h->len; i++) { + c = &g_array_index(h, LttvHookClosure, i); + if(new_c.hook == c->hook && new_c.hook_data == c->hook_data) { + g_assert(new_c.prio == c->prio); + c->ref_count++; + return; + } + } + + + for(i = 0; i < h->len; i++) { + c = &g_array_index(h, LttvHookClosure, i); + if(new_c.prio < c->prio) { + g_array_insert_val(h,i,new_c); + return; + } + } + if(i == h->len) + g_array_append_val(h,new_c); +} -void lttv_hooks_add_list(LttvHooks *h, LttvHooks *list) +/* lttv_hooks_add_list + * + * Adds a sorted list into another sorted list. + * + * Note : h->len is modified, but only incremented. This assures + * its coherence through the function. + * + * j is an index to the element following the last one added in the + * destination array. + */ +void lttv_hooks_add_list(LttvHooks *h, const LttvHooks *list) { - guint i; + guint i,j,k; + LttvHookClosure *c; + const LttvHookClosure *new_c; if(list == NULL) return; - for(i = 0 ; i < list->len; i++) { - g_array_append_val(h,g_array_index(list, LttvHookClosure, i)); + for(i = 0, j = 0 ; i < list->len; i++) { + new_c = &g_array_index(list, LttvHookClosure, i); + gboolean found=FALSE; + + /* Preliminary check for duplication */ + /* only hook and hook data is checked, not priority */ + for(k = 0; k < h->len; k++) { + c = &g_array_index(h, LttvHookClosure, k); + if(new_c->hook == c->hook && new_c->hook_data == c->hook_data) { + /* Found another identical entry : increment its ref_count and + * jump over the source index */ + g_assert(new_c->prio == c->prio); + found=TRUE; + c->ref_count++; + break; + } + } + + if(!found) { + /* If not found, add it to the destination array */ + while(j < h->len) { + c = &g_array_index(h, LttvHookClosure, j); + if(new_c->prio < c->prio) { + g_array_insert_val(h,j,*new_c); + j++; + break; + } + else j++; + } + if(j == h->len) { + g_array_append_val(h,*new_c); + j++; + } + } } } @@ -73,9 +148,16 @@ void *lttv_hooks_remove(LttvHooks *h, LttvHook f) for(i = 0 ; i < h->len ; i++) { c = &g_array_index(h, LttvHookClosure, i); if(c->hook == f) { - hook_data = c->hook_data; - lttv_hooks_remove_by_position(h, i); - return hook_data; + if(c->ref_count == 1) { + hook_data = c->hook_data; + lttv_hooks_remove_by_position(h, i); + return hook_data; + } else { + g_assert(c->ref_count != 0); + c->ref_count--; + return NULL; /* We do not want anyone to free a hook_data + still referenced */ + } } } return NULL; @@ -91,8 +173,14 @@ void lttv_hooks_remove_data(LttvHooks *h, LttvHook f, void *hook_data) for(i = 0 ; i < h->len ; i++) { c = &g_array_index(h, LttvHookClosure, i); if(c->hook == f && c->hook_data == hook_data) { - lttv_hooks_remove_by_position(h, i); - return; + if(c->ref_count == 1) { + lttv_hooks_remove_by_position(h, i); + return; + } else { + g_assert(c->ref_count != 0); + c->ref_count--; + return; + } } } } @@ -109,7 +197,12 @@ void lttv_hooks_remove_list(LttvHooks *h, LttvHooks *list) c = &g_array_index(h, LttvHookClosure, i); c_list = &g_array_index(list, LttvHookClosure, j); if(c->hook == c_list->hook && c->hook_data == c_list->hook_data) { - lttv_hooks_remove_by_position(h, i); + if(c->ref_count == 1) { + lttv_hooks_remove_by_position(h, i); + } else { + g_assert(c->ref_count != 0); + c->ref_count--; + } j++; } else i++; @@ -133,13 +226,23 @@ unsigned lttv_hooks_number(LttvHooks *h) } -void lttv_hooks_get(LttvHooks *h, unsigned i, LttvHook *f, void **hook_data) +void lttv_hooks_get(LttvHooks *h, unsigned i, LttvHook *f, void **hook_data, + LttvHookPrio *p) { LttvHookClosure *c; + if(i >= h->len) + { + *f = NULL; + *hook_data = NULL; + *p = 0; + return; + } + c = &g_array_index(h, LttvHookClosure, i); *f = c->hook; *hook_data = c->hook_data; + *p = c->prio; } @@ -148,7 +251,6 @@ void lttv_hooks_remove_by_position(LttvHooks *h, unsigned i) g_array_remove_index(h, i); } - gboolean lttv_hooks_call(LttvHooks *h, void *call_data) { gboolean ret, sum_ret = FALSE; @@ -181,6 +283,107 @@ gboolean lttv_hooks_call_check(LttvHooks *h, void *call_data) return FALSE; } +gboolean lttv_hooks_call_merge(LttvHooks *h1, void *call_data1, + LttvHooks *h2, void *call_data2) +{ + gboolean ret, sum_ret = FALSE; + + LttvHookClosure *c1, *c2; + + guint i, j; + + if(h1 != NULL && h2 != NULL) { + for(i = 0, j = 0 ; i < h1->len && j < h2->len ;) { + c1 = &g_array_index(h1, LttvHookClosure, i); + c2 = &g_array_index(h2, LttvHookClosure, j); + if(c1->prio <= c2->prio) { + ret = c1->hook(c1->hook_data,call_data1); + sum_ret = sum_ret || ret; + i++; + } + else { + ret = c2->hook(c2->hook_data,call_data2); + sum_ret = sum_ret || ret; + j++; + } + } + /* Finish the last list with hooks left */ + for(;i < h1->len; i++) { + c1 = &g_array_index(h1, LttvHookClosure, i); + ret = c1->hook(c1->hook_data,call_data1); + sum_ret = sum_ret || ret; + } + for(;j < h2->len; j++) { + c2 = &g_array_index(h2, LttvHookClosure, j); + ret = c2->hook(c2->hook_data,call_data2); + sum_ret = sum_ret || ret; + } + } + else if(h1 != NULL && h2 == NULL) { + for(i = 0 ; i < h1->len ; i++) { + c1 = &g_array_index(h1, LttvHookClosure, i); + ret = c1->hook(c1->hook_data,call_data1); + sum_ret = sum_ret || ret; + } + } + else if(h1 == NULL && h2 != NULL) { + for(j = 0 ; j < h2->len ; j++) { + c2 = &g_array_index(h2, LttvHookClosure, j); + ret = c2->hook(c2->hook_data,call_data2); + sum_ret = sum_ret || ret; + } + } + + return sum_ret; +} + +gboolean lttv_hooks_call_check_merge(LttvHooks *h1, void *call_data1, + LttvHooks *h2, void *call_data2) +{ + LttvHookClosure *c1, *c2; + + guint i, j; + + if(h1 != NULL && h2 != NULL) { + for(i = 0, j = 0 ; i < h1->len && j < h2->len ;) { + c1 = &g_array_index(h1, LttvHookClosure, i); + c2 = &g_array_index(h2, LttvHookClosure, j); + if(c1->prio <= c2->prio) { + if(c1->hook(c1->hook_data,call_data1)) return TRUE; + i++; + } + else { + if(c2->hook(c2->hook_data,call_data2)) return TRUE; + j++; + } + } + /* Finish the last list with hooks left */ + for(;i < h1->len; i++) { + c1 = &g_array_index(h1, LttvHookClosure, i); + if(c1->hook(c1->hook_data,call_data1)) return TRUE; + } + for(;j < h2->len; j++) { + c2 = &g_array_index(h2, LttvHookClosure, j); + if(c2->hook(c2->hook_data,call_data2)) return TRUE; + } + } + else if(h1 != NULL && h2 == NULL) { + for(i = 0 ; i < h1->len ; i++) { + c1 = &g_array_index(h1, LttvHookClosure, i); + if(c1->hook(c1->hook_data,call_data1)) return TRUE; + } + } + else if(h1 == NULL && h2 != NULL) { + for(j = 0 ; j < h2->len ; j++) { + c2 = &g_array_index(h2, LttvHookClosure, j); + if(c2->hook(c2->hook_data,call_data2)) return TRUE; + } + } + + return FALSE; + +} + LttvHooksById *lttv_hooks_by_id_new() {