subr_eventhandler.c revision 67535
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 67535 2000-10-25 00:01:39Z jhb $ 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; 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