Changeset View
Changeset View
Standalone View
Standalone View
sys/sys/eventhandler.h
Show First 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
struct eventhandler_list { | struct eventhandler_list { | ||||
char *el_name; | char *el_name; | ||||
int el_flags; /* Unused. */ | int el_flags; /* Unused. */ | ||||
u_int el_runcount; | u_int el_runcount; | ||||
struct mtx el_lock; | struct mtx el_lock; | ||||
TAILQ_ENTRY(eventhandler_list) el_link; | TAILQ_ENTRY(eventhandler_list) el_link; | ||||
TAILQ_HEAD(,eventhandler_entry) el_entries; | CK_LIST_HEAD(,eventhandler_entry) el_entries; | ||||
epoch_t *el_pepoch; | |||||
}; | }; | ||||
#define EHL_LOCK(p) mtx_lock(&(p)->el_lock) | #define EHL_LOCK(p) mtx_lock(&(p)->el_lock) | ||||
#define EHL_UNLOCK(p) mtx_unlock(&(p)->el_lock) | #define EHL_UNLOCK(p) mtx_unlock(&(p)->el_lock) | ||||
#define EHL_LOCK_ASSERT(p, x) mtx_assert(&(p)->el_lock, x) | #define EHL_LOCK_ASSERT(p, x) mtx_assert(&(p)->el_lock, x) | ||||
#define EHL_TYPE_EPOCH(list) ((list)->el_pepoch != NULL) | |||||
/* | /* | ||||
* Macro to invoke the handlers for a given event. | * Macro to invoke the handlers for a given event. | ||||
*/ | */ | ||||
#define _EVENTHANDLER_INVOKE(name, list, ...) do { \ | #define _EVENTHANDLER_INVOKE(name, list, ...) do { \ | ||||
struct eventhandler_entry *_ep; \ | struct eventhandler_entry *_ep; \ | ||||
struct eventhandler_entry_ ## name *_t; \ | struct eventhandler_entry_ ## name *_t; \ | ||||
\ | \ | ||||
EHL_LOCK_ASSERT((list), MA_OWNED); \ | EHL_LOCK_ASSERT((list), MA_OWNED); \ | ||||
(list)->el_runcount++; \ | (list)->el_runcount++; \ | ||||
KASSERT((list)->el_runcount > 0, \ | KASSERT((list)->el_runcount > 0, \ | ||||
("eventhandler_invoke: runcount overflow")); \ | ("eventhandler_invoke: runcount overflow")); \ | ||||
CTR0(KTR_EVH, "eventhandler_invoke(\"" __STRING(name) "\")"); \ | CTR0(KTR_EVH, "eventhandler_invoke(\"" __STRING(name) "\")"); \ | ||||
TAILQ_FOREACH(_ep, &((list)->el_entries), ee_link) { \ | CK_LIST_FOREACH(_ep, &((list)->el_entries), ee_link) { \ | ||||
if (_ep->ee_priority != EHE_DEAD_PRIORITY) { \ | if (_ep->ee_priority != EHE_DEAD_PRIORITY) { \ | ||||
EHL_UNLOCK((list)); \ | EHL_UNLOCK((list)); \ | ||||
_t = (struct eventhandler_entry_ ## name *)_ep; \ | _t = (struct eventhandler_entry_ ## name *)_ep; \ | ||||
CTR1(KTR_EVH, "eventhandler_invoke: executing %p", \ | CTR1(KTR_EVH, "eventhandler_invoke: executing %p", \ | ||||
(void *)_t->eh_func); \ | (void *)_t->eh_func); \ | ||||
_t->eh_func(_ep->ee_arg , ## __VA_ARGS__); \ | _t->eh_func(_ep->ee_arg , ## __VA_ARGS__); \ | ||||
EHL_LOCK((list)); \ | EHL_LOCK((list)); \ | ||||
} \ | } \ | ||||
} \ | } \ | ||||
KASSERT((list)->el_runcount > 0, \ | KASSERT((list)->el_runcount > 0, \ | ||||
("eventhandler_invoke: runcount underflow")); \ | ("eventhandler_invoke: runcount underflow")); \ | ||||
(list)->el_runcount--; \ | (list)->el_runcount--; \ | ||||
if ((list)->el_runcount == 0) \ | if ((list)->el_runcount == 0) \ | ||||
eventhandler_prune_list(list); \ | eventhandler_prune_list(list); \ | ||||
EHL_UNLOCK((list)); \ | EHL_UNLOCK((list)); \ | ||||
} while (0) | } while (0) | ||||
/* | /* | ||||
* Optimized version of the above that can be used for epoch-based lists | |||||
*/ | |||||
#define _EVENTHANDLER_INVOKE_EPOCH(name, list, ...) do { \ | |||||
struct eventhandler_entry *_ep; \ | |||||
struct eventhandler_entry_ ## name *_t; \ | |||||
\ | |||||
MPASS(in_epoch(*((list)->el_pepoch))); \ | |||||
CTR0(KTR_EVH, "eventhandler_invoke_ep(\"" __STRING(name) "\")");\ | |||||
CK_LIST_FOREACH(_ep, &((list)->el_entries), ee_link) { \ | |||||
_t = (struct eventhandler_entry_ ## name *)_ep; \ | |||||
CTR1(KTR_EVH, "eventhandler_invoke_ep: executing %p", \ | |||||
(void *)_t->eh_func); \ | |||||
_t->eh_func(_ep->ee_arg , ## __VA_ARGS__); \ | |||||
} \ | |||||
} while (0) | |||||
/* | |||||
* You can optionally use the EVENTHANDLER_LIST and EVENTHANDLER_DIRECT macros | * You can optionally use the EVENTHANDLER_LIST and EVENTHANDLER_DIRECT macros | ||||
* to pre-define a symbol for the eventhandler list. This symbol can be used by | * to pre-define a symbol for the eventhandler list. This symbol can be used by | ||||
* EVENTHANDLER_DIRECT_INVOKE, which has the advantage of not needing to do a | * EVENTHANDLER_DIRECT_INVOKE, which has the advantage of not needing to do a | ||||
* locked search of the global list of eventhandler lists. At least | * locked search of the global list of eventhandler lists. At least | ||||
* EVENTHANDLER_LIST_DEFINE must be used for EVENTHANDLER_DIRECT_INVOKE to | * EVENTHANDLER_LIST_DEFINE must be used for EVENTHANDLER_DIRECT_INVOKE to | ||||
* work. EVENTHANDLER_LIST_DECLARE is only needed if the call to | * work. EVENTHANDLER_LIST_DECLARE is only needed if the call to | ||||
* EVENTHANDLER_DIRECT_INVOKE is in a different compilation unit from | * EVENTHANDLER_DIRECT_INVOKE is in a different compilation unit from | ||||
* EVENTHANDLER_LIST_DEFINE. If the events are even relatively high frequency | * EVENTHANDLER_LIST_DEFINE. If the events are even relatively high frequency | ||||
* it is suggested that you directly define a list for them. | * it is suggested that you directly define a list for them. | ||||
*/ | */ | ||||
#define EVENTHANDLER_LIST_DEFINE(name) \ | #define EVENTHANDLER_LIST_DEFINE(name) \ | ||||
struct eventhandler_list *_eventhandler_list_ ## name ; \ | struct eventhandler_list *_eventhandler_list_ ## name ; \ | ||||
static void _ehl_init_ ## name (void * ctx __unused) \ | static void _ehl_init_ ## name (void * ctx __unused) \ | ||||
{ \ | { \ | ||||
_eventhandler_list_ ## name = eventhandler_create_list(#name); \ | _eventhandler_list_ ## name = eventhandler_create_list_epoch(#name, NULL); \ | ||||
} \ | } \ | ||||
SYSINIT(name ## _ehl_init, SI_SUB_EVENTHANDLER, SI_ORDER_ANY, \ | SYSINIT(name ## _ehl_init, SI_SUB_EVENTHANDLER, SI_ORDER_ANY, \ | ||||
_ehl_init_ ## name, NULL); \ | _ehl_init_ ## name, NULL); \ | ||||
struct __hack | struct __hack | ||||
#define EVENTHANDLER_DIRECT_INVOKE(name, ...) do { \ | #define EVENTHANDLER_DIRECT_INVOKE(name, ...) do { \ | ||||
struct eventhandler_list *_el; \ | struct eventhandler_list *_el; \ | ||||
\ | \ | ||||
_el = _eventhandler_list_ ## name ; \ | _el = _eventhandler_list_ ## name ; \ | ||||
if (!TAILQ_EMPTY(&_el->el_entries)) { \ | if (!CK_LIST_EMPTY(&_el->el_entries)) { \ | ||||
EHL_LOCK(_el); \ | EHL_LOCK(_el); \ | ||||
_EVENTHANDLER_INVOKE(name, _el , ## __VA_ARGS__); \ | _EVENTHANDLER_INVOKE(name, _el , ## __VA_ARGS__); \ | ||||
} \ | } \ | ||||
} while (0) | } while (0) | ||||
#define EVENTHANDLER_DEFINE_EPOCH(name, _epoch) \ | |||||
struct eventhandler_list *_eventhandler_list_ ## name ; \ | |||||
static void _ehl_init_ ## name (void * ctx __unused) \ | |||||
{ \ | |||||
_eventhandler_list_ ## name = eventhandler_create_list_epoch(#name, &_epoch); \ | |||||
} \ | |||||
SYSINIT(name ## _ehl_init, SI_SUB_EVENTHANDLER, SI_ORDER_ANY, \ | |||||
_ehl_init_ ## name, NULL); \ | |||||
struct __hack | |||||
#define EVENTHANDLER_INVOKE_EPOCH(name, ...) do { \ | |||||
struct eventhandler_list *_el; \ | |||||
\ | |||||
_el = _eventhandler_list_ ## name ; \ | |||||
if (!CK_LIST_EMPTY(&_el->el_entries)) { \ | |||||
_EVENTHANDLER_INVOKE_EPOCH(name, _el , ## __VA_ARGS__); \ | |||||
} \ | |||||
} while (0) | |||||
#define EVENTHANDLER_DEFINE(name, func, arg, priority) \ | #define EVENTHANDLER_DEFINE(name, func, arg, priority) \ | ||||
static eventhandler_tag name ## _tag; \ | static eventhandler_tag name ## _tag; \ | ||||
static void name ## _evh_init(void *ctx) \ | static void name ## _evh_init(void *ctx) \ | ||||
{ \ | { \ | ||||
name ## _tag = EVENTHANDLER_REGISTER(name, func, ctx, \ | name ## _tag = EVENTHANDLER_REGISTER(name, func, ctx, \ | ||||
priority); \ | priority); \ | ||||
} \ | } \ | ||||
SYSINIT(name ## _evh_init, SI_SUB_CONFIGURE, SI_ORDER_ANY, \ | SYSINIT(name ## _evh_init, SI_SUB_CONFIGURE, SI_ORDER_ANY, \ | ||||
name ## _evh_init, arg); \ | name ## _evh_init, arg); \ | ||||
struct __hack | struct __hack | ||||
#define EVENTHANDLER_INVOKE(name, ...) \ | #define EVENTHANDLER_INVOKE(name, ...) \ | ||||
do { \ | do { \ | ||||
struct eventhandler_list *_el; \ | struct eventhandler_list *_el; \ | ||||
\ | \ | ||||
if ((_el = eventhandler_find_list(#name)) != NULL) \ | if ((_el = eventhandler_find_list(#name)) != NULL) \ | ||||
_EVENTHANDLER_INVOKE(name, _el , ## __VA_ARGS__); \ | _EVENTHANDLER_INVOKE(name, _el , ## __VA_ARGS__); \ | ||||
} while (0) | } while (0) | ||||
#define EVENTHANDLER_REGISTER(name, func, arg, priority) \ | #define EVENTHANDLER_REGISTER(name, func, arg, priority) \ | ||||
eventhandler_register(NULL, #name, func, arg, priority) | eventhandler_register_epoch(NULL, #name, NULL, func, arg, priority) | ||||
#define EVENTHANDLER_REGISTER_EPOCH(name, epoch, func, arg, priority) \ | |||||
eventhandler_register_epoch(NULL, #name, &epoch, func, arg, priority) | |||||
#define EVENTHANDLER_DEREGISTER(name, tag) \ | #define EVENTHANDLER_DEREGISTER(name, tag) \ | ||||
do { \ | do { \ | ||||
struct eventhandler_list *_el; \ | struct eventhandler_list *_el; \ | ||||
\ | \ | ||||
if ((_el = eventhandler_find_list(#name)) != NULL) \ | if ((_el = eventhandler_find_list(#name)) != NULL) \ | ||||
eventhandler_deregister(_el, tag); \ | eventhandler_deregister(_el, tag); \ | ||||
} while (0) | } while (0) | ||||
#define EVENTHANDLER_DEREGISTER_NOWAIT(name, tag) \ | #define EVENTHANDLER_DEREGISTER_NOWAIT(name, tag) \ | ||||
do { \ | do { \ | ||||
struct eventhandler_list *_el; \ | struct eventhandler_list *_el; \ | ||||
\ | \ | ||||
if ((_el = eventhandler_find_list(#name)) != NULL) \ | if ((_el = eventhandler_find_list(#name)) != NULL) \ | ||||
eventhandler_deregister_nowait(_el, tag); \ | eventhandler_deregister_nowait(_el, tag); \ | ||||
} while (0) | } while (0) | ||||
eventhandler_tag eventhandler_register(struct eventhandler_list *list, | eventhandler_tag eventhandler_register(struct eventhandler_list *list, | ||||
const char *name, void *func, void *arg, int priority); | const char *name, void *func, void *arg, int priority); | ||||
eventhandler_tag eventhandler_register_epoch(struct eventhandler_list *list, | |||||
const char *name, epoch_t *pepoch, void *func, void *arg, int priority); | |||||
void eventhandler_deregister(struct eventhandler_list *list, | void eventhandler_deregister(struct eventhandler_list *list, | ||||
eventhandler_tag tag); | eventhandler_tag tag); | ||||
void eventhandler_deregister_nowait(struct eventhandler_list *list, | void eventhandler_deregister_nowait(struct eventhandler_list *list, | ||||
eventhandler_tag tag); | eventhandler_tag tag); | ||||
struct eventhandler_list *eventhandler_find_list(const char *name); | struct eventhandler_list *eventhandler_find_list(const char *name); | ||||
void eventhandler_prune_list(struct eventhandler_list *list); | void eventhandler_prune_list(struct eventhandler_list *list); | ||||
struct eventhandler_list *eventhandler_create_list(const char *name); | struct eventhandler_list *eventhandler_create_list(const char *name); | ||||
struct eventhandler_list *eventhandler_create_list_epoch(const char *name, | |||||
epoch_t *pepoch); | |||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
typedef void (*vimage_iterator_func_t)(void *, ...); | typedef void (*vimage_iterator_func_t)(void *, ...); | ||||
eventhandler_tag vimage_eventhandler_register(struct eventhandler_list *list, | eventhandler_tag vimage_eventhandler_register(struct eventhandler_list *list, | ||||
const char *name, void *func, void *arg, int priority, | const char *name, void *func, void *arg, int priority, | ||||
vimage_iterator_func_t); | vimage_iterator_func_t); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 146 Lines • Show Last 20 Lines |