#include #include #include #include #include "hook.h" #include "utils.h" int xce_hook_init(hooksys_t* s, int maxtypes) { int i; if ((s == NULL) || (maxtypes <= 0)) { return -EINVAL; } s->maxtypes = 0; s->hooks = (xlist_t*)calloc(maxtypes, sizeof(xlist_t)); if (s->hooks == NULL) { return -ENOMEM; } s->maxtypes = maxtypes; for (i = 0; i < s->maxtypes; i++) { xlist_init(&(s->hooks[i]), 8); } return 0; } int xce_add_hook(hooksys_t* s, int typ, hook_fn_t fn, void* data) { hook_item_t* it; if (s == NULL) { return -EINVAL; } if (fn == NULL) { return -EINVAL; } if ((typ < 0) || (typ >= s->maxtypes)) { return -EINVAL; } /* Scan for a disabled (NULL-fn) slot of the same type to reuse */ { xlist_t* l = &s->hooks[typ]; int i; for (i = 0; i < l->count; i++) { hook_item_t* slot = (hook_item_t*)l->data[i]; if (!slot) continue; hook_fn_t cur = atomic_load_explicit(&slot->fn, memory_order_acquire); if (cur == NULL) { slot->data = data; atomic_store_explicit(&slot->fn, fn, memory_order_release); return 0; } } } /* No reusable slot — allocate new */ it = (hook_item_t*)calloc(1, sizeof(*it)); if (it == NULL) { return -ENOMEM; } it->data = data; atomic_store_explicit(&it->fn, fn, memory_order_release); xlist_store(&(s->hooks[typ]), it); return 0; } int xce_disable_hook(hooksys_t* s, int typ, hook_fn_t fn) { xlist_t* l; int i; if (!s || !fn || typ < 0 || typ >= s->maxtypes) { return -EINVAL; } l = &s->hooks[typ]; for (i = 0; i < l->count; i++) { hook_item_t* it = (hook_item_t*)l->data[i]; if (!it) continue; hook_fn_t cur = atomic_load_explicit(&it->fn, memory_order_acquire); if (cur == fn) { atomic_store_explicit(&it->fn, (hook_fn_t)NULL, memory_order_release); return 0; } } return -ENOENT; } /* HOOK_BEFORE_EVENT returns * negative value will cause * fail */ int xce_run_hooks(hooksys_t* s, int type, int situation, int detail, ...) { xlist_t* l; int i; int rc = 0; if (s == NULL) { return -EINVAL; } if ((type < 0) || (type >= s->maxtypes)) { return -EINVAL; } l = &(s->hooks[type]); for (i = 0; i < l->count; i++) { hook_item_t* it = l->data[i]; hook_fn_t local_fn; va_list ap; if (it == NULL) { continue; } local_fn = atomic_load_explicit(&it->fn, memory_order_acquire); if (!local_fn) { continue; /* disabled slot */ } va_start(ap, detail); rc = local_fn(type, situation, detail, it->data, ap); va_end(ap); if ((situation == HOOK_BEFORE_EVENT) && (rc < 0)) { break; } } return rc; } static int free_hook_item(void* data1, void* data2) { if (data1 == NULL) { return -EINVAL; } free(data1); return 0; } void xce_hook_fini(hooksys_t* s) { int i; if (s == NULL) { return; } if (s->hooks == NULL) { return; } for (i = 0; i < s->maxtypes; i++) { xlist_iter(&(s->hooks[i]), (xlist_iter_fn_t)free_hook_item, NULL); xlist_fini(&(s->hooks[i])); } FREEUP(s->hooks); }