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