#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/eventhandler.h>
MALLOC_DEFINE(M_EVENTHANDLER, "eventhandler", "Event handler records");
static TAILQ_HEAD(, eventhandler_list) eventhandler_lists = TAILQ_HEAD_INITIALIZER(eventhandler_lists);
static struct lwkt_token evlist_token = LWKT_TOKEN_INITIALIZER(evlist_token);
struct eventhandler_entry_generic
{
struct eventhandler_entry ee;
void (* func)(void);
};
eventhandler_tag
eventhandler_register(struct eventhandler_list *list, const char *name,
void *func, void *arg, int priority)
{
struct eventhandler_entry_generic *eg;
struct eventhandler_entry *ep;
lwkt_gettoken(&evlist_token);
while (list == NULL) {
list = eventhandler_find_list(name);
if (list)
break;
list = kmalloc(sizeof(struct eventhandler_list) + strlen(name) + 1,
M_EVENTHANDLER, M_INTWAIT);
if (eventhandler_find_list(name)) {
kfree(list, M_EVENTHANDLER);
list = NULL;
} else {
list->el_flags = 0;
list->el_name = (char *)list + sizeof(struct eventhandler_list);
strcpy(list->el_name, name);
TAILQ_INSERT_HEAD(&eventhandler_lists, list, el_link);
}
}
if (!(list->el_flags & EHE_INITTED)) {
TAILQ_INIT(&list->el_entries);
list->el_flags = EHE_INITTED;
}
eg = kmalloc(sizeof(struct eventhandler_entry_generic),
M_EVENTHANDLER, M_INTWAIT);
eg->func = func;
eg->ee.ee_arg = arg;
eg->ee.ee_priority = priority;
for (ep = TAILQ_FIRST(&list->el_entries);
ep != NULL;
ep = TAILQ_NEXT(ep, ee_link)) {
if (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);
lwkt_reltoken(&evlist_token);
return(&eg->ee);
}
void
eventhandler_deregister(struct eventhandler_list *list, eventhandler_tag tag)
{
struct eventhandler_entry *ep = tag;
lwkt_gettoken(&evlist_token);
if (ep != NULL) {
TAILQ_REMOVE(&list->el_entries, ep, ee_link);
kfree(ep, M_EVENTHANDLER);
} else {
while (!TAILQ_EMPTY(&list->el_entries)) {
ep = TAILQ_FIRST(&list->el_entries);
TAILQ_REMOVE(&list->el_entries, ep, ee_link);
kfree(ep, M_EVENTHANDLER);
}
}
lwkt_reltoken(&evlist_token);
}
struct eventhandler_list *
eventhandler_find_list(const char *name)
{
struct eventhandler_list *list;
lwkt_gettoken(&evlist_token);
for (list = TAILQ_FIRST(&eventhandler_lists);
list != NULL;
list = TAILQ_NEXT(list, el_link)) {
if (!strcmp(name, list->el_name))
break;
}
lwkt_reltoken(&evlist_token);
return(list);
}