xref: /illumos-gate/usr/src/uts/common/os/evchannels.c (revision e04145d0)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*e04145d0Seschrock  * Common Development and Distribution License (the "License").
6*e04145d0Seschrock  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*e04145d0Seschrock  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * This file contains the source of the general purpose event channel extension
307c478bd9Sstevel@tonic-gate  * to the sysevent framework. This implementation is made up mainly of four
317c478bd9Sstevel@tonic-gate  * layers of functionality: the event queues (evch_evq_*()), the handling of
327c478bd9Sstevel@tonic-gate  * channels (evch_ch*()), the kernel interface (sysevent_evc_*()) and the
337c478bd9Sstevel@tonic-gate  * interface for the sysevent pseudo driver (evch_usr*()).
347c478bd9Sstevel@tonic-gate  * Libsysevent.so uses the pseudo driver sysevent's ioctl to access the event
357c478bd9Sstevel@tonic-gate  * channel extensions. The driver in turn uses the evch_usr*() functions below.
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * The interfaces for user land and kernel are declared in sys/sysevent.h
387c478bd9Sstevel@tonic-gate  * Internal data structures for event channels are defined in
397c478bd9Sstevel@tonic-gate  * sys/sysevent_impl.h.
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * The basic data structure for an event channel is of type evch_chan_t.
427c478bd9Sstevel@tonic-gate  * All channels are maintained by a list named evch_list. The list head
437c478bd9Sstevel@tonic-gate  * is of type evch_dlist_t.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <sys/types.h>
477c478bd9Sstevel@tonic-gate #include <sys/errno.h>
487c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
497c478bd9Sstevel@tonic-gate #include <sys/debug.h>
507c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
517c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
527c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
537c478bd9Sstevel@tonic-gate #include <sys/callb.h>
547c478bd9Sstevel@tonic-gate #include <sys/sysevent.h>
557c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h>
567c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
577c478bd9Sstevel@tonic-gate #include <sys/disp.h>
587c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
597c478bd9Sstevel@tonic-gate #include <sys/door.h>
607c478bd9Sstevel@tonic-gate #include <sys/zone.h>
61*e04145d0Seschrock #include <sys/sdt.h>
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /* Back-off delay for door_ki_upcall */
647c478bd9Sstevel@tonic-gate #define	EVCH_MIN_PAUSE	8
657c478bd9Sstevel@tonic-gate #define	EVCH_MAX_PAUSE	128
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #define	GEVENT(ev)	((evch_gevent_t *)((char *)ev - \
687c478bd9Sstevel@tonic-gate 			    offsetof(evch_gevent_t, ge_payload)))
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #define	EVCH_EVQ_EVCOUNT(x)	((&(x)->eq_eventq)->sq_count)
717c478bd9Sstevel@tonic-gate #define	EVCH_EVQ_HIGHWM(x)	((&(x)->eq_eventq)->sq_highwm)
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate struct evch_globals {
747c478bd9Sstevel@tonic-gate 	evch_dlist_t evch_list;
757c478bd9Sstevel@tonic-gate 	kmutex_t evch_list_lock;
767c478bd9Sstevel@tonic-gate };
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /* Variables used by event channel routines */
797c478bd9Sstevel@tonic-gate static int		evq_initcomplete = 0;
807c478bd9Sstevel@tonic-gate static zone_key_t	evch_zone_key;
817c478bd9Sstevel@tonic-gate static uint32_t		evch_channels_max;
827c478bd9Sstevel@tonic-gate static uint32_t		evch_bindings_max = EVCH_MAX_BINDS_PER_CHANNEL;
837c478bd9Sstevel@tonic-gate static uint32_t		evch_events_max;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate static void evch_evq_unsub(evch_eventq_t *, evch_evqsub_t *);
867c478bd9Sstevel@tonic-gate static void evch_evq_destroy(evch_eventq_t *);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate /*
897c478bd9Sstevel@tonic-gate  * List handling. These functions handle a doubly linked list. The list has
907c478bd9Sstevel@tonic-gate  * to be protected by the calling functions. evch_dlist_t is the list head.
917c478bd9Sstevel@tonic-gate  * Every node of the list has to put a evch_dlelem_t data type in its data
927c478bd9Sstevel@tonic-gate  * structure as its first element.
937c478bd9Sstevel@tonic-gate  *
947c478bd9Sstevel@tonic-gate  * evch_dl_init		- Initialize list head
957c478bd9Sstevel@tonic-gate  * evch_dl_fini		- Terminate list handling
967c478bd9Sstevel@tonic-gate  * evch_dl_is_init	- Returns one if list is initialized
977c478bd9Sstevel@tonic-gate  * evch_dl_add		- Add element to end of list
987c478bd9Sstevel@tonic-gate  * evch_dl_del		- Remove given element from list
997c478bd9Sstevel@tonic-gate  * evch_dl_search	- Lookup element in list
1007c478bd9Sstevel@tonic-gate  * evch_dl_getnum	- Get number of elements in list
1017c478bd9Sstevel@tonic-gate  * evch_dl_next		- Get next elements of list
1027c478bd9Sstevel@tonic-gate  */
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate static void
1057c478bd9Sstevel@tonic-gate evch_dl_init(evch_dlist_t *hp)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate 	hp->dh_head.dl_prev = hp->dh_head.dl_next = &hp->dh_head;
1087c478bd9Sstevel@tonic-gate 	hp->dh_count = 0;
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * Assumes that list is empty.
1137c478bd9Sstevel@tonic-gate  */
1147c478bd9Sstevel@tonic-gate static void
1157c478bd9Sstevel@tonic-gate evch_dl_fini(evch_dlist_t *hp)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate 	hp->dh_head.dl_prev = hp->dh_head.dl_next = NULL;
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate static int
1217c478bd9Sstevel@tonic-gate evch_dl_is_init(evch_dlist_t *hp)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	return (hp->dh_head.dl_next != NULL ? 1 : 0);
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate  * Add an element at the end of the list.
1287c478bd9Sstevel@tonic-gate  */
1297c478bd9Sstevel@tonic-gate static void
1307c478bd9Sstevel@tonic-gate evch_dl_add(evch_dlist_t *hp, evch_dlelem_t *el)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	evch_dlelem_t	*x = hp->dh_head.dl_prev;
1337c478bd9Sstevel@tonic-gate 	evch_dlelem_t	*y = &hp->dh_head;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	x->dl_next = el;
1367c478bd9Sstevel@tonic-gate 	y->dl_prev = el;
1377c478bd9Sstevel@tonic-gate 	el->dl_next = y;
1387c478bd9Sstevel@tonic-gate 	el->dl_prev = x;
1397c478bd9Sstevel@tonic-gate 	hp->dh_count++;
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate /*
1437c478bd9Sstevel@tonic-gate  * Remove arbitrary element out of dlist.
1447c478bd9Sstevel@tonic-gate  */
1457c478bd9Sstevel@tonic-gate static void
1467c478bd9Sstevel@tonic-gate evch_dl_del(evch_dlist_t *hp, evch_dlelem_t *p)
1477c478bd9Sstevel@tonic-gate {
1487c478bd9Sstevel@tonic-gate 	ASSERT(hp->dh_count > 0 && p != &hp->dh_head);
1497c478bd9Sstevel@tonic-gate 	p->dl_prev->dl_next = p->dl_next;
1507c478bd9Sstevel@tonic-gate 	p->dl_next->dl_prev = p->dl_prev;
1517c478bd9Sstevel@tonic-gate 	p->dl_prev = NULL;
1527c478bd9Sstevel@tonic-gate 	p->dl_next = NULL;
1537c478bd9Sstevel@tonic-gate 	hp->dh_count--;
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate  * Search an element in a list. Caller provides comparison callback function.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate static evch_dlelem_t *
1607c478bd9Sstevel@tonic-gate evch_dl_search(evch_dlist_t *hp, int (*cmp)(evch_dlelem_t *, char *), char *s)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	evch_dlelem_t *p;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	for (p = hp->dh_head.dl_next; p != &hp->dh_head; p = p->dl_next) {
1657c478bd9Sstevel@tonic-gate 		if (cmp(p, s) == 0) {
1667c478bd9Sstevel@tonic-gate 			return (p);
1677c478bd9Sstevel@tonic-gate 		}
1687c478bd9Sstevel@tonic-gate 	}
1697c478bd9Sstevel@tonic-gate 	return (NULL);
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate /*
1737c478bd9Sstevel@tonic-gate  * Return number of elements in the list.
1747c478bd9Sstevel@tonic-gate  */
1757c478bd9Sstevel@tonic-gate static int
1767c478bd9Sstevel@tonic-gate evch_dl_getnum(evch_dlist_t *hp)
1777c478bd9Sstevel@tonic-gate {
1787c478bd9Sstevel@tonic-gate 	return (hp->dh_count);
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  * Find next element of a evch_dlist_t list. Find first element if el == NULL.
1837c478bd9Sstevel@tonic-gate  * Returns NULL if end of list is reached.
1847c478bd9Sstevel@tonic-gate  */
1857c478bd9Sstevel@tonic-gate static void *
1867c478bd9Sstevel@tonic-gate evch_dl_next(evch_dlist_t *hp, void *el)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate 	evch_dlelem_t *ep = (evch_dlelem_t *)el;
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	if (hp->dh_count == 0) {
1917c478bd9Sstevel@tonic-gate 		return (NULL);
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
1947c478bd9Sstevel@tonic-gate 		return (hp->dh_head.dl_next);
1957c478bd9Sstevel@tonic-gate 	}
1967c478bd9Sstevel@tonic-gate 	if ((ep = ep->dl_next) == (evch_dlelem_t *)hp) {
1977c478bd9Sstevel@tonic-gate 		return (NULL);
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 	return ((void *)ep);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate  * Queue handling routines. Mutexes have to be entered previously.
2047c478bd9Sstevel@tonic-gate  *
2057c478bd9Sstevel@tonic-gate  * evch_q_init	- Initialize queue head
2067c478bd9Sstevel@tonic-gate  * evch_q_in	- Put element into queue
2077c478bd9Sstevel@tonic-gate  * evch_q_out	- Get element out of queue
2087c478bd9Sstevel@tonic-gate  * evch_q_next	- Iterate over the elements of a queue
2097c478bd9Sstevel@tonic-gate  */
2107c478bd9Sstevel@tonic-gate static void
2117c478bd9Sstevel@tonic-gate evch_q_init(evch_squeue_t *q)
2127c478bd9Sstevel@tonic-gate {
2137c478bd9Sstevel@tonic-gate 	q->sq_head = NULL;
2147c478bd9Sstevel@tonic-gate 	q->sq_tail = (evch_qelem_t *)q;
2157c478bd9Sstevel@tonic-gate 	q->sq_count = 0;
2167c478bd9Sstevel@tonic-gate 	q->sq_highwm = 0;
2177c478bd9Sstevel@tonic-gate }
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate /*
2207c478bd9Sstevel@tonic-gate  * Put element into the queue q
2217c478bd9Sstevel@tonic-gate  */
2227c478bd9Sstevel@tonic-gate static void
2237c478bd9Sstevel@tonic-gate evch_q_in(evch_squeue_t *q, evch_qelem_t *el)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate 	q->sq_tail->q_next = el;
2267c478bd9Sstevel@tonic-gate 	el->q_next = NULL;
2277c478bd9Sstevel@tonic-gate 	q->sq_tail = el;
2287c478bd9Sstevel@tonic-gate 	q->sq_count++;
2297c478bd9Sstevel@tonic-gate 	if (q->sq_count > q->sq_highwm) {
2307c478bd9Sstevel@tonic-gate 		q->sq_highwm = q->sq_count;
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate /*
2357c478bd9Sstevel@tonic-gate  * Returns NULL if queue is empty.
2367c478bd9Sstevel@tonic-gate  */
2377c478bd9Sstevel@tonic-gate static evch_qelem_t *
2387c478bd9Sstevel@tonic-gate evch_q_out(evch_squeue_t *q)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate 	evch_qelem_t *el;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	if ((el = q->sq_head) != NULL) {
2437c478bd9Sstevel@tonic-gate 		q->sq_head = el->q_next;
2447c478bd9Sstevel@tonic-gate 		q->sq_count--;
2457c478bd9Sstevel@tonic-gate 		if (q->sq_head == NULL) {
2467c478bd9Sstevel@tonic-gate 			q->sq_tail = (evch_qelem_t *)q;
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 	return (el);
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate /*
2537c478bd9Sstevel@tonic-gate  * Returns element after *el or first if el == NULL. NULL is returned
2547c478bd9Sstevel@tonic-gate  * if queue is empty or *el points to the last element in the queue.
2557c478bd9Sstevel@tonic-gate  */
2567c478bd9Sstevel@tonic-gate static evch_qelem_t *
2577c478bd9Sstevel@tonic-gate evch_q_next(evch_squeue_t *q, evch_qelem_t *el)
2587c478bd9Sstevel@tonic-gate {
2597c478bd9Sstevel@tonic-gate 	if (el == NULL)
2607c478bd9Sstevel@tonic-gate 		return (q->sq_head);
2617c478bd9Sstevel@tonic-gate 	return (el->q_next);
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate  * Event queue handling functions. An event queue is the basic building block
2667c478bd9Sstevel@tonic-gate  * of an event channel. One event queue makes up the publisher-side event queue.
2677c478bd9Sstevel@tonic-gate  * Further event queues build the per-subscriber queues of an event channel.
2687c478bd9Sstevel@tonic-gate  * Each queue is associated an event delivery thread.
2697c478bd9Sstevel@tonic-gate  * These functions support a two-step initialization. First step, when kernel
2707c478bd9Sstevel@tonic-gate  * memory is ready and second when threads are ready.
2717c478bd9Sstevel@tonic-gate  * Events consist of an administrating evch_gevent_t structure with the event
2727c478bd9Sstevel@tonic-gate  * data appended as variable length payload.
2737c478bd9Sstevel@tonic-gate  * The internal interface functions for the event queue handling are:
2747c478bd9Sstevel@tonic-gate  *
2757c478bd9Sstevel@tonic-gate  * evch_evq_create	- create an event queue
2767c478bd9Sstevel@tonic-gate  * evch_evq_thrcreate	- create thread for an event queue.
2777c478bd9Sstevel@tonic-gate  * evch_evq_destroy	- delete an event queue
2787c478bd9Sstevel@tonic-gate  * evch_evq_sub		- Subscribe to event delivery from an event queue
2797c478bd9Sstevel@tonic-gate  * evch_evq_unsub	- Unsubscribe
2807c478bd9Sstevel@tonic-gate  * evch_evq_pub		- Post an event into an event queue
2817c478bd9Sstevel@tonic-gate  * evch_evq_stop	- Put delivery thread on hold
2827c478bd9Sstevel@tonic-gate  * evch_evq_continue	- Resume event delivery thread
2837c478bd9Sstevel@tonic-gate  * evch_evq_status	- Return status of delivery thread, running or on hold
2847c478bd9Sstevel@tonic-gate  * evch_evq_evzalloc	- Allocate an event structure
2857c478bd9Sstevel@tonic-gate  * evch_evq_evfree	- Free an event structure
2867c478bd9Sstevel@tonic-gate  * evch_evq_evadd_dest	- Add a destructor function to an event structure
2877c478bd9Sstevel@tonic-gate  * evch_evq_evnext	- Iterate over events non-destructive
2887c478bd9Sstevel@tonic-gate  */
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2917c478bd9Sstevel@tonic-gate static void *
2927c478bd9Sstevel@tonic-gate evch_zoneinit(zoneid_t zoneid)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate 	struct evch_globals *eg;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	eg = kmem_zalloc(sizeof (*eg), KM_SLEEP);
2977c478bd9Sstevel@tonic-gate 	evch_dl_init(&eg->evch_list);
2987c478bd9Sstevel@tonic-gate 	return (eg);
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3027c478bd9Sstevel@tonic-gate static void
3037c478bd9Sstevel@tonic-gate evch_zonefree(zoneid_t zoneid, void *arg)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate 	struct evch_globals *eg = arg;
3067c478bd9Sstevel@tonic-gate 	evch_chan_t *chp;
3077c478bd9Sstevel@tonic-gate 	evch_subd_t *sdp;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	mutex_enter(&eg->evch_list_lock);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	/*
3127c478bd9Sstevel@tonic-gate 	 * Keep picking the head element off the list until there are no
3137c478bd9Sstevel@tonic-gate 	 * more.
3147c478bd9Sstevel@tonic-gate 	 */
3157c478bd9Sstevel@tonic-gate 	while ((chp = evch_dl_next(&eg->evch_list, NULL)) != NULL) {
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 		/*
3187c478bd9Sstevel@tonic-gate 		 * Since all processes are gone, all bindings should be gone,
3197c478bd9Sstevel@tonic-gate 		 * and only channels with SUB_KEEP subscribers should remain.
3207c478bd9Sstevel@tonic-gate 		 */
3217c478bd9Sstevel@tonic-gate 		mutex_enter(&chp->ch_mutex);
3227c478bd9Sstevel@tonic-gate 		ASSERT(chp->ch_bindings == 0);
3237c478bd9Sstevel@tonic-gate 		ASSERT(evch_dl_getnum(&chp->ch_subscr) != 0);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 		/* Forcibly unsubscribe each remaining subscription */
3267c478bd9Sstevel@tonic-gate 		while ((sdp = evch_dl_next(&chp->ch_subscr, NULL)) != NULL) {
3277c478bd9Sstevel@tonic-gate 			/*
3287c478bd9Sstevel@tonic-gate 			 * We should only be tearing down persistent
3297c478bd9Sstevel@tonic-gate 			 * subscribers at this point, since all processes
3307c478bd9Sstevel@tonic-gate 			 * from this zone are gone.
3317c478bd9Sstevel@tonic-gate 			 */
3327c478bd9Sstevel@tonic-gate 			ASSERT(sdp->sd_active == 0);
3337c478bd9Sstevel@tonic-gate 			ASSERT((sdp->sd_persist & EVCH_SUB_KEEP) != 0);
3347c478bd9Sstevel@tonic-gate 			/*
3357c478bd9Sstevel@tonic-gate 			 * Disconnect subscriber queue from main event queue.
3367c478bd9Sstevel@tonic-gate 			 */
3377c478bd9Sstevel@tonic-gate 			evch_evq_unsub(chp->ch_queue, sdp->sd_msub);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 			/* Destruct per subscriber queue */
3407c478bd9Sstevel@tonic-gate 			evch_evq_unsub(sdp->sd_queue, sdp->sd_ssub);
3417c478bd9Sstevel@tonic-gate 			evch_evq_destroy(sdp->sd_queue);
3427c478bd9Sstevel@tonic-gate 			/*
3437c478bd9Sstevel@tonic-gate 			 * Eliminate the subscriber data from channel list.
3447c478bd9Sstevel@tonic-gate 			 */
3457c478bd9Sstevel@tonic-gate 			evch_dl_del(&chp->ch_subscr, &sdp->sd_link);
3467c478bd9Sstevel@tonic-gate 			kmem_free(sdp->sd_classname, sdp->sd_clnsize);
3477c478bd9Sstevel@tonic-gate 			kmem_free(sdp->sd_ident, strlen(sdp->sd_ident) + 1);
3487c478bd9Sstevel@tonic-gate 			kmem_free(sdp, sizeof (evch_subd_t));
3497c478bd9Sstevel@tonic-gate 		}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 		/* Channel must now have no subscribers */
3527c478bd9Sstevel@tonic-gate 		ASSERT(evch_dl_getnum(&chp->ch_subscr) == 0);
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 		/* Just like unbind */
3557c478bd9Sstevel@tonic-gate 		mutex_exit(&chp->ch_mutex);
3567c478bd9Sstevel@tonic-gate 		evch_dl_del(&eg->evch_list, &chp->ch_link);
3577c478bd9Sstevel@tonic-gate 		evch_evq_destroy(chp->ch_queue);
3587c478bd9Sstevel@tonic-gate 		mutex_destroy(&chp->ch_mutex);
3597c478bd9Sstevel@tonic-gate 		mutex_destroy(&chp->ch_pubmx);
3607c478bd9Sstevel@tonic-gate 		cv_destroy(&chp->ch_pubcv);
3617c478bd9Sstevel@tonic-gate 		kmem_free(chp->ch_name, chp->ch_namelen);
3627c478bd9Sstevel@tonic-gate 		kmem_free(chp, sizeof (evch_chan_t));
3637c478bd9Sstevel@tonic-gate 	}
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	mutex_exit(&eg->evch_list_lock);
3667c478bd9Sstevel@tonic-gate 	/* all channels should now be gone */
3677c478bd9Sstevel@tonic-gate 	ASSERT(evch_dl_getnum(&eg->evch_list) == 0);
3687c478bd9Sstevel@tonic-gate 	kmem_free(eg, sizeof (*eg));
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  * Frees evch_gevent_t structure including the payload, if the reference count
3737c478bd9Sstevel@tonic-gate  * drops to or below zero. Below zero happens when the event is freed
3747c478bd9Sstevel@tonic-gate  * without beeing queued into a queue.
3757c478bd9Sstevel@tonic-gate  */
3767c478bd9Sstevel@tonic-gate static void
3777c478bd9Sstevel@tonic-gate evch_gevent_free(evch_gevent_t *evp)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	int32_t refcnt;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	refcnt = (int32_t)atomic_add_32_nv(&evp->ge_refcount, -1);
3827c478bd9Sstevel@tonic-gate 	if (refcnt <= 0) {
3837c478bd9Sstevel@tonic-gate 		if (evp->ge_destruct != NULL) {
3847c478bd9Sstevel@tonic-gate 			evp->ge_destruct((void *)&(evp->ge_payload),
3857c478bd9Sstevel@tonic-gate 			    evp->ge_dstcookie);
3867c478bd9Sstevel@tonic-gate 		}
3877c478bd9Sstevel@tonic-gate 		kmem_free(evp, evp->ge_size);
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate /*
3927c478bd9Sstevel@tonic-gate  * Deliver is called for every subscription to the current event
3937c478bd9Sstevel@tonic-gate  * It calls the registered filter function and then the registered delivery
3947c478bd9Sstevel@tonic-gate  * callback routine. Returns 0 on success. The callback routine returns
3957c478bd9Sstevel@tonic-gate  * EVQ_AGAIN or EVQ_SLEEP in case the event could not be delivered.
3967c478bd9Sstevel@tonic-gate  */
3977c478bd9Sstevel@tonic-gate static int
3987c478bd9Sstevel@tonic-gate evch_deliver(evch_evqsub_t *sp, evch_gevent_t *ep)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	void		*uep = &ep->ge_payload;
4017c478bd9Sstevel@tonic-gate 	int		res = EVQ_DELIVER;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	if (sp->su_filter != NULL) {
4047c478bd9Sstevel@tonic-gate 		res = sp->su_filter(uep, sp->su_fcookie);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 	if (res == EVQ_DELIVER) {
4077c478bd9Sstevel@tonic-gate 		return (sp->su_callb(uep, sp->su_cbcookie));
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 	return (0);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate  * Holds event delivery in case of eq_holdmode set or in case the
4147c478bd9Sstevel@tonic-gate  * event queue is empty. Mutex must be held when called.
4157c478bd9Sstevel@tonic-gate  * Wakes up a thread waiting for the delivery thread reaching the hold mode.
4167c478bd9Sstevel@tonic-gate  */
4177c478bd9Sstevel@tonic-gate static void
4187c478bd9Sstevel@tonic-gate evch_delivery_hold(evch_eventq_t *eqp, callb_cpr_t *cpip)
4197c478bd9Sstevel@tonic-gate {
4207c478bd9Sstevel@tonic-gate 	if (eqp->eq_tabortflag == 0) {
4217c478bd9Sstevel@tonic-gate 		do {
4227c478bd9Sstevel@tonic-gate 			if (eqp->eq_holdmode) {
4237c478bd9Sstevel@tonic-gate 				cv_signal(&eqp->eq_onholdcv);
4247c478bd9Sstevel@tonic-gate 			}
4257c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(cpip);
4267c478bd9Sstevel@tonic-gate 			cv_wait(&eqp->eq_thrsleepcv, &eqp->eq_queuemx);
4277c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(cpip, &eqp->eq_queuemx);
4287c478bd9Sstevel@tonic-gate 		} while (eqp->eq_holdmode);
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate /*
4337c478bd9Sstevel@tonic-gate  * Event delivery thread. Enumerates all subscribers and calls evch_deliver()
4347c478bd9Sstevel@tonic-gate  * for each one.
4357c478bd9Sstevel@tonic-gate  */
4367c478bd9Sstevel@tonic-gate static void
4377c478bd9Sstevel@tonic-gate evch_delivery_thr(evch_eventq_t *eqp)
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate 	evch_qelem_t	*qep;
4407c478bd9Sstevel@tonic-gate 	callb_cpr_t	cprinfo;
4417c478bd9Sstevel@tonic-gate 	int		res;
4427c478bd9Sstevel@tonic-gate 	evch_evqsub_t	*sub;
4437c478bd9Sstevel@tonic-gate 	int		deltime;
4447c478bd9Sstevel@tonic-gate 	int		repeatcount;
4457c478bd9Sstevel@tonic-gate 	char		thnam[32];
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	(void) snprintf(thnam, sizeof (thnam), "sysevent_chan-%d",
4487c478bd9Sstevel@tonic-gate 	    (int)eqp->eq_thrid);
4497c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &eqp->eq_queuemx, callb_generic_cpr, thnam);
4507c478bd9Sstevel@tonic-gate 	mutex_enter(&eqp->eq_queuemx);
4517c478bd9Sstevel@tonic-gate 	while (eqp->eq_tabortflag == 0) {
4527c478bd9Sstevel@tonic-gate 		while (eqp->eq_holdmode == 0 && eqp->eq_tabortflag == 0 &&
4537c478bd9Sstevel@tonic-gate 		    (qep = evch_q_out(&eqp->eq_eventq)) != NULL) {
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 			/* Filter and deliver event to all subscribers */
4567c478bd9Sstevel@tonic-gate 			deltime = EVCH_MIN_PAUSE;
4577c478bd9Sstevel@tonic-gate 			repeatcount = EVCH_MAX_TRY_DELIVERY;
4587c478bd9Sstevel@tonic-gate 			eqp->eq_curevent = qep->q_objref;
4597c478bd9Sstevel@tonic-gate 			sub = evch_dl_next(&eqp->eq_subscr, NULL);
4607c478bd9Sstevel@tonic-gate 			while (sub != NULL) {
4617c478bd9Sstevel@tonic-gate 				eqp->eq_dactive = 1;
4627c478bd9Sstevel@tonic-gate 				mutex_exit(&eqp->eq_queuemx);
4637c478bd9Sstevel@tonic-gate 				res = evch_deliver(sub, qep->q_objref);
4647c478bd9Sstevel@tonic-gate 				mutex_enter(&eqp->eq_queuemx);
4657c478bd9Sstevel@tonic-gate 				eqp->eq_dactive = 0;
4667c478bd9Sstevel@tonic-gate 				cv_signal(&eqp->eq_dactivecv);
4677c478bd9Sstevel@tonic-gate 				switch (res) {
4687c478bd9Sstevel@tonic-gate 				case EVQ_SLEEP:
4697c478bd9Sstevel@tonic-gate 					/*
4707c478bd9Sstevel@tonic-gate 					 * Wait for subscriber to return.
4717c478bd9Sstevel@tonic-gate 					 */
4727c478bd9Sstevel@tonic-gate 					eqp->eq_holdmode = 1;
4737c478bd9Sstevel@tonic-gate 					evch_delivery_hold(eqp, &cprinfo);
4747c478bd9Sstevel@tonic-gate 					if (eqp->eq_tabortflag) {
4757c478bd9Sstevel@tonic-gate 						break;
4767c478bd9Sstevel@tonic-gate 					}
4777c478bd9Sstevel@tonic-gate 					continue;
4787c478bd9Sstevel@tonic-gate 				case EVQ_AGAIN:
4797c478bd9Sstevel@tonic-gate 					CALLB_CPR_SAFE_BEGIN(&cprinfo);
4807c478bd9Sstevel@tonic-gate 					mutex_exit(&eqp->eq_queuemx);
4817c478bd9Sstevel@tonic-gate 					delay(deltime);
4827c478bd9Sstevel@tonic-gate 					deltime =
4837c478bd9Sstevel@tonic-gate 					    deltime > EVCH_MAX_PAUSE ?
4847c478bd9Sstevel@tonic-gate 					    deltime : deltime << 1;
4857c478bd9Sstevel@tonic-gate 					mutex_enter(&eqp->eq_queuemx);
4867c478bd9Sstevel@tonic-gate 					CALLB_CPR_SAFE_END(&cprinfo,
4877c478bd9Sstevel@tonic-gate 					    &eqp->eq_queuemx);
4887c478bd9Sstevel@tonic-gate 					if (repeatcount-- > 0) {
4897c478bd9Sstevel@tonic-gate 						continue;
4907c478bd9Sstevel@tonic-gate 					}
4917c478bd9Sstevel@tonic-gate 					break;
4927c478bd9Sstevel@tonic-gate 				}
4937c478bd9Sstevel@tonic-gate 				if (eqp->eq_tabortflag) {
4947c478bd9Sstevel@tonic-gate 					break;
4957c478bd9Sstevel@tonic-gate 				}
4967c478bd9Sstevel@tonic-gate 				sub = evch_dl_next(&eqp->eq_subscr, sub);
4977c478bd9Sstevel@tonic-gate 				repeatcount = EVCH_MAX_TRY_DELIVERY;
4987c478bd9Sstevel@tonic-gate 			}
4997c478bd9Sstevel@tonic-gate 			eqp->eq_curevent = NULL;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 			/* Free event data and queue element */
5027c478bd9Sstevel@tonic-gate 			evch_gevent_free((evch_gevent_t *)qep->q_objref);
5037c478bd9Sstevel@tonic-gate 			kmem_free(qep, qep->q_objsize);
5047c478bd9Sstevel@tonic-gate 		}
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 		/* Wait for next event or end of hold mode if set */
5077c478bd9Sstevel@tonic-gate 		evch_delivery_hold(eqp, &cprinfo);
5087c478bd9Sstevel@tonic-gate 	}
5097c478bd9Sstevel@tonic-gate 	CALLB_CPR_EXIT(&cprinfo);	/* Does mutex_exit of eqp->eq_queuemx */
5107c478bd9Sstevel@tonic-gate 	thread_exit();
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate /*
5147c478bd9Sstevel@tonic-gate  * Create the event delivery thread for an existing event queue.
5157c478bd9Sstevel@tonic-gate  */
5167c478bd9Sstevel@tonic-gate static void
5177c478bd9Sstevel@tonic-gate evch_evq_thrcreate(evch_eventq_t *eqp)
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate 	kthread_t *thp;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	thp = thread_create(NULL, 0, evch_delivery_thr, (char *)eqp, 0, &p0,
5227c478bd9Sstevel@tonic-gate 	    TS_RUN, minclsyspri);
5237c478bd9Sstevel@tonic-gate 	eqp->eq_thrid = thp->t_did;
5247c478bd9Sstevel@tonic-gate }
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate /*
5277c478bd9Sstevel@tonic-gate  * Create event queue.
5287c478bd9Sstevel@tonic-gate  */
5297c478bd9Sstevel@tonic-gate static evch_eventq_t *
5307c478bd9Sstevel@tonic-gate evch_evq_create()
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	evch_eventq_t *p;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	/* Allocate and initialize event queue descriptor */
5357c478bd9Sstevel@tonic-gate 	p = kmem_zalloc(sizeof (evch_eventq_t), KM_SLEEP);
5367c478bd9Sstevel@tonic-gate 	mutex_init(&p->eq_queuemx, NULL, MUTEX_DEFAULT, NULL);
5377c478bd9Sstevel@tonic-gate 	cv_init(&p->eq_thrsleepcv, NULL, CV_DEFAULT, NULL);
5387c478bd9Sstevel@tonic-gate 	evch_q_init(&p->eq_eventq);
5397c478bd9Sstevel@tonic-gate 	evch_dl_init(&p->eq_subscr);
5407c478bd9Sstevel@tonic-gate 	cv_init(&p->eq_dactivecv, NULL, CV_DEFAULT, NULL);
5417c478bd9Sstevel@tonic-gate 	cv_init(&p->eq_onholdcv, NULL, CV_DEFAULT, NULL);
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	/* Create delivery thread */
5447c478bd9Sstevel@tonic-gate 	if (evq_initcomplete) {
5457c478bd9Sstevel@tonic-gate 		evch_evq_thrcreate(p);
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 	return (p);
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate /*
5517c478bd9Sstevel@tonic-gate  * Destroy an event queue. All subscribers have to be unsubscribed prior to
5527c478bd9Sstevel@tonic-gate  * this call.
5537c478bd9Sstevel@tonic-gate  */
5547c478bd9Sstevel@tonic-gate static void
5557c478bd9Sstevel@tonic-gate evch_evq_destroy(evch_eventq_t *eqp)
5567c478bd9Sstevel@tonic-gate {
5577c478bd9Sstevel@tonic-gate 	evch_qelem_t *qep;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	ASSERT(evch_dl_getnum(&eqp->eq_subscr) == 0);
5607c478bd9Sstevel@tonic-gate 	/* Kill delivery thread */
5617c478bd9Sstevel@tonic-gate 	if (eqp->eq_thrid != NULL) {
5627c478bd9Sstevel@tonic-gate 		mutex_enter(&eqp->eq_queuemx);
5637c478bd9Sstevel@tonic-gate 		eqp->eq_tabortflag = 1;
5647c478bd9Sstevel@tonic-gate 		eqp->eq_holdmode = 0;
5657c478bd9Sstevel@tonic-gate 		cv_signal(&eqp->eq_thrsleepcv);
5667c478bd9Sstevel@tonic-gate 		mutex_exit(&eqp->eq_queuemx);
5677c478bd9Sstevel@tonic-gate 		thread_join(eqp->eq_thrid);
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	/* Get rid of stale events in the event queue */
5717c478bd9Sstevel@tonic-gate 	while ((qep = (evch_qelem_t *)evch_q_out(&eqp->eq_eventq)) != NULL) {
5727c478bd9Sstevel@tonic-gate 		evch_gevent_free((evch_gevent_t *)qep->q_objref);
5737c478bd9Sstevel@tonic-gate 		kmem_free(qep, qep->q_objsize);
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	/* Wrap up event queue structure */
5777c478bd9Sstevel@tonic-gate 	cv_destroy(&eqp->eq_onholdcv);
5787c478bd9Sstevel@tonic-gate 	cv_destroy(&eqp->eq_dactivecv);
5797c478bd9Sstevel@tonic-gate 	cv_destroy(&eqp->eq_thrsleepcv);
5807c478bd9Sstevel@tonic-gate 	evch_dl_fini(&eqp->eq_subscr);
5817c478bd9Sstevel@tonic-gate 	mutex_destroy(&eqp->eq_queuemx);
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	/* Free descriptor structure */
5847c478bd9Sstevel@tonic-gate 	kmem_free(eqp, sizeof (evch_eventq_t));
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate /*
5887c478bd9Sstevel@tonic-gate  * Subscribe to an event queue. Every subscriber provides a filter callback
5897c478bd9Sstevel@tonic-gate  * routine and an event delivery callback routine.
5907c478bd9Sstevel@tonic-gate  */
5917c478bd9Sstevel@tonic-gate static evch_evqsub_t *
5927c478bd9Sstevel@tonic-gate evch_evq_sub(evch_eventq_t *eqp, filter_f filter, void *fcookie,
5937c478bd9Sstevel@tonic-gate     deliver_f callb, void *cbcookie)
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate 	evch_evqsub_t *sp = kmem_zalloc(sizeof (evch_evqsub_t), KM_SLEEP);
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	/* Initialize subscriber structure */
5987c478bd9Sstevel@tonic-gate 	sp->su_filter = filter;
5997c478bd9Sstevel@tonic-gate 	sp->su_fcookie = fcookie;
6007c478bd9Sstevel@tonic-gate 	sp->su_callb = callb;
6017c478bd9Sstevel@tonic-gate 	sp->su_cbcookie = cbcookie;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	/* Add subscription to queue */
6047c478bd9Sstevel@tonic-gate 	mutex_enter(&eqp->eq_queuemx);
6057c478bd9Sstevel@tonic-gate 	evch_dl_add(&eqp->eq_subscr, &sp->su_link);
6067c478bd9Sstevel@tonic-gate 	mutex_exit(&eqp->eq_queuemx);
6077c478bd9Sstevel@tonic-gate 	return (sp);
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate /*
6117c478bd9Sstevel@tonic-gate  * Unsubscribe from an event queue.
6127c478bd9Sstevel@tonic-gate  */
6137c478bd9Sstevel@tonic-gate static void
6147c478bd9Sstevel@tonic-gate evch_evq_unsub(evch_eventq_t *eqp, evch_evqsub_t *sp)
6157c478bd9Sstevel@tonic-gate {
6167c478bd9Sstevel@tonic-gate 	mutex_enter(&eqp->eq_queuemx);
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	/* Wait if delivery is just in progress */
6197c478bd9Sstevel@tonic-gate 	if (eqp->eq_dactive) {
6207c478bd9Sstevel@tonic-gate 		cv_wait(&eqp->eq_dactivecv, &eqp->eq_queuemx);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 	evch_dl_del(&eqp->eq_subscr, &sp->su_link);
6237c478bd9Sstevel@tonic-gate 	mutex_exit(&eqp->eq_queuemx);
6247c478bd9Sstevel@tonic-gate 	kmem_free(sp, sizeof (evch_evqsub_t));
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate /*
6287c478bd9Sstevel@tonic-gate  * Publish an event. Returns 0 on success and -1 if memory alloc failed.
6297c478bd9Sstevel@tonic-gate  */
6307c478bd9Sstevel@tonic-gate static int
6317c478bd9Sstevel@tonic-gate evch_evq_pub(evch_eventq_t *eqp, void *ev, int flags)
6327c478bd9Sstevel@tonic-gate {
6337c478bd9Sstevel@tonic-gate 	size_t size;
6347c478bd9Sstevel@tonic-gate 	evch_qelem_t	*qep;
6357c478bd9Sstevel@tonic-gate 	evch_gevent_t	*evp = GEVENT(ev);
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	size = sizeof (evch_qelem_t);
6387c478bd9Sstevel@tonic-gate 	if (flags & EVCH_TRYHARD) {
6397c478bd9Sstevel@tonic-gate 		qep = kmem_alloc_tryhard(size, &size, KM_NOSLEEP);
6407c478bd9Sstevel@tonic-gate 	} else {
6417c478bd9Sstevel@tonic-gate 		qep = kmem_alloc(size, flags & EVCH_NOSLEEP ?
6427c478bd9Sstevel@tonic-gate 		    KM_NOSLEEP : KM_SLEEP);
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate 	if (qep == NULL) {
6457c478bd9Sstevel@tonic-gate 		return (-1);
6467c478bd9Sstevel@tonic-gate 	}
6477c478bd9Sstevel@tonic-gate 	qep->q_objref = (void *)evp;
6487c478bd9Sstevel@tonic-gate 	qep->q_objsize = size;
6497c478bd9Sstevel@tonic-gate 	atomic_add_32(&evp->ge_refcount, 1);
6507c478bd9Sstevel@tonic-gate 	mutex_enter(&eqp->eq_queuemx);
6517c478bd9Sstevel@tonic-gate 	evch_q_in(&eqp->eq_eventq, qep);
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	/* Wakeup delivery thread */
6547c478bd9Sstevel@tonic-gate 	cv_signal(&eqp->eq_thrsleepcv);
6557c478bd9Sstevel@tonic-gate 	mutex_exit(&eqp->eq_queuemx);
6567c478bd9Sstevel@tonic-gate 	return (0);
6577c478bd9Sstevel@tonic-gate }
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate /*
6607c478bd9Sstevel@tonic-gate  * Enter hold mode of an event queue. Event delivery thread stops event
6617c478bd9Sstevel@tonic-gate  * handling after delivery of current event (if any).
6627c478bd9Sstevel@tonic-gate  */
6637c478bd9Sstevel@tonic-gate static void
6647c478bd9Sstevel@tonic-gate evch_evq_stop(evch_eventq_t *eqp)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate 	mutex_enter(&eqp->eq_queuemx);
6677c478bd9Sstevel@tonic-gate 	eqp->eq_holdmode = 1;
6687c478bd9Sstevel@tonic-gate 	if (evq_initcomplete) {
6697c478bd9Sstevel@tonic-gate 		cv_signal(&eqp->eq_thrsleepcv);
6707c478bd9Sstevel@tonic-gate 		cv_wait(&eqp->eq_onholdcv, &eqp->eq_queuemx);
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 	mutex_exit(&eqp->eq_queuemx);
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate /*
6767c478bd9Sstevel@tonic-gate  * Continue event delivery.
6777c478bd9Sstevel@tonic-gate  */
6787c478bd9Sstevel@tonic-gate static void
6797c478bd9Sstevel@tonic-gate evch_evq_continue(evch_eventq_t *eqp)
6807c478bd9Sstevel@tonic-gate {
6817c478bd9Sstevel@tonic-gate 	mutex_enter(&eqp->eq_queuemx);
6827c478bd9Sstevel@tonic-gate 	eqp->eq_holdmode = 0;
6837c478bd9Sstevel@tonic-gate 	cv_signal(&eqp->eq_thrsleepcv);
6847c478bd9Sstevel@tonic-gate 	mutex_exit(&eqp->eq_queuemx);
6857c478bd9Sstevel@tonic-gate }
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate /*
6887c478bd9Sstevel@tonic-gate  * Returns status of delivery thread. 0 if running and 1 if on hold.
6897c478bd9Sstevel@tonic-gate  */
6907c478bd9Sstevel@tonic-gate static int
6917c478bd9Sstevel@tonic-gate evch_evq_status(evch_eventq_t *eqp)
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 	return (eqp->eq_holdmode);
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate /*
6977c478bd9Sstevel@tonic-gate  * Add a destructor function to an event structure.
6987c478bd9Sstevel@tonic-gate  */
6997c478bd9Sstevel@tonic-gate static void
7007c478bd9Sstevel@tonic-gate evch_evq_evadd_dest(void *ev, destr_f destructor, void *cookie)
7017c478bd9Sstevel@tonic-gate {
7027c478bd9Sstevel@tonic-gate 	evch_gevent_t *evp = GEVENT(ev);
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	evp->ge_destruct = destructor;
7057c478bd9Sstevel@tonic-gate 	evp->ge_dstcookie = cookie;
7067c478bd9Sstevel@tonic-gate }
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate /*
7097c478bd9Sstevel@tonic-gate  * Allocate evch_gevent_t structure. Return address of payload offset of
7107c478bd9Sstevel@tonic-gate  * evch_gevent_t.  If EVCH_TRYHARD allocation is requested, we use
7117c478bd9Sstevel@tonic-gate  * kmem_alloc_tryhard to alloc memory of at least paylsize bytes.
7127c478bd9Sstevel@tonic-gate  *
7137c478bd9Sstevel@tonic-gate  * If either memory allocation is unsuccessful, we return NULL.
7147c478bd9Sstevel@tonic-gate  */
7157c478bd9Sstevel@tonic-gate static void *
7167c478bd9Sstevel@tonic-gate evch_evq_evzalloc(size_t paylsize, int flag)
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate 	evch_gevent_t	*evp;
7197c478bd9Sstevel@tonic-gate 	size_t		rsize, evsize;
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	rsize = offsetof(evch_gevent_t, ge_payload) + paylsize;
7227c478bd9Sstevel@tonic-gate 	if (flag & EVCH_TRYHARD) {
7237c478bd9Sstevel@tonic-gate 		evp = kmem_alloc_tryhard(rsize, &evsize, KM_NOSLEEP);
7247c478bd9Sstevel@tonic-gate 		bzero(evp, rsize);
7257c478bd9Sstevel@tonic-gate 		evp->ge_size = evsize;
7267c478bd9Sstevel@tonic-gate 	} else {
7277c478bd9Sstevel@tonic-gate 		evp = kmem_alloc(rsize, flag & EVCH_NOSLEEP ? KM_NOSLEEP :
7287c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
7297c478bd9Sstevel@tonic-gate 		bzero(evp, rsize);
7307c478bd9Sstevel@tonic-gate 		evp->ge_size = rsize;
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	if (evp) {
7347c478bd9Sstevel@tonic-gate 		return (&evp->ge_payload);
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 	return (evp);
7377c478bd9Sstevel@tonic-gate }
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate /*
7407c478bd9Sstevel@tonic-gate  * Free event structure. Argument ev is address of payload offset.
7417c478bd9Sstevel@tonic-gate  */
7427c478bd9Sstevel@tonic-gate static void
7437c478bd9Sstevel@tonic-gate evch_evq_evfree(void *ev)
7447c478bd9Sstevel@tonic-gate {
7457c478bd9Sstevel@tonic-gate 	evch_gevent_free(GEVENT(ev));
7467c478bd9Sstevel@tonic-gate }
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate /*
7497c478bd9Sstevel@tonic-gate  * Iterate over all events in the event queue. Begin with an event
7507c478bd9Sstevel@tonic-gate  * which is currently being delivered. No mutexes are grabbed and no
7517c478bd9Sstevel@tonic-gate  * resources allocated so that this function can be called in panic
7527c478bd9Sstevel@tonic-gate  * context too. This function has to be called with ev == NULL initially.
7537c478bd9Sstevel@tonic-gate  * Actually argument ev is only a flag. Internally the member eq_nextev
7547c478bd9Sstevel@tonic-gate  * is used to determine the next event. But ev allows for the convenient
7557c478bd9Sstevel@tonic-gate  * use like
7567c478bd9Sstevel@tonic-gate  *	ev = NULL;
7577c478bd9Sstevel@tonic-gate  *	while ((ev = evch_evq_evnext(evp, ev)) != NULL) ...
7587c478bd9Sstevel@tonic-gate  */
7597c478bd9Sstevel@tonic-gate static void *
7607c478bd9Sstevel@tonic-gate evch_evq_evnext(evch_eventq_t *evq, void *ev)
7617c478bd9Sstevel@tonic-gate {
7627c478bd9Sstevel@tonic-gate 	if (ev == NULL) {
7637c478bd9Sstevel@tonic-gate 		evq->eq_nextev = NULL;
7647c478bd9Sstevel@tonic-gate 		if (evq->eq_curevent != NULL)
7657c478bd9Sstevel@tonic-gate 			return (&evq->eq_curevent->ge_payload);
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate 	evq->eq_nextev = evch_q_next(&evq->eq_eventq, evq->eq_nextev);
7687c478bd9Sstevel@tonic-gate 	if (evq->eq_nextev == NULL)
7697c478bd9Sstevel@tonic-gate 		return (NULL);
7707c478bd9Sstevel@tonic-gate 	return (&((evch_gevent_t *)evq->eq_nextev->q_objref)->ge_payload);
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate /*
7747c478bd9Sstevel@tonic-gate  * Channel handling functions. First some support functions. Functions belonging
7757c478bd9Sstevel@tonic-gate  * to the channel handling interface start with evch_ch. The following functions
7767c478bd9Sstevel@tonic-gate  * make up the channel handling internal interfaces:
7777c478bd9Sstevel@tonic-gate  *
7787c478bd9Sstevel@tonic-gate  * evch_chinit		- Initialize channel handling
7797c478bd9Sstevel@tonic-gate  * evch_chinitthr	- Second step init: initialize threads
7807c478bd9Sstevel@tonic-gate  * evch_chbind		- Bind to a channel
7817c478bd9Sstevel@tonic-gate  * evch_chunbind	- Unbind from a channel
7827c478bd9Sstevel@tonic-gate  * evch_chsubscribe	- Subscribe to a sysevent class
7837c478bd9Sstevel@tonic-gate  * evch_chunsubscribe	- Unsubscribe
7847c478bd9Sstevel@tonic-gate  * evch_chpublish	- Publish an event
7857c478bd9Sstevel@tonic-gate  * evch_chgetnames	- Get names of all channels
7867c478bd9Sstevel@tonic-gate  * evch_chgetchdata	- Get data of a channel
7877c478bd9Sstevel@tonic-gate  * evch_chrdevent_init  - Init event q traversal
7887c478bd9Sstevel@tonic-gate  * evch_chgetnextev	- Read out events queued for a subscriber
7897c478bd9Sstevel@tonic-gate  * evch_chrdevent_fini  - Finish event q traversal
7907c478bd9Sstevel@tonic-gate  */
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate /*
7937c478bd9Sstevel@tonic-gate  * Compare channel name. Used for evch_dl_search to find a channel with the
7947c478bd9Sstevel@tonic-gate  * name s.
7957c478bd9Sstevel@tonic-gate  */
7967c478bd9Sstevel@tonic-gate static int
7977c478bd9Sstevel@tonic-gate evch_namecmp(evch_dlelem_t *ep, char *s)
7987c478bd9Sstevel@tonic-gate {
7997c478bd9Sstevel@tonic-gate 	return (strcmp(((evch_chan_t *)ep)->ch_name, s));
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate /*
8037c478bd9Sstevel@tonic-gate  * Sysevent filter callback routine. Enables event delivery only if it matches
8047c478bd9Sstevel@tonic-gate  * the event class string given by parameter cookie.
8057c478bd9Sstevel@tonic-gate  */
8067c478bd9Sstevel@tonic-gate static int
8077c478bd9Sstevel@tonic-gate evch_class_filter(void *ev, void *cookie)
8087c478bd9Sstevel@tonic-gate {
8097c478bd9Sstevel@tonic-gate 	char *class = (char *)cookie;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	if (class == NULL || strcmp(SE_CLASS_NAME(ev), class) == 0) {
8127c478bd9Sstevel@tonic-gate 		return (EVQ_DELIVER);
8137c478bd9Sstevel@tonic-gate 	}
8147c478bd9Sstevel@tonic-gate 	return (EVQ_IGNORE);
8157c478bd9Sstevel@tonic-gate }
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate /*
8187c478bd9Sstevel@tonic-gate  * Callback routine to propagate the event into a per subscriber queue.
8197c478bd9Sstevel@tonic-gate  */
8207c478bd9Sstevel@tonic-gate static int
8217c478bd9Sstevel@tonic-gate evch_subq_deliver(void *evp, void *cookie)
8227c478bd9Sstevel@tonic-gate {
8237c478bd9Sstevel@tonic-gate 	evch_subd_t *p = (evch_subd_t *)cookie;
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	(void) evch_evq_pub(p->sd_queue, evp, EVCH_SLEEP);
8267c478bd9Sstevel@tonic-gate 	return (EVQ_CONT);
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate /*
8307c478bd9Sstevel@tonic-gate  * Call kernel callback routine for sysevent kernel delivery.
8317c478bd9Sstevel@tonic-gate  */
8327c478bd9Sstevel@tonic-gate static int
8337c478bd9Sstevel@tonic-gate evch_kern_deliver(void *evp, void *cookie)
8347c478bd9Sstevel@tonic-gate {
8357c478bd9Sstevel@tonic-gate 	sysevent_impl_t	*ev = (sysevent_impl_t *)evp;
8367c478bd9Sstevel@tonic-gate 	evch_subd_t	*sdp = (evch_subd_t *)cookie;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	return (sdp->sd_callback(ev, sdp->sd_cbcookie));
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate /*
8427c478bd9Sstevel@tonic-gate  * Door upcall for user land sysevent delivery.
8437c478bd9Sstevel@tonic-gate  */
8447c478bd9Sstevel@tonic-gate static int
8457c478bd9Sstevel@tonic-gate evch_door_deliver(void *evp, void *cookie)
8467c478bd9Sstevel@tonic-gate {
8477c478bd9Sstevel@tonic-gate 	int		error;
8487c478bd9Sstevel@tonic-gate 	size_t		size;
8497c478bd9Sstevel@tonic-gate 	sysevent_impl_t	*ev = (sysevent_impl_t *)evp;
8507c478bd9Sstevel@tonic-gate 	door_arg_t	darg;
8517c478bd9Sstevel@tonic-gate 	evch_subd_t	*sdp = (evch_subd_t *)cookie;
8527c478bd9Sstevel@tonic-gate 	int		nticks = EVCH_MIN_PAUSE;
8537c478bd9Sstevel@tonic-gate 	uint32_t	retval;
8547c478bd9Sstevel@tonic-gate 	int		retry = 20;
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	/* Initialize door args */
8577c478bd9Sstevel@tonic-gate 	size = sizeof (sysevent_impl_t) + SE_PAYLOAD_SZ(ev);
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	darg.rbuf = (char *)&retval;
8607c478bd9Sstevel@tonic-gate 	darg.rsize = sizeof (retval);
8617c478bd9Sstevel@tonic-gate 	darg.data_ptr = (char *)ev;
8627c478bd9Sstevel@tonic-gate 	darg.data_size = size;
8637c478bd9Sstevel@tonic-gate 	darg.desc_ptr = NULL;
8647c478bd9Sstevel@tonic-gate 	darg.desc_num = 0;
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	for (;;) {
8677c478bd9Sstevel@tonic-gate 		if ((error = door_ki_upcall(sdp->sd_door, &darg)) == 0) {
8687c478bd9Sstevel@tonic-gate 			break;
8697c478bd9Sstevel@tonic-gate 		}
8707c478bd9Sstevel@tonic-gate 		switch (error) {
8717c478bd9Sstevel@tonic-gate 		case EAGAIN:
8727c478bd9Sstevel@tonic-gate 			/* Cannot deliver event - process may be forking */
8737c478bd9Sstevel@tonic-gate 			delay(nticks);
8747c478bd9Sstevel@tonic-gate 			nticks <<= 1;
8757c478bd9Sstevel@tonic-gate 			if (nticks > EVCH_MAX_PAUSE) {
8767c478bd9Sstevel@tonic-gate 				nticks = EVCH_MAX_PAUSE;
8777c478bd9Sstevel@tonic-gate 			}
8787c478bd9Sstevel@tonic-gate 			if (retry-- <= 0) {
8797c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "event delivery thread: "
8807c478bd9Sstevel@tonic-gate 				    "door_ki_upcall error EAGAIN\n");
8817c478bd9Sstevel@tonic-gate 				return (EVQ_CONT);
8827c478bd9Sstevel@tonic-gate 			}
8837c478bd9Sstevel@tonic-gate 			break;
8847c478bd9Sstevel@tonic-gate 		case EINTR:
8857c478bd9Sstevel@tonic-gate 		case EBADF:
8867c478bd9Sstevel@tonic-gate 			/* Process died */
8877c478bd9Sstevel@tonic-gate 			return (EVQ_SLEEP);
8887c478bd9Sstevel@tonic-gate 		default:
8897c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
8907c478bd9Sstevel@tonic-gate 			    "event delivery thread: door_ki_upcall error %d\n",
8917c478bd9Sstevel@tonic-gate 			    error);
8927c478bd9Sstevel@tonic-gate 			return (EVQ_CONT);
8937c478bd9Sstevel@tonic-gate 		}
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 	if (retval == EAGAIN) {
8967c478bd9Sstevel@tonic-gate 		return (EVQ_AGAIN);
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 	return (EVQ_CONT);
8997c478bd9Sstevel@tonic-gate }
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate /*
9027c478bd9Sstevel@tonic-gate  * Callback routine for evch_dl_search() to compare subscriber id's. Used by
9037c478bd9Sstevel@tonic-gate  * evch_subscribe() and evch_chrdevent_init().
9047c478bd9Sstevel@tonic-gate  */
9057c478bd9Sstevel@tonic-gate static int
9067c478bd9Sstevel@tonic-gate evch_subidcmp(evch_dlelem_t *ep, char *s)
9077c478bd9Sstevel@tonic-gate {
9087c478bd9Sstevel@tonic-gate 	return (strcmp(((evch_subd_t *)ep)->sd_ident, s));
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate /*
9127c478bd9Sstevel@tonic-gate  * Callback routine for evch_dl_search() to find a subscriber with EVCH_SUB_DUMP
9137c478bd9Sstevel@tonic-gate  * set (indicated by sub->sd_dump != 0). Used by evch_chrdevent_init() and
9147c478bd9Sstevel@tonic-gate  * evch_subscribe(). Needs to returns 0 if subscriber with sd_dump set is
9157c478bd9Sstevel@tonic-gate  * found.
9167c478bd9Sstevel@tonic-gate  */
9177c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
9187c478bd9Sstevel@tonic-gate static int
9197c478bd9Sstevel@tonic-gate evch_dumpflgcmp(evch_dlelem_t *ep, char *s)
9207c478bd9Sstevel@tonic-gate {
9217c478bd9Sstevel@tonic-gate 	return (((evch_subd_t *)ep)->sd_dump ? 0 : 1);
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate /*
9257c478bd9Sstevel@tonic-gate  * Event destructor function. Used to maintain the number of events per channel.
9267c478bd9Sstevel@tonic-gate  */
9277c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9287c478bd9Sstevel@tonic-gate static void
9297c478bd9Sstevel@tonic-gate evch_destr_event(void *ev, void *ch)
9307c478bd9Sstevel@tonic-gate {
9317c478bd9Sstevel@tonic-gate 	evch_chan_t *chp = (evch_chan_t *)ch;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	mutex_enter(&chp->ch_pubmx);
9347c478bd9Sstevel@tonic-gate 	chp->ch_nevents--;
9357c478bd9Sstevel@tonic-gate 	cv_signal(&chp->ch_pubcv);
9367c478bd9Sstevel@tonic-gate 	mutex_exit(&chp->ch_pubmx);
9377c478bd9Sstevel@tonic-gate }
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate /*
9407c478bd9Sstevel@tonic-gate  * Integer square root according to Newton's iteration.
9417c478bd9Sstevel@tonic-gate  */
9427c478bd9Sstevel@tonic-gate static uint32_t
9437c478bd9Sstevel@tonic-gate evch_isqrt(uint64_t n)
9447c478bd9Sstevel@tonic-gate {
9457c478bd9Sstevel@tonic-gate 	uint64_t	x = n >> 1;
9467c478bd9Sstevel@tonic-gate 	uint64_t	xn = x - 1;
9477c478bd9Sstevel@tonic-gate 	static uint32_t	lowval[] = { 0, 1, 1, 2 };
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	if (n < 4) {
9507c478bd9Sstevel@tonic-gate 		return (lowval[n]);
9517c478bd9Sstevel@tonic-gate 	}
9527c478bd9Sstevel@tonic-gate 	while (xn < x) {
9537c478bd9Sstevel@tonic-gate 		x = xn;
9547c478bd9Sstevel@tonic-gate 		xn = (x + n / x) / 2;
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 	return ((uint32_t)xn);
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate /*
9607c478bd9Sstevel@tonic-gate  * First step sysevent channel initialization. Called when kernel memory
9617c478bd9Sstevel@tonic-gate  * allocator is initialized.
9627c478bd9Sstevel@tonic-gate  */
9637c478bd9Sstevel@tonic-gate static void
9647c478bd9Sstevel@tonic-gate evch_chinit()
9657c478bd9Sstevel@tonic-gate {
9667c478bd9Sstevel@tonic-gate 	size_t k;
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	/*
9697c478bd9Sstevel@tonic-gate 	 * Calculate limits: max no of channels and max no of events per
9707c478bd9Sstevel@tonic-gate 	 * channel. The smallest machine with 128 MByte will allow for
9717c478bd9Sstevel@tonic-gate 	 * >= 8 channels and an upper limit of 2048 events per channel.
9727c478bd9Sstevel@tonic-gate 	 * The event limit is the number of channels times 256 (hence
9737c478bd9Sstevel@tonic-gate 	 * the shift factor of 8). These number where selected arbitrarily.
9747c478bd9Sstevel@tonic-gate 	 */
9757c478bd9Sstevel@tonic-gate 	k = kmem_maxavail() >> 20;
9767c478bd9Sstevel@tonic-gate 	evch_channels_max = min(evch_isqrt(k), EVCH_MAX_CHANNELS);
9777c478bd9Sstevel@tonic-gate 	evch_events_max = evch_channels_max << 8;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	/*
9807c478bd9Sstevel@tonic-gate 	 * Will trigger creation of the global zone's evch state.
9817c478bd9Sstevel@tonic-gate 	 */
9827c478bd9Sstevel@tonic-gate 	zone_key_create(&evch_zone_key, evch_zoneinit, NULL, evch_zonefree);
9837c478bd9Sstevel@tonic-gate }
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate /*
9867c478bd9Sstevel@tonic-gate  * Second step sysevent channel initialization. Called when threads are ready.
9877c478bd9Sstevel@tonic-gate  */
9887c478bd9Sstevel@tonic-gate static void
9897c478bd9Sstevel@tonic-gate evch_chinitthr()
9907c478bd9Sstevel@tonic-gate {
9917c478bd9Sstevel@tonic-gate 	struct evch_globals *eg;
9927c478bd9Sstevel@tonic-gate 	evch_chan_t	*chp;
9937c478bd9Sstevel@tonic-gate 	evch_subd_t	*sdp;
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	/*
9967c478bd9Sstevel@tonic-gate 	 * We're early enough in boot that we know that only the global
9977c478bd9Sstevel@tonic-gate 	 * zone exists; we only need to initialize its threads.
9987c478bd9Sstevel@tonic-gate 	 */
9997c478bd9Sstevel@tonic-gate 	eg = zone_getspecific(evch_zone_key, global_zone);
10007c478bd9Sstevel@tonic-gate 	ASSERT(eg != NULL);
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	for (chp = evch_dl_next(&eg->evch_list, NULL); chp != NULL;
10037c478bd9Sstevel@tonic-gate 	    chp = evch_dl_next(&eg->evch_list, chp)) {
10047c478bd9Sstevel@tonic-gate 		for (sdp = evch_dl_next(&chp->ch_subscr, NULL); sdp;
10057c478bd9Sstevel@tonic-gate 		    sdp = evch_dl_next(&chp->ch_subscr, sdp)) {
10067c478bd9Sstevel@tonic-gate 			evch_evq_thrcreate(sdp->sd_queue);
10077c478bd9Sstevel@tonic-gate 		}
10087c478bd9Sstevel@tonic-gate 		evch_evq_thrcreate(chp->ch_queue);
10097c478bd9Sstevel@tonic-gate 	}
10107c478bd9Sstevel@tonic-gate 	evq_initcomplete = 1;
10117c478bd9Sstevel@tonic-gate }
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate /*
10147c478bd9Sstevel@tonic-gate  * Sysevent channel bind. Create channel and allocate binding structure.
10157c478bd9Sstevel@tonic-gate  */
10167c478bd9Sstevel@tonic-gate static int
10177c478bd9Sstevel@tonic-gate evch_chbind(const char *chnam, evch_bind_t **scpp, uint32_t flags)
10187c478bd9Sstevel@tonic-gate {
10197c478bd9Sstevel@tonic-gate 	struct evch_globals *eg;
10207c478bd9Sstevel@tonic-gate 	evch_bind_t	*bp;
10217c478bd9Sstevel@tonic-gate 	evch_chan_t	*p;
10227c478bd9Sstevel@tonic-gate 	char		*chn;
10237c478bd9Sstevel@tonic-gate 	size_t		namlen;
10247c478bd9Sstevel@tonic-gate 	int		rv;
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	eg = zone_getspecific(evch_zone_key, curproc->p_zone);
10277c478bd9Sstevel@tonic-gate 	ASSERT(eg != NULL);
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	/* Create channel if it does not exist */
10307c478bd9Sstevel@tonic-gate 	ASSERT(evch_dl_is_init(&eg->evch_list));
10317c478bd9Sstevel@tonic-gate 	if ((namlen = strlen(chnam) + 1) > MAX_CHNAME_LEN) {
10327c478bd9Sstevel@tonic-gate 		return (EINVAL);
10337c478bd9Sstevel@tonic-gate 	}
10347c478bd9Sstevel@tonic-gate 	mutex_enter(&eg->evch_list_lock);
10357c478bd9Sstevel@tonic-gate 	if ((p = (evch_chan_t *)evch_dl_search(&eg->evch_list, evch_namecmp,
10367c478bd9Sstevel@tonic-gate 	    (char *)chnam)) == NULL) {
10377c478bd9Sstevel@tonic-gate 		if (flags & EVCH_CREAT) {
10387c478bd9Sstevel@tonic-gate 			if (evch_dl_getnum(&eg->evch_list) >=
10397c478bd9Sstevel@tonic-gate 			    evch_channels_max) {
10407c478bd9Sstevel@tonic-gate 				mutex_exit(&eg->evch_list_lock);
10417c478bd9Sstevel@tonic-gate 				return (ENOMEM);
10427c478bd9Sstevel@tonic-gate 			}
10437c478bd9Sstevel@tonic-gate 			chn = kmem_alloc(namlen, KM_SLEEP);
10447c478bd9Sstevel@tonic-gate 			bcopy(chnam, chn, namlen);
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 			/* Allocate and initialize channel descriptor */
10477c478bd9Sstevel@tonic-gate 			p = kmem_zalloc(sizeof (evch_chan_t), KM_SLEEP);
10487c478bd9Sstevel@tonic-gate 			p->ch_name = chn;
10497c478bd9Sstevel@tonic-gate 			p->ch_namelen = namlen;
10507c478bd9Sstevel@tonic-gate 			mutex_init(&p->ch_mutex, NULL, MUTEX_DEFAULT, NULL);
10517c478bd9Sstevel@tonic-gate 			p->ch_queue = evch_evq_create();
10527c478bd9Sstevel@tonic-gate 			evch_dl_init(&p->ch_subscr);
10537c478bd9Sstevel@tonic-gate 			if (evq_initcomplete) {
10547c478bd9Sstevel@tonic-gate 				p->ch_uid = crgetuid(curthread->t_cred);
10557c478bd9Sstevel@tonic-gate 				p->ch_gid = crgetgid(curthread->t_cred);
10567c478bd9Sstevel@tonic-gate 			}
10577c478bd9Sstevel@tonic-gate 			cv_init(&p->ch_pubcv, NULL, CV_DEFAULT, NULL);
10587c478bd9Sstevel@tonic-gate 			mutex_init(&p->ch_pubmx, NULL, MUTEX_DEFAULT, NULL);
10597c478bd9Sstevel@tonic-gate 			p->ch_maxev = min(EVCH_DEFAULT_EVENTS, evch_events_max);
10607c478bd9Sstevel@tonic-gate 			p->ch_maxsubscr = EVCH_MAX_SUBSCRIPTIONS;
10617c478bd9Sstevel@tonic-gate 			p->ch_maxbinds = evch_bindings_max;
10627c478bd9Sstevel@tonic-gate 			p->ch_ctime = gethrestime_sec();
10637c478bd9Sstevel@tonic-gate 			if (flags & EVCH_HOLD_PEND) {
10647c478bd9Sstevel@tonic-gate 				p->ch_holdpend = 1;
10657c478bd9Sstevel@tonic-gate 				evch_evq_stop(p->ch_queue);
10667c478bd9Sstevel@tonic-gate 			}
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 			/* Put new descriptor into channel list */
10697c478bd9Sstevel@tonic-gate 			evch_dl_add(&eg->evch_list, (evch_dlelem_t *)p);
10707c478bd9Sstevel@tonic-gate 		} else {
10717c478bd9Sstevel@tonic-gate 			mutex_exit(&eg->evch_list_lock);
10727c478bd9Sstevel@tonic-gate 			return (ENOENT);
10737c478bd9Sstevel@tonic-gate 		}
10747c478bd9Sstevel@tonic-gate 	}
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	/* Check for max binds and create binding */
10777c478bd9Sstevel@tonic-gate 	mutex_enter(&p->ch_mutex);
10787c478bd9Sstevel@tonic-gate 	if (p->ch_bindings >= p->ch_maxbinds) {
10797c478bd9Sstevel@tonic-gate 		rv = ENOMEM;
10807c478bd9Sstevel@tonic-gate 		/*
10817c478bd9Sstevel@tonic-gate 		 * No need to destroy the channel because this call did not
10827c478bd9Sstevel@tonic-gate 		 * create it. Other bindings will be present if ch_maxbinds
10837c478bd9Sstevel@tonic-gate 		 * is exceeded.
10847c478bd9Sstevel@tonic-gate 		 */
10857c478bd9Sstevel@tonic-gate 		goto errorexit;
10867c478bd9Sstevel@tonic-gate 	}
10877c478bd9Sstevel@tonic-gate 	bp = kmem_alloc(sizeof (evch_bind_t), KM_SLEEP);
10887c478bd9Sstevel@tonic-gate 	bp->bd_channel = p;
10897c478bd9Sstevel@tonic-gate 	bp->bd_sublst = NULL;
10907c478bd9Sstevel@tonic-gate 	p->ch_bindings++;
10917c478bd9Sstevel@tonic-gate 	rv = 0;
10927c478bd9Sstevel@tonic-gate 	*scpp = bp;
10937c478bd9Sstevel@tonic-gate errorexit:
10947c478bd9Sstevel@tonic-gate 	mutex_exit(&p->ch_mutex);
10957c478bd9Sstevel@tonic-gate 	mutex_exit(&eg->evch_list_lock);
10967c478bd9Sstevel@tonic-gate 	return (rv);
10977c478bd9Sstevel@tonic-gate }
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate /*
11007c478bd9Sstevel@tonic-gate  * Unbind: Free bind structure. Remove channel if last binding was freed.
11017c478bd9Sstevel@tonic-gate  */
11027c478bd9Sstevel@tonic-gate static void
11037c478bd9Sstevel@tonic-gate evch_chunbind(evch_bind_t *bp)
11047c478bd9Sstevel@tonic-gate {
11057c478bd9Sstevel@tonic-gate 	struct evch_globals *eg;
11067c478bd9Sstevel@tonic-gate 	evch_chan_t *chp = bp->bd_channel;
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 	eg = zone_getspecific(evch_zone_key, curproc->p_zone);
11097c478bd9Sstevel@tonic-gate 	ASSERT(eg != NULL);
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	mutex_enter(&eg->evch_list_lock);
11127c478bd9Sstevel@tonic-gate 	mutex_enter(&chp->ch_mutex);
11137c478bd9Sstevel@tonic-gate 	ASSERT(chp->ch_bindings > 0);
11147c478bd9Sstevel@tonic-gate 	chp->ch_bindings--;
11157c478bd9Sstevel@tonic-gate 	kmem_free(bp, sizeof (evch_bind_t));
11167c478bd9Sstevel@tonic-gate 	if (chp->ch_bindings == 0 && evch_dl_getnum(&chp->ch_subscr) == 0) {
11177c478bd9Sstevel@tonic-gate 		/*
11187c478bd9Sstevel@tonic-gate 		 * No more bindings or persistent subscriber, destroy channel.
11197c478bd9Sstevel@tonic-gate 		 */
11207c478bd9Sstevel@tonic-gate 		mutex_exit(&chp->ch_mutex);
11217c478bd9Sstevel@tonic-gate 		evch_dl_del(&eg->evch_list, &chp->ch_link);
11227c478bd9Sstevel@tonic-gate 		evch_evq_destroy(chp->ch_queue);
11237c478bd9Sstevel@tonic-gate 		mutex_destroy(&chp->ch_mutex);
11247c478bd9Sstevel@tonic-gate 		mutex_destroy(&chp->ch_pubmx);
11257c478bd9Sstevel@tonic-gate 		cv_destroy(&chp->ch_pubcv);
11267c478bd9Sstevel@tonic-gate 		kmem_free(chp->ch_name, chp->ch_namelen);
11277c478bd9Sstevel@tonic-gate 		kmem_free(chp, sizeof (evch_chan_t));
11287c478bd9Sstevel@tonic-gate 	} else
11297c478bd9Sstevel@tonic-gate 		mutex_exit(&chp->ch_mutex);
11307c478bd9Sstevel@tonic-gate 	mutex_exit(&eg->evch_list_lock);
11317c478bd9Sstevel@tonic-gate }
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate /*
11347c478bd9Sstevel@tonic-gate  * Subscribe to a channel. dtype is either EVCH_DELKERN for kernel callbacks
11357c478bd9Sstevel@tonic-gate  * or EVCH_DELDOOR for door upcall delivery to user land. Depending on dtype
11367c478bd9Sstevel@tonic-gate  * dinfo gives the call back routine address or the door handle.
11377c478bd9Sstevel@tonic-gate  */
11387c478bd9Sstevel@tonic-gate static int
11397c478bd9Sstevel@tonic-gate evch_chsubscribe(evch_bind_t *bp, int dtype, const char *sid, const char *class,
11407c478bd9Sstevel@tonic-gate     void *dinfo, void *cookie, int flags, pid_t pid)
11417c478bd9Sstevel@tonic-gate {
11427c478bd9Sstevel@tonic-gate 	evch_chan_t	*chp = bp->bd_channel;
11437c478bd9Sstevel@tonic-gate 	evch_eventq_t	*eqp = chp->ch_queue;
11447c478bd9Sstevel@tonic-gate 	evch_subd_t	*sdp;
11457c478bd9Sstevel@tonic-gate 	evch_subd_t	*esp;
11467c478bd9Sstevel@tonic-gate 	int		(*delivfkt)();
11477c478bd9Sstevel@tonic-gate 	char		*clb = NULL;
11487c478bd9Sstevel@tonic-gate 	int		clblen = 0;
11497c478bd9Sstevel@tonic-gate 	char		*subid;
11507c478bd9Sstevel@tonic-gate 	int		subidblen;
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	/*
11537c478bd9Sstevel@tonic-gate 	 * Check if only known flags are set.
11547c478bd9Sstevel@tonic-gate 	 */
11557c478bd9Sstevel@tonic-gate 	if (flags & ~(EVCH_SUB_KEEP | EVCH_SUB_DUMP))
11567c478bd9Sstevel@tonic-gate 		return (EINVAL);
11577c478bd9Sstevel@tonic-gate 	/*
11587c478bd9Sstevel@tonic-gate 	 * Check if we have already a subscription with that name and if we
11597c478bd9Sstevel@tonic-gate 	 * have to reconnect the subscriber to a persistent subscription.
11607c478bd9Sstevel@tonic-gate 	 */
11617c478bd9Sstevel@tonic-gate 	mutex_enter(&chp->ch_mutex);
11627c478bd9Sstevel@tonic-gate 	if ((esp = (evch_subd_t *)evch_dl_search(&chp->ch_subscr,
11637c478bd9Sstevel@tonic-gate 	    evch_subidcmp, (char *)sid)) != NULL) {
11647c478bd9Sstevel@tonic-gate 		int error = 0;
11657c478bd9Sstevel@tonic-gate 		if ((flags & EVCH_SUB_KEEP) && (esp->sd_active == 0)) {
11667c478bd9Sstevel@tonic-gate 			/*
11677c478bd9Sstevel@tonic-gate 			 * Subscription with the name on hold, reconnect to
11687c478bd9Sstevel@tonic-gate 			 * existing queue.
11697c478bd9Sstevel@tonic-gate 			 */
11707c478bd9Sstevel@tonic-gate 			ASSERT(dtype == EVCH_DELDOOR);
11717c478bd9Sstevel@tonic-gate 			esp->sd_subnxt = bp->bd_sublst;
11727c478bd9Sstevel@tonic-gate 			bp->bd_sublst = esp;
11737c478bd9Sstevel@tonic-gate 			esp->sd_pid = pid;
11747c478bd9Sstevel@tonic-gate 			esp->sd_door = (door_handle_t)dinfo;
11757c478bd9Sstevel@tonic-gate 			esp->sd_active++;
11767c478bd9Sstevel@tonic-gate 			evch_evq_continue(esp->sd_queue);
11777c478bd9Sstevel@tonic-gate 		} else {
11787c478bd9Sstevel@tonic-gate 			/* Subscriber with given name already exists */
11797c478bd9Sstevel@tonic-gate 			error = EEXIST;
11807c478bd9Sstevel@tonic-gate 		}
11817c478bd9Sstevel@tonic-gate 		mutex_exit(&chp->ch_mutex);
11827c478bd9Sstevel@tonic-gate 		return (error);
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	if (evch_dl_getnum(&chp->ch_subscr) >= chp->ch_maxsubscr) {
11867c478bd9Sstevel@tonic-gate 		mutex_exit(&chp->ch_mutex);
11877c478bd9Sstevel@tonic-gate 		return (ENOMEM);
11887c478bd9Sstevel@tonic-gate 	}
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	if (flags & EVCH_SUB_DUMP && evch_dl_search(&chp->ch_subscr,
11917c478bd9Sstevel@tonic-gate 	    evch_dumpflgcmp, NULL) != NULL) {
11927c478bd9Sstevel@tonic-gate 		/*
11937c478bd9Sstevel@tonic-gate 		 * Subscription with EVCH_SUB_DUMP flagged already exists.
11947c478bd9Sstevel@tonic-gate 		 * Only one subscription with EVCH_SUB_DUMP possible. Return
11957c478bd9Sstevel@tonic-gate 		 * error.
11967c478bd9Sstevel@tonic-gate 		 */
11977c478bd9Sstevel@tonic-gate 		mutex_exit(&chp->ch_mutex);
11987c478bd9Sstevel@tonic-gate 		return (EINVAL);
11997c478bd9Sstevel@tonic-gate 	}
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	if (class != NULL) {
12027c478bd9Sstevel@tonic-gate 		clblen = strlen(class) + 1;
12037c478bd9Sstevel@tonic-gate 		clb = kmem_alloc(clblen, KM_SLEEP);
12047c478bd9Sstevel@tonic-gate 		bcopy(class, clb, clblen);
12057c478bd9Sstevel@tonic-gate 	}
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 	subidblen = strlen(sid) + 1;
12087c478bd9Sstevel@tonic-gate 	subid = kmem_alloc(subidblen, KM_SLEEP);
12097c478bd9Sstevel@tonic-gate 	bcopy(sid, subid, subidblen);
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	/* Create per subscriber queue */
12127c478bd9Sstevel@tonic-gate 	sdp = kmem_zalloc(sizeof (evch_subd_t), KM_SLEEP);
12137c478bd9Sstevel@tonic-gate 	sdp->sd_queue = evch_evq_create();
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	/* Subscribe to subscriber queue */
12167c478bd9Sstevel@tonic-gate 	sdp->sd_persist = flags & EVCH_SUB_KEEP ? 1 : 0;
12177c478bd9Sstevel@tonic-gate 	sdp->sd_dump = flags & EVCH_SUB_DUMP ? 1 : 0;
12187c478bd9Sstevel@tonic-gate 	sdp->sd_type = dtype;
12197c478bd9Sstevel@tonic-gate 	sdp->sd_cbcookie = cookie;
12207c478bd9Sstevel@tonic-gate 	sdp->sd_ident = subid;
12217c478bd9Sstevel@tonic-gate 	if (dtype == EVCH_DELKERN) {
12227c478bd9Sstevel@tonic-gate 		sdp->sd_callback = (kerndlv_f)dinfo;
12237c478bd9Sstevel@tonic-gate 		delivfkt = evch_kern_deliver;
12247c478bd9Sstevel@tonic-gate 	} else {
12257c478bd9Sstevel@tonic-gate 		sdp->sd_door = (door_handle_t)dinfo;
12267c478bd9Sstevel@tonic-gate 		delivfkt = evch_door_deliver;
12277c478bd9Sstevel@tonic-gate 	}
12287c478bd9Sstevel@tonic-gate 	sdp->sd_ssub =
12297c478bd9Sstevel@tonic-gate 	    evch_evq_sub(sdp->sd_queue, NULL, NULL, delivfkt, (void *)sdp);
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	/* Connect per subscriber queue to main event queue */
12327c478bd9Sstevel@tonic-gate 	sdp->sd_msub = evch_evq_sub(eqp, evch_class_filter, clb,
12337c478bd9Sstevel@tonic-gate 	    evch_subq_deliver, (void *)sdp);
12347c478bd9Sstevel@tonic-gate 	sdp->sd_classname = clb;
12357c478bd9Sstevel@tonic-gate 	sdp->sd_clnsize = clblen;
12367c478bd9Sstevel@tonic-gate 	sdp->sd_pid = pid;
12377c478bd9Sstevel@tonic-gate 	sdp->sd_active++;
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 	/* Add subscription to binding */
12407c478bd9Sstevel@tonic-gate 	sdp->sd_subnxt = bp->bd_sublst;
12417c478bd9Sstevel@tonic-gate 	bp->bd_sublst = sdp;
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	/* Add subscription to channel */
12447c478bd9Sstevel@tonic-gate 	evch_dl_add(&chp->ch_subscr, &sdp->sd_link);
12457c478bd9Sstevel@tonic-gate 	if (chp->ch_holdpend && evch_dl_getnum(&chp->ch_subscr) == 1) {
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 		/* Let main event queue run in case of HOLDPEND */
12487c478bd9Sstevel@tonic-gate 		evch_evq_continue(eqp);
12497c478bd9Sstevel@tonic-gate 	}
12507c478bd9Sstevel@tonic-gate 	mutex_exit(&chp->ch_mutex);
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	return (0);
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate /*
12567c478bd9Sstevel@tonic-gate  * If flag == EVCH_SUB_KEEP only non-persistent subscriptions are deleted.
12577c478bd9Sstevel@tonic-gate  * When sid == NULL all subscriptions except the ones with EVCH_SUB_KEEP set
12587c478bd9Sstevel@tonic-gate  * are removed.
12597c478bd9Sstevel@tonic-gate  */
12607c478bd9Sstevel@tonic-gate static void
12617c478bd9Sstevel@tonic-gate evch_chunsubscribe(evch_bind_t *bp, const char *sid, uint32_t flags)
12627c478bd9Sstevel@tonic-gate {
12637c478bd9Sstevel@tonic-gate 	evch_subd_t	*sdp;
12647c478bd9Sstevel@tonic-gate 	evch_subd_t	*next;
12657c478bd9Sstevel@tonic-gate 	evch_subd_t	*prev;
12667c478bd9Sstevel@tonic-gate 	evch_chan_t	*chp = bp->bd_channel;
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 	mutex_enter(&chp->ch_mutex);
12697c478bd9Sstevel@tonic-gate 	if (chp->ch_holdpend) {
12707c478bd9Sstevel@tonic-gate 		evch_evq_stop(chp->ch_queue);	/* Hold main event queue */
12717c478bd9Sstevel@tonic-gate 	}
12727c478bd9Sstevel@tonic-gate 	prev = NULL;
12737c478bd9Sstevel@tonic-gate 	for (sdp = bp->bd_sublst; sdp; sdp = next) {
12747c478bd9Sstevel@tonic-gate 		if (sid == NULL || strcmp(sid, sdp->sd_ident) == 0) {
12757c478bd9Sstevel@tonic-gate 			if (flags == 0 || sdp->sd_persist == 0) {
12767c478bd9Sstevel@tonic-gate 				/*
12777c478bd9Sstevel@tonic-gate 				 * Disconnect subscriber queue from main event
12787c478bd9Sstevel@tonic-gate 				 * queue.
12797c478bd9Sstevel@tonic-gate 				 */
12807c478bd9Sstevel@tonic-gate 				evch_evq_unsub(chp->ch_queue, sdp->sd_msub);
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 				/* Destruct per subscriber queue */
12837c478bd9Sstevel@tonic-gate 				evch_evq_unsub(sdp->sd_queue, sdp->sd_ssub);
12847c478bd9Sstevel@tonic-gate 				evch_evq_destroy(sdp->sd_queue);
12857c478bd9Sstevel@tonic-gate 				/*
12867c478bd9Sstevel@tonic-gate 				 * Eliminate the subscriber data from channel
12877c478bd9Sstevel@tonic-gate 				 * list.
12887c478bd9Sstevel@tonic-gate 				 */
12897c478bd9Sstevel@tonic-gate 				evch_dl_del(&chp->ch_subscr, &sdp->sd_link);
12907c478bd9Sstevel@tonic-gate 				kmem_free(sdp->sd_classname, sdp->sd_clnsize);
12917c478bd9Sstevel@tonic-gate 				if (sdp->sd_type == EVCH_DELDOOR) {
12927c478bd9Sstevel@tonic-gate 					door_ki_rele(sdp->sd_door);
12937c478bd9Sstevel@tonic-gate 				}
12947c478bd9Sstevel@tonic-gate 				next = sdp->sd_subnxt;
12957c478bd9Sstevel@tonic-gate 				if (prev) {
12967c478bd9Sstevel@tonic-gate 					prev->sd_subnxt = next;
12977c478bd9Sstevel@tonic-gate 				} else {
12987c478bd9Sstevel@tonic-gate 					bp->bd_sublst = next;
12997c478bd9Sstevel@tonic-gate 				}
13007c478bd9Sstevel@tonic-gate 				kmem_free(sdp->sd_ident,
13017c478bd9Sstevel@tonic-gate 				    strlen(sdp->sd_ident) + 1);
13027c478bd9Sstevel@tonic-gate 				kmem_free(sdp, sizeof (evch_subd_t));
13037c478bd9Sstevel@tonic-gate 			} else {
13047c478bd9Sstevel@tonic-gate 				/*
13057c478bd9Sstevel@tonic-gate 				 * EVCH_SUB_KEEP case
13067c478bd9Sstevel@tonic-gate 				 */
13077c478bd9Sstevel@tonic-gate 				evch_evq_stop(sdp->sd_queue);
13087c478bd9Sstevel@tonic-gate 				if (sdp->sd_type == EVCH_DELDOOR) {
13097c478bd9Sstevel@tonic-gate 					door_ki_rele(sdp->sd_door);
13107c478bd9Sstevel@tonic-gate 				}
13117c478bd9Sstevel@tonic-gate 				sdp->sd_active--;
13127c478bd9Sstevel@tonic-gate 				ASSERT(sdp->sd_active == 0);
13137c478bd9Sstevel@tonic-gate 				next = sdp->sd_subnxt;
13147c478bd9Sstevel@tonic-gate 				prev = sdp;
13157c478bd9Sstevel@tonic-gate 			}
13167c478bd9Sstevel@tonic-gate 			if (sid != NULL) {
13177c478bd9Sstevel@tonic-gate 				break;
13187c478bd9Sstevel@tonic-gate 			}
13197c478bd9Sstevel@tonic-gate 		} else {
13207c478bd9Sstevel@tonic-gate 			next = sdp->sd_subnxt;
13217c478bd9Sstevel@tonic-gate 			prev = sdp;
13227c478bd9Sstevel@tonic-gate 		}
13237c478bd9Sstevel@tonic-gate 	}
13247c478bd9Sstevel@tonic-gate 	if (!(chp->ch_holdpend && evch_dl_getnum(&chp->ch_subscr) == 0)) {
13257c478bd9Sstevel@tonic-gate 		/*
13267c478bd9Sstevel@tonic-gate 		 * Continue dispatch thread except if no subscribers are present
13277c478bd9Sstevel@tonic-gate 		 * in HOLDPEND mode.
13287c478bd9Sstevel@tonic-gate 		 */
13297c478bd9Sstevel@tonic-gate 		evch_evq_continue(chp->ch_queue);
13307c478bd9Sstevel@tonic-gate 	}
13317c478bd9Sstevel@tonic-gate 	mutex_exit(&chp->ch_mutex);
13327c478bd9Sstevel@tonic-gate }
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate /*
13357c478bd9Sstevel@tonic-gate  * Publish an event. Returns zero on success and an error code else.
13367c478bd9Sstevel@tonic-gate  */
13377c478bd9Sstevel@tonic-gate static int
13387c478bd9Sstevel@tonic-gate evch_chpublish(evch_bind_t *bp, sysevent_impl_t *ev, int flags)
13397c478bd9Sstevel@tonic-gate {
13407c478bd9Sstevel@tonic-gate 	evch_chan_t *chp = bp->bd_channel;
13417c478bd9Sstevel@tonic-gate 
1342*e04145d0Seschrock 	DTRACE_SYSEVENT2(post, evch_bind_t *, bp, sysevent_impl_t *, ev);
1343*e04145d0Seschrock 
13447c478bd9Sstevel@tonic-gate 	mutex_enter(&chp->ch_pubmx);
13457c478bd9Sstevel@tonic-gate 	if (chp->ch_nevents >= chp->ch_maxev) {
13467c478bd9Sstevel@tonic-gate 		if (!(flags & EVCH_QWAIT)) {
13477c478bd9Sstevel@tonic-gate 			evch_evq_evfree(ev);
13487c478bd9Sstevel@tonic-gate 			mutex_exit(&chp->ch_pubmx);
13497c478bd9Sstevel@tonic-gate 			return (EAGAIN);
13507c478bd9Sstevel@tonic-gate 		} else {
13517c478bd9Sstevel@tonic-gate 			while (chp->ch_nevents >= chp->ch_maxev) {
13527c478bd9Sstevel@tonic-gate 				if (cv_wait_sig(&chp->ch_pubcv,
13537c478bd9Sstevel@tonic-gate 				    &chp->ch_pubmx) == 0) {
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 					/* Got Signal, return EINTR */
13567c478bd9Sstevel@tonic-gate 					evch_evq_evfree(ev);
13577c478bd9Sstevel@tonic-gate 					mutex_exit(&chp->ch_pubmx);
13587c478bd9Sstevel@tonic-gate 					return (EINTR);
13597c478bd9Sstevel@tonic-gate 				}
13607c478bd9Sstevel@tonic-gate 			}
13617c478bd9Sstevel@tonic-gate 		}
13627c478bd9Sstevel@tonic-gate 	}
13637c478bd9Sstevel@tonic-gate 	chp->ch_nevents++;
13647c478bd9Sstevel@tonic-gate 	mutex_exit(&chp->ch_pubmx);
13657c478bd9Sstevel@tonic-gate 	SE_TIME(ev) = gethrtime();
13667c478bd9Sstevel@tonic-gate 	SE_SEQ(ev) = log_sysevent_new_id();
13677c478bd9Sstevel@tonic-gate 	/*
13687c478bd9Sstevel@tonic-gate 	 * Add the destructor function to the event structure, now that the
13697c478bd9Sstevel@tonic-gate 	 * event is accounted for. The only task of the descructor is to
13707c478bd9Sstevel@tonic-gate 	 * decrement the channel event count. The evq_*() routines (including
13717c478bd9Sstevel@tonic-gate 	 * the event delivery thread) do not have knowledge of the channel
13727c478bd9Sstevel@tonic-gate 	 * data. So the anonymous destructor handles the channel data for it.
13737c478bd9Sstevel@tonic-gate 	 */
13747c478bd9Sstevel@tonic-gate 	evch_evq_evadd_dest(ev, evch_destr_event, (void *)chp);
13757c478bd9Sstevel@tonic-gate 	return (evch_evq_pub(chp->ch_queue, ev, flags) == 0 ? 0 : EAGAIN);
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate /*
13797c478bd9Sstevel@tonic-gate  * Fills a buffer consecutive with the names of all available channels.
13807c478bd9Sstevel@tonic-gate  * Returns the length of all name strings or -1 if buffer size was unsufficient.
13817c478bd9Sstevel@tonic-gate  */
13827c478bd9Sstevel@tonic-gate static int
13837c478bd9Sstevel@tonic-gate evch_chgetnames(char *buf, size_t size)
13847c478bd9Sstevel@tonic-gate {
13857c478bd9Sstevel@tonic-gate 	struct evch_globals *eg;
13867c478bd9Sstevel@tonic-gate 	int		len = 0;
13877c478bd9Sstevel@tonic-gate 	char		*addr = buf;
13887c478bd9Sstevel@tonic-gate 	int		max = size;
13897c478bd9Sstevel@tonic-gate 	evch_chan_t	*chp;
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 	eg = zone_getspecific(evch_zone_key, curproc->p_zone);
13927c478bd9Sstevel@tonic-gate 	ASSERT(eg != NULL);
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 	mutex_enter(&eg->evch_list_lock);
13957c478bd9Sstevel@tonic-gate 	for (chp = evch_dl_next(&eg->evch_list, NULL); chp != NULL;
13967c478bd9Sstevel@tonic-gate 	    chp = evch_dl_next(&eg->evch_list, chp)) {
13977c478bd9Sstevel@tonic-gate 		len += chp->ch_namelen;
13987c478bd9Sstevel@tonic-gate 		if (len >= max) {
13997c478bd9Sstevel@tonic-gate 			mutex_exit(&eg->evch_list_lock);
14007c478bd9Sstevel@tonic-gate 			return (-1);
14017c478bd9Sstevel@tonic-gate 		}
14027c478bd9Sstevel@tonic-gate 		bcopy(chp->ch_name, addr, chp->ch_namelen);
14037c478bd9Sstevel@tonic-gate 		addr += chp->ch_namelen;
14047c478bd9Sstevel@tonic-gate 	}
14057c478bd9Sstevel@tonic-gate 	mutex_exit(&eg->evch_list_lock);
14067c478bd9Sstevel@tonic-gate 	addr[0] = 0;
14077c478bd9Sstevel@tonic-gate 	return (len + 1);
14087c478bd9Sstevel@tonic-gate }
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate /*
14117c478bd9Sstevel@tonic-gate  * Fills the data of one channel and all subscribers of that channel into
14127c478bd9Sstevel@tonic-gate  * a buffer. Returns -1 if the channel name is invalid and 0 on buffer overflow.
14137c478bd9Sstevel@tonic-gate  */
14147c478bd9Sstevel@tonic-gate static int
14157c478bd9Sstevel@tonic-gate evch_chgetchdata(char *chname, void *buf, size_t size)
14167c478bd9Sstevel@tonic-gate {
14177c478bd9Sstevel@tonic-gate 	struct evch_globals *eg;
14187c478bd9Sstevel@tonic-gate 	char		*cpaddr;
14197c478bd9Sstevel@tonic-gate 	int		bufmax;
14207c478bd9Sstevel@tonic-gate 	int		buflen;
14217c478bd9Sstevel@tonic-gate 	evch_chan_t	*chp;
14227c478bd9Sstevel@tonic-gate 	sev_chinfo_t	*p = (sev_chinfo_t *)buf;
14237c478bd9Sstevel@tonic-gate 	int		chdlen;
14247c478bd9Sstevel@tonic-gate 	evch_subd_t	*sdp;
14257c478bd9Sstevel@tonic-gate 	sev_subinfo_t	*subp;
14267c478bd9Sstevel@tonic-gate 	int		idlen;
14277c478bd9Sstevel@tonic-gate 	int		len;
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 	eg = zone_getspecific(evch_zone_key, curproc->p_zone);
14307c478bd9Sstevel@tonic-gate 	ASSERT(eg != NULL);
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 	mutex_enter(&eg->evch_list_lock);
14337c478bd9Sstevel@tonic-gate 	chp = (evch_chan_t *)evch_dl_search(&eg->evch_list, evch_namecmp,
14347c478bd9Sstevel@tonic-gate 	    chname);
14357c478bd9Sstevel@tonic-gate 	if (chp == NULL) {
14367c478bd9Sstevel@tonic-gate 		mutex_exit(&eg->evch_list_lock);
14377c478bd9Sstevel@tonic-gate 		return (-1);
14387c478bd9Sstevel@tonic-gate 	}
14397c478bd9Sstevel@tonic-gate 	chdlen = offsetof(sev_chinfo_t, cd_subinfo);
14407c478bd9Sstevel@tonic-gate 	if (size < chdlen) {
14417c478bd9Sstevel@tonic-gate 		mutex_exit(&eg->evch_list_lock);
14427c478bd9Sstevel@tonic-gate 		return (0);
14437c478bd9Sstevel@tonic-gate 	}
14447c478bd9Sstevel@tonic-gate 	p->cd_version = 0;
14457c478bd9Sstevel@tonic-gate 	p->cd_suboffs = chdlen;
14467c478bd9Sstevel@tonic-gate 	p->cd_uid = chp->ch_uid;
14477c478bd9Sstevel@tonic-gate 	p->cd_gid = chp->ch_gid;
14487c478bd9Sstevel@tonic-gate 	p->cd_perms = 0;
14497c478bd9Sstevel@tonic-gate 	p->cd_ctime = chp->ch_ctime;
14507c478bd9Sstevel@tonic-gate 	p->cd_maxev = chp->ch_maxev;
14517c478bd9Sstevel@tonic-gate 	p->cd_evhwm = EVCH_EVQ_HIGHWM(chp->ch_queue);
14527c478bd9Sstevel@tonic-gate 	p->cd_nevents = EVCH_EVQ_EVCOUNT(chp->ch_queue);
14537c478bd9Sstevel@tonic-gate 	p->cd_maxsub = chp->ch_maxsubscr;
14547c478bd9Sstevel@tonic-gate 	p->cd_nsub = evch_dl_getnum(&chp->ch_subscr);
14557c478bd9Sstevel@tonic-gate 	p->cd_maxbinds = chp->ch_maxbinds;
14567c478bd9Sstevel@tonic-gate 	p->cd_nbinds = chp->ch_bindings;
14577c478bd9Sstevel@tonic-gate 	p->cd_holdpend = chp->ch_holdpend;
14587c478bd9Sstevel@tonic-gate 	p->cd_limev = evch_events_max;
14597c478bd9Sstevel@tonic-gate 	cpaddr = (char *)p + chdlen;
14607c478bd9Sstevel@tonic-gate 	bufmax = size - chdlen;
14617c478bd9Sstevel@tonic-gate 	buflen = 0;
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	for (sdp = evch_dl_next(&chp->ch_subscr, NULL); sdp != NULL;
14647c478bd9Sstevel@tonic-gate 	    sdp = evch_dl_next(&chp->ch_subscr, sdp)) {
14657c478bd9Sstevel@tonic-gate 		idlen = strlen(sdp->sd_ident) + 1;
14667c478bd9Sstevel@tonic-gate 		len = SE_ALIGN(offsetof(sev_subinfo_t, sb_strings) + idlen +
14677c478bd9Sstevel@tonic-gate 		    sdp->sd_clnsize);
14687c478bd9Sstevel@tonic-gate 		buflen += len;
14697c478bd9Sstevel@tonic-gate 		if (buflen >= bufmax) {
14707c478bd9Sstevel@tonic-gate 			mutex_exit(&eg->evch_list_lock);
14717c478bd9Sstevel@tonic-gate 			return (0);
14727c478bd9Sstevel@tonic-gate 		}
14737c478bd9Sstevel@tonic-gate 		subp = (sev_subinfo_t *)cpaddr;
14747c478bd9Sstevel@tonic-gate 		subp->sb_nextoff = len;
14757c478bd9Sstevel@tonic-gate 		subp->sb_stroff = offsetof(sev_subinfo_t, sb_strings);
14767c478bd9Sstevel@tonic-gate 		if (sdp->sd_classname) {
14777c478bd9Sstevel@tonic-gate 			bcopy(sdp->sd_classname, subp->sb_strings + idlen,
14787c478bd9Sstevel@tonic-gate 			    sdp->sd_clnsize);
14797c478bd9Sstevel@tonic-gate 			subp->sb_clnamoff = idlen;
14807c478bd9Sstevel@tonic-gate 		} else {
14817c478bd9Sstevel@tonic-gate 			subp->sb_clnamoff = idlen - 1;
14827c478bd9Sstevel@tonic-gate 		}
14837c478bd9Sstevel@tonic-gate 		subp->sb_pid = sdp->sd_pid;
14847c478bd9Sstevel@tonic-gate 		subp->sb_nevents = EVCH_EVQ_EVCOUNT(sdp->sd_queue);
14857c478bd9Sstevel@tonic-gate 		subp->sb_evhwm = EVCH_EVQ_HIGHWM(sdp->sd_queue);
14867c478bd9Sstevel@tonic-gate 		subp->sb_persist = sdp->sd_persist;
14877c478bd9Sstevel@tonic-gate 		subp->sb_status = evch_evq_status(sdp->sd_queue);
14887c478bd9Sstevel@tonic-gate 		subp->sb_active = sdp->sd_active;
14897c478bd9Sstevel@tonic-gate 		subp->sb_dump = sdp->sd_dump;
14907c478bd9Sstevel@tonic-gate 		bcopy(sdp->sd_ident, subp->sb_strings, idlen);
14917c478bd9Sstevel@tonic-gate 		cpaddr += len;
14927c478bd9Sstevel@tonic-gate 	}
14937c478bd9Sstevel@tonic-gate 	mutex_exit(&eg->evch_list_lock);
14947c478bd9Sstevel@tonic-gate 	return (chdlen + buflen);
14957c478bd9Sstevel@tonic-gate }
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate /*
14987c478bd9Sstevel@tonic-gate  * Init iteration of all events of a channel. This function creates a new
14997c478bd9Sstevel@tonic-gate  * event queue and puts all events from the channel into that queue.
15007c478bd9Sstevel@tonic-gate  * Subsequent calls to evch_chgetnextev will deliver the events from that
15017c478bd9Sstevel@tonic-gate  * queue. Only one thread per channel is allowed to read through the events.
15027c478bd9Sstevel@tonic-gate  * Returns 0 on success and 1 if there is already someone reading the
15037c478bd9Sstevel@tonic-gate  * events.
15047c478bd9Sstevel@tonic-gate  * If argument subid == NULL, we look for a subscriber which has
15057c478bd9Sstevel@tonic-gate  * flag EVCH_SUB_DUMP set.
15067c478bd9Sstevel@tonic-gate  */
15077c478bd9Sstevel@tonic-gate /*
15087c478bd9Sstevel@tonic-gate  * Static variables that are used to traverse events of a channel in panic case.
15097c478bd9Sstevel@tonic-gate  */
15107c478bd9Sstevel@tonic-gate static evch_chan_t	*evch_chan;
15117c478bd9Sstevel@tonic-gate static evch_eventq_t	*evch_subq;
15127c478bd9Sstevel@tonic-gate static sysevent_impl_t	*evch_curev;
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate static evchanq_t *
15157c478bd9Sstevel@tonic-gate evch_chrdevent_init(evch_chan_t *chp, char *subid)
15167c478bd9Sstevel@tonic-gate {
15177c478bd9Sstevel@tonic-gate 	evch_subd_t	*sdp;
15187c478bd9Sstevel@tonic-gate 	void		*ev;
15197c478bd9Sstevel@tonic-gate 	int		pmqstat;	/* Prev status of main queue */
15207c478bd9Sstevel@tonic-gate 	int		psqstat;	/* Prev status of subscriber queue */
15217c478bd9Sstevel@tonic-gate 	evchanq_t	*snp;		/* Pointer to q with snapshot of ev */
15227c478bd9Sstevel@tonic-gate 	compare_f	compfunc;
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	compfunc = subid == NULL ? evch_dumpflgcmp : evch_subidcmp;
15257c478bd9Sstevel@tonic-gate 	if (panicstr != NULL) {
15267c478bd9Sstevel@tonic-gate 		evch_chan = chp;
15277c478bd9Sstevel@tonic-gate 		evch_subq = NULL;
15287c478bd9Sstevel@tonic-gate 		evch_curev = NULL;
15297c478bd9Sstevel@tonic-gate 		if ((sdp = (evch_subd_t *)evch_dl_search(&chp->ch_subscr,
15307c478bd9Sstevel@tonic-gate 		    compfunc, subid)) != NULL) {
15317c478bd9Sstevel@tonic-gate 			evch_subq = sdp->sd_queue;
15327c478bd9Sstevel@tonic-gate 		}
15337c478bd9Sstevel@tonic-gate 		return (NULL);
15347c478bd9Sstevel@tonic-gate 	}
15357c478bd9Sstevel@tonic-gate 	mutex_enter(&chp->ch_mutex);
15367c478bd9Sstevel@tonic-gate 	sdp = (evch_subd_t *)evch_dl_search(&chp->ch_subscr, compfunc, subid);
15377c478bd9Sstevel@tonic-gate 	/*
15387c478bd9Sstevel@tonic-gate 	 * Stop main event queue and subscriber queue if not already
15397c478bd9Sstevel@tonic-gate 	 * in stop mode.
15407c478bd9Sstevel@tonic-gate 	 */
15417c478bd9Sstevel@tonic-gate 	pmqstat = evch_evq_status(chp->ch_queue);
15427c478bd9Sstevel@tonic-gate 	if (pmqstat == 0)
15437c478bd9Sstevel@tonic-gate 		evch_evq_stop(chp->ch_queue);
15447c478bd9Sstevel@tonic-gate 	if (sdp != NULL) {
15457c478bd9Sstevel@tonic-gate 		psqstat = evch_evq_status(sdp->sd_queue);
15467c478bd9Sstevel@tonic-gate 		if (psqstat == 0)
15477c478bd9Sstevel@tonic-gate 			evch_evq_stop(sdp->sd_queue);
15487c478bd9Sstevel@tonic-gate 	}
15497c478bd9Sstevel@tonic-gate 	/*
15507c478bd9Sstevel@tonic-gate 	 * Create event queue to make a snapshot of all events in the
15517c478bd9Sstevel@tonic-gate 	 * channel.
15527c478bd9Sstevel@tonic-gate 	 */
15537c478bd9Sstevel@tonic-gate 	snp = kmem_alloc(sizeof (evchanq_t), KM_SLEEP);
15547c478bd9Sstevel@tonic-gate 	snp->sn_queue = evch_evq_create();
15557c478bd9Sstevel@tonic-gate 	evch_evq_stop(snp->sn_queue);
15567c478bd9Sstevel@tonic-gate 	/*
15577c478bd9Sstevel@tonic-gate 	 * Make a snapshot of the subscriber queue and the main event queue.
15587c478bd9Sstevel@tonic-gate 	 */
15597c478bd9Sstevel@tonic-gate 	if (sdp != NULL) {
15607c478bd9Sstevel@tonic-gate 		ev = NULL;
15617c478bd9Sstevel@tonic-gate 		while ((ev = evch_evq_evnext(sdp->sd_queue, ev)) != NULL) {
15627c478bd9Sstevel@tonic-gate 			(void) evch_evq_pub(snp->sn_queue, ev, EVCH_SLEEP);
15637c478bd9Sstevel@tonic-gate 		}
15647c478bd9Sstevel@tonic-gate 	}
15657c478bd9Sstevel@tonic-gate 	ev = NULL;
15667c478bd9Sstevel@tonic-gate 	while ((ev = evch_evq_evnext(chp->ch_queue, ev)) != NULL) {
15677c478bd9Sstevel@tonic-gate 		(void) evch_evq_pub(snp->sn_queue, ev, EVCH_SLEEP);
15687c478bd9Sstevel@tonic-gate 	}
15697c478bd9Sstevel@tonic-gate 	snp->sn_nxtev = NULL;
15707c478bd9Sstevel@tonic-gate 	/*
15717c478bd9Sstevel@tonic-gate 	 * Restart main and subscriber queue if previously stopped
15727c478bd9Sstevel@tonic-gate 	 */
15737c478bd9Sstevel@tonic-gate 	if (sdp != NULL && psqstat == 0)
15747c478bd9Sstevel@tonic-gate 		evch_evq_continue(sdp->sd_queue);
15757c478bd9Sstevel@tonic-gate 	if (pmqstat == 0)
15767c478bd9Sstevel@tonic-gate 		evch_evq_continue(chp->ch_queue);
15777c478bd9Sstevel@tonic-gate 	mutex_exit(&chp->ch_mutex);
15787c478bd9Sstevel@tonic-gate 	return (snp);
15797c478bd9Sstevel@tonic-gate }
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate /*
15827c478bd9Sstevel@tonic-gate  * Free all resources of the event queue snapshot. In case of panic
15837c478bd9Sstevel@tonic-gate  * context snp must be NULL and no resources need to be free'ed.
15847c478bd9Sstevel@tonic-gate  */
15857c478bd9Sstevel@tonic-gate static void
15867c478bd9Sstevel@tonic-gate evch_chrdevent_fini(evchanq_t *snp)
15877c478bd9Sstevel@tonic-gate {
15887c478bd9Sstevel@tonic-gate 	if (snp != NULL) {
15897c478bd9Sstevel@tonic-gate 		evch_evq_destroy(snp->sn_queue);
15907c478bd9Sstevel@tonic-gate 		kmem_free(snp, sizeof (evchanq_t));
15917c478bd9Sstevel@tonic-gate 	}
15927c478bd9Sstevel@tonic-gate }
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate /*
15957c478bd9Sstevel@tonic-gate  * Get address of next event from an event channel.
15967c478bd9Sstevel@tonic-gate  * This function might be called in a panic context. In that case
15977c478bd9Sstevel@tonic-gate  * no resources will be allocated and no locks grabbed.
15987c478bd9Sstevel@tonic-gate  * In normal operation context a snapshot of the event queues of the
15997c478bd9Sstevel@tonic-gate  * specified event channel will be taken.
16007c478bd9Sstevel@tonic-gate  */
16017c478bd9Sstevel@tonic-gate static sysevent_impl_t *
16027c478bd9Sstevel@tonic-gate evch_chgetnextev(evchanq_t *snp)
16037c478bd9Sstevel@tonic-gate {
16047c478bd9Sstevel@tonic-gate 	if (panicstr != NULL) {
16057c478bd9Sstevel@tonic-gate 		if (evch_chan == NULL)
16067c478bd9Sstevel@tonic-gate 			return (NULL);
16077c478bd9Sstevel@tonic-gate 		if (evch_subq != NULL) {
16087c478bd9Sstevel@tonic-gate 			/*
16097c478bd9Sstevel@tonic-gate 			 * We have a subscriber queue. Traverse this queue
16107c478bd9Sstevel@tonic-gate 			 * first.
16117c478bd9Sstevel@tonic-gate 			 */
16127c478bd9Sstevel@tonic-gate 			if ((evch_curev = (sysevent_impl_t *)
16137c478bd9Sstevel@tonic-gate 			    evch_evq_evnext(evch_subq, evch_curev)) != NULL) {
16147c478bd9Sstevel@tonic-gate 				return (evch_curev);
16157c478bd9Sstevel@tonic-gate 			} else {
16167c478bd9Sstevel@tonic-gate 				/*
16177c478bd9Sstevel@tonic-gate 				 * All subscriber events traversed. evch_subq
16187c478bd9Sstevel@tonic-gate 				 * == NULL indicates to take the main event
16197c478bd9Sstevel@tonic-gate 				 * queue now.
16207c478bd9Sstevel@tonic-gate 				 */
16217c478bd9Sstevel@tonic-gate 				evch_subq = NULL;
16227c478bd9Sstevel@tonic-gate 			}
16237c478bd9Sstevel@tonic-gate 		}
16247c478bd9Sstevel@tonic-gate 		/*
16257c478bd9Sstevel@tonic-gate 		 * Traverse the main event queue.
16267c478bd9Sstevel@tonic-gate 		 */
16277c478bd9Sstevel@tonic-gate 		if ((evch_curev = (sysevent_impl_t *)
16287c478bd9Sstevel@tonic-gate 		    evch_evq_evnext(evch_chan->ch_queue, evch_curev)) ==
16297c478bd9Sstevel@tonic-gate 		    NULL) {
16307c478bd9Sstevel@tonic-gate 			evch_chan = NULL;
16317c478bd9Sstevel@tonic-gate 		}
16327c478bd9Sstevel@tonic-gate 		return (evch_curev);
16337c478bd9Sstevel@tonic-gate 	}
16347c478bd9Sstevel@tonic-gate 	ASSERT(snp != NULL);
16357c478bd9Sstevel@tonic-gate 	snp->sn_nxtev = (sysevent_impl_t *)evch_evq_evnext(snp->sn_queue,
16367c478bd9Sstevel@tonic-gate 	    snp->sn_nxtev);
16377c478bd9Sstevel@tonic-gate 	return (snp->sn_nxtev);
16387c478bd9Sstevel@tonic-gate }
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate /*
16417c478bd9Sstevel@tonic-gate  * The functions below build up the interface for the kernel to bind/unbind,
16427c478bd9Sstevel@tonic-gate  * subscribe/unsubscribe and publish to event channels. It consists of the
16437c478bd9Sstevel@tonic-gate  * following functions:
16447c478bd9Sstevel@tonic-gate  *
16457c478bd9Sstevel@tonic-gate  * sysevent_evc_bind	    - Bind to a channel. Create a channel if required
16467c478bd9Sstevel@tonic-gate  * sysevent_evc_unbind	    - Unbind from a channel. Destroy ch. if last unbind
16477c478bd9Sstevel@tonic-gate  * sysevent_evc_subscribe   - Subscribe to events from a channel
16487c478bd9Sstevel@tonic-gate  * sysevent_evc_unsubscribe - Unsubscribe from an event class
16497c478bd9Sstevel@tonic-gate  * sysevent_evc_publish	    - Publish an event to an event channel
16507c478bd9Sstevel@tonic-gate  * sysevent_evc_control	    - Various control operation on event channel
16517c478bd9Sstevel@tonic-gate  *
16527c478bd9Sstevel@tonic-gate  * The function below are for evaluating a sysevent:
16537c478bd9Sstevel@tonic-gate  *
16547c478bd9Sstevel@tonic-gate  * sysevent_get_class_name  - Get pointer to event class string
16557c478bd9Sstevel@tonic-gate  * sysevent_get_subclass_name - Get pointer to event subclass string
16567c478bd9Sstevel@tonic-gate  * sysevent_get_seq	    - Get unique event sequence number
16577c478bd9Sstevel@tonic-gate  * sysevent_get_time	    - Get hrestime of event publish
16587c478bd9Sstevel@tonic-gate  * sysevent_get_size	    - Get size of event structure
16597c478bd9Sstevel@tonic-gate  * sysevent_get_pub	    - Get publisher string
16607c478bd9Sstevel@tonic-gate  * sysevent_get_attr_list   - Get copy of attribute list
16617c478bd9Sstevel@tonic-gate  *
16627c478bd9Sstevel@tonic-gate  * The following interfaces represent stability level project privat
16637c478bd9Sstevel@tonic-gate  * and allow to save the events of an event channel even in a panic case.
16647c478bd9Sstevel@tonic-gate  *
16657c478bd9Sstevel@tonic-gate  * sysevent_evc_walk_init   - Take a snapshot of the events in a channel
16667c478bd9Sstevel@tonic-gate  * sysevent_evc_walk_step   - Read next event from snapshot
16677c478bd9Sstevel@tonic-gate  * sysevent_evc_walk_fini   - Free resources from event channel snapshot
16687c478bd9Sstevel@tonic-gate  * sysevent_evc_event_attr  - Get event payload address and size
16697c478bd9Sstevel@tonic-gate  */
16707c478bd9Sstevel@tonic-gate /*
16717c478bd9Sstevel@tonic-gate  * allocate sysevent structure with optional space for attributes
16727c478bd9Sstevel@tonic-gate  */
16737c478bd9Sstevel@tonic-gate static sysevent_impl_t *
16747c478bd9Sstevel@tonic-gate sysevent_evc_alloc(const char *class, const char *subclass, const char *pub,
16757c478bd9Sstevel@tonic-gate     size_t pub_sz, size_t atsz, uint32_t flag)
16767c478bd9Sstevel@tonic-gate {
16777c478bd9Sstevel@tonic-gate 	int		payload_sz;
16787c478bd9Sstevel@tonic-gate 	int		class_sz, subclass_sz;
16797c478bd9Sstevel@tonic-gate 	int 		aligned_class_sz, aligned_subclass_sz, aligned_pub_sz;
16807c478bd9Sstevel@tonic-gate 	sysevent_impl_t	*ev;
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	/*
16837c478bd9Sstevel@tonic-gate 	 * Calculate and reserve space for the class, subclass and
16847c478bd9Sstevel@tonic-gate 	 * publisher strings in the event buffer
16857c478bd9Sstevel@tonic-gate 	 */
16867c478bd9Sstevel@tonic-gate 	class_sz = strlen(class) + 1;
16877c478bd9Sstevel@tonic-gate 	subclass_sz = strlen(subclass) + 1;
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate 	ASSERT((class_sz <= MAX_CLASS_LEN) && (subclass_sz <=
16907c478bd9Sstevel@tonic-gate 	    MAX_SUBCLASS_LEN) && (pub_sz <= MAX_PUB_LEN));
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate 	/* String sizes must be 64-bit aligned in the event buffer */
16937c478bd9Sstevel@tonic-gate 	aligned_class_sz = SE_ALIGN(class_sz);
16947c478bd9Sstevel@tonic-gate 	aligned_subclass_sz = SE_ALIGN(subclass_sz);
16957c478bd9Sstevel@tonic-gate 	aligned_pub_sz = SE_ALIGN(pub_sz);
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	/*
16987c478bd9Sstevel@tonic-gate 	 * Calculate payload size. Consider the space needed for alignment
16997c478bd9Sstevel@tonic-gate 	 * and subtract the size of the uint64_t placeholder variables of
17007c478bd9Sstevel@tonic-gate 	 * sysevent_impl_t.
17017c478bd9Sstevel@tonic-gate 	 */
17027c478bd9Sstevel@tonic-gate 	payload_sz = (aligned_class_sz - sizeof (uint64_t)) +
17037c478bd9Sstevel@tonic-gate 	    (aligned_subclass_sz - sizeof (uint64_t)) +
17047c478bd9Sstevel@tonic-gate 	    (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t) +
17057c478bd9Sstevel@tonic-gate 	    atsz;
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	/*
17087c478bd9Sstevel@tonic-gate 	 * Allocate event buffer plus additional payload overhead
17097c478bd9Sstevel@tonic-gate 	 */
17107c478bd9Sstevel@tonic-gate 	if ((ev = evch_evq_evzalloc(sizeof (sysevent_impl_t) +
17117c478bd9Sstevel@tonic-gate 	    payload_sz, flag)) == NULL) {
17127c478bd9Sstevel@tonic-gate 		return (NULL);
17137c478bd9Sstevel@tonic-gate 	}
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate 	/* Initialize the event buffer data */
17167c478bd9Sstevel@tonic-gate 	SE_VERSION(ev) = SYS_EVENT_VERSION;
17177c478bd9Sstevel@tonic-gate 	bcopy(class, SE_CLASS_NAME(ev), class_sz);
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 	SE_SUBCLASS_OFF(ev) = SE_ALIGN(offsetof(sysevent_impl_t,
17207c478bd9Sstevel@tonic-gate 	    se_class_name)) + aligned_class_sz;
17217c478bd9Sstevel@tonic-gate 	bcopy(subclass, SE_SUBCLASS_NAME(ev), subclass_sz);
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	SE_PUB_OFF(ev) = SE_SUBCLASS_OFF(ev) + aligned_subclass_sz;
17247c478bd9Sstevel@tonic-gate 	bcopy(pub, SE_PUB_NAME(ev), pub_sz);
17257c478bd9Sstevel@tonic-gate 
17267c478bd9Sstevel@tonic-gate 	SE_ATTR_PTR(ev) = (uint64_t)0;
17277c478bd9Sstevel@tonic-gate 	SE_PAYLOAD_SZ(ev) = payload_sz;
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 	return (ev);
17307c478bd9Sstevel@tonic-gate }
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate /*
17337c478bd9Sstevel@tonic-gate  * Initialize event channel handling queues.
17347c478bd9Sstevel@tonic-gate  */
17357c478bd9Sstevel@tonic-gate void
17367c478bd9Sstevel@tonic-gate sysevent_evc_init()
17377c478bd9Sstevel@tonic-gate {
17387c478bd9Sstevel@tonic-gate 	evch_chinit();
17397c478bd9Sstevel@tonic-gate }
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate /*
17427c478bd9Sstevel@tonic-gate  * Second initialization step: create threads, if event channels are already
17437c478bd9Sstevel@tonic-gate  * created
17447c478bd9Sstevel@tonic-gate  */
17457c478bd9Sstevel@tonic-gate void
17467c478bd9Sstevel@tonic-gate sysevent_evc_thrinit()
17477c478bd9Sstevel@tonic-gate {
17487c478bd9Sstevel@tonic-gate 	evch_chinitthr();
17497c478bd9Sstevel@tonic-gate }
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate int
17527c478bd9Sstevel@tonic-gate sysevent_evc_bind(const char *ch_name, evchan_t **scpp, uint32_t flags)
17537c478bd9Sstevel@tonic-gate {
17547c478bd9Sstevel@tonic-gate 	ASSERT(ch_name != NULL && scpp != NULL);
17557c478bd9Sstevel@tonic-gate 	ASSERT((flags & ~EVCH_B_FLAGS) == 0);
17567c478bd9Sstevel@tonic-gate 	return (evch_chbind(ch_name, (evch_bind_t **)scpp, flags));
17577c478bd9Sstevel@tonic-gate }
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate void
17607c478bd9Sstevel@tonic-gate sysevent_evc_unbind(evchan_t *scp)
17617c478bd9Sstevel@tonic-gate {
17627c478bd9Sstevel@tonic-gate 	evch_bind_t *bp = (evch_bind_t *)scp;
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	ASSERT(scp != NULL);
17657c478bd9Sstevel@tonic-gate 	evch_chunsubscribe(bp, NULL, 0);
17667c478bd9Sstevel@tonic-gate 	evch_chunbind(bp);
17677c478bd9Sstevel@tonic-gate }
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate int
17707c478bd9Sstevel@tonic-gate sysevent_evc_subscribe(evchan_t *scp, const char *sid, const char *class,
17717c478bd9Sstevel@tonic-gate     int (*callb)(sysevent_t *ev, void *cookie),
17727c478bd9Sstevel@tonic-gate     void *cookie, uint32_t flags)
17737c478bd9Sstevel@tonic-gate {
17747c478bd9Sstevel@tonic-gate 	ASSERT(scp != NULL && sid != NULL && class != NULL && callb != NULL);
17757c478bd9Sstevel@tonic-gate 	ASSERT(flags == 0);
17767c478bd9Sstevel@tonic-gate 	if (strlen(sid) > MAX_SUBID_LEN) {
17777c478bd9Sstevel@tonic-gate 		return (EINVAL);
17787c478bd9Sstevel@tonic-gate 	}
17797c478bd9Sstevel@tonic-gate 	if (strcmp(class, EC_ALL) == 0) {
17807c478bd9Sstevel@tonic-gate 		class = NULL;
17817c478bd9Sstevel@tonic-gate 	}
17827c478bd9Sstevel@tonic-gate 	return (evch_chsubscribe((evch_bind_t *)scp, EVCH_DELKERN, sid, class,
17837c478bd9Sstevel@tonic-gate 	    (void *)callb, cookie, 0, 0));
17847c478bd9Sstevel@tonic-gate }
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate void
17877c478bd9Sstevel@tonic-gate sysevent_evc_unsubscribe(evchan_t *scp, const char *sid)
17887c478bd9Sstevel@tonic-gate {
17897c478bd9Sstevel@tonic-gate 	ASSERT(scp != NULL && sid != NULL);
17907c478bd9Sstevel@tonic-gate 	if (strcmp(sid, EVCH_ALLSUB) == 0) {
17917c478bd9Sstevel@tonic-gate 		sid = NULL;
17927c478bd9Sstevel@tonic-gate 	}
17937c478bd9Sstevel@tonic-gate 	evch_chunsubscribe((evch_bind_t *)scp, sid, 0);
17947c478bd9Sstevel@tonic-gate }
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate /*
17977c478bd9Sstevel@tonic-gate  * Publish kernel event. Returns 0 on success, error code else.
17987c478bd9Sstevel@tonic-gate  * Optional attribute data is packed into the event structure.
17997c478bd9Sstevel@tonic-gate  */
18007c478bd9Sstevel@tonic-gate int
18017c478bd9Sstevel@tonic-gate sysevent_evc_publish(evchan_t *scp, const char *class, const char *subclass,
18027c478bd9Sstevel@tonic-gate     const char *vendor, const char *pubs, nvlist_t *attr, uint32_t flags)
18037c478bd9Sstevel@tonic-gate {
18047c478bd9Sstevel@tonic-gate 	sysevent_impl_t	*evp;
18057c478bd9Sstevel@tonic-gate 	char		pub[MAX_PUB_LEN];
18067c478bd9Sstevel@tonic-gate 	int		pub_sz;		/* includes terminating 0 */
18077c478bd9Sstevel@tonic-gate 	int		km_flags;
18087c478bd9Sstevel@tonic-gate 	size_t		asz = 0;
18097c478bd9Sstevel@tonic-gate 	uint64_t	attr_offset;
18107c478bd9Sstevel@tonic-gate 	caddr_t		patt;
18117c478bd9Sstevel@tonic-gate 	int		err;
18127c478bd9Sstevel@tonic-gate 
18137c478bd9Sstevel@tonic-gate 	ASSERT(scp != NULL && class != NULL && subclass != NULL &&
18147c478bd9Sstevel@tonic-gate 	    vendor != NULL && pubs != NULL);
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 	ASSERT((flags & ~(EVCH_SLEEP | EVCH_NOSLEEP | EVCH_TRYHARD |
18177c478bd9Sstevel@tonic-gate 	    EVCH_QWAIT)) == 0);
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate 	km_flags = flags & (EVCH_SLEEP | EVCH_NOSLEEP | EVCH_TRYHARD);
18207c478bd9Sstevel@tonic-gate 	ASSERT(km_flags == EVCH_SLEEP || km_flags == EVCH_NOSLEEP ||
18217c478bd9Sstevel@tonic-gate 	    km_flags == EVCH_TRYHARD);
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 	pub_sz = snprintf(pub, MAX_PUB_LEN, "%s:kern:%s", vendor, pubs) + 1;
18247c478bd9Sstevel@tonic-gate 	if (pub_sz > MAX_PUB_LEN)
18257c478bd9Sstevel@tonic-gate 		return (EINVAL);
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 	if (attr != NULL) {
18287c478bd9Sstevel@tonic-gate 		if ((err = nvlist_size(attr, &asz, NV_ENCODE_NATIVE)) != 0) {
18297c478bd9Sstevel@tonic-gate 			return (err);
18307c478bd9Sstevel@tonic-gate 		}
18317c478bd9Sstevel@tonic-gate 	}
18327c478bd9Sstevel@tonic-gate 	evp = sysevent_evc_alloc(class, subclass, pub, pub_sz, asz, km_flags);
18337c478bd9Sstevel@tonic-gate 	if (evp == NULL) {
18347c478bd9Sstevel@tonic-gate 		return (ENOMEM);
18357c478bd9Sstevel@tonic-gate 	}
18367c478bd9Sstevel@tonic-gate 	if (attr != NULL) {
18377c478bd9Sstevel@tonic-gate 		/*
18387c478bd9Sstevel@tonic-gate 		 * Pack attributes into event buffer. Event buffer already
18397c478bd9Sstevel@tonic-gate 		 * has enough room for the packed nvlist.
18407c478bd9Sstevel@tonic-gate 		 */
18417c478bd9Sstevel@tonic-gate 		attr_offset = SE_ATTR_OFF(evp);
18427c478bd9Sstevel@tonic-gate 		patt = (caddr_t)evp + attr_offset;
18437c478bd9Sstevel@tonic-gate 
18447c478bd9Sstevel@tonic-gate 		err = nvlist_pack(attr, &patt, &asz, NV_ENCODE_NATIVE,
18457c478bd9Sstevel@tonic-gate 		    km_flags & EVCH_SLEEP ? KM_SLEEP : KM_NOSLEEP);
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 		ASSERT(err != ENOMEM);
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate 		if (err != 0) {
18507c478bd9Sstevel@tonic-gate 			return (EINVAL);
18517c478bd9Sstevel@tonic-gate 		}
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 		evp->seh_attr_off = attr_offset;
18547c478bd9Sstevel@tonic-gate 		SE_FLAG(evp) = SE_PACKED_BUF;
18557c478bd9Sstevel@tonic-gate 	}
18567c478bd9Sstevel@tonic-gate 	return (evch_chpublish((evch_bind_t *)scp, evp, flags));
18577c478bd9Sstevel@tonic-gate }
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate int
18607c478bd9Sstevel@tonic-gate sysevent_evc_control(evchan_t *scp, int cmd, ...)
18617c478bd9Sstevel@tonic-gate {
18627c478bd9Sstevel@tonic-gate 	va_list		ap;
18637c478bd9Sstevel@tonic-gate 	evch_chan_t	*chp = ((evch_bind_t *)scp)->bd_channel;
18647c478bd9Sstevel@tonic-gate 	uint32_t	*chlenp;
18657c478bd9Sstevel@tonic-gate 	uint32_t	chlen;
18667c478bd9Sstevel@tonic-gate 	uint32_t	ochlen;
18677c478bd9Sstevel@tonic-gate 	int		rc = 0;
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate 	if (scp == NULL) {
18707c478bd9Sstevel@tonic-gate 		return (EINVAL);
18717c478bd9Sstevel@tonic-gate 	}
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate 	va_start(ap, cmd);
18747c478bd9Sstevel@tonic-gate 	mutex_enter(&chp->ch_mutex);
18757c478bd9Sstevel@tonic-gate 	switch (cmd) {
18767c478bd9Sstevel@tonic-gate 	case EVCH_GET_CHAN_LEN:
18777c478bd9Sstevel@tonic-gate 		chlenp = va_arg(ap, uint32_t *);
18787c478bd9Sstevel@tonic-gate 		*chlenp = chp->ch_maxev;
18797c478bd9Sstevel@tonic-gate 		break;
18807c478bd9Sstevel@tonic-gate 	case EVCH_SET_CHAN_LEN:
18817c478bd9Sstevel@tonic-gate 		chlen = va_arg(ap, uint32_t);
18827c478bd9Sstevel@tonic-gate 		ochlen = chp->ch_maxev;
18837c478bd9Sstevel@tonic-gate 		chp->ch_maxev = min(chlen, evch_events_max);
18847c478bd9Sstevel@tonic-gate 		if (ochlen < chp->ch_maxev) {
18857c478bd9Sstevel@tonic-gate 			cv_signal(&chp->ch_pubcv);
18867c478bd9Sstevel@tonic-gate 		}
18877c478bd9Sstevel@tonic-gate 		break;
18887c478bd9Sstevel@tonic-gate 	case EVCH_GET_CHAN_LEN_MAX:
18897c478bd9Sstevel@tonic-gate 		*va_arg(ap, uint32_t *) = evch_events_max;
18907c478bd9Sstevel@tonic-gate 		break;
18917c478bd9Sstevel@tonic-gate 	default:
18927c478bd9Sstevel@tonic-gate 		rc = EINVAL;
18937c478bd9Sstevel@tonic-gate 	}
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 	mutex_exit(&chp->ch_mutex);
18967c478bd9Sstevel@tonic-gate 	va_end(ap);
18977c478bd9Sstevel@tonic-gate 	return (rc);
18987c478bd9Sstevel@tonic-gate }
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate /*
19017c478bd9Sstevel@tonic-gate  * Project private interface to take a snapshot of all events of the
19027c478bd9Sstevel@tonic-gate  * specified event channel. Argument subscr may be a subscriber id, the empty
19037c478bd9Sstevel@tonic-gate  * string "", or NULL. The empty string indicates that no subscriber is
19047c478bd9Sstevel@tonic-gate  * selected, for example if a previous subscriber died. sysevent_evc_walk_next()
19057c478bd9Sstevel@tonic-gate  * will deliver events from the main event queue in this case. If subscr is
19067c478bd9Sstevel@tonic-gate  * NULL, the subscriber with the EVCH_SUB_DUMP flag set (subd->sd_dump != 0)
19077c478bd9Sstevel@tonic-gate  * will be selected.
19087c478bd9Sstevel@tonic-gate  *
19097c478bd9Sstevel@tonic-gate  * In panic case this function returns NULL. This is legal. The NULL has
19107c478bd9Sstevel@tonic-gate  * to be delivered to sysevent_evc_walk_step() and sysevent_evc_walk_fini().
19117c478bd9Sstevel@tonic-gate  */
19127c478bd9Sstevel@tonic-gate evchanq_t *
19137c478bd9Sstevel@tonic-gate sysevent_evc_walk_init(evchan_t *scp, char *subscr)
19147c478bd9Sstevel@tonic-gate {
19157c478bd9Sstevel@tonic-gate 	if (panicstr != NULL && scp == NULL)
19167c478bd9Sstevel@tonic-gate 		return (NULL);
19177c478bd9Sstevel@tonic-gate 	ASSERT(scp != NULL);
19187c478bd9Sstevel@tonic-gate 	return (evch_chrdevent_init(((evch_bind_t *)scp)->bd_channel, subscr));
19197c478bd9Sstevel@tonic-gate }
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate /*
19227c478bd9Sstevel@tonic-gate  * Project private interface to read events from a previously taken
19237c478bd9Sstevel@tonic-gate  * snapshot (with sysevent_evc_walk_init). In case of panic events
19247c478bd9Sstevel@tonic-gate  * are retrieved directly from the channel data structures. No resources
19257c478bd9Sstevel@tonic-gate  * are allocated and no mutexes are grabbed in panic context.
19267c478bd9Sstevel@tonic-gate  */
19277c478bd9Sstevel@tonic-gate sysevent_t *
19287c478bd9Sstevel@tonic-gate sysevent_evc_walk_step(evchanq_t *evcq)
19297c478bd9Sstevel@tonic-gate {
19307c478bd9Sstevel@tonic-gate 	return ((sysevent_t *)evch_chgetnextev(evcq));
19317c478bd9Sstevel@tonic-gate }
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate /*
19347c478bd9Sstevel@tonic-gate  * Project private interface to free a previously taken snapshot.
19357c478bd9Sstevel@tonic-gate  */
19367c478bd9Sstevel@tonic-gate void
19377c478bd9Sstevel@tonic-gate sysevent_evc_walk_fini(evchanq_t *evcq)
19387c478bd9Sstevel@tonic-gate {
19397c478bd9Sstevel@tonic-gate 	evch_chrdevent_fini(evcq);
19407c478bd9Sstevel@tonic-gate }
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate /*
19437c478bd9Sstevel@tonic-gate  * Get address and size of an event payload. Returns NULL when no
19447c478bd9Sstevel@tonic-gate  * payload present.
19457c478bd9Sstevel@tonic-gate  */
19467c478bd9Sstevel@tonic-gate char *
19477c478bd9Sstevel@tonic-gate sysevent_evc_event_attr(sysevent_t *ev, size_t *plsize)
19487c478bd9Sstevel@tonic-gate {
19497c478bd9Sstevel@tonic-gate 	char	*attrp;
19507c478bd9Sstevel@tonic-gate 	size_t	aoff;
19517c478bd9Sstevel@tonic-gate 	size_t	asz;
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	aoff = SE_ATTR_OFF(ev);
19547c478bd9Sstevel@tonic-gate 	attrp = (char *)ev + aoff;
19557c478bd9Sstevel@tonic-gate 	asz = *plsize = SE_SIZE(ev) - aoff;
19567c478bd9Sstevel@tonic-gate 	return (asz ? attrp : NULL);
19577c478bd9Sstevel@tonic-gate }
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate /*
19607c478bd9Sstevel@tonic-gate  * sysevent_get_class_name - Get class name string
19617c478bd9Sstevel@tonic-gate  */
19627c478bd9Sstevel@tonic-gate char *
19637c478bd9Sstevel@tonic-gate sysevent_get_class_name(sysevent_t *ev)
19647c478bd9Sstevel@tonic-gate {
19657c478bd9Sstevel@tonic-gate 	return (SE_CLASS_NAME(ev));
19667c478bd9Sstevel@tonic-gate }
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate /*
19697c478bd9Sstevel@tonic-gate  * sysevent_get_subclass_name - Get subclass name string
19707c478bd9Sstevel@tonic-gate  */
19717c478bd9Sstevel@tonic-gate char *
19727c478bd9Sstevel@tonic-gate sysevent_get_subclass_name(sysevent_t *ev)
19737c478bd9Sstevel@tonic-gate {
19747c478bd9Sstevel@tonic-gate 	return (SE_SUBCLASS_NAME(ev));
19757c478bd9Sstevel@tonic-gate }
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate /*
19787c478bd9Sstevel@tonic-gate  * sysevent_get_seq - Get event sequence id
19797c478bd9Sstevel@tonic-gate  */
19807c478bd9Sstevel@tonic-gate uint64_t
19817c478bd9Sstevel@tonic-gate sysevent_get_seq(sysevent_t *ev)
19827c478bd9Sstevel@tonic-gate {
19837c478bd9Sstevel@tonic-gate 	return (SE_SEQ(ev));
19847c478bd9Sstevel@tonic-gate }
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate /*
19877c478bd9Sstevel@tonic-gate  * sysevent_get_time - Get event timestamp
19887c478bd9Sstevel@tonic-gate  */
19897c478bd9Sstevel@tonic-gate void
19907c478bd9Sstevel@tonic-gate sysevent_get_time(sysevent_t *ev, hrtime_t *etime)
19917c478bd9Sstevel@tonic-gate {
19927c478bd9Sstevel@tonic-gate 	*etime = SE_TIME(ev);
19937c478bd9Sstevel@tonic-gate }
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate /*
19967c478bd9Sstevel@tonic-gate  * sysevent_get_size - Get event buffer size
19977c478bd9Sstevel@tonic-gate  */
19987c478bd9Sstevel@tonic-gate size_t
19997c478bd9Sstevel@tonic-gate sysevent_get_size(sysevent_t *ev)
20007c478bd9Sstevel@tonic-gate {
20017c478bd9Sstevel@tonic-gate 	return ((size_t)SE_SIZE(ev));
20027c478bd9Sstevel@tonic-gate }
20037c478bd9Sstevel@tonic-gate 
20047c478bd9Sstevel@tonic-gate /*
20057c478bd9Sstevel@tonic-gate  * sysevent_get_pub - Get publisher name string
20067c478bd9Sstevel@tonic-gate  */
20077c478bd9Sstevel@tonic-gate char *
20087c478bd9Sstevel@tonic-gate sysevent_get_pub(sysevent_t *ev)
20097c478bd9Sstevel@tonic-gate {
20107c478bd9Sstevel@tonic-gate 	return (SE_PUB_NAME(ev));
20117c478bd9Sstevel@tonic-gate }
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate /*
20147c478bd9Sstevel@tonic-gate  * sysevent_get_attr_list - stores address of a copy of the attribute list
20157c478bd9Sstevel@tonic-gate  * associated with the given sysevent buffer. The list must be freed by the
20167c478bd9Sstevel@tonic-gate  * caller.
20177c478bd9Sstevel@tonic-gate  */
20187c478bd9Sstevel@tonic-gate int
20197c478bd9Sstevel@tonic-gate sysevent_get_attr_list(sysevent_t *ev, nvlist_t **nvlist)
20207c478bd9Sstevel@tonic-gate {
20217c478bd9Sstevel@tonic-gate 	int		error;
20227c478bd9Sstevel@tonic-gate 	caddr_t		attr;
20237c478bd9Sstevel@tonic-gate 	size_t		attr_len;
20247c478bd9Sstevel@tonic-gate 	uint64_t	attr_offset;
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate 	*nvlist = NULL;
20277c478bd9Sstevel@tonic-gate 	if (SE_FLAG(ev) != SE_PACKED_BUF) {
20287c478bd9Sstevel@tonic-gate 		return (EINVAL);
20297c478bd9Sstevel@tonic-gate 	}
20307c478bd9Sstevel@tonic-gate 	attr_offset = SE_ATTR_OFF(ev);
20317c478bd9Sstevel@tonic-gate 	if (SE_SIZE(ev) == attr_offset) {
20327c478bd9Sstevel@tonic-gate 		return (EINVAL);
20337c478bd9Sstevel@tonic-gate 	}
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 	/* unpack nvlist */
20367c478bd9Sstevel@tonic-gate 	attr = (caddr_t)ev + attr_offset;
20377c478bd9Sstevel@tonic-gate 	attr_len = SE_SIZE(ev) - attr_offset;
20387c478bd9Sstevel@tonic-gate 	if ((error = nvlist_unpack(attr, attr_len, nvlist, 0)) != 0) {
20397c478bd9Sstevel@tonic-gate 		error = error != ENOMEM ? EINVAL : error;
20407c478bd9Sstevel@tonic-gate 		return (error);
20417c478bd9Sstevel@tonic-gate 	}
20427c478bd9Sstevel@tonic-gate 	return (0);
20437c478bd9Sstevel@tonic-gate }
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate /*
20467c478bd9Sstevel@tonic-gate  * Functions called by the sysevent driver for general purpose event channels
20477c478bd9Sstevel@tonic-gate  *
20487c478bd9Sstevel@tonic-gate  * evch_usrchanopen	- Create/Bind to an event channel
20497c478bd9Sstevel@tonic-gate  * evch_usrchanclose	- Unbind/Destroy event channel
20507c478bd9Sstevel@tonic-gate  * evch_usrallocev	- Allocate event data structure
20517c478bd9Sstevel@tonic-gate  * evch_usrfreeev	- Free event data structure
20527c478bd9Sstevel@tonic-gate  * evch_usrpostevent	- Publish event
20537c478bd9Sstevel@tonic-gate  * evch_usrsubscribe	- Subscribe (register callback function)
20547c478bd9Sstevel@tonic-gate  * evch_usrunsubscribe	- Unsubscribe
20557c478bd9Sstevel@tonic-gate  * evch_usrcontrol_set	- Set channel properties
20567c478bd9Sstevel@tonic-gate  * evch_usrcontrol_get	- Get channel properties
20577c478bd9Sstevel@tonic-gate  * evch_usrgetchnames	- Get list of channel names
20587c478bd9Sstevel@tonic-gate  * evch_usrgetchdata	- Get data of an event channel
20597c478bd9Sstevel@tonic-gate  */
20607c478bd9Sstevel@tonic-gate evchan_t *
20617c478bd9Sstevel@tonic-gate evch_usrchanopen(const char *name, uint32_t flags, int *err)
20627c478bd9Sstevel@tonic-gate {
20637c478bd9Sstevel@tonic-gate 	evch_bind_t *bp = NULL;
20647c478bd9Sstevel@tonic-gate 
20657c478bd9Sstevel@tonic-gate 	*err = evch_chbind(name, &bp, flags);
20667c478bd9Sstevel@tonic-gate 	return ((evchan_t *)bp);
20677c478bd9Sstevel@tonic-gate }
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate /*
20707c478bd9Sstevel@tonic-gate  * Unbind from the channel.
20717c478bd9Sstevel@tonic-gate  */
20727c478bd9Sstevel@tonic-gate void
20737c478bd9Sstevel@tonic-gate evch_usrchanclose(evchan_t *cbp)
20747c478bd9Sstevel@tonic-gate {
20757c478bd9Sstevel@tonic-gate 	evch_chunbind((evch_bind_t *)cbp);
20767c478bd9Sstevel@tonic-gate }
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate /*
20797c478bd9Sstevel@tonic-gate  * Allocates log_evch_eventq_t structure but returns the pointer of the embedded
20807c478bd9Sstevel@tonic-gate  * sysevent_impl_t structure as the opaque sysevent_t * data type
20817c478bd9Sstevel@tonic-gate  */
20827c478bd9Sstevel@tonic-gate sysevent_impl_t *
20837c478bd9Sstevel@tonic-gate evch_usrallocev(size_t evsize, uint32_t flags)
20847c478bd9Sstevel@tonic-gate {
20857c478bd9Sstevel@tonic-gate 	return ((sysevent_impl_t *)evch_evq_evzalloc(evsize, flags));
20867c478bd9Sstevel@tonic-gate }
20877c478bd9Sstevel@tonic-gate 
20887c478bd9Sstevel@tonic-gate /*
20897c478bd9Sstevel@tonic-gate  * Free evch_eventq_t structure
20907c478bd9Sstevel@tonic-gate  */
20917c478bd9Sstevel@tonic-gate void
20927c478bd9Sstevel@tonic-gate evch_usrfreeev(sysevent_impl_t *ev)
20937c478bd9Sstevel@tonic-gate {
20947c478bd9Sstevel@tonic-gate 	evch_evq_evfree((void *)ev);
20957c478bd9Sstevel@tonic-gate }
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate /*
20987c478bd9Sstevel@tonic-gate  * Posts an event to the given channel. The event structure has to be
20997c478bd9Sstevel@tonic-gate  * allocated by evch_usrallocev(). Returns zero on success and an error
21007c478bd9Sstevel@tonic-gate  * code else. Attributes have to be packed and included in the event structure.
21017c478bd9Sstevel@tonic-gate  *
21027c478bd9Sstevel@tonic-gate  */
21037c478bd9Sstevel@tonic-gate int
21047c478bd9Sstevel@tonic-gate evch_usrpostevent(evchan_t *bp, sysevent_impl_t *ev, uint32_t flags)
21057c478bd9Sstevel@tonic-gate {
21067c478bd9Sstevel@tonic-gate 	return (evch_chpublish((evch_bind_t *)bp, ev, flags));
21077c478bd9Sstevel@tonic-gate }
21087c478bd9Sstevel@tonic-gate 
21097c478bd9Sstevel@tonic-gate /*
21107c478bd9Sstevel@tonic-gate  * Subscribe function for user land subscriptions
21117c478bd9Sstevel@tonic-gate  */
21127c478bd9Sstevel@tonic-gate int
21137c478bd9Sstevel@tonic-gate evch_usrsubscribe(evchan_t *bp, const char *sid, const char *class,
21147c478bd9Sstevel@tonic-gate     int d, uint32_t flags)
21157c478bd9Sstevel@tonic-gate {
21167c478bd9Sstevel@tonic-gate 	door_handle_t	dh = door_ki_lookup(d);
21177c478bd9Sstevel@tonic-gate 	int		rv;
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 	if (dh == NULL) {
21207c478bd9Sstevel@tonic-gate 		return (EINVAL);
21217c478bd9Sstevel@tonic-gate 	}
21227c478bd9Sstevel@tonic-gate 	if ((rv = evch_chsubscribe((evch_bind_t *)bp, EVCH_DELDOOR, sid, class,
21237c478bd9Sstevel@tonic-gate 	    (void *)dh, NULL, flags, curproc->p_pid)) != 0) {
21247c478bd9Sstevel@tonic-gate 		door_ki_rele(dh);
21257c478bd9Sstevel@tonic-gate 	}
21267c478bd9Sstevel@tonic-gate 	return (rv);
21277c478bd9Sstevel@tonic-gate }
21287c478bd9Sstevel@tonic-gate 
21297c478bd9Sstevel@tonic-gate /*
21307c478bd9Sstevel@tonic-gate  * Flag can be EVCH_SUB_KEEP or 0. EVCH_SUB_KEEP preserves persistent
21317c478bd9Sstevel@tonic-gate  * subscribers
21327c478bd9Sstevel@tonic-gate  */
21337c478bd9Sstevel@tonic-gate void
21347c478bd9Sstevel@tonic-gate evch_usrunsubscribe(evchan_t *bp, const char *subid, uint32_t flags)
21357c478bd9Sstevel@tonic-gate {
21367c478bd9Sstevel@tonic-gate 	evch_chunsubscribe((evch_bind_t *)bp, subid, flags);
21377c478bd9Sstevel@tonic-gate }
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21407c478bd9Sstevel@tonic-gate int
21417c478bd9Sstevel@tonic-gate evch_usrcontrol_set(evchan_t *bp, int cmd, uint32_t value)
21427c478bd9Sstevel@tonic-gate {
21437c478bd9Sstevel@tonic-gate 	evch_chan_t	*chp = ((evch_bind_t *)bp)->bd_channel;
21447c478bd9Sstevel@tonic-gate 	uid_t		uid = crgetuid(curthread->t_cred);
21457c478bd9Sstevel@tonic-gate 	int		rc = 0;
21467c478bd9Sstevel@tonic-gate 
21477c478bd9Sstevel@tonic-gate 	mutex_enter(&chp->ch_mutex);
21487c478bd9Sstevel@tonic-gate 	switch (cmd) {
21497c478bd9Sstevel@tonic-gate 	case EVCH_SET_CHAN_LEN:
21507c478bd9Sstevel@tonic-gate 		if (uid && uid != chp->ch_uid) {
21517c478bd9Sstevel@tonic-gate 			rc = EACCES;
21527c478bd9Sstevel@tonic-gate 			break;
21537c478bd9Sstevel@tonic-gate 		}
21547c478bd9Sstevel@tonic-gate 		chp->ch_maxev = min(value, evch_events_max);
21557c478bd9Sstevel@tonic-gate 		break;
21567c478bd9Sstevel@tonic-gate 	default:
21577c478bd9Sstevel@tonic-gate 		rc = EINVAL;
21587c478bd9Sstevel@tonic-gate 	}
21597c478bd9Sstevel@tonic-gate 	mutex_exit(&chp->ch_mutex);
21607c478bd9Sstevel@tonic-gate 	return (rc);
21617c478bd9Sstevel@tonic-gate }
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21647c478bd9Sstevel@tonic-gate int
21657c478bd9Sstevel@tonic-gate evch_usrcontrol_get(evchan_t *bp, int cmd, uint32_t *value)
21667c478bd9Sstevel@tonic-gate {
21677c478bd9Sstevel@tonic-gate 	evch_chan_t	*chp = ((evch_bind_t *)bp)->bd_channel;
21687c478bd9Sstevel@tonic-gate 	int		rc = 0;
21697c478bd9Sstevel@tonic-gate 
21707c478bd9Sstevel@tonic-gate 	mutex_enter(&chp->ch_mutex);
21717c478bd9Sstevel@tonic-gate 	switch (cmd) {
21727c478bd9Sstevel@tonic-gate 	case EVCH_GET_CHAN_LEN:
21737c478bd9Sstevel@tonic-gate 		*value = chp->ch_maxev;
21747c478bd9Sstevel@tonic-gate 		break;
21757c478bd9Sstevel@tonic-gate 	case EVCH_GET_CHAN_LEN_MAX:
21767c478bd9Sstevel@tonic-gate 		*value = evch_events_max;
21777c478bd9Sstevel@tonic-gate 		break;
21787c478bd9Sstevel@tonic-gate 	default:
21797c478bd9Sstevel@tonic-gate 		rc = EINVAL;
21807c478bd9Sstevel@tonic-gate 	}
21817c478bd9Sstevel@tonic-gate 	mutex_exit(&chp->ch_mutex);
21827c478bd9Sstevel@tonic-gate 	return (rc);
21837c478bd9Sstevel@tonic-gate }
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate int
21867c478bd9Sstevel@tonic-gate evch_usrgetchnames(char *buf, size_t size)
21877c478bd9Sstevel@tonic-gate {
21887c478bd9Sstevel@tonic-gate 	return (evch_chgetnames(buf, size));
21897c478bd9Sstevel@tonic-gate }
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate int
21927c478bd9Sstevel@tonic-gate evch_usrgetchdata(char *chname, void *buf, size_t size)
21937c478bd9Sstevel@tonic-gate {
21947c478bd9Sstevel@tonic-gate 	return (evch_chgetchdata(chname, buf, size));
21957c478bd9Sstevel@tonic-gate }
2196