Make the EVENTHANDLER mechanism MP-safe. Events can now be invoked
without holding the Giant lock.
This commit is contained in:
parent
8456e16e24
commit
6595c331f3
@ -58,9 +58,13 @@ eventhandler_register(struct eventhandler_list *list, char *name,
|
||||
/* avoid the need for a SYSINIT just to init the list */
|
||||
if (!eventhandler_lists_initted) {
|
||||
TAILQ_INIT(&eventhandler_lists);
|
||||
mtx_init(&eventhandler_mutex, "eventhandler", MTX_DEF);
|
||||
eventhandler_lists_initted = 1;
|
||||
}
|
||||
|
||||
/* lock the eventhandler lists */
|
||||
mtx_enter(&eventhandler_mutex, MTX_DEF);
|
||||
|
||||
/* Do we need to find/create the (slow) list? */
|
||||
if (list == NULL) {
|
||||
/* look for a matching, existing list */
|
||||
@ -69,8 +73,10 @@ eventhandler_register(struct eventhandler_list *list, char *name,
|
||||
/* Do we need to create the list? */
|
||||
if (list == NULL) {
|
||||
if ((list = malloc(sizeof(struct eventhandler_list) + strlen(name) + 1,
|
||||
M_EVENTHANDLER, M_NOWAIT)) == NULL)
|
||||
M_EVENTHANDLER, M_NOWAIT)) == NULL) {
|
||||
mtx_exit(&eventhandler_mutex, MTX_DEF);
|
||||
return(NULL);
|
||||
}
|
||||
list->el_flags = 0;
|
||||
list->el_name = (char *)list + sizeof(struct eventhandler_list);
|
||||
strcpy(list->el_name, name);
|
||||
@ -79,18 +85,22 @@ eventhandler_register(struct eventhandler_list *list, char *name,
|
||||
}
|
||||
if (!(list->el_flags & EHE_INITTED)) {
|
||||
TAILQ_INIT(&list->el_entries);
|
||||
mtx_init(&list->el_mutex, name, MTX_DEF);
|
||||
list->el_flags = EHE_INITTED;
|
||||
}
|
||||
|
||||
/* allocate an entry for this handler, populate it */
|
||||
if ((eg = malloc(sizeof(struct eventhandler_entry_generic),
|
||||
M_EVENTHANDLER, M_NOWAIT)) == NULL)
|
||||
M_EVENTHANDLER, M_NOWAIT)) == NULL) {
|
||||
mtx_exit(&eventhandler_mutex, MTX_DEF);
|
||||
return(NULL);
|
||||
}
|
||||
eg->func = func;
|
||||
eg->ee.ee_arg = arg;
|
||||
eg->ee.ee_priority = priority;
|
||||
|
||||
/* sort it into the list */
|
||||
mtx_enter(&list->el_mutex, MTX_DEF);
|
||||
for (ep = TAILQ_FIRST(&list->el_entries);
|
||||
ep != NULL;
|
||||
ep = TAILQ_NEXT(ep, ee_link)) {
|
||||
@ -101,6 +111,8 @@ eventhandler_register(struct eventhandler_list *list, char *name,
|
||||
}
|
||||
if (ep == NULL)
|
||||
TAILQ_INSERT_TAIL(&list->el_entries, &eg->ee, ee_link);
|
||||
mtx_exit(&list->el_mutex, MTX_DEF);
|
||||
mtx_exit(&eventhandler_mutex, MTX_DEF);
|
||||
return(&eg->ee);
|
||||
}
|
||||
|
||||
@ -110,6 +122,7 @@ eventhandler_deregister(struct eventhandler_list *list, eventhandler_tag tag)
|
||||
struct eventhandler_entry *ep = tag;
|
||||
|
||||
/* XXX insert diagnostic check here? */
|
||||
mtx_enter(&list->el_mutex, MTX_DEF);
|
||||
if (ep != NULL) {
|
||||
/* remove just this entry */
|
||||
TAILQ_REMOVE(&list->el_entries, ep, ee_link);
|
||||
@ -122,19 +135,24 @@ eventhandler_deregister(struct eventhandler_list *list, eventhandler_tag tag)
|
||||
free(ep, M_EVENTHANDLER);
|
||||
}
|
||||
}
|
||||
mtx_exit(&list->el_mutex, MTX_DEF);
|
||||
}
|
||||
|
||||
struct eventhandler_list *
|
||||
eventhandler_find_list(char *name)
|
||||
{
|
||||
struct eventhandler_list *list;
|
||||
|
||||
|
||||
/* scan looking for the requested list */
|
||||
mtx_enter(&eventhandler_mutex, MTX_DEF);
|
||||
for (list = TAILQ_FIRST(&eventhandler_lists);
|
||||
list != NULL;
|
||||
list = TAILQ_NEXT(list, el_link)) {
|
||||
if (!strcmp(name, list->el_name))
|
||||
break;
|
||||
}
|
||||
mtx_exit(&eventhandler_mutex, MTX_DEF);
|
||||
|
||||
return(list);
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,8 @@
|
||||
*/
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <sys/proc.h> /* XXX should these be prerequisites? */
|
||||
#include <machine/mutex.h>
|
||||
|
||||
#ifndef SYS_EVENTHANDLER_H
|
||||
#define SYS_EVENTHANDLER_H
|
||||
@ -40,14 +42,16 @@ struct eventhandler_entry
|
||||
|
||||
struct eventhandler_list
|
||||
{
|
||||
TAILQ_ENTRY(eventhandler_list) el_link;
|
||||
char *el_name;
|
||||
int el_flags;
|
||||
#define EHE_INITTED (1<<0)
|
||||
struct mtx el_mutex;
|
||||
TAILQ_ENTRY(eventhandler_list) el_link;
|
||||
TAILQ_HEAD(,eventhandler_entry) el_entries;
|
||||
};
|
||||
|
||||
typedef struct eventhandler_entry *eventhandler_tag;
|
||||
struct mtx eventhandler_mutex;
|
||||
|
||||
/*
|
||||
* Fast handler lists require the eventhandler list be present
|
||||
@ -72,29 +76,33 @@ struct __hack
|
||||
struct eventhandler_list Xeventhandler_list_ ## name = { #name }; \
|
||||
struct __hack
|
||||
|
||||
#define EVENTHANDLER_FAST_INVOKE(name, args...) \
|
||||
do { \
|
||||
struct eventhandler_list *_el = &Xeventhandler_list_ ## name ; \
|
||||
struct eventhandler_entry *_ep = TAILQ_FIRST(&(_el->el_entries)); \
|
||||
\
|
||||
while (_ep != NULL) { \
|
||||
((struct eventhandler_entry_ ## name *)_ep)->eh_func(_ep->ee_arg , ## args); \
|
||||
_ep = TAILQ_NEXT(_ep, ee_link); \
|
||||
} \
|
||||
#define EVENTHANDLER_FAST_INVOKE(name, args...) \
|
||||
do { \
|
||||
struct eventhandler_list *_el = &Xeventhandler_list_ ## name ; \
|
||||
struct eventhandler_entry *_ep = TAILQ_FIRST(&(_el->el_entries)); \
|
||||
\
|
||||
if (_el->el_flags & EHE_INITTED) { \
|
||||
mtx_enter(&_el->el_mutex, MTX_DEF); \
|
||||
while (_ep != NULL) { \
|
||||
((struct eventhandler_entry_ ## name *)_ep)->eh_func(_ep->ee_arg , \
|
||||
## args); \
|
||||
_ep = TAILQ_NEXT(_ep, ee_link); \
|
||||
} \
|
||||
mtx_exit(&_el->el_mutex, MTX_DEF); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define EVENTHANDLER_FAST_REGISTER(name, func, arg, priority) \
|
||||
eventhandler_register(Xeventhandler_list_ ## name, #name, func, arg, priority)
|
||||
eventhandler_register(&Xeventhandler_list_ ## name, #name, func, arg, priority)
|
||||
|
||||
#define EVENTHANDLER_FAST_DEREGISTER(name, tag) \
|
||||
eventhandler_deregister(Xeventhandler_list ## name, tag)
|
||||
|
||||
eventhandler_deregister(&Xeventhandler_list ## name, tag)
|
||||
|
||||
/*
|
||||
* Slow handlerss are entirely dynamic; lists are created
|
||||
* Slow handlers are entirely dynamic; lists are created
|
||||
* when entries are added to them, and thus have no concept of "owner",
|
||||
*
|
||||
* Slow handlerss need to be declared, but do not need to be defined. The
|
||||
* Slow handlers need to be declared, but do not need to be defined. The
|
||||
* declaration must be in scope wherever the handler is to be invoked.
|
||||
*/
|
||||
#define EVENTHANDLER_DECLARE(name, type) \
|
||||
@ -105,18 +113,22 @@ struct eventhandler_entry_ ## name \
|
||||
}; \
|
||||
struct __hack
|
||||
|
||||
#define EVENTHANDLER_INVOKE(name, args...) \
|
||||
do { \
|
||||
struct eventhandler_list *_el; \
|
||||
struct eventhandler_entry *_ep; \
|
||||
\
|
||||
if ((_el = eventhandler_find_list(#name)) != NULL) { \
|
||||
for (_ep = TAILQ_FIRST(&(_el->el_entries)); \
|
||||
_ep != NULL; \
|
||||
_ep = TAILQ_NEXT(_ep, ee_link)) { \
|
||||
((struct eventhandler_entry_ ## name *)_ep)->eh_func(_ep->ee_arg , ## args); \
|
||||
} \
|
||||
} \
|
||||
#define EVENTHANDLER_INVOKE(name, args...) \
|
||||
do { \
|
||||
struct eventhandler_list *_el; \
|
||||
struct eventhandler_entry *_ep; \
|
||||
\
|
||||
if (((_el = eventhandler_find_list(#name)) != NULL) && \
|
||||
(_el->el_flags & EHE_INITTED)) { \
|
||||
mtx_enter(&_el->el_mutex, MTX_DEF); \
|
||||
for (_ep = TAILQ_FIRST(&(_el->el_entries)); \
|
||||
_ep != NULL; \
|
||||
_ep = TAILQ_NEXT(_ep, ee_link)) { \
|
||||
((struct eventhandler_entry_ ## name *)_ep)->eh_func(_ep->ee_arg , \
|
||||
## args); \
|
||||
} \
|
||||
mtx_exit(&_el->el_mutex, MTX_DEF); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define EVENTHANDLER_REGISTER(name, func, arg, priority) \
|
||||
@ -155,4 +167,11 @@ EVENTHANDLER_DECLARE(shutdown_pre_sync, shutdown_fn); /* before fs sync */
|
||||
EVENTHANDLER_DECLARE(shutdown_post_sync, shutdown_fn); /* after fs sync */
|
||||
EVENTHANDLER_DECLARE(shutdown_final, shutdown_fn);
|
||||
|
||||
/* Idle process event */
|
||||
typedef void (*idle_eventhandler_t) __P((void *, int));
|
||||
|
||||
#define IDLE_PRI_LAST 20000
|
||||
EVENTHANDLER_FAST_DECLARE(idle_event, idle_eventhandler_t);
|
||||
|
||||
|
||||
#endif /* SYS_EVENTHANDLER_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user