diff --git a/sys/kern/subr_eventhandler.c b/sys/kern/subr_eventhandler.c index 37c482cbd7ff..5894099abd2e 100644 --- a/sys/kern/subr_eventhandler.c +++ b/sys/kern/subr_eventhandler.c @@ -68,15 +68,15 @@ SYSINIT(eventhandlers, SI_SUB_EVENTHANDLER, SI_ORDER_FIRST, eventhandler_init, * Insertion is O(n) due to the priority scan, but optimises to O(1) * if all priorities are identical. */ -eventhandler_tag -eventhandler_register(struct eventhandler_list *list, const char *name, - void *func, void *arg, int priority) +static eventhandler_tag +eventhandler_register_internal(struct eventhandler_list *list, + const char *name, eventhandler_tag epn) { struct eventhandler_list *new_list; - struct eventhandler_entry_generic *eg; struct eventhandler_entry *ep; KASSERT(eventhandler_lists_initted, ("eventhandler registered too early")); + KASSERT(epn != NULL, ("%s: cannot register NULL event", __func__)); /* lock the eventhandler lists */ mtx_lock(&eventhandler_mutex); @@ -117,32 +117,69 @@ eventhandler_register(struct eventhandler_list *list, const char *name, } mtx_unlock(&eventhandler_mutex); + KASSERT(epn->ee_priority != EHE_DEAD_PRIORITY, + ("%s: handler for %s registered with dead priority", __func__, name)); + + /* sort it into the list */ + CTR4(KTR_EVH, "%s: adding item %p (function %p) to \"%s\"", __func__, epn, + ((struct eventhandler_entry_generic *)epn)->func, name); + EHL_LOCK(list); + TAILQ_FOREACH(ep, &list->el_entries, ee_link) { + if (ep->ee_priority != EHE_DEAD_PRIORITY && + epn->ee_priority < ep->ee_priority) { + TAILQ_INSERT_BEFORE(ep, epn, ee_link); + break; + } + } + if (ep == NULL) + TAILQ_INSERT_TAIL(&list->el_entries, epn, ee_link); + EHL_UNLOCK(list); + return(epn); +} + +eventhandler_tag +eventhandler_register(struct eventhandler_list *list, const char *name, + void *func, void *arg, int priority) +{ + struct eventhandler_entry_generic *eg; + /* allocate an entry for this handler, populate it */ eg = malloc(sizeof(struct eventhandler_entry_generic), M_EVENTHANDLER, M_WAITOK | M_ZERO); eg->func = func; eg->ee.ee_arg = arg; eg->ee.ee_priority = priority; - KASSERT(priority != EHE_DEAD_PRIORITY, - ("%s: handler for %s registered with dead priority", __func__, name)); - /* sort it into the list */ - CTR4(KTR_EVH, "%s: adding item %p (function %p) to \"%s\"", __func__, eg, - func, name); - EHL_LOCK(list); - TAILQ_FOREACH(ep, &list->el_entries, ee_link) { - if (ep->ee_priority != EHE_DEAD_PRIORITY && - eg->ee.ee_priority < ep->ee_priority) { - TAILQ_INSERT_BEFORE(ep, &eg->ee, ee_link); - break; - } - } - if (ep == NULL) - TAILQ_INSERT_TAIL(&list->el_entries, &eg->ee, ee_link); - EHL_UNLOCK(list); - return(&eg->ee); + return (eventhandler_register_internal(list, name, &eg->ee)); } +#ifdef VIMAGE +struct eventhandler_entry_generic_vimage +{ + struct eventhandler_entry ee; + vimage_iterator_func_t func; /* Vimage iterator function. */ + struct eventhandler_entry_vimage v_ee; /* Original func, arg. */ +}; + +eventhandler_tag +vimage_eventhandler_register(struct eventhandler_list *list, const char *name, + void *func, void *arg, int priority, vimage_iterator_func_t iterfunc) +{ + struct eventhandler_entry_generic_vimage *eg; + + /* allocate an entry for this handler, populate it */ + eg = malloc(sizeof(struct eventhandler_entry_generic_vimage), + M_EVENTHANDLER, M_WAITOK | M_ZERO); + eg->func = iterfunc; + eg->v_ee.func = func; + eg->v_ee.ee_arg = arg; + eg->ee.ee_arg = &eg->v_ee; + eg->ee.ee_priority = priority; + + return (eventhandler_register_internal(list, name, &eg->ee)); +} +#endif + void eventhandler_deregister(struct eventhandler_list *list, eventhandler_tag tag) { diff --git a/sys/net/vnet.c b/sys/net/vnet.c index 323ed0855630..1dac03abf1d4 100644 --- a/sys/net/vnet.c +++ b/sys/net/vnet.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -55,6 +56,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #ifdef DDB #include #include @@ -637,6 +640,39 @@ vnet_sysuninit(void) VNET_SYSINIT_RUNLOCK(); } +/* + * EVENTHANDLER(9) extensions. + */ +/* + * Invoke the eventhandler function originally registered with the possibly + * registered argument for all virtual network stack instances. + * + * This iterator can only be used for eventhandlers that do not take any + * additional arguments, as we do ignore the variadic arguments from the + * EVENTHANDLER_INVOKE() call. + */ +void +vnet_global_eventhandler_iterator_func(void *arg, ...) +{ + VNET_ITERATOR_DECL(vnet_iter); + struct eventhandler_entry_vimage *v_ee; + + /* + * There is a bug here in that we should actually cast things to + * (struct eventhandler_entry_ ## name *) but that's not easily + * possible in here so just re-using the variadic version we + * defined for the generic vimage case. + */ + v_ee = arg; + VNET_LIST_RLOCK(); + VNET_FOREACH(vnet_iter) { + CURVNET_SET(vnet_iter); + ((vimage_iterator_func_t)v_ee->func)(v_ee->ee_arg); + CURVNET_RESTORE(); + } + VNET_LIST_RUNLOCK(); +} + #ifdef VNET_DEBUG struct vnet_recursion { SLIST_ENTRY(vnet_recursion) vnr_le; @@ -696,6 +732,9 @@ vnet_log_recursion(struct vnet *old_vnet, const char *old_fn, int line) } #endif /* VNET_DEBUG */ +/* + * DDB(4). + */ #ifdef DDB DB_SHOW_COMMAND(vnets, db_show_vnets) { diff --git a/sys/net/vnet.h b/sys/net/vnet.h index d9a1ee0b6793..fb2cc393cb72 100644 --- a/sys/net/vnet.h +++ b/sys/net/vnet.h @@ -313,6 +313,29 @@ void vnet_register_sysuninit(void *arg); void vnet_deregister_sysinit(void *arg); void vnet_deregister_sysuninit(void *arg); +/* + * EVENTHANDLER(9) extensions. + */ +#include + +void vnet_global_eventhandler_iterator_func(void *, ...); +#define VNET_GLOBAL_EVENTHANDLER_REGISTER_TAG(tag, name, func, arg, priority) \ +do { \ + if (IS_DEFAULT_VNET(curvnet)) { \ + (tag) = vimage_eventhandler_register(NULL, #name, func, \ + arg, priority, \ + vnet_global_eventhandler_iterator_func); \ + } \ +} while(0) +#define VNET_GLOBAL_EVENTHANDLER_REGISTER(name, func, arg, priority) \ +do { \ + if (IS_DEFAULT_VNET(curvnet)) { \ + vimage_eventhandler_register(NULL, #name, func, \ + arg, priority, \ + vnet_global_eventhandler_iterator_func); \ + } \ +} while(0) + #else /* !VIMAGE */ /* @@ -384,6 +407,13 @@ void vnet_deregister_sysuninit(void *arg); #define VNET_SYSUNINIT(ident, subsystem, order, func, arg) \ SYSUNINIT(ident, subsystem, order, func, arg) +/* + * Without VIMAGE revert to the default implementation. + */ +#define VNET_GLOBAL_EVENTHANDLER_REGISTER_TAG(tag, name, func, arg, priority) \ + (tag) = eventhandler_register(NULL, #name, func, arg, priority) +#define VNET_GLOBAL_EVENTHANDLER_REGISTER(name, func, arg, priority) \ + eventhandler_register(NULL, #name, func, arg, priority) #endif /* VIMAGE */ #endif /* _KERNEL */ diff --git a/sys/sys/eventhandler.h b/sys/sys/eventhandler.h index 1f26d48f6581..3f8846faab90 100644 --- a/sys/sys/eventhandler.h +++ b/sys/sys/eventhandler.h @@ -41,6 +41,14 @@ struct eventhandler_entry { void *ee_arg; }; +#ifdef VIMAGE +struct eventhandler_entry_vimage { + void (* func)(void); /* Original function registered. */ + void *ee_arg; /* Original argument registered. */ + void *sparep[2]; +}; +#endif + struct eventhandler_list { char *el_name; int el_flags; @@ -142,6 +150,14 @@ void eventhandler_deregister(struct eventhandler_list *list, struct eventhandler_list *eventhandler_find_list(const char *name); void eventhandler_prune_list(struct eventhandler_list *list); +#ifdef VIMAGE +typedef void (*vimage_iterator_func_t)(void *, ...); + +eventhandler_tag vimage_eventhandler_register(struct eventhandler_list *list, + const char *name, void *func, void *arg, int priority, + vimage_iterator_func_t); +#endif + /* * Standard system event queues. */