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