1 /*- 2 * Copyright (c) 1999 Michael Smith <msmith@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <sys/param.h> 30 #include <sys/kernel.h> 31 #include <sys/malloc.h> 32 #include <sys/systm.h> 33 #include <sys/eventhandler.h> 34 35 MALLOC_DEFINE(M_EVENTHANDLER, "eventhandler", "Event handler records"); 36 37 /* List of 'slow' lists */ 38 static TAILQ_HEAD(, eventhandler_list) eventhandler_lists; 39 static int eventhandler_lists_initted = 0; 40 static struct mtx eventhandler_mutex; 41 42 struct eventhandler_entry_generic 43 { 44 struct eventhandler_entry ee; 45 void (* func)(void); 46 }; 47 48 /* 49 * Insertion is O(n) due to the priority scan, but optimises to O(1) 50 * if all priorities are identical. 51 */ 52 eventhandler_tag 53 eventhandler_register(struct eventhandler_list *list, char *name, 54 void *func, void *arg, int priority) 55 { 56 struct eventhandler_entry_generic *eg; 57 struct eventhandler_entry *ep; 58 59 /* avoid the need for a SYSINIT just to init the list */ 60 if (!eventhandler_lists_initted) { 61 TAILQ_INIT(&eventhandler_lists); 62 mtx_init(&eventhandler_mutex, "eventhandler", MTX_DEF); 63 eventhandler_lists_initted = 1; 64 } 65 66 /* lock the eventhandler lists */ 67 mtx_enter(&eventhandler_mutex, MTX_DEF); 68 69 /* Do we need to find/create the (slow) list? */ 70 if (list == NULL) { 71 /* look for a matching, existing list */ 72 list = eventhandler_find_list(name); 73 74 /* Do we need to create the list? */ 75 if (list == NULL) { 76 if ((list = malloc(sizeof(struct eventhandler_list) + strlen(name) + 1, 77 M_EVENTHANDLER, M_NOWAIT)) == NULL) { 78 mtx_exit(&eventhandler_mutex, MTX_DEF); 79 return(NULL); 80 } 81 list->el_flags = 0; 82 list->el_name = (char *)list + sizeof(struct eventhandler_list); 83 strcpy(list->el_name, name); 84 TAILQ_INSERT_HEAD(&eventhandler_lists, list, el_link); 85 } 86 } 87 if (!(list->el_flags & EHE_INITTED)) { 88 TAILQ_INIT(&list->el_entries); 89 mtx_init(&list->el_mutex, name, MTX_DEF); 90 list->el_flags = EHE_INITTED; 91 } 92 93 /* allocate an entry for this handler, populate it */ 94 if ((eg = malloc(sizeof(struct eventhandler_entry_generic), 95 M_EVENTHANDLER, M_NOWAIT)) == NULL) { 96 mtx_exit(&eventhandler_mutex, MTX_DEF); 97 return(NULL); 98 } 99 eg->func = func; 100 eg->ee.ee_arg = arg; 101 eg->ee.ee_priority = priority; 102 103 /* sort it into the list */ 104 mtx_enter(&list->el_mutex, MTX_DEF); 105 for (ep = TAILQ_FIRST(&list->el_entries); 106 ep != NULL; 107 ep = TAILQ_NEXT(ep, ee_link)) { 108 if (eg->ee.ee_priority < ep->ee_priority) { 109 TAILQ_INSERT_BEFORE(ep, &eg->ee, ee_link); 110 break; 111 } 112 } 113 if (ep == NULL) 114 TAILQ_INSERT_TAIL(&list->el_entries, &eg->ee, ee_link); 115 mtx_exit(&list->el_mutex, MTX_DEF); 116 mtx_exit(&eventhandler_mutex, MTX_DEF); 117 return(&eg->ee); 118 } 119 120 void 121 eventhandler_deregister(struct eventhandler_list *list, eventhandler_tag tag) 122 { 123 struct eventhandler_entry *ep = tag; 124 125 /* XXX insert diagnostic check here? */ 126 mtx_enter(&list->el_mutex, MTX_DEF); 127 if (ep != NULL) { 128 /* remove just this entry */ 129 TAILQ_REMOVE(&list->el_entries, ep, ee_link); 130 free(ep, M_EVENTHANDLER); 131 } else { 132 /* remove entire list */ 133 while (!TAILQ_EMPTY(&list->el_entries)) { 134 ep = TAILQ_FIRST(&list->el_entries); 135 TAILQ_REMOVE(&list->el_entries, ep, ee_link); 136 free(ep, M_EVENTHANDLER); 137 } 138 } 139 mtx_exit(&list->el_mutex, MTX_DEF); 140 } 141 142 struct eventhandler_list * 143 eventhandler_find_list(char *name) 144 { 145 struct eventhandler_list *list; 146 147 /* scan looking for the requested list */ 148 mtx_enter(&eventhandler_mutex, MTX_DEF); 149 for (list = TAILQ_FIRST(&eventhandler_lists); 150 list != NULL; 151 list = TAILQ_NEXT(list, el_link)) { 152 if (!strcmp(name, list->el_name)) 153 break; 154 } 155 mtx_exit(&eventhandler_mutex, MTX_DEF); 156 157 return(list); 158 } 159 160