Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/subr_eventhandler.c
Show All 31 Lines | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/ktr.h> | #include <sys/ktr.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/rmlock.h> | |||||
#include <sys/eventhandler.h> | #include <sys/eventhandler.h> | ||||
static MALLOC_DEFINE(M_EVENTHANDLER, "eventhandler", "Event handler records"); | static MALLOC_DEFINE(M_EVENTHANDLER, "eventhandler", "Event handler records"); | ||||
/* List of all eventhandler lists */ | /* List of all eventhandler lists */ | ||||
static TAILQ_HEAD(, eventhandler_list) eventhandler_lists; | static TAILQ_HEAD(, eventhandler_list) eventhandler_lists; | ||||
static int eventhandler_lists_initted = 0; | static int eventhandler_lists_initted = 0; | ||||
static struct mtx eventhandler_mutex; | static struct mtx eventhandler_mutex; | ||||
▲ Show 20 Lines • Show All 263 Lines • ▼ Show 20 Lines | eventhandler_create_list(const char *name) | ||||
KASSERT(eventhandler_lists_initted, | KASSERT(eventhandler_lists_initted, | ||||
("eventhandler list created too early")); | ("eventhandler list created too early")); | ||||
mtx_lock(&eventhandler_mutex); | mtx_lock(&eventhandler_mutex); | ||||
list = eventhandler_find_or_create_list(name); | list = eventhandler_find_or_create_list(name); | ||||
mtx_unlock(&eventhandler_mutex); | mtx_unlock(&eventhandler_mutex); | ||||
return (list); | 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]); | |||||
} | |||||
} | |||||
} | |||||
void | |||||
static_eventhandler_init(struct static_eventhandler *seh) | |||||
{ | |||||
bzero(seh, sizeof(*seh)); | |||||
rms_init(&seh->lock, "seh eventhandler"); | |||||
} | |||||
void | |||||
static_eventhandler_register(struct static_eventhandler *seh, void *pcb, | |||||
enum static_eventhandler_prio prio) | |||||
markj: Wrong indentation. | |||||
{ | |||||
static_eventhandler_cb **newcb, **tofree_cb, *cb; | |||||
size_t newsize; | |||||
enum static_eventhandler_prio *newprio, *tofree_prio; | |||||
int i; | |||||
if (prio == STATIC_EVENTHANDLER_PRIO_INVALID) | |||||
Not Done Inline ActionsThe namespace is still "eventhandler" so this should be called eventhandler_init_static() or so. markj: The namespace is still "eventhandler" so this should be called eventhandler_init_static() or so. | |||||
panic("invalid priority passed"); | |||||
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); | |||||
Not Done Inline ActionsWhy the tautological cast ? kib: Why the tautological cast ? | |||||
Done Inline Actionsmissed cleanup. mjg: missed cleanup. | |||||
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); | |||||
Not Done Inline ActionsShould this be under invariants ? kib: Should this be under invariants ? | |||||
Done Inline ActionsThis is executing rarely enough that imo should stay until the dust settles down. mjg: This is executing rarely enough that imo should stay until the dust settles down. | |||||
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)); | |||||
Not Done Inline ActionsIn the description you said that eventhandlers might deregister themselves. Where does it happen in practice? markj: In the description you said that eventhandlers might deregister themselves. Where does it… | |||||
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); | |||||
} | } |
Wrong indentation.