subr_eventhandler.c revision 60938
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 60938 2000-05-26 02:09:24Z jake $
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
3550107SmsmithMALLOC_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;
4050107Smsmith
4150107Smsmithstruct eventhandler_entry_generic
4250107Smsmith{
4350107Smsmith    struct eventhandler_entry	ee;
4450107Smsmith    void			(* func)(void);
4550107Smsmith};
4650107Smsmith
4750107Smsmith/*
4850107Smsmith * Insertion is O(n) due to the priority scan, but optimises to O(1)
4950107Smsmith * if all priorities are identical.
5050107Smsmith */
5150107Smsmitheventhandler_tag
5250107Smsmitheventhandler_register(struct eventhandler_list *list, char *name,
5350107Smsmith		      void *func, void *arg, int priority)
5450107Smsmith{
5550107Smsmith    struct eventhandler_entry_generic	*eg;
5650107Smsmith    struct eventhandler_entry		*ep;
5750107Smsmith
5850107Smsmith    /* avoid the need for a SYSINIT just to init the list */
5950107Smsmith    if (!eventhandler_lists_initted) {
6050107Smsmith	TAILQ_INIT(&eventhandler_lists);
6150107Smsmith	eventhandler_lists_initted = 1;
6250107Smsmith    }
6350107Smsmith
6450107Smsmith    /* Do we need to find/create the (slow) list? */
6550107Smsmith    if (list == NULL) {
6650107Smsmith	/* look for a matching, existing list */
6750107Smsmith	list = eventhandler_find_list(name);
6850107Smsmith
6950107Smsmith	/* Do we need to create the list? */
7050107Smsmith	if (list == NULL) {
7150107Smsmith	    if ((list = malloc(sizeof(struct eventhandler_list) + strlen(name) + 1,
7250107Smsmith			       M_EVENTHANDLER, M_NOWAIT)) == NULL)
7350107Smsmith		return(NULL);
7450107Smsmith	    list->el_flags = 0;
7550107Smsmith	    list->el_name = (char *)list + sizeof(struct eventhandler_list);
7650107Smsmith	    strcpy(list->el_name, name);
7750107Smsmith	    TAILQ_INSERT_HEAD(&eventhandler_lists, list, el_link);
7850107Smsmith	}
7950107Smsmith    }
8050107Smsmith    if (!(list->el_flags & EHE_INITTED)) {
8150107Smsmith	TAILQ_INIT(&list->el_entries);
8250107Smsmith	list->el_flags = EHE_INITTED;
8350107Smsmith    }
8450107Smsmith
8550107Smsmith    /* allocate an entry for this handler, populate it */
8650107Smsmith    if ((eg = malloc(sizeof(struct eventhandler_entry_generic),
8750107Smsmith		     M_EVENTHANDLER, M_NOWAIT)) == NULL)
8850107Smsmith	return(NULL);
8950107Smsmith    eg->func = func;
9050107Smsmith    eg->ee.ee_arg = arg;
9150107Smsmith    eg->ee.ee_priority = priority;
9250107Smsmith
9350107Smsmith    /* sort it into the list */
9450107Smsmith    for (ep = TAILQ_FIRST(&list->el_entries);
9550107Smsmith	 ep != NULL;
9650107Smsmith	 ep = TAILQ_NEXT(ep, ee_link)) {
9750107Smsmith	if (eg->ee.ee_priority < ep->ee_priority) {
9850107Smsmith	    TAILQ_INSERT_BEFORE(ep, &eg->ee, ee_link);
9950107Smsmith	    break;
10050107Smsmith	}
10150107Smsmith    }
10250107Smsmith    if (ep == NULL)
10350107Smsmith	TAILQ_INSERT_TAIL(&list->el_entries, &eg->ee, ee_link);
10450107Smsmith    return(&eg->ee);
10550107Smsmith}
10650107Smsmith
10750107Smsmithvoid
10850107Smsmitheventhandler_deregister(struct eventhandler_list *list, eventhandler_tag tag)
10950107Smsmith{
11050107Smsmith    struct eventhandler_entry	*ep = tag;
11150107Smsmith
11250107Smsmith    /* XXX insert diagnostic check here? */
11350107Smsmith    if (ep != NULL) {
11450107Smsmith	/* remove just this entry */
11550107Smsmith	TAILQ_REMOVE(&list->el_entries, ep, ee_link);
11650107Smsmith	free(ep, M_EVENTHANDLER);
11750107Smsmith    } else {
11850107Smsmith	/* remove entire list */
11950107Smsmith	while (!TAILQ_EMPTY(&list->el_entries)) {
12050107Smsmith	    ep = TAILQ_FIRST(&list->el_entries);
12153225Sphk	    TAILQ_REMOVE(&list->el_entries, ep, ee_link);
12250107Smsmith	    free(ep, M_EVENTHANDLER);
12350107Smsmith	}
12450107Smsmith    }
12550107Smsmith}
12650107Smsmith
12750107Smsmithstruct eventhandler_list *
12850107Smsmitheventhandler_find_list(char *name)
12950107Smsmith{
13050107Smsmith    struct eventhandler_list	*list;
13150107Smsmith
13250107Smsmith    /* scan looking for the requested list */
13350107Smsmith    for (list = TAILQ_FIRST(&eventhandler_lists);
13450107Smsmith	 list != NULL;
13550107Smsmith	 list = TAILQ_NEXT(list, el_link)) {
13650107Smsmith	if (!strcmp(name, list->el_name))
13750107Smsmith	    break;
13850107Smsmith    }
13950107Smsmith    return(list);
14050107Smsmith}
141