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