subr_eventhandler.c revision 69774
150107Smsmith/*-
250107Smsmith * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
350107Smsmith * All rights reserved.
450107Smsmith *
550107Smsmith * Redistribution and use in source and binary forms, with or without
650107Smsmith * modification, are permitted provided that the following conditions
750107Smsmith * are met:
850107Smsmith * 1. Redistributions of source code must retain the above copyright
950107Smsmith *    notice, this list of conditions and the following disclaimer.
1050107Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1150107Smsmith *    notice, this list of conditions and the following disclaimer in the
1250107Smsmith *    documentation and/or other materials provided with the distribution.
1350107Smsmith *
1450107Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1550107Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1650107Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1750107Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1850107Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1950107Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2050107Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2150107Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2250107Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2350107Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2450107Smsmith * SUCH DAMAGE.
2550107Smsmith *
2650477Speter * $FreeBSD: head/sys/kern/subr_eventhandler.c 69774 2000-12-08 20:09:00Z phk $
2750107Smsmith */
2850107Smsmith
2950107Smsmith#include <sys/param.h>
3050107Smsmith#include <sys/kernel.h>
3150107Smsmith#include <sys/malloc.h>
3250107Smsmith#include <sys/systm.h>
3350107Smsmith#include <sys/eventhandler.h>
3450107Smsmith
3569774Sphkstatic MALLOC_DEFINE(M_EVENTHANDLER, "eventhandler", "Event handler records");
3650107Smsmith
3750107Smsmith/* List of 'slow' lists */
3860938Sjakestatic TAILQ_HEAD(, eventhandler_list)	eventhandler_lists;
3950107Smsmithstatic int				eventhandler_lists_initted = 0;
4067535Sjhbstatic struct mtx			eventhandler_mutex;
4150107Smsmith
4250107Smsmithstruct eventhandler_entry_generic
4350107Smsmith{
4450107Smsmith    struct eventhandler_entry	ee;
4550107Smsmith    void			(* func)(void);
4650107Smsmith};
4750107Smsmith
4850107Smsmith/*
4950107Smsmith * Insertion is O(n) due to the priority scan, but optimises to O(1)
5050107Smsmith * if all priorities are identical.
5150107Smsmith */
5250107Smsmitheventhandler_tag
5350107Smsmitheventhandler_register(struct eventhandler_list *list, char *name,
5450107Smsmith		      void *func, void *arg, int priority)
5550107Smsmith{
5650107Smsmith    struct eventhandler_entry_generic	*eg;
5750107Smsmith    struct eventhandler_entry		*ep;
5850107Smsmith
5950107Smsmith    /* avoid the need for a SYSINIT just to init the list */
6050107Smsmith    if (!eventhandler_lists_initted) {
6150107Smsmith	TAILQ_INIT(&eventhandler_lists);
6266205Smsmith	mtx_init(&eventhandler_mutex, "eventhandler", MTX_DEF);
6350107Smsmith	eventhandler_lists_initted = 1;
6450107Smsmith    }
6550107Smsmith
6666205Smsmith    /* lock the eventhandler lists */
6766205Smsmith    mtx_enter(&eventhandler_mutex, MTX_DEF);
6866205Smsmith
6950107Smsmith    /* Do we need to find/create the (slow) list? */
7050107Smsmith    if (list == NULL) {
7150107Smsmith	/* look for a matching, existing list */
7250107Smsmith	list = eventhandler_find_list(name);
7350107Smsmith
7450107Smsmith	/* Do we need to create the list? */
7550107Smsmith	if (list == NULL) {
7650107Smsmith	    if ((list = malloc(sizeof(struct eventhandler_list) + strlen(name) + 1,
7766205Smsmith			       M_EVENTHANDLER, M_NOWAIT)) == NULL) {
7866205Smsmith		mtx_exit(&eventhandler_mutex, MTX_DEF);
7950107Smsmith		return(NULL);
8066205Smsmith	    }
8150107Smsmith	    list->el_flags = 0;
8250107Smsmith	    list->el_name = (char *)list + sizeof(struct eventhandler_list);
8350107Smsmith	    strcpy(list->el_name, name);
8450107Smsmith	    TAILQ_INSERT_HEAD(&eventhandler_lists, list, el_link);
8550107Smsmith	}
8650107Smsmith    }
8750107Smsmith    if (!(list->el_flags & EHE_INITTED)) {
8850107Smsmith	TAILQ_INIT(&list->el_entries);
8966205Smsmith	mtx_init(&list->el_mutex, name, MTX_DEF);
9050107Smsmith	list->el_flags = EHE_INITTED;
9150107Smsmith    }
9250107Smsmith
9350107Smsmith    /* allocate an entry for this handler, populate it */
9450107Smsmith    if ((eg = malloc(sizeof(struct eventhandler_entry_generic),
9566205Smsmith		     M_EVENTHANDLER, M_NOWAIT)) == NULL) {
9666205Smsmith	mtx_exit(&eventhandler_mutex, MTX_DEF);
9750107Smsmith	return(NULL);
9866205Smsmith    }
9950107Smsmith    eg->func = func;
10050107Smsmith    eg->ee.ee_arg = arg;
10150107Smsmith    eg->ee.ee_priority = priority;
10250107Smsmith
10350107Smsmith    /* sort it into the list */
10466205Smsmith    mtx_enter(&list->el_mutex, MTX_DEF);
10550107Smsmith    for (ep = TAILQ_FIRST(&list->el_entries);
10650107Smsmith	 ep != NULL;
10750107Smsmith	 ep = TAILQ_NEXT(ep, ee_link)) {
10850107Smsmith	if (eg->ee.ee_priority < ep->ee_priority) {
10950107Smsmith	    TAILQ_INSERT_BEFORE(ep, &eg->ee, ee_link);
11050107Smsmith	    break;
11150107Smsmith	}
11250107Smsmith    }
11350107Smsmith    if (ep == NULL)
11450107Smsmith	TAILQ_INSERT_TAIL(&list->el_entries, &eg->ee, ee_link);
11566205Smsmith    mtx_exit(&list->el_mutex, MTX_DEF);
11666205Smsmith    mtx_exit(&eventhandler_mutex, MTX_DEF);
11750107Smsmith    return(&eg->ee);
11850107Smsmith}
11950107Smsmith
12050107Smsmithvoid
12150107Smsmitheventhandler_deregister(struct eventhandler_list *list, eventhandler_tag tag)
12250107Smsmith{
12350107Smsmith    struct eventhandler_entry	*ep = tag;
12450107Smsmith
12550107Smsmith    /* XXX insert diagnostic check here? */
12666205Smsmith    mtx_enter(&list->el_mutex, MTX_DEF);
12750107Smsmith    if (ep != NULL) {
12850107Smsmith	/* remove just this entry */
12950107Smsmith	TAILQ_REMOVE(&list->el_entries, ep, ee_link);
13050107Smsmith	free(ep, M_EVENTHANDLER);
13150107Smsmith    } else {
13250107Smsmith	/* remove entire list */
13350107Smsmith	while (!TAILQ_EMPTY(&list->el_entries)) {
13450107Smsmith	    ep = TAILQ_FIRST(&list->el_entries);
13553225Sphk	    TAILQ_REMOVE(&list->el_entries, ep, ee_link);
13650107Smsmith	    free(ep, M_EVENTHANDLER);
13750107Smsmith	}
13850107Smsmith    }
13966205Smsmith    mtx_exit(&list->el_mutex, MTX_DEF);
14050107Smsmith}
14150107Smsmith
14250107Smsmithstruct eventhandler_list *
14350107Smsmitheventhandler_find_list(char *name)
14450107Smsmith{
14550107Smsmith    struct eventhandler_list	*list;
14666205Smsmith
14750107Smsmith    /* scan looking for the requested list */
14866205Smsmith    mtx_enter(&eventhandler_mutex, MTX_DEF);
14950107Smsmith    for (list = TAILQ_FIRST(&eventhandler_lists);
15050107Smsmith	 list != NULL;
15150107Smsmith	 list = TAILQ_NEXT(list, el_link)) {
15250107Smsmith	if (!strcmp(name, list->el_name))
15350107Smsmith	    break;
15450107Smsmith    }
15566205Smsmith    mtx_exit(&eventhandler_mutex, MTX_DEF);
15666205Smsmith
15750107Smsmith    return(list);
15850107Smsmith}
15966205Smsmith
160