Index: sys/kern/subr_eventhandler.c =================================================================== --- sys/kern/subr_eventhandler.c +++ sys/kern/subr_eventhandler.c @@ -37,6 +37,7 @@ #include #include #include +#include #include static MALLOC_DEFINE(M_EVENTHANDLER, "eventhandler", "Event handler records"); @@ -317,3 +318,226 @@ return (list); } + +/* + * Static event handler points. + */ +static void +static_eventhandler_validate(struct static_eventhandler *seh) +{ + int i; + + for (i = 0; i < seh->count; i++) { + if (seh->cb[i] != NULL) { + switch (seh->prio[i]) { + case STATIC_EVENTHANDLER_PRIO_FIRST: + case STATIC_EVENTHANDLER_PRIO_ANY: + case STATIC_EVENTHANDLER_PRIO_LAST: + break; + default: + case STATIC_EVENTHANDLER_PRIO_INVALID: + panic("seh %p bad priority %d at %d\n", seh, seh->prio[i], i); + break; + } + } + } + + for (i = 1; i < seh->count; i++) { + if (seh->prio[i] < seh->prio[i - 1]) { + panic("seh %p unsorted priorities (%d < %d) at %d\n", seh, + seh->prio[i], seh->prio[i - 1], i); + } + } + + for (i = seh->count; i < seh->size; i++) { + if (seh->cb[i] != NULL) { + panic("seh %p callback %p found past the end\n", seh, + seh->cb[i]); + } + if (seh->prio[i] != STATIC_EVENTHANDLER_PRIO_INVALID) { + panic("seh %p prio %d found past the end\n", seh, + seh->prio[i]); + } + } +} + +static void +static_eventhandler_assert_prio(struct static_eventhandler *seh, + enum static_eventhandler_prio prio) +{ + + switch (prio) { + case STATIC_EVENTHANDLER_PRIO_FIRST: + case STATIC_EVENTHANDLER_PRIO_ANY: + case STATIC_EVENTHANDLER_PRIO_LAST: + break; + default: + case STATIC_EVENTHANDLER_PRIO_INVALID: + panic("invalid priority %d passed", prio); + break; + } +} + +void +static_eventhandler_init(struct static_eventhandler *seh) +{ + + rms_init(&seh->lock, seh->ident); +} + +void +static_eventhandler_register(struct static_eventhandler *seh, void *pcb, + enum static_eventhandler_prio prio) +{ + static_eventhandler_cb **newcb, **tofree_cb, *cb; + size_t newsize; + enum static_eventhandler_prio *newprio, *tofree_prio; + int i; + + static_eventhandler_assert_prio(seh, prio); + + cb = (void *)pcb; + tofree_cb = NULL; + tofree_prio = NULL; + rms_wlock(&seh->lock); + MPASS(seh->count <= seh->size); + if (seh->cb == NULL) { + seh->size = 8; + seh->cb = malloc(sizeof(seh->cb[0]) * seh->size, M_EVENTHANDLER, + M_WAITOK | M_ZERO); + seh->prio = malloc(sizeof(seh->prio[0]) * seh->size, M_EVENTHANDLER, + M_WAITOK | M_ZERO); + } else if (seh->count == seh->size) { + newsize = seh->size * 2; + newcb = malloc(sizeof(seh->cb[0]) * newsize, + M_EVENTHANDLER, M_WAITOK | M_ZERO); + newprio = malloc(sizeof(seh->prio[0]) * newsize, + M_EVENTHANDLER, M_WAITOK | M_ZERO); + memcpy(newcb, seh->cb, sizeof(seh->cb[0]) * seh->size); + memcpy(newprio, seh->prio, sizeof(seh->prio[0]) * seh->size); + + tofree_cb = seh->cb; + tofree_prio = seh->prio; + seh->cb = newcb; + seh->prio = newprio; + seh->size = newsize; + } + + static_eventhandler_validate(seh); + + for (i = 0; i < seh->size; i++) { + if (seh->cb[i] == cb) + panic("callback %p already registered", cb); + } + + switch (prio) { + case STATIC_EVENTHANDLER_PRIO_INVALID: + /* appease clang */ + panic("should not be here"); + break; + case STATIC_EVENTHANDLER_PRIO_FIRST: + memmove(&seh->cb[1], seh->cb, + sizeof(seh->cb[0]) * seh->count); + memmove(&seh->prio[1], seh->prio, + sizeof(seh->prio[0]) * seh->count); + seh->cb[0] = cb; + seh->prio[0] = prio; + seh->count++; + break; + case STATIC_EVENTHANDLER_PRIO_ANY: + for (i = 0; i < seh->count; i++) { + if (seh->prio[i] != STATIC_EVENTHANDLER_PRIO_FIRST) + break; + } + if (i == seh->count) { + /* + * Insert at the end. + */ + seh->cb[seh->count] = cb; + seh->prio[seh->count] = prio; + seh->count++; + } else { + /* + * Move all entries to handle STATIC_EVENTHANDLER_PRIO_LAST. + */ + memmove(&seh->cb[i + 1], seh->cb, + sizeof(seh->cb[0]) * (seh->count - i)); + memmove(&seh->prio[i + 1], seh->prio, + sizeof(seh->prio[0]) * (seh->count - i)); + seh->cb[i] = cb; + seh->prio[i] = prio; + seh->count++; + } + break; + case STATIC_EVENTHANDLER_PRIO_LAST: + seh->cb[seh->count] = cb; + seh->prio[seh->count] = prio; + seh->count++; + break; + } + rms_wunlock(&seh->lock); + free(tofree_cb, M_EVENTHANDLER); + free(tofree_prio, M_EVENTHANDLER); +} + +void +static_eventhandler_deregister(struct static_eventhandler *seh, void *pcb) +{ + static_eventhandler_cb *cb; + int i; + + cb = pcb; + rms_wlock(&seh->lock); + MPASS(seh->count <= seh->size); + static_eventhandler_validate(seh); + + for (i = 0; i < seh->count; i++) { + if (seh->cb[i] == cb) + break; + } + + if (i == seh->count) + panic("callback %p not found", cb); + + switch (seh->prio[i]) { + case STATIC_EVENTHANDLER_PRIO_INVALID: + /* appease clang */ + panic("should not be here"); + break; + case STATIC_EVENTHANDLER_PRIO_FIRST: + memmove(seh->cb, &seh->cb[1], + sizeof(seh->cb[0]) * (seh->count - 1)); + memmove(seh->prio, &seh->prio[1], + sizeof(seh->prio[0]) * (seh->count - 1)); + break; + case STATIC_EVENTHANDLER_PRIO_ANY: + memmove(&seh->cb[i], &seh->cb[i + 1], + sizeof(seh->cb[0]) * (seh->count - i)); + memmove(&seh->prio[i], &seh->cb[i + 1], + sizeof(seh->cb[0]) * (seh->count - i)); + break; + case STATIC_EVENTHANDLER_PRIO_LAST: + seh->cb[i] = seh->cb[seh->count - 1]; + seh->prio[i] = seh->prio[seh->count - 1]; + break; + } + seh->cb[seh->count] = NULL; + seh->prio[seh->count] = STATIC_EVENTHANDLER_PRIO_INVALID; + seh->count--; + rms_wunlock(&seh->lock); +} + +void +static_eventhandler_invoke(struct static_eventhandler *seh, void *arg) +{ + int i; + + if (seh->count == 0) + return; + + rms_rlock(&seh->lock); + for (i = 0; i < seh->count; i++) { + (seh->cb[i])(arg); + } + rms_runlock(&seh->lock); +} Index: sys/sys/_eventhandler.h =================================================================== --- sys/sys/_eventhandler.h +++ sys/sys/_eventhandler.h @@ -69,4 +69,52 @@ }; \ struct __hack +/* + * Headers to accomodate _rmlock.h + */ +#include +#include +#include +#include +#include +#include + +typedef void static_eventhandler_cb(void *); + +enum static_eventhandler_prio { + STATIC_EVENTHANDLER_PRIO_INVALID, + STATIC_EVENTHANDLER_PRIO_FIRST, + STATIC_EVENTHANDLER_PRIO_ANY, + STATIC_EVENTHANDLER_PRIO_LAST +}; + +struct static_eventhandler { + const char *ident; + enum static_eventhandler_prio *prio; + struct rmslock lock; + u_int count; + u_int size; + static_eventhandler_cb **cb; +}; + +#define STATIC_EVENTHANDLER_DECLARE(name) \ +extern struct static_eventhandler static_eventhandler_ ## name + +#define STATIC_EVENTHANDLER_REGISTER(name, func, prio) \ + static_eventhandler_register(&static_eventhandler_ ## name, func, \ + STATIC_EVENTHANDLER_PRIO_ ## prio) + +#define STATIC_EVENTHANDLER_DEREGISTER(name, func) \ + static_eventhandler_deregister(&static_eventhandler_ ## name, func) + +#define STATIC_EVENTHANDLER_INVOKE(name, arg) \ + static_eventhandler_invoke(&static_eventhandler_ ## name, arg) + +#define STATIC_EVENTHANDLER_DEFINE(name) \ +struct static_eventhandler static_eventhandler_ ## name = { \ + .ident = __STRING(name), \ +}; \ +SYSINIT(_seh_init_ ## name, SI_SUB_EVENTHANDLER, SI_ORDER_ANY, \ + static_eventhandler_init, &static_eventhandler_ ## name); + #endif Index: sys/sys/eventhandler.h =================================================================== --- sys/sys/eventhandler.h +++ sys/sys/eventhandler.h @@ -317,4 +317,13 @@ typedef void (*rt_addrmsg_fn)(void *, struct ifaddr *, int); EVENTHANDLER_DECLARE(rt_addrmsg, rt_addrmsg_fn); +/* + * Static eventhandler support. + */ +void static_eventhandler_init(struct static_eventhandler *seh); +void static_eventhandler_register(struct static_eventhandler *seh, void *func, + enum static_eventhandler_prio prio); +void static_eventhandler_deregister(struct static_eventhandler *seh, void *func); +void static_eventhandler_invoke(struct static_eventhandler *seh, void *arg); + #endif /* _SYS_EVENTHANDLER_H_ */