xref: /xnu-10063.121.3/bsd/kern/subr_eventhandler.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1*2c2f96dcSApple OSS Distributions /*
2*2c2f96dcSApple OSS Distributions  * Copyright (c) 2016-2019 Apple Inc. All rights reserved.
3*2c2f96dcSApple OSS Distributions  *
4*2c2f96dcSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*2c2f96dcSApple OSS Distributions  *
6*2c2f96dcSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*2c2f96dcSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*2c2f96dcSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*2c2f96dcSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*2c2f96dcSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*2c2f96dcSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*2c2f96dcSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*2c2f96dcSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*2c2f96dcSApple OSS Distributions  *
15*2c2f96dcSApple OSS Distributions  * Please obtain a copy of the License at
16*2c2f96dcSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*2c2f96dcSApple OSS Distributions  *
18*2c2f96dcSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*2c2f96dcSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*2c2f96dcSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*2c2f96dcSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*2c2f96dcSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*2c2f96dcSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*2c2f96dcSApple OSS Distributions  * limitations under the License.
25*2c2f96dcSApple OSS Distributions  *
26*2c2f96dcSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*2c2f96dcSApple OSS Distributions  */
28*2c2f96dcSApple OSS Distributions /*-
29*2c2f96dcSApple OSS Distributions  * Copyright (c) 1999 Michael Smith <[email protected]>
30*2c2f96dcSApple OSS Distributions  * All rights reserved.
31*2c2f96dcSApple OSS Distributions  *
32*2c2f96dcSApple OSS Distributions  * Redistribution and use in source and binary forms, with or without
33*2c2f96dcSApple OSS Distributions  * modification, are permitted provided that the following conditions
34*2c2f96dcSApple OSS Distributions  * are met:
35*2c2f96dcSApple OSS Distributions  * 1. Redistributions of source code must retain the above copyright
36*2c2f96dcSApple OSS Distributions  *    notice, this list of conditions and the following disclaimer.
37*2c2f96dcSApple OSS Distributions  * 2. Redistributions in binary form must reproduce the above copyright
38*2c2f96dcSApple OSS Distributions  *    notice, this list of conditions and the following disclaimer in the
39*2c2f96dcSApple OSS Distributions  *    documentation and/or other materials provided with the distribution.
40*2c2f96dcSApple OSS Distributions  *
41*2c2f96dcSApple OSS Distributions  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
42*2c2f96dcSApple OSS Distributions  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43*2c2f96dcSApple OSS Distributions  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44*2c2f96dcSApple OSS Distributions  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45*2c2f96dcSApple OSS Distributions  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46*2c2f96dcSApple OSS Distributions  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47*2c2f96dcSApple OSS Distributions  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48*2c2f96dcSApple OSS Distributions  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49*2c2f96dcSApple OSS Distributions  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50*2c2f96dcSApple OSS Distributions  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51*2c2f96dcSApple OSS Distributions  * SUCH DAMAGE.
52*2c2f96dcSApple OSS Distributions  */
53*2c2f96dcSApple OSS Distributions 
54*2c2f96dcSApple OSS Distributions #include <sys/cdefs.h>
55*2c2f96dcSApple OSS Distributions #include <sys/param.h>
56*2c2f96dcSApple OSS Distributions #include <sys/kernel.h>
57*2c2f96dcSApple OSS Distributions #include <kern/queue.h>
58*2c2f96dcSApple OSS Distributions #include <kern/locks.h>
59*2c2f96dcSApple OSS Distributions #include <sys/malloc.h>
60*2c2f96dcSApple OSS Distributions #include <sys/proc.h>
61*2c2f96dcSApple OSS Distributions #include <sys/systm.h>
62*2c2f96dcSApple OSS Distributions #include <sys/eventhandler.h>
63*2c2f96dcSApple OSS Distributions #include <sys/sysctl.h>
64*2c2f96dcSApple OSS Distributions #include <sys/mcache.h> /* for VERIFY() */
65*2c2f96dcSApple OSS Distributions 
66*2c2f96dcSApple OSS Distributions int evh_debug = 0;
67*2c2f96dcSApple OSS Distributions 
68*2c2f96dcSApple OSS Distributions SYSCTL_NODE(_kern, OID_AUTO, eventhandler, CTLFLAG_RW | CTLFLAG_LOCKED,
69*2c2f96dcSApple OSS Distributions     0, "Eventhandler");
70*2c2f96dcSApple OSS Distributions SYSCTL_INT(_kern_eventhandler, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_LOCKED,
71*2c2f96dcSApple OSS Distributions     &evh_debug, 0, "Eventhandler debug mode");
72*2c2f96dcSApple OSS Distributions 
73*2c2f96dcSApple OSS Distributions struct eventhandler_entry_arg eventhandler_entry_dummy_arg = { .ee_fm_uuid = { 0 }, .ee_fr_uuid = { 0 } };
74*2c2f96dcSApple OSS Distributions 
75*2c2f96dcSApple OSS Distributions /* List of 'slow' lists */
76*2c2f96dcSApple OSS Distributions static struct eventhandler_lists_ctxt evthdlr_lists_ctxt_glb;
77*2c2f96dcSApple OSS Distributions static LCK_GRP_DECLARE(eventhandler_mutex_grp, "eventhandler");
78*2c2f96dcSApple OSS Distributions 
79*2c2f96dcSApple OSS Distributions LCK_GRP_DECLARE(el_lock_grp, "eventhandler list");
80*2c2f96dcSApple OSS Distributions LCK_ATTR_DECLARE(el_lock_attr, 0, 0);
81*2c2f96dcSApple OSS Distributions 
82*2c2f96dcSApple OSS Distributions struct eventhandler_entry_generic {
83*2c2f96dcSApple OSS Distributions 	struct eventhandler_entry       ee;
84*2c2f96dcSApple OSS Distributions 	void                           *func;
85*2c2f96dcSApple OSS Distributions };
86*2c2f96dcSApple OSS Distributions 
87*2c2f96dcSApple OSS Distributions static struct eventhandler_list *_eventhandler_find_list(
88*2c2f96dcSApple OSS Distributions 	struct eventhandler_lists_ctxt *evthdlr_lists_ctxt, const char *name);
89*2c2f96dcSApple OSS Distributions 
90*2c2f96dcSApple OSS Distributions void
eventhandler_lists_ctxt_init(struct eventhandler_lists_ctxt * evthdlr_lists_ctxt)91*2c2f96dcSApple OSS Distributions eventhandler_lists_ctxt_init(struct eventhandler_lists_ctxt *evthdlr_lists_ctxt)
92*2c2f96dcSApple OSS Distributions {
93*2c2f96dcSApple OSS Distributions 	VERIFY(evthdlr_lists_ctxt != NULL);
94*2c2f96dcSApple OSS Distributions 
95*2c2f96dcSApple OSS Distributions 	TAILQ_INIT(&evthdlr_lists_ctxt->eventhandler_lists);
96*2c2f96dcSApple OSS Distributions 	evthdlr_lists_ctxt->eventhandler_lists_initted = 1;
97*2c2f96dcSApple OSS Distributions 	lck_mtx_init(&evthdlr_lists_ctxt->eventhandler_mutex,
98*2c2f96dcSApple OSS Distributions 	    &eventhandler_mutex_grp, LCK_ATTR_NULL);
99*2c2f96dcSApple OSS Distributions }
100*2c2f96dcSApple OSS Distributions 
101*2c2f96dcSApple OSS Distributions /*
102*2c2f96dcSApple OSS Distributions  * Initialize the eventhandler list.
103*2c2f96dcSApple OSS Distributions  */
104*2c2f96dcSApple OSS Distributions void
eventhandler_init(void)105*2c2f96dcSApple OSS Distributions eventhandler_init(void)
106*2c2f96dcSApple OSS Distributions {
107*2c2f96dcSApple OSS Distributions 	eventhandler_lists_ctxt_init(&evthdlr_lists_ctxt_glb);
108*2c2f96dcSApple OSS Distributions }
109*2c2f96dcSApple OSS Distributions 
110*2c2f96dcSApple OSS Distributions /*
111*2c2f96dcSApple OSS Distributions  * Insertion is O(n) due to the priority scan, but optimises to O(1)
112*2c2f96dcSApple OSS Distributions  * if all priorities are identical.
113*2c2f96dcSApple OSS Distributions  */
114*2c2f96dcSApple OSS Distributions static eventhandler_tag
eventhandler_register_internal(struct eventhandler_lists_ctxt * evthdlr_lists_ctxt,struct eventhandler_list * list,const char * name,eventhandler_tag epn)115*2c2f96dcSApple OSS Distributions eventhandler_register_internal(
116*2c2f96dcSApple OSS Distributions 	struct eventhandler_lists_ctxt *evthdlr_lists_ctxt,
117*2c2f96dcSApple OSS Distributions 	struct eventhandler_list *list,
118*2c2f96dcSApple OSS Distributions 	const char *name, eventhandler_tag epn)
119*2c2f96dcSApple OSS Distributions {
120*2c2f96dcSApple OSS Distributions 	struct eventhandler_list                *__single new_list;
121*2c2f96dcSApple OSS Distributions 	struct eventhandler_entry               *__single ep;
122*2c2f96dcSApple OSS Distributions 
123*2c2f96dcSApple OSS Distributions 	VERIFY(strlen(name) <= (sizeof(new_list->el_name) - 1));
124*2c2f96dcSApple OSS Distributions 
125*2c2f96dcSApple OSS Distributions 	if (evthdlr_lists_ctxt == NULL) {
126*2c2f96dcSApple OSS Distributions 		evthdlr_lists_ctxt = &evthdlr_lists_ctxt_glb;
127*2c2f96dcSApple OSS Distributions 	}
128*2c2f96dcSApple OSS Distributions 
129*2c2f96dcSApple OSS Distributions 	VERIFY(evthdlr_lists_ctxt->eventhandler_lists_initted); /* eventhandler registered too early */
130*2c2f96dcSApple OSS Distributions 	VERIFY(epn != NULL); /* cannot register NULL event */
131*2c2f96dcSApple OSS Distributions 
132*2c2f96dcSApple OSS Distributions 	/* lock the eventhandler lists */
133*2c2f96dcSApple OSS Distributions 	lck_mtx_lock_spin(&evthdlr_lists_ctxt->eventhandler_mutex);
134*2c2f96dcSApple OSS Distributions 
135*2c2f96dcSApple OSS Distributions 	/* Do we need to find/create the (slow) list? */
136*2c2f96dcSApple OSS Distributions 	if (list == NULL) {
137*2c2f96dcSApple OSS Distributions 		/* look for a matching, existing list */
138*2c2f96dcSApple OSS Distributions 		list = _eventhandler_find_list(evthdlr_lists_ctxt, name);
139*2c2f96dcSApple OSS Distributions 
140*2c2f96dcSApple OSS Distributions 		/* Do we need to create the list? */
141*2c2f96dcSApple OSS Distributions 		if (list == NULL) {
142*2c2f96dcSApple OSS Distributions 			lck_mtx_convert_spin(&evthdlr_lists_ctxt->eventhandler_mutex);
143*2c2f96dcSApple OSS Distributions 			new_list = kalloc_type(struct eventhandler_list, Z_WAITOK_ZERO);
144*2c2f96dcSApple OSS Distributions 			evhlog((LOG_DEBUG, "%s: creating list \"%s\"", __func__, name));
145*2c2f96dcSApple OSS Distributions 			list = new_list;
146*2c2f96dcSApple OSS Distributions 			list->el_flags = 0;
147*2c2f96dcSApple OSS Distributions 			list->el_runcount = 0;
148*2c2f96dcSApple OSS Distributions 			bzero(&list->el_lock, sizeof(list->el_lock));
149*2c2f96dcSApple OSS Distributions 			(void) snprintf(list->el_name, sizeof(list->el_name), "%s", name);
150*2c2f96dcSApple OSS Distributions 			TAILQ_INSERT_HEAD(&evthdlr_lists_ctxt->eventhandler_lists, list, el_link);
151*2c2f96dcSApple OSS Distributions 		}
152*2c2f96dcSApple OSS Distributions 	}
153*2c2f96dcSApple OSS Distributions 	if (!(list->el_flags & EHL_INITTED)) {
154*2c2f96dcSApple OSS Distributions 		TAILQ_INIT(&list->el_entries);
155*2c2f96dcSApple OSS Distributions 		EHL_LOCK_INIT(list);
156*2c2f96dcSApple OSS Distributions 		list->el_flags |= EHL_INITTED;
157*2c2f96dcSApple OSS Distributions 	}
158*2c2f96dcSApple OSS Distributions 	lck_mtx_unlock(&evthdlr_lists_ctxt->eventhandler_mutex);
159*2c2f96dcSApple OSS Distributions 
160*2c2f96dcSApple OSS Distributions 	KASSERT(epn->ee_priority != EHE_DEAD_PRIORITY,
161*2c2f96dcSApple OSS Distributions 	    ("%s: handler for %s registered with dead priority", __func__, name));
162*2c2f96dcSApple OSS Distributions 
163*2c2f96dcSApple OSS Distributions 	/* sort it into the list */
164*2c2f96dcSApple OSS Distributions 	evhlog((LOG_DEBUG, "%s: adding item %p (function %p to \"%s\"", __func__, (void *)VM_KERNEL_ADDRPERM(epn),
165*2c2f96dcSApple OSS Distributions 	    (void *)VM_KERNEL_UNSLIDE(((struct eventhandler_entry_generic *)epn)->func), name));
166*2c2f96dcSApple OSS Distributions 	EHL_LOCK(list);
167*2c2f96dcSApple OSS Distributions 	TAILQ_FOREACH(ep, &list->el_entries, ee_link) {
168*2c2f96dcSApple OSS Distributions 		if (ep->ee_priority != EHE_DEAD_PRIORITY &&
169*2c2f96dcSApple OSS Distributions 		    epn->ee_priority < ep->ee_priority) {
170*2c2f96dcSApple OSS Distributions 			TAILQ_INSERT_BEFORE(ep, epn, ee_link);
171*2c2f96dcSApple OSS Distributions 			break;
172*2c2f96dcSApple OSS Distributions 		}
173*2c2f96dcSApple OSS Distributions 	}
174*2c2f96dcSApple OSS Distributions 	if (ep == NULL) {
175*2c2f96dcSApple OSS Distributions 		TAILQ_INSERT_TAIL(&list->el_entries, epn, ee_link);
176*2c2f96dcSApple OSS Distributions 	}
177*2c2f96dcSApple OSS Distributions 	EHL_UNLOCK(list);
178*2c2f96dcSApple OSS Distributions 	return epn;
179*2c2f96dcSApple OSS Distributions }
180*2c2f96dcSApple OSS Distributions 
181*2c2f96dcSApple OSS Distributions eventhandler_tag
eventhandler_register(struct eventhandler_lists_ctxt * evthdlr_lists_ctxt,struct eventhandler_list * list,const char * name,void * func,struct eventhandler_entry_arg arg,int priority)182*2c2f96dcSApple OSS Distributions eventhandler_register(struct eventhandler_lists_ctxt *evthdlr_lists_ctxt,
183*2c2f96dcSApple OSS Distributions     struct eventhandler_list *list, const char *name,
184*2c2f96dcSApple OSS Distributions     void *func, struct eventhandler_entry_arg arg, int priority)
185*2c2f96dcSApple OSS Distributions {
186*2c2f96dcSApple OSS Distributions 	struct eventhandler_entry_generic       *__single eg;
187*2c2f96dcSApple OSS Distributions 
188*2c2f96dcSApple OSS Distributions 	/* allocate an entry for this handler, populate it */
189*2c2f96dcSApple OSS Distributions 	eg = kalloc_type(struct eventhandler_entry_generic, Z_WAITOK_ZERO);
190*2c2f96dcSApple OSS Distributions 	eg->func = func;
191*2c2f96dcSApple OSS Distributions 	eg->ee.ee_arg = arg;
192*2c2f96dcSApple OSS Distributions 	eg->ee.ee_priority = priority;
193*2c2f96dcSApple OSS Distributions 
194*2c2f96dcSApple OSS Distributions 	return eventhandler_register_internal(evthdlr_lists_ctxt, list, name, &eg->ee);
195*2c2f96dcSApple OSS Distributions }
196*2c2f96dcSApple OSS Distributions 
197*2c2f96dcSApple OSS Distributions void
eventhandler_deregister(struct eventhandler_list * list,eventhandler_tag tag)198*2c2f96dcSApple OSS Distributions eventhandler_deregister(struct eventhandler_list *list, eventhandler_tag tag)
199*2c2f96dcSApple OSS Distributions {
200*2c2f96dcSApple OSS Distributions 	struct eventhandler_entry       *__single ep = tag;
201*2c2f96dcSApple OSS Distributions 
202*2c2f96dcSApple OSS Distributions 	EHL_LOCK_ASSERT(list, LCK_MTX_ASSERT_OWNED);
203*2c2f96dcSApple OSS Distributions 	if (ep != NULL) {
204*2c2f96dcSApple OSS Distributions 		/* remove just this entry */
205*2c2f96dcSApple OSS Distributions 		if (list->el_runcount == 0) {
206*2c2f96dcSApple OSS Distributions 			evhlog((LOG_DEBUG, "%s: removing item %p from \"%s\"", __func__, (void *)VM_KERNEL_ADDRPERM(ep),
207*2c2f96dcSApple OSS Distributions 			    list->el_name));
208*2c2f96dcSApple OSS Distributions 			/*
209*2c2f96dcSApple OSS Distributions 			 * We may have purged the list because of certain events.
210*2c2f96dcSApple OSS Distributions 			 * Make sure that is not the case when a specific entry
211*2c2f96dcSApple OSS Distributions 			 * is being removed.
212*2c2f96dcSApple OSS Distributions 			 */
213*2c2f96dcSApple OSS Distributions 			if (!TAILQ_EMPTY(&list->el_entries)) {
214*2c2f96dcSApple OSS Distributions 				TAILQ_REMOVE(&list->el_entries, ep, ee_link);
215*2c2f96dcSApple OSS Distributions 			}
216*2c2f96dcSApple OSS Distributions 			EHL_LOCK_CONVERT(list);
217*2c2f96dcSApple OSS Distributions 			kfree_type(struct eventhandler_entry, ep);
218*2c2f96dcSApple OSS Distributions 		} else {
219*2c2f96dcSApple OSS Distributions 			evhlog((LOG_DEBUG, "%s: marking item %p from \"%s\" as dead", __func__,
220*2c2f96dcSApple OSS Distributions 			    (void *)VM_KERNEL_ADDRPERM(ep), list->el_name));
221*2c2f96dcSApple OSS Distributions 			ep->ee_priority = EHE_DEAD_PRIORITY;
222*2c2f96dcSApple OSS Distributions 		}
223*2c2f96dcSApple OSS Distributions 	} else {
224*2c2f96dcSApple OSS Distributions 		/* remove entire list */
225*2c2f96dcSApple OSS Distributions 		if (list->el_runcount == 0) {
226*2c2f96dcSApple OSS Distributions 			evhlog((LOG_DEBUG, "%s: removing all items from \"%s\"", __func__,
227*2c2f96dcSApple OSS Distributions 			    list->el_name));
228*2c2f96dcSApple OSS Distributions 			EHL_LOCK_CONVERT(list);
229*2c2f96dcSApple OSS Distributions 			while (!TAILQ_EMPTY(&list->el_entries)) {
230*2c2f96dcSApple OSS Distributions 				ep = TAILQ_FIRST(&list->el_entries);
231*2c2f96dcSApple OSS Distributions 				TAILQ_REMOVE(&list->el_entries, ep, ee_link);
232*2c2f96dcSApple OSS Distributions 				kfree_type(struct eventhandler_entry, ep);
233*2c2f96dcSApple OSS Distributions 			}
234*2c2f96dcSApple OSS Distributions 		} else {
235*2c2f96dcSApple OSS Distributions 			evhlog((LOG_DEBUG, "%s: marking all items from \"%s\" as dead",
236*2c2f96dcSApple OSS Distributions 			    __func__, list->el_name));
237*2c2f96dcSApple OSS Distributions 			TAILQ_FOREACH(ep, &list->el_entries, ee_link)
238*2c2f96dcSApple OSS Distributions 			ep->ee_priority = EHE_DEAD_PRIORITY;
239*2c2f96dcSApple OSS Distributions 		}
240*2c2f96dcSApple OSS Distributions 	}
241*2c2f96dcSApple OSS Distributions 	while (list->el_runcount > 0) {
242*2c2f96dcSApple OSS Distributions 		msleep((caddr_t)list, &list->el_lock, PSPIN, "evhrm", 0);
243*2c2f96dcSApple OSS Distributions 	}
244*2c2f96dcSApple OSS Distributions 	EHL_UNLOCK(list);
245*2c2f96dcSApple OSS Distributions }
246*2c2f96dcSApple OSS Distributions 
247*2c2f96dcSApple OSS Distributions /*
248*2c2f96dcSApple OSS Distributions  * Internal version for use when eventhandler list is already locked.
249*2c2f96dcSApple OSS Distributions  */
250*2c2f96dcSApple OSS Distributions static struct eventhandler_list *
_eventhandler_find_list(struct eventhandler_lists_ctxt * evthdlr_lists_ctxt,const char * name)251*2c2f96dcSApple OSS Distributions _eventhandler_find_list(struct eventhandler_lists_ctxt *evthdlr_lists_ctxt,
252*2c2f96dcSApple OSS Distributions     const char *name)
253*2c2f96dcSApple OSS Distributions {
254*2c2f96dcSApple OSS Distributions 	struct eventhandler_list        *__single list;
255*2c2f96dcSApple OSS Distributions 
256*2c2f96dcSApple OSS Distributions 	VERIFY(evthdlr_lists_ctxt != NULL);
257*2c2f96dcSApple OSS Distributions 
258*2c2f96dcSApple OSS Distributions 	LCK_MTX_ASSERT(&evthdlr_lists_ctxt->eventhandler_mutex, LCK_MTX_ASSERT_OWNED);
259*2c2f96dcSApple OSS Distributions 	TAILQ_FOREACH(list, &evthdlr_lists_ctxt->eventhandler_lists, el_link) {
260*2c2f96dcSApple OSS Distributions 		if (!strlcmp(list->el_name, name, EVENTHANDLER_MAX_NAME)) {
261*2c2f96dcSApple OSS Distributions 			break;
262*2c2f96dcSApple OSS Distributions 		}
263*2c2f96dcSApple OSS Distributions 	}
264*2c2f96dcSApple OSS Distributions 	return list;
265*2c2f96dcSApple OSS Distributions }
266*2c2f96dcSApple OSS Distributions 
267*2c2f96dcSApple OSS Distributions /*
268*2c2f96dcSApple OSS Distributions  * Lookup a "slow" list by name.  Returns with the list locked.
269*2c2f96dcSApple OSS Distributions  */
270*2c2f96dcSApple OSS Distributions struct eventhandler_list *
eventhandler_find_list(struct eventhandler_lists_ctxt * evthdlr_lists_ctxt,const char * name)271*2c2f96dcSApple OSS Distributions eventhandler_find_list(struct eventhandler_lists_ctxt *evthdlr_lists_ctxt,
272*2c2f96dcSApple OSS Distributions     const char *name)
273*2c2f96dcSApple OSS Distributions {
274*2c2f96dcSApple OSS Distributions 	struct eventhandler_list        *__single list;
275*2c2f96dcSApple OSS Distributions 
276*2c2f96dcSApple OSS Distributions 	if (evthdlr_lists_ctxt == NULL) {
277*2c2f96dcSApple OSS Distributions 		evthdlr_lists_ctxt = &evthdlr_lists_ctxt_glb;
278*2c2f96dcSApple OSS Distributions 	}
279*2c2f96dcSApple OSS Distributions 
280*2c2f96dcSApple OSS Distributions 	if (!evthdlr_lists_ctxt->eventhandler_lists_initted) {
281*2c2f96dcSApple OSS Distributions 		return NULL;
282*2c2f96dcSApple OSS Distributions 	}
283*2c2f96dcSApple OSS Distributions 
284*2c2f96dcSApple OSS Distributions 	/* scan looking for the requested list */
285*2c2f96dcSApple OSS Distributions 	lck_mtx_lock_spin(&evthdlr_lists_ctxt->eventhandler_mutex);
286*2c2f96dcSApple OSS Distributions 	list = _eventhandler_find_list(evthdlr_lists_ctxt, name);
287*2c2f96dcSApple OSS Distributions 	if (list != NULL) {
288*2c2f96dcSApple OSS Distributions 		lck_mtx_convert_spin(&evthdlr_lists_ctxt->eventhandler_mutex);
289*2c2f96dcSApple OSS Distributions 		EHL_LOCK_SPIN(list);
290*2c2f96dcSApple OSS Distributions 	}
291*2c2f96dcSApple OSS Distributions 	lck_mtx_unlock(&evthdlr_lists_ctxt->eventhandler_mutex);
292*2c2f96dcSApple OSS Distributions 
293*2c2f96dcSApple OSS Distributions 	return list;
294*2c2f96dcSApple OSS Distributions }
295*2c2f96dcSApple OSS Distributions 
296*2c2f96dcSApple OSS Distributions /*
297*2c2f96dcSApple OSS Distributions  * Prune "dead" entries from an eventhandler list.
298*2c2f96dcSApple OSS Distributions  */
299*2c2f96dcSApple OSS Distributions void
eventhandler_prune_list(struct eventhandler_list * list)300*2c2f96dcSApple OSS Distributions eventhandler_prune_list(struct eventhandler_list *list)
301*2c2f96dcSApple OSS Distributions {
302*2c2f96dcSApple OSS Distributions 	struct eventhandler_entry *__single ep, *__single en;
303*2c2f96dcSApple OSS Distributions 
304*2c2f96dcSApple OSS Distributions 	int pruned = 0;
305*2c2f96dcSApple OSS Distributions 
306*2c2f96dcSApple OSS Distributions 	evhlog((LOG_DEBUG, "%s: pruning list \"%s\"", __func__, list->el_name));
307*2c2f96dcSApple OSS Distributions 	EHL_LOCK_ASSERT(list, LCK_MTX_ASSERT_OWNED);
308*2c2f96dcSApple OSS Distributions 	TAILQ_FOREACH_SAFE(ep, &list->el_entries, ee_link, en) {
309*2c2f96dcSApple OSS Distributions 		if (ep->ee_priority == EHE_DEAD_PRIORITY) {
310*2c2f96dcSApple OSS Distributions 			TAILQ_REMOVE(&list->el_entries, ep, ee_link);
311*2c2f96dcSApple OSS Distributions 			kfree_type(struct eventhandler_entry, ep);
312*2c2f96dcSApple OSS Distributions 			pruned++;
313*2c2f96dcSApple OSS Distributions 		}
314*2c2f96dcSApple OSS Distributions 	}
315*2c2f96dcSApple OSS Distributions 	if (pruned > 0) {
316*2c2f96dcSApple OSS Distributions 		wakeup(list);
317*2c2f96dcSApple OSS Distributions 	}
318*2c2f96dcSApple OSS Distributions }
319*2c2f96dcSApple OSS Distributions 
320*2c2f96dcSApple OSS Distributions /*
321*2c2f96dcSApple OSS Distributions  * This should be called when last reference to an object
322*2c2f96dcSApple OSS Distributions  * is being released.
323*2c2f96dcSApple OSS Distributions  * The individual event type lists must be purged when the object
324*2c2f96dcSApple OSS Distributions  * becomes defunct.
325*2c2f96dcSApple OSS Distributions  */
326*2c2f96dcSApple OSS Distributions void
eventhandler_lists_ctxt_destroy(struct eventhandler_lists_ctxt * evthdlr_lists_ctxt)327*2c2f96dcSApple OSS Distributions eventhandler_lists_ctxt_destroy(struct eventhandler_lists_ctxt *evthdlr_lists_ctxt)
328*2c2f96dcSApple OSS Distributions {
329*2c2f96dcSApple OSS Distributions 	struct eventhandler_list        *__single list = NULL;
330*2c2f96dcSApple OSS Distributions 	struct eventhandler_list        *__single list_next = NULL;
331*2c2f96dcSApple OSS Distributions 
332*2c2f96dcSApple OSS Distributions 	lck_mtx_lock(&evthdlr_lists_ctxt->eventhandler_mutex);
333*2c2f96dcSApple OSS Distributions 	TAILQ_FOREACH_SAFE(list, &evthdlr_lists_ctxt->eventhandler_lists,
334*2c2f96dcSApple OSS Distributions 	    el_link, list_next) {
335*2c2f96dcSApple OSS Distributions 		VERIFY(TAILQ_EMPTY(&list->el_entries));
336*2c2f96dcSApple OSS Distributions 		EHL_LOCK_DESTROY(list);
337*2c2f96dcSApple OSS Distributions 		kfree_type(struct eventhandler_list, list);
338*2c2f96dcSApple OSS Distributions 	}
339*2c2f96dcSApple OSS Distributions 	lck_mtx_unlock(&evthdlr_lists_ctxt->eventhandler_mutex);
340*2c2f96dcSApple OSS Distributions 	lck_mtx_destroy(&evthdlr_lists_ctxt->eventhandler_mutex,
341*2c2f96dcSApple OSS Distributions 	    &eventhandler_mutex_grp);
342*2c2f96dcSApple OSS Distributions 	return;
343*2c2f96dcSApple OSS Distributions }
344