1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * This file contains the source of the general purpose event channel extension 31*7c478bd9Sstevel@tonic-gate * to the sysevent framework. This implementation is made up mainly of four 32*7c478bd9Sstevel@tonic-gate * layers of functionality: the event queues (evch_evq_*()), the handling of 33*7c478bd9Sstevel@tonic-gate * channels (evch_ch*()), the kernel interface (sysevent_evc_*()) and the 34*7c478bd9Sstevel@tonic-gate * interface for the sysevent pseudo driver (evch_usr*()). 35*7c478bd9Sstevel@tonic-gate * Libsysevent.so uses the pseudo driver sysevent's ioctl to access the event 36*7c478bd9Sstevel@tonic-gate * channel extensions. The driver in turn uses the evch_usr*() functions below. 37*7c478bd9Sstevel@tonic-gate * 38*7c478bd9Sstevel@tonic-gate * The interfaces for user land and kernel are declared in sys/sysevent.h 39*7c478bd9Sstevel@tonic-gate * Internal data structures for event channels are defined in 40*7c478bd9Sstevel@tonic-gate * sys/sysevent_impl.h. 41*7c478bd9Sstevel@tonic-gate * 42*7c478bd9Sstevel@tonic-gate * The basic data structure for an event channel is of type evch_chan_t. 43*7c478bd9Sstevel@tonic-gate * All channels are maintained by a list named evch_list. The list head 44*7c478bd9Sstevel@tonic-gate * is of type evch_dlist_t. 45*7c478bd9Sstevel@tonic-gate */ 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/vmem.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/callb.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/sysevent.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/disp.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/door.h> 61*7c478bd9Sstevel@tonic-gate #include <sys/zone.h> 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate /* Back-off delay for door_ki_upcall */ 64*7c478bd9Sstevel@tonic-gate #define EVCH_MIN_PAUSE 8 65*7c478bd9Sstevel@tonic-gate #define EVCH_MAX_PAUSE 128 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate #define GEVENT(ev) ((evch_gevent_t *)((char *)ev - \ 68*7c478bd9Sstevel@tonic-gate offsetof(evch_gevent_t, ge_payload))) 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate #define EVCH_EVQ_EVCOUNT(x) ((&(x)->eq_eventq)->sq_count) 71*7c478bd9Sstevel@tonic-gate #define EVCH_EVQ_HIGHWM(x) ((&(x)->eq_eventq)->sq_highwm) 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate struct evch_globals { 74*7c478bd9Sstevel@tonic-gate evch_dlist_t evch_list; 75*7c478bd9Sstevel@tonic-gate kmutex_t evch_list_lock; 76*7c478bd9Sstevel@tonic-gate }; 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate /* Variables used by event channel routines */ 79*7c478bd9Sstevel@tonic-gate static int evq_initcomplete = 0; 80*7c478bd9Sstevel@tonic-gate static zone_key_t evch_zone_key; 81*7c478bd9Sstevel@tonic-gate static uint32_t evch_channels_max; 82*7c478bd9Sstevel@tonic-gate static uint32_t evch_bindings_max = EVCH_MAX_BINDS_PER_CHANNEL; 83*7c478bd9Sstevel@tonic-gate static uint32_t evch_events_max; 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate static void evch_evq_unsub(evch_eventq_t *, evch_evqsub_t *); 86*7c478bd9Sstevel@tonic-gate static void evch_evq_destroy(evch_eventq_t *); 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate /* 89*7c478bd9Sstevel@tonic-gate * List handling. These functions handle a doubly linked list. The list has 90*7c478bd9Sstevel@tonic-gate * to be protected by the calling functions. evch_dlist_t is the list head. 91*7c478bd9Sstevel@tonic-gate * Every node of the list has to put a evch_dlelem_t data type in its data 92*7c478bd9Sstevel@tonic-gate * structure as its first element. 93*7c478bd9Sstevel@tonic-gate * 94*7c478bd9Sstevel@tonic-gate * evch_dl_init - Initialize list head 95*7c478bd9Sstevel@tonic-gate * evch_dl_fini - Terminate list handling 96*7c478bd9Sstevel@tonic-gate * evch_dl_is_init - Returns one if list is initialized 97*7c478bd9Sstevel@tonic-gate * evch_dl_add - Add element to end of list 98*7c478bd9Sstevel@tonic-gate * evch_dl_del - Remove given element from list 99*7c478bd9Sstevel@tonic-gate * evch_dl_search - Lookup element in list 100*7c478bd9Sstevel@tonic-gate * evch_dl_getnum - Get number of elements in list 101*7c478bd9Sstevel@tonic-gate * evch_dl_next - Get next elements of list 102*7c478bd9Sstevel@tonic-gate */ 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate static void 105*7c478bd9Sstevel@tonic-gate evch_dl_init(evch_dlist_t *hp) 106*7c478bd9Sstevel@tonic-gate { 107*7c478bd9Sstevel@tonic-gate hp->dh_head.dl_prev = hp->dh_head.dl_next = &hp->dh_head; 108*7c478bd9Sstevel@tonic-gate hp->dh_count = 0; 109*7c478bd9Sstevel@tonic-gate } 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate /* 112*7c478bd9Sstevel@tonic-gate * Assumes that list is empty. 113*7c478bd9Sstevel@tonic-gate */ 114*7c478bd9Sstevel@tonic-gate static void 115*7c478bd9Sstevel@tonic-gate evch_dl_fini(evch_dlist_t *hp) 116*7c478bd9Sstevel@tonic-gate { 117*7c478bd9Sstevel@tonic-gate hp->dh_head.dl_prev = hp->dh_head.dl_next = NULL; 118*7c478bd9Sstevel@tonic-gate } 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate static int 121*7c478bd9Sstevel@tonic-gate evch_dl_is_init(evch_dlist_t *hp) 122*7c478bd9Sstevel@tonic-gate { 123*7c478bd9Sstevel@tonic-gate return (hp->dh_head.dl_next != NULL ? 1 : 0); 124*7c478bd9Sstevel@tonic-gate } 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate /* 127*7c478bd9Sstevel@tonic-gate * Add an element at the end of the list. 128*7c478bd9Sstevel@tonic-gate */ 129*7c478bd9Sstevel@tonic-gate static void 130*7c478bd9Sstevel@tonic-gate evch_dl_add(evch_dlist_t *hp, evch_dlelem_t *el) 131*7c478bd9Sstevel@tonic-gate { 132*7c478bd9Sstevel@tonic-gate evch_dlelem_t *x = hp->dh_head.dl_prev; 133*7c478bd9Sstevel@tonic-gate evch_dlelem_t *y = &hp->dh_head; 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate x->dl_next = el; 136*7c478bd9Sstevel@tonic-gate y->dl_prev = el; 137*7c478bd9Sstevel@tonic-gate el->dl_next = y; 138*7c478bd9Sstevel@tonic-gate el->dl_prev = x; 139*7c478bd9Sstevel@tonic-gate hp->dh_count++; 140*7c478bd9Sstevel@tonic-gate } 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate /* 143*7c478bd9Sstevel@tonic-gate * Remove arbitrary element out of dlist. 144*7c478bd9Sstevel@tonic-gate */ 145*7c478bd9Sstevel@tonic-gate static void 146*7c478bd9Sstevel@tonic-gate evch_dl_del(evch_dlist_t *hp, evch_dlelem_t *p) 147*7c478bd9Sstevel@tonic-gate { 148*7c478bd9Sstevel@tonic-gate ASSERT(hp->dh_count > 0 && p != &hp->dh_head); 149*7c478bd9Sstevel@tonic-gate p->dl_prev->dl_next = p->dl_next; 150*7c478bd9Sstevel@tonic-gate p->dl_next->dl_prev = p->dl_prev; 151*7c478bd9Sstevel@tonic-gate p->dl_prev = NULL; 152*7c478bd9Sstevel@tonic-gate p->dl_next = NULL; 153*7c478bd9Sstevel@tonic-gate hp->dh_count--; 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate /* 157*7c478bd9Sstevel@tonic-gate * Search an element in a list. Caller provides comparison callback function. 158*7c478bd9Sstevel@tonic-gate */ 159*7c478bd9Sstevel@tonic-gate static evch_dlelem_t * 160*7c478bd9Sstevel@tonic-gate evch_dl_search(evch_dlist_t *hp, int (*cmp)(evch_dlelem_t *, char *), char *s) 161*7c478bd9Sstevel@tonic-gate { 162*7c478bd9Sstevel@tonic-gate evch_dlelem_t *p; 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate for (p = hp->dh_head.dl_next; p != &hp->dh_head; p = p->dl_next) { 165*7c478bd9Sstevel@tonic-gate if (cmp(p, s) == 0) { 166*7c478bd9Sstevel@tonic-gate return (p); 167*7c478bd9Sstevel@tonic-gate } 168*7c478bd9Sstevel@tonic-gate } 169*7c478bd9Sstevel@tonic-gate return (NULL); 170*7c478bd9Sstevel@tonic-gate } 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * Return number of elements in the list. 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate static int 176*7c478bd9Sstevel@tonic-gate evch_dl_getnum(evch_dlist_t *hp) 177*7c478bd9Sstevel@tonic-gate { 178*7c478bd9Sstevel@tonic-gate return (hp->dh_count); 179*7c478bd9Sstevel@tonic-gate } 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate /* 182*7c478bd9Sstevel@tonic-gate * Find next element of a evch_dlist_t list. Find first element if el == NULL. 183*7c478bd9Sstevel@tonic-gate * Returns NULL if end of list is reached. 184*7c478bd9Sstevel@tonic-gate */ 185*7c478bd9Sstevel@tonic-gate static void * 186*7c478bd9Sstevel@tonic-gate evch_dl_next(evch_dlist_t *hp, void *el) 187*7c478bd9Sstevel@tonic-gate { 188*7c478bd9Sstevel@tonic-gate evch_dlelem_t *ep = (evch_dlelem_t *)el; 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate if (hp->dh_count == 0) { 191*7c478bd9Sstevel@tonic-gate return (NULL); 192*7c478bd9Sstevel@tonic-gate } 193*7c478bd9Sstevel@tonic-gate if (ep == NULL) { 194*7c478bd9Sstevel@tonic-gate return (hp->dh_head.dl_next); 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate if ((ep = ep->dl_next) == (evch_dlelem_t *)hp) { 197*7c478bd9Sstevel@tonic-gate return (NULL); 198*7c478bd9Sstevel@tonic-gate } 199*7c478bd9Sstevel@tonic-gate return ((void *)ep); 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate /* 203*7c478bd9Sstevel@tonic-gate * Queue handling routines. Mutexes have to be entered previously. 204*7c478bd9Sstevel@tonic-gate * 205*7c478bd9Sstevel@tonic-gate * evch_q_init - Initialize queue head 206*7c478bd9Sstevel@tonic-gate * evch_q_in - Put element into queue 207*7c478bd9Sstevel@tonic-gate * evch_q_out - Get element out of queue 208*7c478bd9Sstevel@tonic-gate * evch_q_next - Iterate over the elements of a queue 209*7c478bd9Sstevel@tonic-gate */ 210*7c478bd9Sstevel@tonic-gate static void 211*7c478bd9Sstevel@tonic-gate evch_q_init(evch_squeue_t *q) 212*7c478bd9Sstevel@tonic-gate { 213*7c478bd9Sstevel@tonic-gate q->sq_head = NULL; 214*7c478bd9Sstevel@tonic-gate q->sq_tail = (evch_qelem_t *)q; 215*7c478bd9Sstevel@tonic-gate q->sq_count = 0; 216*7c478bd9Sstevel@tonic-gate q->sq_highwm = 0; 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate /* 220*7c478bd9Sstevel@tonic-gate * Put element into the queue q 221*7c478bd9Sstevel@tonic-gate */ 222*7c478bd9Sstevel@tonic-gate static void 223*7c478bd9Sstevel@tonic-gate evch_q_in(evch_squeue_t *q, evch_qelem_t *el) 224*7c478bd9Sstevel@tonic-gate { 225*7c478bd9Sstevel@tonic-gate q->sq_tail->q_next = el; 226*7c478bd9Sstevel@tonic-gate el->q_next = NULL; 227*7c478bd9Sstevel@tonic-gate q->sq_tail = el; 228*7c478bd9Sstevel@tonic-gate q->sq_count++; 229*7c478bd9Sstevel@tonic-gate if (q->sq_count > q->sq_highwm) { 230*7c478bd9Sstevel@tonic-gate q->sq_highwm = q->sq_count; 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate } 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate /* 235*7c478bd9Sstevel@tonic-gate * Returns NULL if queue is empty. 236*7c478bd9Sstevel@tonic-gate */ 237*7c478bd9Sstevel@tonic-gate static evch_qelem_t * 238*7c478bd9Sstevel@tonic-gate evch_q_out(evch_squeue_t *q) 239*7c478bd9Sstevel@tonic-gate { 240*7c478bd9Sstevel@tonic-gate evch_qelem_t *el; 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate if ((el = q->sq_head) != NULL) { 243*7c478bd9Sstevel@tonic-gate q->sq_head = el->q_next; 244*7c478bd9Sstevel@tonic-gate q->sq_count--; 245*7c478bd9Sstevel@tonic-gate if (q->sq_head == NULL) { 246*7c478bd9Sstevel@tonic-gate q->sq_tail = (evch_qelem_t *)q; 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate return (el); 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate /* 253*7c478bd9Sstevel@tonic-gate * Returns element after *el or first if el == NULL. NULL is returned 254*7c478bd9Sstevel@tonic-gate * if queue is empty or *el points to the last element in the queue. 255*7c478bd9Sstevel@tonic-gate */ 256*7c478bd9Sstevel@tonic-gate static evch_qelem_t * 257*7c478bd9Sstevel@tonic-gate evch_q_next(evch_squeue_t *q, evch_qelem_t *el) 258*7c478bd9Sstevel@tonic-gate { 259*7c478bd9Sstevel@tonic-gate if (el == NULL) 260*7c478bd9Sstevel@tonic-gate return (q->sq_head); 261*7c478bd9Sstevel@tonic-gate return (el->q_next); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate /* 265*7c478bd9Sstevel@tonic-gate * Event queue handling functions. An event queue is the basic building block 266*7c478bd9Sstevel@tonic-gate * of an event channel. One event queue makes up the publisher-side event queue. 267*7c478bd9Sstevel@tonic-gate * Further event queues build the per-subscriber queues of an event channel. 268*7c478bd9Sstevel@tonic-gate * Each queue is associated an event delivery thread. 269*7c478bd9Sstevel@tonic-gate * These functions support a two-step initialization. First step, when kernel 270*7c478bd9Sstevel@tonic-gate * memory is ready and second when threads are ready. 271*7c478bd9Sstevel@tonic-gate * Events consist of an administrating evch_gevent_t structure with the event 272*7c478bd9Sstevel@tonic-gate * data appended as variable length payload. 273*7c478bd9Sstevel@tonic-gate * The internal interface functions for the event queue handling are: 274*7c478bd9Sstevel@tonic-gate * 275*7c478bd9Sstevel@tonic-gate * evch_evq_create - create an event queue 276*7c478bd9Sstevel@tonic-gate * evch_evq_thrcreate - create thread for an event queue. 277*7c478bd9Sstevel@tonic-gate * evch_evq_destroy - delete an event queue 278*7c478bd9Sstevel@tonic-gate * evch_evq_sub - Subscribe to event delivery from an event queue 279*7c478bd9Sstevel@tonic-gate * evch_evq_unsub - Unsubscribe 280*7c478bd9Sstevel@tonic-gate * evch_evq_pub - Post an event into an event queue 281*7c478bd9Sstevel@tonic-gate * evch_evq_stop - Put delivery thread on hold 282*7c478bd9Sstevel@tonic-gate * evch_evq_continue - Resume event delivery thread 283*7c478bd9Sstevel@tonic-gate * evch_evq_status - Return status of delivery thread, running or on hold 284*7c478bd9Sstevel@tonic-gate * evch_evq_evzalloc - Allocate an event structure 285*7c478bd9Sstevel@tonic-gate * evch_evq_evfree - Free an event structure 286*7c478bd9Sstevel@tonic-gate * evch_evq_evadd_dest - Add a destructor function to an event structure 287*7c478bd9Sstevel@tonic-gate * evch_evq_evnext - Iterate over events non-destructive 288*7c478bd9Sstevel@tonic-gate */ 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 291*7c478bd9Sstevel@tonic-gate static void * 292*7c478bd9Sstevel@tonic-gate evch_zoneinit(zoneid_t zoneid) 293*7c478bd9Sstevel@tonic-gate { 294*7c478bd9Sstevel@tonic-gate struct evch_globals *eg; 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate eg = kmem_zalloc(sizeof (*eg), KM_SLEEP); 297*7c478bd9Sstevel@tonic-gate evch_dl_init(&eg->evch_list); 298*7c478bd9Sstevel@tonic-gate return (eg); 299*7c478bd9Sstevel@tonic-gate } 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 302*7c478bd9Sstevel@tonic-gate static void 303*7c478bd9Sstevel@tonic-gate evch_zonefree(zoneid_t zoneid, void *arg) 304*7c478bd9Sstevel@tonic-gate { 305*7c478bd9Sstevel@tonic-gate struct evch_globals *eg = arg; 306*7c478bd9Sstevel@tonic-gate evch_chan_t *chp; 307*7c478bd9Sstevel@tonic-gate evch_subd_t *sdp; 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate mutex_enter(&eg->evch_list_lock); 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate /* 312*7c478bd9Sstevel@tonic-gate * Keep picking the head element off the list until there are no 313*7c478bd9Sstevel@tonic-gate * more. 314*7c478bd9Sstevel@tonic-gate */ 315*7c478bd9Sstevel@tonic-gate while ((chp = evch_dl_next(&eg->evch_list, NULL)) != NULL) { 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate /* 318*7c478bd9Sstevel@tonic-gate * Since all processes are gone, all bindings should be gone, 319*7c478bd9Sstevel@tonic-gate * and only channels with SUB_KEEP subscribers should remain. 320*7c478bd9Sstevel@tonic-gate */ 321*7c478bd9Sstevel@tonic-gate mutex_enter(&chp->ch_mutex); 322*7c478bd9Sstevel@tonic-gate ASSERT(chp->ch_bindings == 0); 323*7c478bd9Sstevel@tonic-gate ASSERT(evch_dl_getnum(&chp->ch_subscr) != 0); 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate /* Forcibly unsubscribe each remaining subscription */ 326*7c478bd9Sstevel@tonic-gate while ((sdp = evch_dl_next(&chp->ch_subscr, NULL)) != NULL) { 327*7c478bd9Sstevel@tonic-gate /* 328*7c478bd9Sstevel@tonic-gate * We should only be tearing down persistent 329*7c478bd9Sstevel@tonic-gate * subscribers at this point, since all processes 330*7c478bd9Sstevel@tonic-gate * from this zone are gone. 331*7c478bd9Sstevel@tonic-gate */ 332*7c478bd9Sstevel@tonic-gate ASSERT(sdp->sd_active == 0); 333*7c478bd9Sstevel@tonic-gate ASSERT((sdp->sd_persist & EVCH_SUB_KEEP) != 0); 334*7c478bd9Sstevel@tonic-gate /* 335*7c478bd9Sstevel@tonic-gate * Disconnect subscriber queue from main event queue. 336*7c478bd9Sstevel@tonic-gate */ 337*7c478bd9Sstevel@tonic-gate evch_evq_unsub(chp->ch_queue, sdp->sd_msub); 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate /* Destruct per subscriber queue */ 340*7c478bd9Sstevel@tonic-gate evch_evq_unsub(sdp->sd_queue, sdp->sd_ssub); 341*7c478bd9Sstevel@tonic-gate evch_evq_destroy(sdp->sd_queue); 342*7c478bd9Sstevel@tonic-gate /* 343*7c478bd9Sstevel@tonic-gate * Eliminate the subscriber data from channel list. 344*7c478bd9Sstevel@tonic-gate */ 345*7c478bd9Sstevel@tonic-gate evch_dl_del(&chp->ch_subscr, &sdp->sd_link); 346*7c478bd9Sstevel@tonic-gate kmem_free(sdp->sd_classname, sdp->sd_clnsize); 347*7c478bd9Sstevel@tonic-gate kmem_free(sdp->sd_ident, strlen(sdp->sd_ident) + 1); 348*7c478bd9Sstevel@tonic-gate kmem_free(sdp, sizeof (evch_subd_t)); 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate /* Channel must now have no subscribers */ 352*7c478bd9Sstevel@tonic-gate ASSERT(evch_dl_getnum(&chp->ch_subscr) == 0); 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate /* Just like unbind */ 355*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_mutex); 356*7c478bd9Sstevel@tonic-gate evch_dl_del(&eg->evch_list, &chp->ch_link); 357*7c478bd9Sstevel@tonic-gate evch_evq_destroy(chp->ch_queue); 358*7c478bd9Sstevel@tonic-gate mutex_destroy(&chp->ch_mutex); 359*7c478bd9Sstevel@tonic-gate mutex_destroy(&chp->ch_pubmx); 360*7c478bd9Sstevel@tonic-gate cv_destroy(&chp->ch_pubcv); 361*7c478bd9Sstevel@tonic-gate kmem_free(chp->ch_name, chp->ch_namelen); 362*7c478bd9Sstevel@tonic-gate kmem_free(chp, sizeof (evch_chan_t)); 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate mutex_exit(&eg->evch_list_lock); 366*7c478bd9Sstevel@tonic-gate /* all channels should now be gone */ 367*7c478bd9Sstevel@tonic-gate ASSERT(evch_dl_getnum(&eg->evch_list) == 0); 368*7c478bd9Sstevel@tonic-gate kmem_free(eg, sizeof (*eg)); 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * Frees evch_gevent_t structure including the payload, if the reference count 373*7c478bd9Sstevel@tonic-gate * drops to or below zero. Below zero happens when the event is freed 374*7c478bd9Sstevel@tonic-gate * without beeing queued into a queue. 375*7c478bd9Sstevel@tonic-gate */ 376*7c478bd9Sstevel@tonic-gate static void 377*7c478bd9Sstevel@tonic-gate evch_gevent_free(evch_gevent_t *evp) 378*7c478bd9Sstevel@tonic-gate { 379*7c478bd9Sstevel@tonic-gate int32_t refcnt; 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate refcnt = (int32_t)atomic_add_32_nv(&evp->ge_refcount, -1); 382*7c478bd9Sstevel@tonic-gate if (refcnt <= 0) { 383*7c478bd9Sstevel@tonic-gate if (evp->ge_destruct != NULL) { 384*7c478bd9Sstevel@tonic-gate evp->ge_destruct((void *)&(evp->ge_payload), 385*7c478bd9Sstevel@tonic-gate evp->ge_dstcookie); 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate kmem_free(evp, evp->ge_size); 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate /* 392*7c478bd9Sstevel@tonic-gate * Deliver is called for every subscription to the current event 393*7c478bd9Sstevel@tonic-gate * It calls the registered filter function and then the registered delivery 394*7c478bd9Sstevel@tonic-gate * callback routine. Returns 0 on success. The callback routine returns 395*7c478bd9Sstevel@tonic-gate * EVQ_AGAIN or EVQ_SLEEP in case the event could not be delivered. 396*7c478bd9Sstevel@tonic-gate */ 397*7c478bd9Sstevel@tonic-gate static int 398*7c478bd9Sstevel@tonic-gate evch_deliver(evch_evqsub_t *sp, evch_gevent_t *ep) 399*7c478bd9Sstevel@tonic-gate { 400*7c478bd9Sstevel@tonic-gate void *uep = &ep->ge_payload; 401*7c478bd9Sstevel@tonic-gate int res = EVQ_DELIVER; 402*7c478bd9Sstevel@tonic-gate 403*7c478bd9Sstevel@tonic-gate if (sp->su_filter != NULL) { 404*7c478bd9Sstevel@tonic-gate res = sp->su_filter(uep, sp->su_fcookie); 405*7c478bd9Sstevel@tonic-gate } 406*7c478bd9Sstevel@tonic-gate if (res == EVQ_DELIVER) { 407*7c478bd9Sstevel@tonic-gate return (sp->su_callb(uep, sp->su_cbcookie)); 408*7c478bd9Sstevel@tonic-gate } 409*7c478bd9Sstevel@tonic-gate return (0); 410*7c478bd9Sstevel@tonic-gate } 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate /* 413*7c478bd9Sstevel@tonic-gate * Holds event delivery in case of eq_holdmode set or in case the 414*7c478bd9Sstevel@tonic-gate * event queue is empty. Mutex must be held when called. 415*7c478bd9Sstevel@tonic-gate * Wakes up a thread waiting for the delivery thread reaching the hold mode. 416*7c478bd9Sstevel@tonic-gate */ 417*7c478bd9Sstevel@tonic-gate static void 418*7c478bd9Sstevel@tonic-gate evch_delivery_hold(evch_eventq_t *eqp, callb_cpr_t *cpip) 419*7c478bd9Sstevel@tonic-gate { 420*7c478bd9Sstevel@tonic-gate if (eqp->eq_tabortflag == 0) { 421*7c478bd9Sstevel@tonic-gate do { 422*7c478bd9Sstevel@tonic-gate if (eqp->eq_holdmode) { 423*7c478bd9Sstevel@tonic-gate cv_signal(&eqp->eq_onholdcv); 424*7c478bd9Sstevel@tonic-gate } 425*7c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(cpip); 426*7c478bd9Sstevel@tonic-gate cv_wait(&eqp->eq_thrsleepcv, &eqp->eq_queuemx); 427*7c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(cpip, &eqp->eq_queuemx); 428*7c478bd9Sstevel@tonic-gate } while (eqp->eq_holdmode); 429*7c478bd9Sstevel@tonic-gate } 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate /* 433*7c478bd9Sstevel@tonic-gate * Event delivery thread. Enumerates all subscribers and calls evch_deliver() 434*7c478bd9Sstevel@tonic-gate * for each one. 435*7c478bd9Sstevel@tonic-gate */ 436*7c478bd9Sstevel@tonic-gate static void 437*7c478bd9Sstevel@tonic-gate evch_delivery_thr(evch_eventq_t *eqp) 438*7c478bd9Sstevel@tonic-gate { 439*7c478bd9Sstevel@tonic-gate evch_qelem_t *qep; 440*7c478bd9Sstevel@tonic-gate callb_cpr_t cprinfo; 441*7c478bd9Sstevel@tonic-gate int res; 442*7c478bd9Sstevel@tonic-gate evch_evqsub_t *sub; 443*7c478bd9Sstevel@tonic-gate int deltime; 444*7c478bd9Sstevel@tonic-gate int repeatcount; 445*7c478bd9Sstevel@tonic-gate char thnam[32]; 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate (void) snprintf(thnam, sizeof (thnam), "sysevent_chan-%d", 448*7c478bd9Sstevel@tonic-gate (int)eqp->eq_thrid); 449*7c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, &eqp->eq_queuemx, callb_generic_cpr, thnam); 450*7c478bd9Sstevel@tonic-gate mutex_enter(&eqp->eq_queuemx); 451*7c478bd9Sstevel@tonic-gate while (eqp->eq_tabortflag == 0) { 452*7c478bd9Sstevel@tonic-gate while (eqp->eq_holdmode == 0 && eqp->eq_tabortflag == 0 && 453*7c478bd9Sstevel@tonic-gate (qep = evch_q_out(&eqp->eq_eventq)) != NULL) { 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate /* Filter and deliver event to all subscribers */ 456*7c478bd9Sstevel@tonic-gate deltime = EVCH_MIN_PAUSE; 457*7c478bd9Sstevel@tonic-gate repeatcount = EVCH_MAX_TRY_DELIVERY; 458*7c478bd9Sstevel@tonic-gate eqp->eq_curevent = qep->q_objref; 459*7c478bd9Sstevel@tonic-gate sub = evch_dl_next(&eqp->eq_subscr, NULL); 460*7c478bd9Sstevel@tonic-gate while (sub != NULL) { 461*7c478bd9Sstevel@tonic-gate eqp->eq_dactive = 1; 462*7c478bd9Sstevel@tonic-gate mutex_exit(&eqp->eq_queuemx); 463*7c478bd9Sstevel@tonic-gate res = evch_deliver(sub, qep->q_objref); 464*7c478bd9Sstevel@tonic-gate mutex_enter(&eqp->eq_queuemx); 465*7c478bd9Sstevel@tonic-gate eqp->eq_dactive = 0; 466*7c478bd9Sstevel@tonic-gate cv_signal(&eqp->eq_dactivecv); 467*7c478bd9Sstevel@tonic-gate switch (res) { 468*7c478bd9Sstevel@tonic-gate case EVQ_SLEEP: 469*7c478bd9Sstevel@tonic-gate /* 470*7c478bd9Sstevel@tonic-gate * Wait for subscriber to return. 471*7c478bd9Sstevel@tonic-gate */ 472*7c478bd9Sstevel@tonic-gate eqp->eq_holdmode = 1; 473*7c478bd9Sstevel@tonic-gate evch_delivery_hold(eqp, &cprinfo); 474*7c478bd9Sstevel@tonic-gate if (eqp->eq_tabortflag) { 475*7c478bd9Sstevel@tonic-gate break; 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate continue; 478*7c478bd9Sstevel@tonic-gate case EVQ_AGAIN: 479*7c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo); 480*7c478bd9Sstevel@tonic-gate mutex_exit(&eqp->eq_queuemx); 481*7c478bd9Sstevel@tonic-gate delay(deltime); 482*7c478bd9Sstevel@tonic-gate deltime = 483*7c478bd9Sstevel@tonic-gate deltime > EVCH_MAX_PAUSE ? 484*7c478bd9Sstevel@tonic-gate deltime : deltime << 1; 485*7c478bd9Sstevel@tonic-gate mutex_enter(&eqp->eq_queuemx); 486*7c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, 487*7c478bd9Sstevel@tonic-gate &eqp->eq_queuemx); 488*7c478bd9Sstevel@tonic-gate if (repeatcount-- > 0) { 489*7c478bd9Sstevel@tonic-gate continue; 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate break; 492*7c478bd9Sstevel@tonic-gate } 493*7c478bd9Sstevel@tonic-gate if (eqp->eq_tabortflag) { 494*7c478bd9Sstevel@tonic-gate break; 495*7c478bd9Sstevel@tonic-gate } 496*7c478bd9Sstevel@tonic-gate sub = evch_dl_next(&eqp->eq_subscr, sub); 497*7c478bd9Sstevel@tonic-gate repeatcount = EVCH_MAX_TRY_DELIVERY; 498*7c478bd9Sstevel@tonic-gate } 499*7c478bd9Sstevel@tonic-gate eqp->eq_curevent = NULL; 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate /* Free event data and queue element */ 502*7c478bd9Sstevel@tonic-gate evch_gevent_free((evch_gevent_t *)qep->q_objref); 503*7c478bd9Sstevel@tonic-gate kmem_free(qep, qep->q_objsize); 504*7c478bd9Sstevel@tonic-gate } 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate /* Wait for next event or end of hold mode if set */ 507*7c478bd9Sstevel@tonic-gate evch_delivery_hold(eqp, &cprinfo); 508*7c478bd9Sstevel@tonic-gate } 509*7c478bd9Sstevel@tonic-gate CALLB_CPR_EXIT(&cprinfo); /* Does mutex_exit of eqp->eq_queuemx */ 510*7c478bd9Sstevel@tonic-gate thread_exit(); 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate 513*7c478bd9Sstevel@tonic-gate /* 514*7c478bd9Sstevel@tonic-gate * Create the event delivery thread for an existing event queue. 515*7c478bd9Sstevel@tonic-gate */ 516*7c478bd9Sstevel@tonic-gate static void 517*7c478bd9Sstevel@tonic-gate evch_evq_thrcreate(evch_eventq_t *eqp) 518*7c478bd9Sstevel@tonic-gate { 519*7c478bd9Sstevel@tonic-gate kthread_t *thp; 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate thp = thread_create(NULL, 0, evch_delivery_thr, (char *)eqp, 0, &p0, 522*7c478bd9Sstevel@tonic-gate TS_RUN, minclsyspri); 523*7c478bd9Sstevel@tonic-gate eqp->eq_thrid = thp->t_did; 524*7c478bd9Sstevel@tonic-gate } 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate /* 527*7c478bd9Sstevel@tonic-gate * Create event queue. 528*7c478bd9Sstevel@tonic-gate */ 529*7c478bd9Sstevel@tonic-gate static evch_eventq_t * 530*7c478bd9Sstevel@tonic-gate evch_evq_create() 531*7c478bd9Sstevel@tonic-gate { 532*7c478bd9Sstevel@tonic-gate evch_eventq_t *p; 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate /* Allocate and initialize event queue descriptor */ 535*7c478bd9Sstevel@tonic-gate p = kmem_zalloc(sizeof (evch_eventq_t), KM_SLEEP); 536*7c478bd9Sstevel@tonic-gate mutex_init(&p->eq_queuemx, NULL, MUTEX_DEFAULT, NULL); 537*7c478bd9Sstevel@tonic-gate cv_init(&p->eq_thrsleepcv, NULL, CV_DEFAULT, NULL); 538*7c478bd9Sstevel@tonic-gate evch_q_init(&p->eq_eventq); 539*7c478bd9Sstevel@tonic-gate evch_dl_init(&p->eq_subscr); 540*7c478bd9Sstevel@tonic-gate cv_init(&p->eq_dactivecv, NULL, CV_DEFAULT, NULL); 541*7c478bd9Sstevel@tonic-gate cv_init(&p->eq_onholdcv, NULL, CV_DEFAULT, NULL); 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate /* Create delivery thread */ 544*7c478bd9Sstevel@tonic-gate if (evq_initcomplete) { 545*7c478bd9Sstevel@tonic-gate evch_evq_thrcreate(p); 546*7c478bd9Sstevel@tonic-gate } 547*7c478bd9Sstevel@tonic-gate return (p); 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate /* 551*7c478bd9Sstevel@tonic-gate * Destroy an event queue. All subscribers have to be unsubscribed prior to 552*7c478bd9Sstevel@tonic-gate * this call. 553*7c478bd9Sstevel@tonic-gate */ 554*7c478bd9Sstevel@tonic-gate static void 555*7c478bd9Sstevel@tonic-gate evch_evq_destroy(evch_eventq_t *eqp) 556*7c478bd9Sstevel@tonic-gate { 557*7c478bd9Sstevel@tonic-gate evch_qelem_t *qep; 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate ASSERT(evch_dl_getnum(&eqp->eq_subscr) == 0); 560*7c478bd9Sstevel@tonic-gate /* Kill delivery thread */ 561*7c478bd9Sstevel@tonic-gate if (eqp->eq_thrid != NULL) { 562*7c478bd9Sstevel@tonic-gate mutex_enter(&eqp->eq_queuemx); 563*7c478bd9Sstevel@tonic-gate eqp->eq_tabortflag = 1; 564*7c478bd9Sstevel@tonic-gate eqp->eq_holdmode = 0; 565*7c478bd9Sstevel@tonic-gate cv_signal(&eqp->eq_thrsleepcv); 566*7c478bd9Sstevel@tonic-gate mutex_exit(&eqp->eq_queuemx); 567*7c478bd9Sstevel@tonic-gate thread_join(eqp->eq_thrid); 568*7c478bd9Sstevel@tonic-gate } 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate /* Get rid of stale events in the event queue */ 571*7c478bd9Sstevel@tonic-gate while ((qep = (evch_qelem_t *)evch_q_out(&eqp->eq_eventq)) != NULL) { 572*7c478bd9Sstevel@tonic-gate evch_gevent_free((evch_gevent_t *)qep->q_objref); 573*7c478bd9Sstevel@tonic-gate kmem_free(qep, qep->q_objsize); 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate /* Wrap up event queue structure */ 577*7c478bd9Sstevel@tonic-gate cv_destroy(&eqp->eq_onholdcv); 578*7c478bd9Sstevel@tonic-gate cv_destroy(&eqp->eq_dactivecv); 579*7c478bd9Sstevel@tonic-gate cv_destroy(&eqp->eq_thrsleepcv); 580*7c478bd9Sstevel@tonic-gate evch_dl_fini(&eqp->eq_subscr); 581*7c478bd9Sstevel@tonic-gate mutex_destroy(&eqp->eq_queuemx); 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate /* Free descriptor structure */ 584*7c478bd9Sstevel@tonic-gate kmem_free(eqp, sizeof (evch_eventq_t)); 585*7c478bd9Sstevel@tonic-gate } 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate /* 588*7c478bd9Sstevel@tonic-gate * Subscribe to an event queue. Every subscriber provides a filter callback 589*7c478bd9Sstevel@tonic-gate * routine and an event delivery callback routine. 590*7c478bd9Sstevel@tonic-gate */ 591*7c478bd9Sstevel@tonic-gate static evch_evqsub_t * 592*7c478bd9Sstevel@tonic-gate evch_evq_sub(evch_eventq_t *eqp, filter_f filter, void *fcookie, 593*7c478bd9Sstevel@tonic-gate deliver_f callb, void *cbcookie) 594*7c478bd9Sstevel@tonic-gate { 595*7c478bd9Sstevel@tonic-gate evch_evqsub_t *sp = kmem_zalloc(sizeof (evch_evqsub_t), KM_SLEEP); 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate /* Initialize subscriber structure */ 598*7c478bd9Sstevel@tonic-gate sp->su_filter = filter; 599*7c478bd9Sstevel@tonic-gate sp->su_fcookie = fcookie; 600*7c478bd9Sstevel@tonic-gate sp->su_callb = callb; 601*7c478bd9Sstevel@tonic-gate sp->su_cbcookie = cbcookie; 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate /* Add subscription to queue */ 604*7c478bd9Sstevel@tonic-gate mutex_enter(&eqp->eq_queuemx); 605*7c478bd9Sstevel@tonic-gate evch_dl_add(&eqp->eq_subscr, &sp->su_link); 606*7c478bd9Sstevel@tonic-gate mutex_exit(&eqp->eq_queuemx); 607*7c478bd9Sstevel@tonic-gate return (sp); 608*7c478bd9Sstevel@tonic-gate } 609*7c478bd9Sstevel@tonic-gate 610*7c478bd9Sstevel@tonic-gate /* 611*7c478bd9Sstevel@tonic-gate * Unsubscribe from an event queue. 612*7c478bd9Sstevel@tonic-gate */ 613*7c478bd9Sstevel@tonic-gate static void 614*7c478bd9Sstevel@tonic-gate evch_evq_unsub(evch_eventq_t *eqp, evch_evqsub_t *sp) 615*7c478bd9Sstevel@tonic-gate { 616*7c478bd9Sstevel@tonic-gate mutex_enter(&eqp->eq_queuemx); 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate /* Wait if delivery is just in progress */ 619*7c478bd9Sstevel@tonic-gate if (eqp->eq_dactive) { 620*7c478bd9Sstevel@tonic-gate cv_wait(&eqp->eq_dactivecv, &eqp->eq_queuemx); 621*7c478bd9Sstevel@tonic-gate } 622*7c478bd9Sstevel@tonic-gate evch_dl_del(&eqp->eq_subscr, &sp->su_link); 623*7c478bd9Sstevel@tonic-gate mutex_exit(&eqp->eq_queuemx); 624*7c478bd9Sstevel@tonic-gate kmem_free(sp, sizeof (evch_evqsub_t)); 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate /* 628*7c478bd9Sstevel@tonic-gate * Publish an event. Returns 0 on success and -1 if memory alloc failed. 629*7c478bd9Sstevel@tonic-gate */ 630*7c478bd9Sstevel@tonic-gate static int 631*7c478bd9Sstevel@tonic-gate evch_evq_pub(evch_eventq_t *eqp, void *ev, int flags) 632*7c478bd9Sstevel@tonic-gate { 633*7c478bd9Sstevel@tonic-gate size_t size; 634*7c478bd9Sstevel@tonic-gate evch_qelem_t *qep; 635*7c478bd9Sstevel@tonic-gate evch_gevent_t *evp = GEVENT(ev); 636*7c478bd9Sstevel@tonic-gate 637*7c478bd9Sstevel@tonic-gate size = sizeof (evch_qelem_t); 638*7c478bd9Sstevel@tonic-gate if (flags & EVCH_TRYHARD) { 639*7c478bd9Sstevel@tonic-gate qep = kmem_alloc_tryhard(size, &size, KM_NOSLEEP); 640*7c478bd9Sstevel@tonic-gate } else { 641*7c478bd9Sstevel@tonic-gate qep = kmem_alloc(size, flags & EVCH_NOSLEEP ? 642*7c478bd9Sstevel@tonic-gate KM_NOSLEEP : KM_SLEEP); 643*7c478bd9Sstevel@tonic-gate } 644*7c478bd9Sstevel@tonic-gate if (qep == NULL) { 645*7c478bd9Sstevel@tonic-gate return (-1); 646*7c478bd9Sstevel@tonic-gate } 647*7c478bd9Sstevel@tonic-gate qep->q_objref = (void *)evp; 648*7c478bd9Sstevel@tonic-gate qep->q_objsize = size; 649*7c478bd9Sstevel@tonic-gate atomic_add_32(&evp->ge_refcount, 1); 650*7c478bd9Sstevel@tonic-gate mutex_enter(&eqp->eq_queuemx); 651*7c478bd9Sstevel@tonic-gate evch_q_in(&eqp->eq_eventq, qep); 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate /* Wakeup delivery thread */ 654*7c478bd9Sstevel@tonic-gate cv_signal(&eqp->eq_thrsleepcv); 655*7c478bd9Sstevel@tonic-gate mutex_exit(&eqp->eq_queuemx); 656*7c478bd9Sstevel@tonic-gate return (0); 657*7c478bd9Sstevel@tonic-gate } 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate /* 660*7c478bd9Sstevel@tonic-gate * Enter hold mode of an event queue. Event delivery thread stops event 661*7c478bd9Sstevel@tonic-gate * handling after delivery of current event (if any). 662*7c478bd9Sstevel@tonic-gate */ 663*7c478bd9Sstevel@tonic-gate static void 664*7c478bd9Sstevel@tonic-gate evch_evq_stop(evch_eventq_t *eqp) 665*7c478bd9Sstevel@tonic-gate { 666*7c478bd9Sstevel@tonic-gate mutex_enter(&eqp->eq_queuemx); 667*7c478bd9Sstevel@tonic-gate eqp->eq_holdmode = 1; 668*7c478bd9Sstevel@tonic-gate if (evq_initcomplete) { 669*7c478bd9Sstevel@tonic-gate cv_signal(&eqp->eq_thrsleepcv); 670*7c478bd9Sstevel@tonic-gate cv_wait(&eqp->eq_onholdcv, &eqp->eq_queuemx); 671*7c478bd9Sstevel@tonic-gate } 672*7c478bd9Sstevel@tonic-gate mutex_exit(&eqp->eq_queuemx); 673*7c478bd9Sstevel@tonic-gate } 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate /* 676*7c478bd9Sstevel@tonic-gate * Continue event delivery. 677*7c478bd9Sstevel@tonic-gate */ 678*7c478bd9Sstevel@tonic-gate static void 679*7c478bd9Sstevel@tonic-gate evch_evq_continue(evch_eventq_t *eqp) 680*7c478bd9Sstevel@tonic-gate { 681*7c478bd9Sstevel@tonic-gate mutex_enter(&eqp->eq_queuemx); 682*7c478bd9Sstevel@tonic-gate eqp->eq_holdmode = 0; 683*7c478bd9Sstevel@tonic-gate cv_signal(&eqp->eq_thrsleepcv); 684*7c478bd9Sstevel@tonic-gate mutex_exit(&eqp->eq_queuemx); 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate /* 688*7c478bd9Sstevel@tonic-gate * Returns status of delivery thread. 0 if running and 1 if on hold. 689*7c478bd9Sstevel@tonic-gate */ 690*7c478bd9Sstevel@tonic-gate static int 691*7c478bd9Sstevel@tonic-gate evch_evq_status(evch_eventq_t *eqp) 692*7c478bd9Sstevel@tonic-gate { 693*7c478bd9Sstevel@tonic-gate return (eqp->eq_holdmode); 694*7c478bd9Sstevel@tonic-gate } 695*7c478bd9Sstevel@tonic-gate 696*7c478bd9Sstevel@tonic-gate /* 697*7c478bd9Sstevel@tonic-gate * Add a destructor function to an event structure. 698*7c478bd9Sstevel@tonic-gate */ 699*7c478bd9Sstevel@tonic-gate static void 700*7c478bd9Sstevel@tonic-gate evch_evq_evadd_dest(void *ev, destr_f destructor, void *cookie) 701*7c478bd9Sstevel@tonic-gate { 702*7c478bd9Sstevel@tonic-gate evch_gevent_t *evp = GEVENT(ev); 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate evp->ge_destruct = destructor; 705*7c478bd9Sstevel@tonic-gate evp->ge_dstcookie = cookie; 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate /* 709*7c478bd9Sstevel@tonic-gate * Allocate evch_gevent_t structure. Return address of payload offset of 710*7c478bd9Sstevel@tonic-gate * evch_gevent_t. If EVCH_TRYHARD allocation is requested, we use 711*7c478bd9Sstevel@tonic-gate * kmem_alloc_tryhard to alloc memory of at least paylsize bytes. 712*7c478bd9Sstevel@tonic-gate * 713*7c478bd9Sstevel@tonic-gate * If either memory allocation is unsuccessful, we return NULL. 714*7c478bd9Sstevel@tonic-gate */ 715*7c478bd9Sstevel@tonic-gate static void * 716*7c478bd9Sstevel@tonic-gate evch_evq_evzalloc(size_t paylsize, int flag) 717*7c478bd9Sstevel@tonic-gate { 718*7c478bd9Sstevel@tonic-gate evch_gevent_t *evp; 719*7c478bd9Sstevel@tonic-gate size_t rsize, evsize; 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate rsize = offsetof(evch_gevent_t, ge_payload) + paylsize; 722*7c478bd9Sstevel@tonic-gate if (flag & EVCH_TRYHARD) { 723*7c478bd9Sstevel@tonic-gate evp = kmem_alloc_tryhard(rsize, &evsize, KM_NOSLEEP); 724*7c478bd9Sstevel@tonic-gate bzero(evp, rsize); 725*7c478bd9Sstevel@tonic-gate evp->ge_size = evsize; 726*7c478bd9Sstevel@tonic-gate } else { 727*7c478bd9Sstevel@tonic-gate evp = kmem_alloc(rsize, flag & EVCH_NOSLEEP ? KM_NOSLEEP : 728*7c478bd9Sstevel@tonic-gate KM_SLEEP); 729*7c478bd9Sstevel@tonic-gate bzero(evp, rsize); 730*7c478bd9Sstevel@tonic-gate evp->ge_size = rsize; 731*7c478bd9Sstevel@tonic-gate } 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate if (evp) { 734*7c478bd9Sstevel@tonic-gate return (&evp->ge_payload); 735*7c478bd9Sstevel@tonic-gate } 736*7c478bd9Sstevel@tonic-gate return (evp); 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate /* 740*7c478bd9Sstevel@tonic-gate * Free event structure. Argument ev is address of payload offset. 741*7c478bd9Sstevel@tonic-gate */ 742*7c478bd9Sstevel@tonic-gate static void 743*7c478bd9Sstevel@tonic-gate evch_evq_evfree(void *ev) 744*7c478bd9Sstevel@tonic-gate { 745*7c478bd9Sstevel@tonic-gate evch_gevent_free(GEVENT(ev)); 746*7c478bd9Sstevel@tonic-gate } 747*7c478bd9Sstevel@tonic-gate 748*7c478bd9Sstevel@tonic-gate /* 749*7c478bd9Sstevel@tonic-gate * Iterate over all events in the event queue. Begin with an event 750*7c478bd9Sstevel@tonic-gate * which is currently being delivered. No mutexes are grabbed and no 751*7c478bd9Sstevel@tonic-gate * resources allocated so that this function can be called in panic 752*7c478bd9Sstevel@tonic-gate * context too. This function has to be called with ev == NULL initially. 753*7c478bd9Sstevel@tonic-gate * Actually argument ev is only a flag. Internally the member eq_nextev 754*7c478bd9Sstevel@tonic-gate * is used to determine the next event. But ev allows for the convenient 755*7c478bd9Sstevel@tonic-gate * use like 756*7c478bd9Sstevel@tonic-gate * ev = NULL; 757*7c478bd9Sstevel@tonic-gate * while ((ev = evch_evq_evnext(evp, ev)) != NULL) ... 758*7c478bd9Sstevel@tonic-gate */ 759*7c478bd9Sstevel@tonic-gate static void * 760*7c478bd9Sstevel@tonic-gate evch_evq_evnext(evch_eventq_t *evq, void *ev) 761*7c478bd9Sstevel@tonic-gate { 762*7c478bd9Sstevel@tonic-gate if (ev == NULL) { 763*7c478bd9Sstevel@tonic-gate evq->eq_nextev = NULL; 764*7c478bd9Sstevel@tonic-gate if (evq->eq_curevent != NULL) 765*7c478bd9Sstevel@tonic-gate return (&evq->eq_curevent->ge_payload); 766*7c478bd9Sstevel@tonic-gate } 767*7c478bd9Sstevel@tonic-gate evq->eq_nextev = evch_q_next(&evq->eq_eventq, evq->eq_nextev); 768*7c478bd9Sstevel@tonic-gate if (evq->eq_nextev == NULL) 769*7c478bd9Sstevel@tonic-gate return (NULL); 770*7c478bd9Sstevel@tonic-gate return (&((evch_gevent_t *)evq->eq_nextev->q_objref)->ge_payload); 771*7c478bd9Sstevel@tonic-gate } 772*7c478bd9Sstevel@tonic-gate 773*7c478bd9Sstevel@tonic-gate /* 774*7c478bd9Sstevel@tonic-gate * Channel handling functions. First some support functions. Functions belonging 775*7c478bd9Sstevel@tonic-gate * to the channel handling interface start with evch_ch. The following functions 776*7c478bd9Sstevel@tonic-gate * make up the channel handling internal interfaces: 777*7c478bd9Sstevel@tonic-gate * 778*7c478bd9Sstevel@tonic-gate * evch_chinit - Initialize channel handling 779*7c478bd9Sstevel@tonic-gate * evch_chinitthr - Second step init: initialize threads 780*7c478bd9Sstevel@tonic-gate * evch_chbind - Bind to a channel 781*7c478bd9Sstevel@tonic-gate * evch_chunbind - Unbind from a channel 782*7c478bd9Sstevel@tonic-gate * evch_chsubscribe - Subscribe to a sysevent class 783*7c478bd9Sstevel@tonic-gate * evch_chunsubscribe - Unsubscribe 784*7c478bd9Sstevel@tonic-gate * evch_chpublish - Publish an event 785*7c478bd9Sstevel@tonic-gate * evch_chgetnames - Get names of all channels 786*7c478bd9Sstevel@tonic-gate * evch_chgetchdata - Get data of a channel 787*7c478bd9Sstevel@tonic-gate * evch_chrdevent_init - Init event q traversal 788*7c478bd9Sstevel@tonic-gate * evch_chgetnextev - Read out events queued for a subscriber 789*7c478bd9Sstevel@tonic-gate * evch_chrdevent_fini - Finish event q traversal 790*7c478bd9Sstevel@tonic-gate */ 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate /* 793*7c478bd9Sstevel@tonic-gate * Compare channel name. Used for evch_dl_search to find a channel with the 794*7c478bd9Sstevel@tonic-gate * name s. 795*7c478bd9Sstevel@tonic-gate */ 796*7c478bd9Sstevel@tonic-gate static int 797*7c478bd9Sstevel@tonic-gate evch_namecmp(evch_dlelem_t *ep, char *s) 798*7c478bd9Sstevel@tonic-gate { 799*7c478bd9Sstevel@tonic-gate return (strcmp(((evch_chan_t *)ep)->ch_name, s)); 800*7c478bd9Sstevel@tonic-gate } 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate /* 803*7c478bd9Sstevel@tonic-gate * Sysevent filter callback routine. Enables event delivery only if it matches 804*7c478bd9Sstevel@tonic-gate * the event class string given by parameter cookie. 805*7c478bd9Sstevel@tonic-gate */ 806*7c478bd9Sstevel@tonic-gate static int 807*7c478bd9Sstevel@tonic-gate evch_class_filter(void *ev, void *cookie) 808*7c478bd9Sstevel@tonic-gate { 809*7c478bd9Sstevel@tonic-gate char *class = (char *)cookie; 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate if (class == NULL || strcmp(SE_CLASS_NAME(ev), class) == 0) { 812*7c478bd9Sstevel@tonic-gate return (EVQ_DELIVER); 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate return (EVQ_IGNORE); 815*7c478bd9Sstevel@tonic-gate } 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate /* 818*7c478bd9Sstevel@tonic-gate * Callback routine to propagate the event into a per subscriber queue. 819*7c478bd9Sstevel@tonic-gate */ 820*7c478bd9Sstevel@tonic-gate static int 821*7c478bd9Sstevel@tonic-gate evch_subq_deliver(void *evp, void *cookie) 822*7c478bd9Sstevel@tonic-gate { 823*7c478bd9Sstevel@tonic-gate evch_subd_t *p = (evch_subd_t *)cookie; 824*7c478bd9Sstevel@tonic-gate 825*7c478bd9Sstevel@tonic-gate (void) evch_evq_pub(p->sd_queue, evp, EVCH_SLEEP); 826*7c478bd9Sstevel@tonic-gate return (EVQ_CONT); 827*7c478bd9Sstevel@tonic-gate } 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate /* 830*7c478bd9Sstevel@tonic-gate * Call kernel callback routine for sysevent kernel delivery. 831*7c478bd9Sstevel@tonic-gate */ 832*7c478bd9Sstevel@tonic-gate static int 833*7c478bd9Sstevel@tonic-gate evch_kern_deliver(void *evp, void *cookie) 834*7c478bd9Sstevel@tonic-gate { 835*7c478bd9Sstevel@tonic-gate sysevent_impl_t *ev = (sysevent_impl_t *)evp; 836*7c478bd9Sstevel@tonic-gate evch_subd_t *sdp = (evch_subd_t *)cookie; 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate return (sdp->sd_callback(ev, sdp->sd_cbcookie)); 839*7c478bd9Sstevel@tonic-gate } 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate /* 842*7c478bd9Sstevel@tonic-gate * Door upcall for user land sysevent delivery. 843*7c478bd9Sstevel@tonic-gate */ 844*7c478bd9Sstevel@tonic-gate static int 845*7c478bd9Sstevel@tonic-gate evch_door_deliver(void *evp, void *cookie) 846*7c478bd9Sstevel@tonic-gate { 847*7c478bd9Sstevel@tonic-gate int error; 848*7c478bd9Sstevel@tonic-gate size_t size; 849*7c478bd9Sstevel@tonic-gate sysevent_impl_t *ev = (sysevent_impl_t *)evp; 850*7c478bd9Sstevel@tonic-gate door_arg_t darg; 851*7c478bd9Sstevel@tonic-gate evch_subd_t *sdp = (evch_subd_t *)cookie; 852*7c478bd9Sstevel@tonic-gate int nticks = EVCH_MIN_PAUSE; 853*7c478bd9Sstevel@tonic-gate uint32_t retval; 854*7c478bd9Sstevel@tonic-gate int retry = 20; 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate /* Initialize door args */ 857*7c478bd9Sstevel@tonic-gate size = sizeof (sysevent_impl_t) + SE_PAYLOAD_SZ(ev); 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate darg.rbuf = (char *)&retval; 860*7c478bd9Sstevel@tonic-gate darg.rsize = sizeof (retval); 861*7c478bd9Sstevel@tonic-gate darg.data_ptr = (char *)ev; 862*7c478bd9Sstevel@tonic-gate darg.data_size = size; 863*7c478bd9Sstevel@tonic-gate darg.desc_ptr = NULL; 864*7c478bd9Sstevel@tonic-gate darg.desc_num = 0; 865*7c478bd9Sstevel@tonic-gate 866*7c478bd9Sstevel@tonic-gate for (;;) { 867*7c478bd9Sstevel@tonic-gate if ((error = door_ki_upcall(sdp->sd_door, &darg)) == 0) { 868*7c478bd9Sstevel@tonic-gate break; 869*7c478bd9Sstevel@tonic-gate } 870*7c478bd9Sstevel@tonic-gate switch (error) { 871*7c478bd9Sstevel@tonic-gate case EAGAIN: 872*7c478bd9Sstevel@tonic-gate /* Cannot deliver event - process may be forking */ 873*7c478bd9Sstevel@tonic-gate delay(nticks); 874*7c478bd9Sstevel@tonic-gate nticks <<= 1; 875*7c478bd9Sstevel@tonic-gate if (nticks > EVCH_MAX_PAUSE) { 876*7c478bd9Sstevel@tonic-gate nticks = EVCH_MAX_PAUSE; 877*7c478bd9Sstevel@tonic-gate } 878*7c478bd9Sstevel@tonic-gate if (retry-- <= 0) { 879*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "event delivery thread: " 880*7c478bd9Sstevel@tonic-gate "door_ki_upcall error EAGAIN\n"); 881*7c478bd9Sstevel@tonic-gate return (EVQ_CONT); 882*7c478bd9Sstevel@tonic-gate } 883*7c478bd9Sstevel@tonic-gate break; 884*7c478bd9Sstevel@tonic-gate case EINTR: 885*7c478bd9Sstevel@tonic-gate case EBADF: 886*7c478bd9Sstevel@tonic-gate /* Process died */ 887*7c478bd9Sstevel@tonic-gate return (EVQ_SLEEP); 888*7c478bd9Sstevel@tonic-gate default: 889*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 890*7c478bd9Sstevel@tonic-gate "event delivery thread: door_ki_upcall error %d\n", 891*7c478bd9Sstevel@tonic-gate error); 892*7c478bd9Sstevel@tonic-gate return (EVQ_CONT); 893*7c478bd9Sstevel@tonic-gate } 894*7c478bd9Sstevel@tonic-gate } 895*7c478bd9Sstevel@tonic-gate if (retval == EAGAIN) { 896*7c478bd9Sstevel@tonic-gate return (EVQ_AGAIN); 897*7c478bd9Sstevel@tonic-gate } 898*7c478bd9Sstevel@tonic-gate return (EVQ_CONT); 899*7c478bd9Sstevel@tonic-gate } 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate /* 902*7c478bd9Sstevel@tonic-gate * Callback routine for evch_dl_search() to compare subscriber id's. Used by 903*7c478bd9Sstevel@tonic-gate * evch_subscribe() and evch_chrdevent_init(). 904*7c478bd9Sstevel@tonic-gate */ 905*7c478bd9Sstevel@tonic-gate static int 906*7c478bd9Sstevel@tonic-gate evch_subidcmp(evch_dlelem_t *ep, char *s) 907*7c478bd9Sstevel@tonic-gate { 908*7c478bd9Sstevel@tonic-gate return (strcmp(((evch_subd_t *)ep)->sd_ident, s)); 909*7c478bd9Sstevel@tonic-gate } 910*7c478bd9Sstevel@tonic-gate 911*7c478bd9Sstevel@tonic-gate /* 912*7c478bd9Sstevel@tonic-gate * Callback routine for evch_dl_search() to find a subscriber with EVCH_SUB_DUMP 913*7c478bd9Sstevel@tonic-gate * set (indicated by sub->sd_dump != 0). Used by evch_chrdevent_init() and 914*7c478bd9Sstevel@tonic-gate * evch_subscribe(). Needs to returns 0 if subscriber with sd_dump set is 915*7c478bd9Sstevel@tonic-gate * found. 916*7c478bd9Sstevel@tonic-gate */ 917*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 918*7c478bd9Sstevel@tonic-gate static int 919*7c478bd9Sstevel@tonic-gate evch_dumpflgcmp(evch_dlelem_t *ep, char *s) 920*7c478bd9Sstevel@tonic-gate { 921*7c478bd9Sstevel@tonic-gate return (((evch_subd_t *)ep)->sd_dump ? 0 : 1); 922*7c478bd9Sstevel@tonic-gate } 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate /* 925*7c478bd9Sstevel@tonic-gate * Event destructor function. Used to maintain the number of events per channel. 926*7c478bd9Sstevel@tonic-gate */ 927*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 928*7c478bd9Sstevel@tonic-gate static void 929*7c478bd9Sstevel@tonic-gate evch_destr_event(void *ev, void *ch) 930*7c478bd9Sstevel@tonic-gate { 931*7c478bd9Sstevel@tonic-gate evch_chan_t *chp = (evch_chan_t *)ch; 932*7c478bd9Sstevel@tonic-gate 933*7c478bd9Sstevel@tonic-gate mutex_enter(&chp->ch_pubmx); 934*7c478bd9Sstevel@tonic-gate chp->ch_nevents--; 935*7c478bd9Sstevel@tonic-gate cv_signal(&chp->ch_pubcv); 936*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_pubmx); 937*7c478bd9Sstevel@tonic-gate } 938*7c478bd9Sstevel@tonic-gate 939*7c478bd9Sstevel@tonic-gate /* 940*7c478bd9Sstevel@tonic-gate * Integer square root according to Newton's iteration. 941*7c478bd9Sstevel@tonic-gate */ 942*7c478bd9Sstevel@tonic-gate static uint32_t 943*7c478bd9Sstevel@tonic-gate evch_isqrt(uint64_t n) 944*7c478bd9Sstevel@tonic-gate { 945*7c478bd9Sstevel@tonic-gate uint64_t x = n >> 1; 946*7c478bd9Sstevel@tonic-gate uint64_t xn = x - 1; 947*7c478bd9Sstevel@tonic-gate static uint32_t lowval[] = { 0, 1, 1, 2 }; 948*7c478bd9Sstevel@tonic-gate 949*7c478bd9Sstevel@tonic-gate if (n < 4) { 950*7c478bd9Sstevel@tonic-gate return (lowval[n]); 951*7c478bd9Sstevel@tonic-gate } 952*7c478bd9Sstevel@tonic-gate while (xn < x) { 953*7c478bd9Sstevel@tonic-gate x = xn; 954*7c478bd9Sstevel@tonic-gate xn = (x + n / x) / 2; 955*7c478bd9Sstevel@tonic-gate } 956*7c478bd9Sstevel@tonic-gate return ((uint32_t)xn); 957*7c478bd9Sstevel@tonic-gate } 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate /* 960*7c478bd9Sstevel@tonic-gate * First step sysevent channel initialization. Called when kernel memory 961*7c478bd9Sstevel@tonic-gate * allocator is initialized. 962*7c478bd9Sstevel@tonic-gate */ 963*7c478bd9Sstevel@tonic-gate static void 964*7c478bd9Sstevel@tonic-gate evch_chinit() 965*7c478bd9Sstevel@tonic-gate { 966*7c478bd9Sstevel@tonic-gate size_t k; 967*7c478bd9Sstevel@tonic-gate 968*7c478bd9Sstevel@tonic-gate /* 969*7c478bd9Sstevel@tonic-gate * Calculate limits: max no of channels and max no of events per 970*7c478bd9Sstevel@tonic-gate * channel. The smallest machine with 128 MByte will allow for 971*7c478bd9Sstevel@tonic-gate * >= 8 channels and an upper limit of 2048 events per channel. 972*7c478bd9Sstevel@tonic-gate * The event limit is the number of channels times 256 (hence 973*7c478bd9Sstevel@tonic-gate * the shift factor of 8). These number where selected arbitrarily. 974*7c478bd9Sstevel@tonic-gate */ 975*7c478bd9Sstevel@tonic-gate k = kmem_maxavail() >> 20; 976*7c478bd9Sstevel@tonic-gate evch_channels_max = min(evch_isqrt(k), EVCH_MAX_CHANNELS); 977*7c478bd9Sstevel@tonic-gate evch_events_max = evch_channels_max << 8; 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate /* 980*7c478bd9Sstevel@tonic-gate * Will trigger creation of the global zone's evch state. 981*7c478bd9Sstevel@tonic-gate */ 982*7c478bd9Sstevel@tonic-gate zone_key_create(&evch_zone_key, evch_zoneinit, NULL, evch_zonefree); 983*7c478bd9Sstevel@tonic-gate } 984*7c478bd9Sstevel@tonic-gate 985*7c478bd9Sstevel@tonic-gate /* 986*7c478bd9Sstevel@tonic-gate * Second step sysevent channel initialization. Called when threads are ready. 987*7c478bd9Sstevel@tonic-gate */ 988*7c478bd9Sstevel@tonic-gate static void 989*7c478bd9Sstevel@tonic-gate evch_chinitthr() 990*7c478bd9Sstevel@tonic-gate { 991*7c478bd9Sstevel@tonic-gate struct evch_globals *eg; 992*7c478bd9Sstevel@tonic-gate evch_chan_t *chp; 993*7c478bd9Sstevel@tonic-gate evch_subd_t *sdp; 994*7c478bd9Sstevel@tonic-gate 995*7c478bd9Sstevel@tonic-gate /* 996*7c478bd9Sstevel@tonic-gate * We're early enough in boot that we know that only the global 997*7c478bd9Sstevel@tonic-gate * zone exists; we only need to initialize its threads. 998*7c478bd9Sstevel@tonic-gate */ 999*7c478bd9Sstevel@tonic-gate eg = zone_getspecific(evch_zone_key, global_zone); 1000*7c478bd9Sstevel@tonic-gate ASSERT(eg != NULL); 1001*7c478bd9Sstevel@tonic-gate 1002*7c478bd9Sstevel@tonic-gate for (chp = evch_dl_next(&eg->evch_list, NULL); chp != NULL; 1003*7c478bd9Sstevel@tonic-gate chp = evch_dl_next(&eg->evch_list, chp)) { 1004*7c478bd9Sstevel@tonic-gate for (sdp = evch_dl_next(&chp->ch_subscr, NULL); sdp; 1005*7c478bd9Sstevel@tonic-gate sdp = evch_dl_next(&chp->ch_subscr, sdp)) { 1006*7c478bd9Sstevel@tonic-gate evch_evq_thrcreate(sdp->sd_queue); 1007*7c478bd9Sstevel@tonic-gate } 1008*7c478bd9Sstevel@tonic-gate evch_evq_thrcreate(chp->ch_queue); 1009*7c478bd9Sstevel@tonic-gate } 1010*7c478bd9Sstevel@tonic-gate evq_initcomplete = 1; 1011*7c478bd9Sstevel@tonic-gate } 1012*7c478bd9Sstevel@tonic-gate 1013*7c478bd9Sstevel@tonic-gate /* 1014*7c478bd9Sstevel@tonic-gate * Sysevent channel bind. Create channel and allocate binding structure. 1015*7c478bd9Sstevel@tonic-gate */ 1016*7c478bd9Sstevel@tonic-gate static int 1017*7c478bd9Sstevel@tonic-gate evch_chbind(const char *chnam, evch_bind_t **scpp, uint32_t flags) 1018*7c478bd9Sstevel@tonic-gate { 1019*7c478bd9Sstevel@tonic-gate struct evch_globals *eg; 1020*7c478bd9Sstevel@tonic-gate evch_bind_t *bp; 1021*7c478bd9Sstevel@tonic-gate evch_chan_t *p; 1022*7c478bd9Sstevel@tonic-gate char *chn; 1023*7c478bd9Sstevel@tonic-gate size_t namlen; 1024*7c478bd9Sstevel@tonic-gate int rv; 1025*7c478bd9Sstevel@tonic-gate 1026*7c478bd9Sstevel@tonic-gate eg = zone_getspecific(evch_zone_key, curproc->p_zone); 1027*7c478bd9Sstevel@tonic-gate ASSERT(eg != NULL); 1028*7c478bd9Sstevel@tonic-gate 1029*7c478bd9Sstevel@tonic-gate /* Create channel if it does not exist */ 1030*7c478bd9Sstevel@tonic-gate ASSERT(evch_dl_is_init(&eg->evch_list)); 1031*7c478bd9Sstevel@tonic-gate if ((namlen = strlen(chnam) + 1) > MAX_CHNAME_LEN) { 1032*7c478bd9Sstevel@tonic-gate return (EINVAL); 1033*7c478bd9Sstevel@tonic-gate } 1034*7c478bd9Sstevel@tonic-gate mutex_enter(&eg->evch_list_lock); 1035*7c478bd9Sstevel@tonic-gate if ((p = (evch_chan_t *)evch_dl_search(&eg->evch_list, evch_namecmp, 1036*7c478bd9Sstevel@tonic-gate (char *)chnam)) == NULL) { 1037*7c478bd9Sstevel@tonic-gate if (flags & EVCH_CREAT) { 1038*7c478bd9Sstevel@tonic-gate if (evch_dl_getnum(&eg->evch_list) >= 1039*7c478bd9Sstevel@tonic-gate evch_channels_max) { 1040*7c478bd9Sstevel@tonic-gate mutex_exit(&eg->evch_list_lock); 1041*7c478bd9Sstevel@tonic-gate return (ENOMEM); 1042*7c478bd9Sstevel@tonic-gate } 1043*7c478bd9Sstevel@tonic-gate chn = kmem_alloc(namlen, KM_SLEEP); 1044*7c478bd9Sstevel@tonic-gate bcopy(chnam, chn, namlen); 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate /* Allocate and initialize channel descriptor */ 1047*7c478bd9Sstevel@tonic-gate p = kmem_zalloc(sizeof (evch_chan_t), KM_SLEEP); 1048*7c478bd9Sstevel@tonic-gate p->ch_name = chn; 1049*7c478bd9Sstevel@tonic-gate p->ch_namelen = namlen; 1050*7c478bd9Sstevel@tonic-gate mutex_init(&p->ch_mutex, NULL, MUTEX_DEFAULT, NULL); 1051*7c478bd9Sstevel@tonic-gate p->ch_queue = evch_evq_create(); 1052*7c478bd9Sstevel@tonic-gate evch_dl_init(&p->ch_subscr); 1053*7c478bd9Sstevel@tonic-gate if (evq_initcomplete) { 1054*7c478bd9Sstevel@tonic-gate p->ch_uid = crgetuid(curthread->t_cred); 1055*7c478bd9Sstevel@tonic-gate p->ch_gid = crgetgid(curthread->t_cred); 1056*7c478bd9Sstevel@tonic-gate } 1057*7c478bd9Sstevel@tonic-gate cv_init(&p->ch_pubcv, NULL, CV_DEFAULT, NULL); 1058*7c478bd9Sstevel@tonic-gate mutex_init(&p->ch_pubmx, NULL, MUTEX_DEFAULT, NULL); 1059*7c478bd9Sstevel@tonic-gate p->ch_maxev = min(EVCH_DEFAULT_EVENTS, evch_events_max); 1060*7c478bd9Sstevel@tonic-gate p->ch_maxsubscr = EVCH_MAX_SUBSCRIPTIONS; 1061*7c478bd9Sstevel@tonic-gate p->ch_maxbinds = evch_bindings_max; 1062*7c478bd9Sstevel@tonic-gate p->ch_ctime = gethrestime_sec(); 1063*7c478bd9Sstevel@tonic-gate if (flags & EVCH_HOLD_PEND) { 1064*7c478bd9Sstevel@tonic-gate p->ch_holdpend = 1; 1065*7c478bd9Sstevel@tonic-gate evch_evq_stop(p->ch_queue); 1066*7c478bd9Sstevel@tonic-gate } 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate /* Put new descriptor into channel list */ 1069*7c478bd9Sstevel@tonic-gate evch_dl_add(&eg->evch_list, (evch_dlelem_t *)p); 1070*7c478bd9Sstevel@tonic-gate } else { 1071*7c478bd9Sstevel@tonic-gate mutex_exit(&eg->evch_list_lock); 1072*7c478bd9Sstevel@tonic-gate return (ENOENT); 1073*7c478bd9Sstevel@tonic-gate } 1074*7c478bd9Sstevel@tonic-gate } 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate /* Check for max binds and create binding */ 1077*7c478bd9Sstevel@tonic-gate mutex_enter(&p->ch_mutex); 1078*7c478bd9Sstevel@tonic-gate if (p->ch_bindings >= p->ch_maxbinds) { 1079*7c478bd9Sstevel@tonic-gate rv = ENOMEM; 1080*7c478bd9Sstevel@tonic-gate /* 1081*7c478bd9Sstevel@tonic-gate * No need to destroy the channel because this call did not 1082*7c478bd9Sstevel@tonic-gate * create it. Other bindings will be present if ch_maxbinds 1083*7c478bd9Sstevel@tonic-gate * is exceeded. 1084*7c478bd9Sstevel@tonic-gate */ 1085*7c478bd9Sstevel@tonic-gate goto errorexit; 1086*7c478bd9Sstevel@tonic-gate } 1087*7c478bd9Sstevel@tonic-gate bp = kmem_alloc(sizeof (evch_bind_t), KM_SLEEP); 1088*7c478bd9Sstevel@tonic-gate bp->bd_channel = p; 1089*7c478bd9Sstevel@tonic-gate bp->bd_sublst = NULL; 1090*7c478bd9Sstevel@tonic-gate p->ch_bindings++; 1091*7c478bd9Sstevel@tonic-gate rv = 0; 1092*7c478bd9Sstevel@tonic-gate *scpp = bp; 1093*7c478bd9Sstevel@tonic-gate errorexit: 1094*7c478bd9Sstevel@tonic-gate mutex_exit(&p->ch_mutex); 1095*7c478bd9Sstevel@tonic-gate mutex_exit(&eg->evch_list_lock); 1096*7c478bd9Sstevel@tonic-gate return (rv); 1097*7c478bd9Sstevel@tonic-gate } 1098*7c478bd9Sstevel@tonic-gate 1099*7c478bd9Sstevel@tonic-gate /* 1100*7c478bd9Sstevel@tonic-gate * Unbind: Free bind structure. Remove channel if last binding was freed. 1101*7c478bd9Sstevel@tonic-gate */ 1102*7c478bd9Sstevel@tonic-gate static void 1103*7c478bd9Sstevel@tonic-gate evch_chunbind(evch_bind_t *bp) 1104*7c478bd9Sstevel@tonic-gate { 1105*7c478bd9Sstevel@tonic-gate struct evch_globals *eg; 1106*7c478bd9Sstevel@tonic-gate evch_chan_t *chp = bp->bd_channel; 1107*7c478bd9Sstevel@tonic-gate 1108*7c478bd9Sstevel@tonic-gate eg = zone_getspecific(evch_zone_key, curproc->p_zone); 1109*7c478bd9Sstevel@tonic-gate ASSERT(eg != NULL); 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate mutex_enter(&eg->evch_list_lock); 1112*7c478bd9Sstevel@tonic-gate mutex_enter(&chp->ch_mutex); 1113*7c478bd9Sstevel@tonic-gate ASSERT(chp->ch_bindings > 0); 1114*7c478bd9Sstevel@tonic-gate chp->ch_bindings--; 1115*7c478bd9Sstevel@tonic-gate kmem_free(bp, sizeof (evch_bind_t)); 1116*7c478bd9Sstevel@tonic-gate if (chp->ch_bindings == 0 && evch_dl_getnum(&chp->ch_subscr) == 0) { 1117*7c478bd9Sstevel@tonic-gate /* 1118*7c478bd9Sstevel@tonic-gate * No more bindings or persistent subscriber, destroy channel. 1119*7c478bd9Sstevel@tonic-gate */ 1120*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_mutex); 1121*7c478bd9Sstevel@tonic-gate evch_dl_del(&eg->evch_list, &chp->ch_link); 1122*7c478bd9Sstevel@tonic-gate evch_evq_destroy(chp->ch_queue); 1123*7c478bd9Sstevel@tonic-gate mutex_destroy(&chp->ch_mutex); 1124*7c478bd9Sstevel@tonic-gate mutex_destroy(&chp->ch_pubmx); 1125*7c478bd9Sstevel@tonic-gate cv_destroy(&chp->ch_pubcv); 1126*7c478bd9Sstevel@tonic-gate kmem_free(chp->ch_name, chp->ch_namelen); 1127*7c478bd9Sstevel@tonic-gate kmem_free(chp, sizeof (evch_chan_t)); 1128*7c478bd9Sstevel@tonic-gate } else 1129*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_mutex); 1130*7c478bd9Sstevel@tonic-gate mutex_exit(&eg->evch_list_lock); 1131*7c478bd9Sstevel@tonic-gate } 1132*7c478bd9Sstevel@tonic-gate 1133*7c478bd9Sstevel@tonic-gate /* 1134*7c478bd9Sstevel@tonic-gate * Subscribe to a channel. dtype is either EVCH_DELKERN for kernel callbacks 1135*7c478bd9Sstevel@tonic-gate * or EVCH_DELDOOR for door upcall delivery to user land. Depending on dtype 1136*7c478bd9Sstevel@tonic-gate * dinfo gives the call back routine address or the door handle. 1137*7c478bd9Sstevel@tonic-gate */ 1138*7c478bd9Sstevel@tonic-gate static int 1139*7c478bd9Sstevel@tonic-gate evch_chsubscribe(evch_bind_t *bp, int dtype, const char *sid, const char *class, 1140*7c478bd9Sstevel@tonic-gate void *dinfo, void *cookie, int flags, pid_t pid) 1141*7c478bd9Sstevel@tonic-gate { 1142*7c478bd9Sstevel@tonic-gate evch_chan_t *chp = bp->bd_channel; 1143*7c478bd9Sstevel@tonic-gate evch_eventq_t *eqp = chp->ch_queue; 1144*7c478bd9Sstevel@tonic-gate evch_subd_t *sdp; 1145*7c478bd9Sstevel@tonic-gate evch_subd_t *esp; 1146*7c478bd9Sstevel@tonic-gate int (*delivfkt)(); 1147*7c478bd9Sstevel@tonic-gate char *clb = NULL; 1148*7c478bd9Sstevel@tonic-gate int clblen = 0; 1149*7c478bd9Sstevel@tonic-gate char *subid; 1150*7c478bd9Sstevel@tonic-gate int subidblen; 1151*7c478bd9Sstevel@tonic-gate 1152*7c478bd9Sstevel@tonic-gate /* 1153*7c478bd9Sstevel@tonic-gate * Check if only known flags are set. 1154*7c478bd9Sstevel@tonic-gate */ 1155*7c478bd9Sstevel@tonic-gate if (flags & ~(EVCH_SUB_KEEP | EVCH_SUB_DUMP)) 1156*7c478bd9Sstevel@tonic-gate return (EINVAL); 1157*7c478bd9Sstevel@tonic-gate /* 1158*7c478bd9Sstevel@tonic-gate * Check if we have already a subscription with that name and if we 1159*7c478bd9Sstevel@tonic-gate * have to reconnect the subscriber to a persistent subscription. 1160*7c478bd9Sstevel@tonic-gate */ 1161*7c478bd9Sstevel@tonic-gate mutex_enter(&chp->ch_mutex); 1162*7c478bd9Sstevel@tonic-gate if ((esp = (evch_subd_t *)evch_dl_search(&chp->ch_subscr, 1163*7c478bd9Sstevel@tonic-gate evch_subidcmp, (char *)sid)) != NULL) { 1164*7c478bd9Sstevel@tonic-gate int error = 0; 1165*7c478bd9Sstevel@tonic-gate if ((flags & EVCH_SUB_KEEP) && (esp->sd_active == 0)) { 1166*7c478bd9Sstevel@tonic-gate /* 1167*7c478bd9Sstevel@tonic-gate * Subscription with the name on hold, reconnect to 1168*7c478bd9Sstevel@tonic-gate * existing queue. 1169*7c478bd9Sstevel@tonic-gate */ 1170*7c478bd9Sstevel@tonic-gate ASSERT(dtype == EVCH_DELDOOR); 1171*7c478bd9Sstevel@tonic-gate esp->sd_subnxt = bp->bd_sublst; 1172*7c478bd9Sstevel@tonic-gate bp->bd_sublst = esp; 1173*7c478bd9Sstevel@tonic-gate esp->sd_pid = pid; 1174*7c478bd9Sstevel@tonic-gate esp->sd_door = (door_handle_t)dinfo; 1175*7c478bd9Sstevel@tonic-gate esp->sd_active++; 1176*7c478bd9Sstevel@tonic-gate evch_evq_continue(esp->sd_queue); 1177*7c478bd9Sstevel@tonic-gate } else { 1178*7c478bd9Sstevel@tonic-gate /* Subscriber with given name already exists */ 1179*7c478bd9Sstevel@tonic-gate error = EEXIST; 1180*7c478bd9Sstevel@tonic-gate } 1181*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_mutex); 1182*7c478bd9Sstevel@tonic-gate return (error); 1183*7c478bd9Sstevel@tonic-gate } 1184*7c478bd9Sstevel@tonic-gate 1185*7c478bd9Sstevel@tonic-gate if (evch_dl_getnum(&chp->ch_subscr) >= chp->ch_maxsubscr) { 1186*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_mutex); 1187*7c478bd9Sstevel@tonic-gate return (ENOMEM); 1188*7c478bd9Sstevel@tonic-gate } 1189*7c478bd9Sstevel@tonic-gate 1190*7c478bd9Sstevel@tonic-gate if (flags & EVCH_SUB_DUMP && evch_dl_search(&chp->ch_subscr, 1191*7c478bd9Sstevel@tonic-gate evch_dumpflgcmp, NULL) != NULL) { 1192*7c478bd9Sstevel@tonic-gate /* 1193*7c478bd9Sstevel@tonic-gate * Subscription with EVCH_SUB_DUMP flagged already exists. 1194*7c478bd9Sstevel@tonic-gate * Only one subscription with EVCH_SUB_DUMP possible. Return 1195*7c478bd9Sstevel@tonic-gate * error. 1196*7c478bd9Sstevel@tonic-gate */ 1197*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_mutex); 1198*7c478bd9Sstevel@tonic-gate return (EINVAL); 1199*7c478bd9Sstevel@tonic-gate } 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate if (class != NULL) { 1202*7c478bd9Sstevel@tonic-gate clblen = strlen(class) + 1; 1203*7c478bd9Sstevel@tonic-gate clb = kmem_alloc(clblen, KM_SLEEP); 1204*7c478bd9Sstevel@tonic-gate bcopy(class, clb, clblen); 1205*7c478bd9Sstevel@tonic-gate } 1206*7c478bd9Sstevel@tonic-gate 1207*7c478bd9Sstevel@tonic-gate subidblen = strlen(sid) + 1; 1208*7c478bd9Sstevel@tonic-gate subid = kmem_alloc(subidblen, KM_SLEEP); 1209*7c478bd9Sstevel@tonic-gate bcopy(sid, subid, subidblen); 1210*7c478bd9Sstevel@tonic-gate 1211*7c478bd9Sstevel@tonic-gate /* Create per subscriber queue */ 1212*7c478bd9Sstevel@tonic-gate sdp = kmem_zalloc(sizeof (evch_subd_t), KM_SLEEP); 1213*7c478bd9Sstevel@tonic-gate sdp->sd_queue = evch_evq_create(); 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate /* Subscribe to subscriber queue */ 1216*7c478bd9Sstevel@tonic-gate sdp->sd_persist = flags & EVCH_SUB_KEEP ? 1 : 0; 1217*7c478bd9Sstevel@tonic-gate sdp->sd_dump = flags & EVCH_SUB_DUMP ? 1 : 0; 1218*7c478bd9Sstevel@tonic-gate sdp->sd_type = dtype; 1219*7c478bd9Sstevel@tonic-gate sdp->sd_cbcookie = cookie; 1220*7c478bd9Sstevel@tonic-gate sdp->sd_ident = subid; 1221*7c478bd9Sstevel@tonic-gate if (dtype == EVCH_DELKERN) { 1222*7c478bd9Sstevel@tonic-gate sdp->sd_callback = (kerndlv_f)dinfo; 1223*7c478bd9Sstevel@tonic-gate delivfkt = evch_kern_deliver; 1224*7c478bd9Sstevel@tonic-gate } else { 1225*7c478bd9Sstevel@tonic-gate sdp->sd_door = (door_handle_t)dinfo; 1226*7c478bd9Sstevel@tonic-gate delivfkt = evch_door_deliver; 1227*7c478bd9Sstevel@tonic-gate } 1228*7c478bd9Sstevel@tonic-gate sdp->sd_ssub = 1229*7c478bd9Sstevel@tonic-gate evch_evq_sub(sdp->sd_queue, NULL, NULL, delivfkt, (void *)sdp); 1230*7c478bd9Sstevel@tonic-gate 1231*7c478bd9Sstevel@tonic-gate /* Connect per subscriber queue to main event queue */ 1232*7c478bd9Sstevel@tonic-gate sdp->sd_msub = evch_evq_sub(eqp, evch_class_filter, clb, 1233*7c478bd9Sstevel@tonic-gate evch_subq_deliver, (void *)sdp); 1234*7c478bd9Sstevel@tonic-gate sdp->sd_classname = clb; 1235*7c478bd9Sstevel@tonic-gate sdp->sd_clnsize = clblen; 1236*7c478bd9Sstevel@tonic-gate sdp->sd_pid = pid; 1237*7c478bd9Sstevel@tonic-gate sdp->sd_active++; 1238*7c478bd9Sstevel@tonic-gate 1239*7c478bd9Sstevel@tonic-gate /* Add subscription to binding */ 1240*7c478bd9Sstevel@tonic-gate sdp->sd_subnxt = bp->bd_sublst; 1241*7c478bd9Sstevel@tonic-gate bp->bd_sublst = sdp; 1242*7c478bd9Sstevel@tonic-gate 1243*7c478bd9Sstevel@tonic-gate /* Add subscription to channel */ 1244*7c478bd9Sstevel@tonic-gate evch_dl_add(&chp->ch_subscr, &sdp->sd_link); 1245*7c478bd9Sstevel@tonic-gate if (chp->ch_holdpend && evch_dl_getnum(&chp->ch_subscr) == 1) { 1246*7c478bd9Sstevel@tonic-gate 1247*7c478bd9Sstevel@tonic-gate /* Let main event queue run in case of HOLDPEND */ 1248*7c478bd9Sstevel@tonic-gate evch_evq_continue(eqp); 1249*7c478bd9Sstevel@tonic-gate } 1250*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_mutex); 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate return (0); 1253*7c478bd9Sstevel@tonic-gate } 1254*7c478bd9Sstevel@tonic-gate 1255*7c478bd9Sstevel@tonic-gate /* 1256*7c478bd9Sstevel@tonic-gate * If flag == EVCH_SUB_KEEP only non-persistent subscriptions are deleted. 1257*7c478bd9Sstevel@tonic-gate * When sid == NULL all subscriptions except the ones with EVCH_SUB_KEEP set 1258*7c478bd9Sstevel@tonic-gate * are removed. 1259*7c478bd9Sstevel@tonic-gate */ 1260*7c478bd9Sstevel@tonic-gate static void 1261*7c478bd9Sstevel@tonic-gate evch_chunsubscribe(evch_bind_t *bp, const char *sid, uint32_t flags) 1262*7c478bd9Sstevel@tonic-gate { 1263*7c478bd9Sstevel@tonic-gate evch_subd_t *sdp; 1264*7c478bd9Sstevel@tonic-gate evch_subd_t *next; 1265*7c478bd9Sstevel@tonic-gate evch_subd_t *prev; 1266*7c478bd9Sstevel@tonic-gate evch_chan_t *chp = bp->bd_channel; 1267*7c478bd9Sstevel@tonic-gate 1268*7c478bd9Sstevel@tonic-gate mutex_enter(&chp->ch_mutex); 1269*7c478bd9Sstevel@tonic-gate if (chp->ch_holdpend) { 1270*7c478bd9Sstevel@tonic-gate evch_evq_stop(chp->ch_queue); /* Hold main event queue */ 1271*7c478bd9Sstevel@tonic-gate } 1272*7c478bd9Sstevel@tonic-gate prev = NULL; 1273*7c478bd9Sstevel@tonic-gate for (sdp = bp->bd_sublst; sdp; sdp = next) { 1274*7c478bd9Sstevel@tonic-gate if (sid == NULL || strcmp(sid, sdp->sd_ident) == 0) { 1275*7c478bd9Sstevel@tonic-gate if (flags == 0 || sdp->sd_persist == 0) { 1276*7c478bd9Sstevel@tonic-gate /* 1277*7c478bd9Sstevel@tonic-gate * Disconnect subscriber queue from main event 1278*7c478bd9Sstevel@tonic-gate * queue. 1279*7c478bd9Sstevel@tonic-gate */ 1280*7c478bd9Sstevel@tonic-gate evch_evq_unsub(chp->ch_queue, sdp->sd_msub); 1281*7c478bd9Sstevel@tonic-gate 1282*7c478bd9Sstevel@tonic-gate /* Destruct per subscriber queue */ 1283*7c478bd9Sstevel@tonic-gate evch_evq_unsub(sdp->sd_queue, sdp->sd_ssub); 1284*7c478bd9Sstevel@tonic-gate evch_evq_destroy(sdp->sd_queue); 1285*7c478bd9Sstevel@tonic-gate /* 1286*7c478bd9Sstevel@tonic-gate * Eliminate the subscriber data from channel 1287*7c478bd9Sstevel@tonic-gate * list. 1288*7c478bd9Sstevel@tonic-gate */ 1289*7c478bd9Sstevel@tonic-gate evch_dl_del(&chp->ch_subscr, &sdp->sd_link); 1290*7c478bd9Sstevel@tonic-gate kmem_free(sdp->sd_classname, sdp->sd_clnsize); 1291*7c478bd9Sstevel@tonic-gate if (sdp->sd_type == EVCH_DELDOOR) { 1292*7c478bd9Sstevel@tonic-gate door_ki_rele(sdp->sd_door); 1293*7c478bd9Sstevel@tonic-gate } 1294*7c478bd9Sstevel@tonic-gate next = sdp->sd_subnxt; 1295*7c478bd9Sstevel@tonic-gate if (prev) { 1296*7c478bd9Sstevel@tonic-gate prev->sd_subnxt = next; 1297*7c478bd9Sstevel@tonic-gate } else { 1298*7c478bd9Sstevel@tonic-gate bp->bd_sublst = next; 1299*7c478bd9Sstevel@tonic-gate } 1300*7c478bd9Sstevel@tonic-gate kmem_free(sdp->sd_ident, 1301*7c478bd9Sstevel@tonic-gate strlen(sdp->sd_ident) + 1); 1302*7c478bd9Sstevel@tonic-gate kmem_free(sdp, sizeof (evch_subd_t)); 1303*7c478bd9Sstevel@tonic-gate } else { 1304*7c478bd9Sstevel@tonic-gate /* 1305*7c478bd9Sstevel@tonic-gate * EVCH_SUB_KEEP case 1306*7c478bd9Sstevel@tonic-gate */ 1307*7c478bd9Sstevel@tonic-gate evch_evq_stop(sdp->sd_queue); 1308*7c478bd9Sstevel@tonic-gate if (sdp->sd_type == EVCH_DELDOOR) { 1309*7c478bd9Sstevel@tonic-gate door_ki_rele(sdp->sd_door); 1310*7c478bd9Sstevel@tonic-gate } 1311*7c478bd9Sstevel@tonic-gate sdp->sd_active--; 1312*7c478bd9Sstevel@tonic-gate ASSERT(sdp->sd_active == 0); 1313*7c478bd9Sstevel@tonic-gate next = sdp->sd_subnxt; 1314*7c478bd9Sstevel@tonic-gate prev = sdp; 1315*7c478bd9Sstevel@tonic-gate } 1316*7c478bd9Sstevel@tonic-gate if (sid != NULL) { 1317*7c478bd9Sstevel@tonic-gate break; 1318*7c478bd9Sstevel@tonic-gate } 1319*7c478bd9Sstevel@tonic-gate } else { 1320*7c478bd9Sstevel@tonic-gate next = sdp->sd_subnxt; 1321*7c478bd9Sstevel@tonic-gate prev = sdp; 1322*7c478bd9Sstevel@tonic-gate } 1323*7c478bd9Sstevel@tonic-gate } 1324*7c478bd9Sstevel@tonic-gate if (!(chp->ch_holdpend && evch_dl_getnum(&chp->ch_subscr) == 0)) { 1325*7c478bd9Sstevel@tonic-gate /* 1326*7c478bd9Sstevel@tonic-gate * Continue dispatch thread except if no subscribers are present 1327*7c478bd9Sstevel@tonic-gate * in HOLDPEND mode. 1328*7c478bd9Sstevel@tonic-gate */ 1329*7c478bd9Sstevel@tonic-gate evch_evq_continue(chp->ch_queue); 1330*7c478bd9Sstevel@tonic-gate } 1331*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_mutex); 1332*7c478bd9Sstevel@tonic-gate } 1333*7c478bd9Sstevel@tonic-gate 1334*7c478bd9Sstevel@tonic-gate /* 1335*7c478bd9Sstevel@tonic-gate * Publish an event. Returns zero on success and an error code else. 1336*7c478bd9Sstevel@tonic-gate */ 1337*7c478bd9Sstevel@tonic-gate static int 1338*7c478bd9Sstevel@tonic-gate evch_chpublish(evch_bind_t *bp, sysevent_impl_t *ev, int flags) 1339*7c478bd9Sstevel@tonic-gate { 1340*7c478bd9Sstevel@tonic-gate evch_chan_t *chp = bp->bd_channel; 1341*7c478bd9Sstevel@tonic-gate 1342*7c478bd9Sstevel@tonic-gate mutex_enter(&chp->ch_pubmx); 1343*7c478bd9Sstevel@tonic-gate if (chp->ch_nevents >= chp->ch_maxev) { 1344*7c478bd9Sstevel@tonic-gate if (!(flags & EVCH_QWAIT)) { 1345*7c478bd9Sstevel@tonic-gate evch_evq_evfree(ev); 1346*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_pubmx); 1347*7c478bd9Sstevel@tonic-gate return (EAGAIN); 1348*7c478bd9Sstevel@tonic-gate } else { 1349*7c478bd9Sstevel@tonic-gate while (chp->ch_nevents >= chp->ch_maxev) { 1350*7c478bd9Sstevel@tonic-gate if (cv_wait_sig(&chp->ch_pubcv, 1351*7c478bd9Sstevel@tonic-gate &chp->ch_pubmx) == 0) { 1352*7c478bd9Sstevel@tonic-gate 1353*7c478bd9Sstevel@tonic-gate /* Got Signal, return EINTR */ 1354*7c478bd9Sstevel@tonic-gate evch_evq_evfree(ev); 1355*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_pubmx); 1356*7c478bd9Sstevel@tonic-gate return (EINTR); 1357*7c478bd9Sstevel@tonic-gate } 1358*7c478bd9Sstevel@tonic-gate } 1359*7c478bd9Sstevel@tonic-gate } 1360*7c478bd9Sstevel@tonic-gate } 1361*7c478bd9Sstevel@tonic-gate chp->ch_nevents++; 1362*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_pubmx); 1363*7c478bd9Sstevel@tonic-gate SE_TIME(ev) = gethrtime(); 1364*7c478bd9Sstevel@tonic-gate SE_SEQ(ev) = log_sysevent_new_id(); 1365*7c478bd9Sstevel@tonic-gate /* 1366*7c478bd9Sstevel@tonic-gate * Add the destructor function to the event structure, now that the 1367*7c478bd9Sstevel@tonic-gate * event is accounted for. The only task of the descructor is to 1368*7c478bd9Sstevel@tonic-gate * decrement the channel event count. The evq_*() routines (including 1369*7c478bd9Sstevel@tonic-gate * the event delivery thread) do not have knowledge of the channel 1370*7c478bd9Sstevel@tonic-gate * data. So the anonymous destructor handles the channel data for it. 1371*7c478bd9Sstevel@tonic-gate */ 1372*7c478bd9Sstevel@tonic-gate evch_evq_evadd_dest(ev, evch_destr_event, (void *)chp); 1373*7c478bd9Sstevel@tonic-gate return (evch_evq_pub(chp->ch_queue, ev, flags) == 0 ? 0 : EAGAIN); 1374*7c478bd9Sstevel@tonic-gate } 1375*7c478bd9Sstevel@tonic-gate 1376*7c478bd9Sstevel@tonic-gate /* 1377*7c478bd9Sstevel@tonic-gate * Fills a buffer consecutive with the names of all available channels. 1378*7c478bd9Sstevel@tonic-gate * Returns the length of all name strings or -1 if buffer size was unsufficient. 1379*7c478bd9Sstevel@tonic-gate */ 1380*7c478bd9Sstevel@tonic-gate static int 1381*7c478bd9Sstevel@tonic-gate evch_chgetnames(char *buf, size_t size) 1382*7c478bd9Sstevel@tonic-gate { 1383*7c478bd9Sstevel@tonic-gate struct evch_globals *eg; 1384*7c478bd9Sstevel@tonic-gate int len = 0; 1385*7c478bd9Sstevel@tonic-gate char *addr = buf; 1386*7c478bd9Sstevel@tonic-gate int max = size; 1387*7c478bd9Sstevel@tonic-gate evch_chan_t *chp; 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate eg = zone_getspecific(evch_zone_key, curproc->p_zone); 1390*7c478bd9Sstevel@tonic-gate ASSERT(eg != NULL); 1391*7c478bd9Sstevel@tonic-gate 1392*7c478bd9Sstevel@tonic-gate mutex_enter(&eg->evch_list_lock); 1393*7c478bd9Sstevel@tonic-gate for (chp = evch_dl_next(&eg->evch_list, NULL); chp != NULL; 1394*7c478bd9Sstevel@tonic-gate chp = evch_dl_next(&eg->evch_list, chp)) { 1395*7c478bd9Sstevel@tonic-gate len += chp->ch_namelen; 1396*7c478bd9Sstevel@tonic-gate if (len >= max) { 1397*7c478bd9Sstevel@tonic-gate mutex_exit(&eg->evch_list_lock); 1398*7c478bd9Sstevel@tonic-gate return (-1); 1399*7c478bd9Sstevel@tonic-gate } 1400*7c478bd9Sstevel@tonic-gate bcopy(chp->ch_name, addr, chp->ch_namelen); 1401*7c478bd9Sstevel@tonic-gate addr += chp->ch_namelen; 1402*7c478bd9Sstevel@tonic-gate } 1403*7c478bd9Sstevel@tonic-gate mutex_exit(&eg->evch_list_lock); 1404*7c478bd9Sstevel@tonic-gate addr[0] = 0; 1405*7c478bd9Sstevel@tonic-gate return (len + 1); 1406*7c478bd9Sstevel@tonic-gate } 1407*7c478bd9Sstevel@tonic-gate 1408*7c478bd9Sstevel@tonic-gate /* 1409*7c478bd9Sstevel@tonic-gate * Fills the data of one channel and all subscribers of that channel into 1410*7c478bd9Sstevel@tonic-gate * a buffer. Returns -1 if the channel name is invalid and 0 on buffer overflow. 1411*7c478bd9Sstevel@tonic-gate */ 1412*7c478bd9Sstevel@tonic-gate static int 1413*7c478bd9Sstevel@tonic-gate evch_chgetchdata(char *chname, void *buf, size_t size) 1414*7c478bd9Sstevel@tonic-gate { 1415*7c478bd9Sstevel@tonic-gate struct evch_globals *eg; 1416*7c478bd9Sstevel@tonic-gate char *cpaddr; 1417*7c478bd9Sstevel@tonic-gate int bufmax; 1418*7c478bd9Sstevel@tonic-gate int buflen; 1419*7c478bd9Sstevel@tonic-gate evch_chan_t *chp; 1420*7c478bd9Sstevel@tonic-gate sev_chinfo_t *p = (sev_chinfo_t *)buf; 1421*7c478bd9Sstevel@tonic-gate int chdlen; 1422*7c478bd9Sstevel@tonic-gate evch_subd_t *sdp; 1423*7c478bd9Sstevel@tonic-gate sev_subinfo_t *subp; 1424*7c478bd9Sstevel@tonic-gate int idlen; 1425*7c478bd9Sstevel@tonic-gate int len; 1426*7c478bd9Sstevel@tonic-gate 1427*7c478bd9Sstevel@tonic-gate eg = zone_getspecific(evch_zone_key, curproc->p_zone); 1428*7c478bd9Sstevel@tonic-gate ASSERT(eg != NULL); 1429*7c478bd9Sstevel@tonic-gate 1430*7c478bd9Sstevel@tonic-gate mutex_enter(&eg->evch_list_lock); 1431*7c478bd9Sstevel@tonic-gate chp = (evch_chan_t *)evch_dl_search(&eg->evch_list, evch_namecmp, 1432*7c478bd9Sstevel@tonic-gate chname); 1433*7c478bd9Sstevel@tonic-gate if (chp == NULL) { 1434*7c478bd9Sstevel@tonic-gate mutex_exit(&eg->evch_list_lock); 1435*7c478bd9Sstevel@tonic-gate return (-1); 1436*7c478bd9Sstevel@tonic-gate } 1437*7c478bd9Sstevel@tonic-gate chdlen = offsetof(sev_chinfo_t, cd_subinfo); 1438*7c478bd9Sstevel@tonic-gate if (size < chdlen) { 1439*7c478bd9Sstevel@tonic-gate mutex_exit(&eg->evch_list_lock); 1440*7c478bd9Sstevel@tonic-gate return (0); 1441*7c478bd9Sstevel@tonic-gate } 1442*7c478bd9Sstevel@tonic-gate p->cd_version = 0; 1443*7c478bd9Sstevel@tonic-gate p->cd_suboffs = chdlen; 1444*7c478bd9Sstevel@tonic-gate p->cd_uid = chp->ch_uid; 1445*7c478bd9Sstevel@tonic-gate p->cd_gid = chp->ch_gid; 1446*7c478bd9Sstevel@tonic-gate p->cd_perms = 0; 1447*7c478bd9Sstevel@tonic-gate p->cd_ctime = chp->ch_ctime; 1448*7c478bd9Sstevel@tonic-gate p->cd_maxev = chp->ch_maxev; 1449*7c478bd9Sstevel@tonic-gate p->cd_evhwm = EVCH_EVQ_HIGHWM(chp->ch_queue); 1450*7c478bd9Sstevel@tonic-gate p->cd_nevents = EVCH_EVQ_EVCOUNT(chp->ch_queue); 1451*7c478bd9Sstevel@tonic-gate p->cd_maxsub = chp->ch_maxsubscr; 1452*7c478bd9Sstevel@tonic-gate p->cd_nsub = evch_dl_getnum(&chp->ch_subscr); 1453*7c478bd9Sstevel@tonic-gate p->cd_maxbinds = chp->ch_maxbinds; 1454*7c478bd9Sstevel@tonic-gate p->cd_nbinds = chp->ch_bindings; 1455*7c478bd9Sstevel@tonic-gate p->cd_holdpend = chp->ch_holdpend; 1456*7c478bd9Sstevel@tonic-gate p->cd_limev = evch_events_max; 1457*7c478bd9Sstevel@tonic-gate cpaddr = (char *)p + chdlen; 1458*7c478bd9Sstevel@tonic-gate bufmax = size - chdlen; 1459*7c478bd9Sstevel@tonic-gate buflen = 0; 1460*7c478bd9Sstevel@tonic-gate 1461*7c478bd9Sstevel@tonic-gate for (sdp = evch_dl_next(&chp->ch_subscr, NULL); sdp != NULL; 1462*7c478bd9Sstevel@tonic-gate sdp = evch_dl_next(&chp->ch_subscr, sdp)) { 1463*7c478bd9Sstevel@tonic-gate idlen = strlen(sdp->sd_ident) + 1; 1464*7c478bd9Sstevel@tonic-gate len = SE_ALIGN(offsetof(sev_subinfo_t, sb_strings) + idlen + 1465*7c478bd9Sstevel@tonic-gate sdp->sd_clnsize); 1466*7c478bd9Sstevel@tonic-gate buflen += len; 1467*7c478bd9Sstevel@tonic-gate if (buflen >= bufmax) { 1468*7c478bd9Sstevel@tonic-gate mutex_exit(&eg->evch_list_lock); 1469*7c478bd9Sstevel@tonic-gate return (0); 1470*7c478bd9Sstevel@tonic-gate } 1471*7c478bd9Sstevel@tonic-gate subp = (sev_subinfo_t *)cpaddr; 1472*7c478bd9Sstevel@tonic-gate subp->sb_nextoff = len; 1473*7c478bd9Sstevel@tonic-gate subp->sb_stroff = offsetof(sev_subinfo_t, sb_strings); 1474*7c478bd9Sstevel@tonic-gate if (sdp->sd_classname) { 1475*7c478bd9Sstevel@tonic-gate bcopy(sdp->sd_classname, subp->sb_strings + idlen, 1476*7c478bd9Sstevel@tonic-gate sdp->sd_clnsize); 1477*7c478bd9Sstevel@tonic-gate subp->sb_clnamoff = idlen; 1478*7c478bd9Sstevel@tonic-gate } else { 1479*7c478bd9Sstevel@tonic-gate subp->sb_clnamoff = idlen - 1; 1480*7c478bd9Sstevel@tonic-gate } 1481*7c478bd9Sstevel@tonic-gate subp->sb_pid = sdp->sd_pid; 1482*7c478bd9Sstevel@tonic-gate subp->sb_nevents = EVCH_EVQ_EVCOUNT(sdp->sd_queue); 1483*7c478bd9Sstevel@tonic-gate subp->sb_evhwm = EVCH_EVQ_HIGHWM(sdp->sd_queue); 1484*7c478bd9Sstevel@tonic-gate subp->sb_persist = sdp->sd_persist; 1485*7c478bd9Sstevel@tonic-gate subp->sb_status = evch_evq_status(sdp->sd_queue); 1486*7c478bd9Sstevel@tonic-gate subp->sb_active = sdp->sd_active; 1487*7c478bd9Sstevel@tonic-gate subp->sb_dump = sdp->sd_dump; 1488*7c478bd9Sstevel@tonic-gate bcopy(sdp->sd_ident, subp->sb_strings, idlen); 1489*7c478bd9Sstevel@tonic-gate cpaddr += len; 1490*7c478bd9Sstevel@tonic-gate } 1491*7c478bd9Sstevel@tonic-gate mutex_exit(&eg->evch_list_lock); 1492*7c478bd9Sstevel@tonic-gate return (chdlen + buflen); 1493*7c478bd9Sstevel@tonic-gate } 1494*7c478bd9Sstevel@tonic-gate 1495*7c478bd9Sstevel@tonic-gate /* 1496*7c478bd9Sstevel@tonic-gate * Init iteration of all events of a channel. This function creates a new 1497*7c478bd9Sstevel@tonic-gate * event queue and puts all events from the channel into that queue. 1498*7c478bd9Sstevel@tonic-gate * Subsequent calls to evch_chgetnextev will deliver the events from that 1499*7c478bd9Sstevel@tonic-gate * queue. Only one thread per channel is allowed to read through the events. 1500*7c478bd9Sstevel@tonic-gate * Returns 0 on success and 1 if there is already someone reading the 1501*7c478bd9Sstevel@tonic-gate * events. 1502*7c478bd9Sstevel@tonic-gate * If argument subid == NULL, we look for a subscriber which has 1503*7c478bd9Sstevel@tonic-gate * flag EVCH_SUB_DUMP set. 1504*7c478bd9Sstevel@tonic-gate */ 1505*7c478bd9Sstevel@tonic-gate /* 1506*7c478bd9Sstevel@tonic-gate * Static variables that are used to traverse events of a channel in panic case. 1507*7c478bd9Sstevel@tonic-gate */ 1508*7c478bd9Sstevel@tonic-gate static evch_chan_t *evch_chan; 1509*7c478bd9Sstevel@tonic-gate static evch_eventq_t *evch_subq; 1510*7c478bd9Sstevel@tonic-gate static sysevent_impl_t *evch_curev; 1511*7c478bd9Sstevel@tonic-gate 1512*7c478bd9Sstevel@tonic-gate static evchanq_t * 1513*7c478bd9Sstevel@tonic-gate evch_chrdevent_init(evch_chan_t *chp, char *subid) 1514*7c478bd9Sstevel@tonic-gate { 1515*7c478bd9Sstevel@tonic-gate evch_subd_t *sdp; 1516*7c478bd9Sstevel@tonic-gate void *ev; 1517*7c478bd9Sstevel@tonic-gate int pmqstat; /* Prev status of main queue */ 1518*7c478bd9Sstevel@tonic-gate int psqstat; /* Prev status of subscriber queue */ 1519*7c478bd9Sstevel@tonic-gate evchanq_t *snp; /* Pointer to q with snapshot of ev */ 1520*7c478bd9Sstevel@tonic-gate compare_f compfunc; 1521*7c478bd9Sstevel@tonic-gate 1522*7c478bd9Sstevel@tonic-gate compfunc = subid == NULL ? evch_dumpflgcmp : evch_subidcmp; 1523*7c478bd9Sstevel@tonic-gate if (panicstr != NULL) { 1524*7c478bd9Sstevel@tonic-gate evch_chan = chp; 1525*7c478bd9Sstevel@tonic-gate evch_subq = NULL; 1526*7c478bd9Sstevel@tonic-gate evch_curev = NULL; 1527*7c478bd9Sstevel@tonic-gate if ((sdp = (evch_subd_t *)evch_dl_search(&chp->ch_subscr, 1528*7c478bd9Sstevel@tonic-gate compfunc, subid)) != NULL) { 1529*7c478bd9Sstevel@tonic-gate evch_subq = sdp->sd_queue; 1530*7c478bd9Sstevel@tonic-gate } 1531*7c478bd9Sstevel@tonic-gate return (NULL); 1532*7c478bd9Sstevel@tonic-gate } 1533*7c478bd9Sstevel@tonic-gate mutex_enter(&chp->ch_mutex); 1534*7c478bd9Sstevel@tonic-gate sdp = (evch_subd_t *)evch_dl_search(&chp->ch_subscr, compfunc, subid); 1535*7c478bd9Sstevel@tonic-gate /* 1536*7c478bd9Sstevel@tonic-gate * Stop main event queue and subscriber queue if not already 1537*7c478bd9Sstevel@tonic-gate * in stop mode. 1538*7c478bd9Sstevel@tonic-gate */ 1539*7c478bd9Sstevel@tonic-gate pmqstat = evch_evq_status(chp->ch_queue); 1540*7c478bd9Sstevel@tonic-gate if (pmqstat == 0) 1541*7c478bd9Sstevel@tonic-gate evch_evq_stop(chp->ch_queue); 1542*7c478bd9Sstevel@tonic-gate if (sdp != NULL) { 1543*7c478bd9Sstevel@tonic-gate psqstat = evch_evq_status(sdp->sd_queue); 1544*7c478bd9Sstevel@tonic-gate if (psqstat == 0) 1545*7c478bd9Sstevel@tonic-gate evch_evq_stop(sdp->sd_queue); 1546*7c478bd9Sstevel@tonic-gate } 1547*7c478bd9Sstevel@tonic-gate /* 1548*7c478bd9Sstevel@tonic-gate * Create event queue to make a snapshot of all events in the 1549*7c478bd9Sstevel@tonic-gate * channel. 1550*7c478bd9Sstevel@tonic-gate */ 1551*7c478bd9Sstevel@tonic-gate snp = kmem_alloc(sizeof (evchanq_t), KM_SLEEP); 1552*7c478bd9Sstevel@tonic-gate snp->sn_queue = evch_evq_create(); 1553*7c478bd9Sstevel@tonic-gate evch_evq_stop(snp->sn_queue); 1554*7c478bd9Sstevel@tonic-gate /* 1555*7c478bd9Sstevel@tonic-gate * Make a snapshot of the subscriber queue and the main event queue. 1556*7c478bd9Sstevel@tonic-gate */ 1557*7c478bd9Sstevel@tonic-gate if (sdp != NULL) { 1558*7c478bd9Sstevel@tonic-gate ev = NULL; 1559*7c478bd9Sstevel@tonic-gate while ((ev = evch_evq_evnext(sdp->sd_queue, ev)) != NULL) { 1560*7c478bd9Sstevel@tonic-gate (void) evch_evq_pub(snp->sn_queue, ev, EVCH_SLEEP); 1561*7c478bd9Sstevel@tonic-gate } 1562*7c478bd9Sstevel@tonic-gate } 1563*7c478bd9Sstevel@tonic-gate ev = NULL; 1564*7c478bd9Sstevel@tonic-gate while ((ev = evch_evq_evnext(chp->ch_queue, ev)) != NULL) { 1565*7c478bd9Sstevel@tonic-gate (void) evch_evq_pub(snp->sn_queue, ev, EVCH_SLEEP); 1566*7c478bd9Sstevel@tonic-gate } 1567*7c478bd9Sstevel@tonic-gate snp->sn_nxtev = NULL; 1568*7c478bd9Sstevel@tonic-gate /* 1569*7c478bd9Sstevel@tonic-gate * Restart main and subscriber queue if previously stopped 1570*7c478bd9Sstevel@tonic-gate */ 1571*7c478bd9Sstevel@tonic-gate if (sdp != NULL && psqstat == 0) 1572*7c478bd9Sstevel@tonic-gate evch_evq_continue(sdp->sd_queue); 1573*7c478bd9Sstevel@tonic-gate if (pmqstat == 0) 1574*7c478bd9Sstevel@tonic-gate evch_evq_continue(chp->ch_queue); 1575*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_mutex); 1576*7c478bd9Sstevel@tonic-gate return (snp); 1577*7c478bd9Sstevel@tonic-gate } 1578*7c478bd9Sstevel@tonic-gate 1579*7c478bd9Sstevel@tonic-gate /* 1580*7c478bd9Sstevel@tonic-gate * Free all resources of the event queue snapshot. In case of panic 1581*7c478bd9Sstevel@tonic-gate * context snp must be NULL and no resources need to be free'ed. 1582*7c478bd9Sstevel@tonic-gate */ 1583*7c478bd9Sstevel@tonic-gate static void 1584*7c478bd9Sstevel@tonic-gate evch_chrdevent_fini(evchanq_t *snp) 1585*7c478bd9Sstevel@tonic-gate { 1586*7c478bd9Sstevel@tonic-gate if (snp != NULL) { 1587*7c478bd9Sstevel@tonic-gate evch_evq_destroy(snp->sn_queue); 1588*7c478bd9Sstevel@tonic-gate kmem_free(snp, sizeof (evchanq_t)); 1589*7c478bd9Sstevel@tonic-gate } 1590*7c478bd9Sstevel@tonic-gate } 1591*7c478bd9Sstevel@tonic-gate 1592*7c478bd9Sstevel@tonic-gate /* 1593*7c478bd9Sstevel@tonic-gate * Get address of next event from an event channel. 1594*7c478bd9Sstevel@tonic-gate * This function might be called in a panic context. In that case 1595*7c478bd9Sstevel@tonic-gate * no resources will be allocated and no locks grabbed. 1596*7c478bd9Sstevel@tonic-gate * In normal operation context a snapshot of the event queues of the 1597*7c478bd9Sstevel@tonic-gate * specified event channel will be taken. 1598*7c478bd9Sstevel@tonic-gate */ 1599*7c478bd9Sstevel@tonic-gate static sysevent_impl_t * 1600*7c478bd9Sstevel@tonic-gate evch_chgetnextev(evchanq_t *snp) 1601*7c478bd9Sstevel@tonic-gate { 1602*7c478bd9Sstevel@tonic-gate if (panicstr != NULL) { 1603*7c478bd9Sstevel@tonic-gate if (evch_chan == NULL) 1604*7c478bd9Sstevel@tonic-gate return (NULL); 1605*7c478bd9Sstevel@tonic-gate if (evch_subq != NULL) { 1606*7c478bd9Sstevel@tonic-gate /* 1607*7c478bd9Sstevel@tonic-gate * We have a subscriber queue. Traverse this queue 1608*7c478bd9Sstevel@tonic-gate * first. 1609*7c478bd9Sstevel@tonic-gate */ 1610*7c478bd9Sstevel@tonic-gate if ((evch_curev = (sysevent_impl_t *) 1611*7c478bd9Sstevel@tonic-gate evch_evq_evnext(evch_subq, evch_curev)) != NULL) { 1612*7c478bd9Sstevel@tonic-gate return (evch_curev); 1613*7c478bd9Sstevel@tonic-gate } else { 1614*7c478bd9Sstevel@tonic-gate /* 1615*7c478bd9Sstevel@tonic-gate * All subscriber events traversed. evch_subq 1616*7c478bd9Sstevel@tonic-gate * == NULL indicates to take the main event 1617*7c478bd9Sstevel@tonic-gate * queue now. 1618*7c478bd9Sstevel@tonic-gate */ 1619*7c478bd9Sstevel@tonic-gate evch_subq = NULL; 1620*7c478bd9Sstevel@tonic-gate } 1621*7c478bd9Sstevel@tonic-gate } 1622*7c478bd9Sstevel@tonic-gate /* 1623*7c478bd9Sstevel@tonic-gate * Traverse the main event queue. 1624*7c478bd9Sstevel@tonic-gate */ 1625*7c478bd9Sstevel@tonic-gate if ((evch_curev = (sysevent_impl_t *) 1626*7c478bd9Sstevel@tonic-gate evch_evq_evnext(evch_chan->ch_queue, evch_curev)) == 1627*7c478bd9Sstevel@tonic-gate NULL) { 1628*7c478bd9Sstevel@tonic-gate evch_chan = NULL; 1629*7c478bd9Sstevel@tonic-gate } 1630*7c478bd9Sstevel@tonic-gate return (evch_curev); 1631*7c478bd9Sstevel@tonic-gate } 1632*7c478bd9Sstevel@tonic-gate ASSERT(snp != NULL); 1633*7c478bd9Sstevel@tonic-gate snp->sn_nxtev = (sysevent_impl_t *)evch_evq_evnext(snp->sn_queue, 1634*7c478bd9Sstevel@tonic-gate snp->sn_nxtev); 1635*7c478bd9Sstevel@tonic-gate return (snp->sn_nxtev); 1636*7c478bd9Sstevel@tonic-gate } 1637*7c478bd9Sstevel@tonic-gate 1638*7c478bd9Sstevel@tonic-gate /* 1639*7c478bd9Sstevel@tonic-gate * The functions below build up the interface for the kernel to bind/unbind, 1640*7c478bd9Sstevel@tonic-gate * subscribe/unsubscribe and publish to event channels. It consists of the 1641*7c478bd9Sstevel@tonic-gate * following functions: 1642*7c478bd9Sstevel@tonic-gate * 1643*7c478bd9Sstevel@tonic-gate * sysevent_evc_bind - Bind to a channel. Create a channel if required 1644*7c478bd9Sstevel@tonic-gate * sysevent_evc_unbind - Unbind from a channel. Destroy ch. if last unbind 1645*7c478bd9Sstevel@tonic-gate * sysevent_evc_subscribe - Subscribe to events from a channel 1646*7c478bd9Sstevel@tonic-gate * sysevent_evc_unsubscribe - Unsubscribe from an event class 1647*7c478bd9Sstevel@tonic-gate * sysevent_evc_publish - Publish an event to an event channel 1648*7c478bd9Sstevel@tonic-gate * sysevent_evc_control - Various control operation on event channel 1649*7c478bd9Sstevel@tonic-gate * 1650*7c478bd9Sstevel@tonic-gate * The function below are for evaluating a sysevent: 1651*7c478bd9Sstevel@tonic-gate * 1652*7c478bd9Sstevel@tonic-gate * sysevent_get_class_name - Get pointer to event class string 1653*7c478bd9Sstevel@tonic-gate * sysevent_get_subclass_name - Get pointer to event subclass string 1654*7c478bd9Sstevel@tonic-gate * sysevent_get_seq - Get unique event sequence number 1655*7c478bd9Sstevel@tonic-gate * sysevent_get_time - Get hrestime of event publish 1656*7c478bd9Sstevel@tonic-gate * sysevent_get_size - Get size of event structure 1657*7c478bd9Sstevel@tonic-gate * sysevent_get_pub - Get publisher string 1658*7c478bd9Sstevel@tonic-gate * sysevent_get_attr_list - Get copy of attribute list 1659*7c478bd9Sstevel@tonic-gate * 1660*7c478bd9Sstevel@tonic-gate * The following interfaces represent stability level project privat 1661*7c478bd9Sstevel@tonic-gate * and allow to save the events of an event channel even in a panic case. 1662*7c478bd9Sstevel@tonic-gate * 1663*7c478bd9Sstevel@tonic-gate * sysevent_evc_walk_init - Take a snapshot of the events in a channel 1664*7c478bd9Sstevel@tonic-gate * sysevent_evc_walk_step - Read next event from snapshot 1665*7c478bd9Sstevel@tonic-gate * sysevent_evc_walk_fini - Free resources from event channel snapshot 1666*7c478bd9Sstevel@tonic-gate * sysevent_evc_event_attr - Get event payload address and size 1667*7c478bd9Sstevel@tonic-gate */ 1668*7c478bd9Sstevel@tonic-gate /* 1669*7c478bd9Sstevel@tonic-gate * allocate sysevent structure with optional space for attributes 1670*7c478bd9Sstevel@tonic-gate */ 1671*7c478bd9Sstevel@tonic-gate static sysevent_impl_t * 1672*7c478bd9Sstevel@tonic-gate sysevent_evc_alloc(const char *class, const char *subclass, const char *pub, 1673*7c478bd9Sstevel@tonic-gate size_t pub_sz, size_t atsz, uint32_t flag) 1674*7c478bd9Sstevel@tonic-gate { 1675*7c478bd9Sstevel@tonic-gate int payload_sz; 1676*7c478bd9Sstevel@tonic-gate int class_sz, subclass_sz; 1677*7c478bd9Sstevel@tonic-gate int aligned_class_sz, aligned_subclass_sz, aligned_pub_sz; 1678*7c478bd9Sstevel@tonic-gate sysevent_impl_t *ev; 1679*7c478bd9Sstevel@tonic-gate 1680*7c478bd9Sstevel@tonic-gate /* 1681*7c478bd9Sstevel@tonic-gate * Calculate and reserve space for the class, subclass and 1682*7c478bd9Sstevel@tonic-gate * publisher strings in the event buffer 1683*7c478bd9Sstevel@tonic-gate */ 1684*7c478bd9Sstevel@tonic-gate class_sz = strlen(class) + 1; 1685*7c478bd9Sstevel@tonic-gate subclass_sz = strlen(subclass) + 1; 1686*7c478bd9Sstevel@tonic-gate 1687*7c478bd9Sstevel@tonic-gate ASSERT((class_sz <= MAX_CLASS_LEN) && (subclass_sz <= 1688*7c478bd9Sstevel@tonic-gate MAX_SUBCLASS_LEN) && (pub_sz <= MAX_PUB_LEN)); 1689*7c478bd9Sstevel@tonic-gate 1690*7c478bd9Sstevel@tonic-gate /* String sizes must be 64-bit aligned in the event buffer */ 1691*7c478bd9Sstevel@tonic-gate aligned_class_sz = SE_ALIGN(class_sz); 1692*7c478bd9Sstevel@tonic-gate aligned_subclass_sz = SE_ALIGN(subclass_sz); 1693*7c478bd9Sstevel@tonic-gate aligned_pub_sz = SE_ALIGN(pub_sz); 1694*7c478bd9Sstevel@tonic-gate 1695*7c478bd9Sstevel@tonic-gate /* 1696*7c478bd9Sstevel@tonic-gate * Calculate payload size. Consider the space needed for alignment 1697*7c478bd9Sstevel@tonic-gate * and subtract the size of the uint64_t placeholder variables of 1698*7c478bd9Sstevel@tonic-gate * sysevent_impl_t. 1699*7c478bd9Sstevel@tonic-gate */ 1700*7c478bd9Sstevel@tonic-gate payload_sz = (aligned_class_sz - sizeof (uint64_t)) + 1701*7c478bd9Sstevel@tonic-gate (aligned_subclass_sz - sizeof (uint64_t)) + 1702*7c478bd9Sstevel@tonic-gate (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t) + 1703*7c478bd9Sstevel@tonic-gate atsz; 1704*7c478bd9Sstevel@tonic-gate 1705*7c478bd9Sstevel@tonic-gate /* 1706*7c478bd9Sstevel@tonic-gate * Allocate event buffer plus additional payload overhead 1707*7c478bd9Sstevel@tonic-gate */ 1708*7c478bd9Sstevel@tonic-gate if ((ev = evch_evq_evzalloc(sizeof (sysevent_impl_t) + 1709*7c478bd9Sstevel@tonic-gate payload_sz, flag)) == NULL) { 1710*7c478bd9Sstevel@tonic-gate return (NULL); 1711*7c478bd9Sstevel@tonic-gate } 1712*7c478bd9Sstevel@tonic-gate 1713*7c478bd9Sstevel@tonic-gate /* Initialize the event buffer data */ 1714*7c478bd9Sstevel@tonic-gate SE_VERSION(ev) = SYS_EVENT_VERSION; 1715*7c478bd9Sstevel@tonic-gate bcopy(class, SE_CLASS_NAME(ev), class_sz); 1716*7c478bd9Sstevel@tonic-gate 1717*7c478bd9Sstevel@tonic-gate SE_SUBCLASS_OFF(ev) = SE_ALIGN(offsetof(sysevent_impl_t, 1718*7c478bd9Sstevel@tonic-gate se_class_name)) + aligned_class_sz; 1719*7c478bd9Sstevel@tonic-gate bcopy(subclass, SE_SUBCLASS_NAME(ev), subclass_sz); 1720*7c478bd9Sstevel@tonic-gate 1721*7c478bd9Sstevel@tonic-gate SE_PUB_OFF(ev) = SE_SUBCLASS_OFF(ev) + aligned_subclass_sz; 1722*7c478bd9Sstevel@tonic-gate bcopy(pub, SE_PUB_NAME(ev), pub_sz); 1723*7c478bd9Sstevel@tonic-gate 1724*7c478bd9Sstevel@tonic-gate SE_ATTR_PTR(ev) = (uint64_t)0; 1725*7c478bd9Sstevel@tonic-gate SE_PAYLOAD_SZ(ev) = payload_sz; 1726*7c478bd9Sstevel@tonic-gate 1727*7c478bd9Sstevel@tonic-gate return (ev); 1728*7c478bd9Sstevel@tonic-gate } 1729*7c478bd9Sstevel@tonic-gate 1730*7c478bd9Sstevel@tonic-gate /* 1731*7c478bd9Sstevel@tonic-gate * Initialize event channel handling queues. 1732*7c478bd9Sstevel@tonic-gate */ 1733*7c478bd9Sstevel@tonic-gate void 1734*7c478bd9Sstevel@tonic-gate sysevent_evc_init() 1735*7c478bd9Sstevel@tonic-gate { 1736*7c478bd9Sstevel@tonic-gate evch_chinit(); 1737*7c478bd9Sstevel@tonic-gate } 1738*7c478bd9Sstevel@tonic-gate 1739*7c478bd9Sstevel@tonic-gate /* 1740*7c478bd9Sstevel@tonic-gate * Second initialization step: create threads, if event channels are already 1741*7c478bd9Sstevel@tonic-gate * created 1742*7c478bd9Sstevel@tonic-gate */ 1743*7c478bd9Sstevel@tonic-gate void 1744*7c478bd9Sstevel@tonic-gate sysevent_evc_thrinit() 1745*7c478bd9Sstevel@tonic-gate { 1746*7c478bd9Sstevel@tonic-gate evch_chinitthr(); 1747*7c478bd9Sstevel@tonic-gate } 1748*7c478bd9Sstevel@tonic-gate 1749*7c478bd9Sstevel@tonic-gate int 1750*7c478bd9Sstevel@tonic-gate sysevent_evc_bind(const char *ch_name, evchan_t **scpp, uint32_t flags) 1751*7c478bd9Sstevel@tonic-gate { 1752*7c478bd9Sstevel@tonic-gate ASSERT(ch_name != NULL && scpp != NULL); 1753*7c478bd9Sstevel@tonic-gate ASSERT((flags & ~EVCH_B_FLAGS) == 0); 1754*7c478bd9Sstevel@tonic-gate return (evch_chbind(ch_name, (evch_bind_t **)scpp, flags)); 1755*7c478bd9Sstevel@tonic-gate } 1756*7c478bd9Sstevel@tonic-gate 1757*7c478bd9Sstevel@tonic-gate void 1758*7c478bd9Sstevel@tonic-gate sysevent_evc_unbind(evchan_t *scp) 1759*7c478bd9Sstevel@tonic-gate { 1760*7c478bd9Sstevel@tonic-gate evch_bind_t *bp = (evch_bind_t *)scp; 1761*7c478bd9Sstevel@tonic-gate 1762*7c478bd9Sstevel@tonic-gate ASSERT(scp != NULL); 1763*7c478bd9Sstevel@tonic-gate evch_chunsubscribe(bp, NULL, 0); 1764*7c478bd9Sstevel@tonic-gate evch_chunbind(bp); 1765*7c478bd9Sstevel@tonic-gate } 1766*7c478bd9Sstevel@tonic-gate 1767*7c478bd9Sstevel@tonic-gate int 1768*7c478bd9Sstevel@tonic-gate sysevent_evc_subscribe(evchan_t *scp, const char *sid, const char *class, 1769*7c478bd9Sstevel@tonic-gate int (*callb)(sysevent_t *ev, void *cookie), 1770*7c478bd9Sstevel@tonic-gate void *cookie, uint32_t flags) 1771*7c478bd9Sstevel@tonic-gate { 1772*7c478bd9Sstevel@tonic-gate ASSERT(scp != NULL && sid != NULL && class != NULL && callb != NULL); 1773*7c478bd9Sstevel@tonic-gate ASSERT(flags == 0); 1774*7c478bd9Sstevel@tonic-gate if (strlen(sid) > MAX_SUBID_LEN) { 1775*7c478bd9Sstevel@tonic-gate return (EINVAL); 1776*7c478bd9Sstevel@tonic-gate } 1777*7c478bd9Sstevel@tonic-gate if (strcmp(class, EC_ALL) == 0) { 1778*7c478bd9Sstevel@tonic-gate class = NULL; 1779*7c478bd9Sstevel@tonic-gate } 1780*7c478bd9Sstevel@tonic-gate return (evch_chsubscribe((evch_bind_t *)scp, EVCH_DELKERN, sid, class, 1781*7c478bd9Sstevel@tonic-gate (void *)callb, cookie, 0, 0)); 1782*7c478bd9Sstevel@tonic-gate } 1783*7c478bd9Sstevel@tonic-gate 1784*7c478bd9Sstevel@tonic-gate void 1785*7c478bd9Sstevel@tonic-gate sysevent_evc_unsubscribe(evchan_t *scp, const char *sid) 1786*7c478bd9Sstevel@tonic-gate { 1787*7c478bd9Sstevel@tonic-gate ASSERT(scp != NULL && sid != NULL); 1788*7c478bd9Sstevel@tonic-gate if (strcmp(sid, EVCH_ALLSUB) == 0) { 1789*7c478bd9Sstevel@tonic-gate sid = NULL; 1790*7c478bd9Sstevel@tonic-gate } 1791*7c478bd9Sstevel@tonic-gate evch_chunsubscribe((evch_bind_t *)scp, sid, 0); 1792*7c478bd9Sstevel@tonic-gate } 1793*7c478bd9Sstevel@tonic-gate 1794*7c478bd9Sstevel@tonic-gate /* 1795*7c478bd9Sstevel@tonic-gate * Publish kernel event. Returns 0 on success, error code else. 1796*7c478bd9Sstevel@tonic-gate * Optional attribute data is packed into the event structure. 1797*7c478bd9Sstevel@tonic-gate */ 1798*7c478bd9Sstevel@tonic-gate int 1799*7c478bd9Sstevel@tonic-gate sysevent_evc_publish(evchan_t *scp, const char *class, const char *subclass, 1800*7c478bd9Sstevel@tonic-gate const char *vendor, const char *pubs, nvlist_t *attr, uint32_t flags) 1801*7c478bd9Sstevel@tonic-gate { 1802*7c478bd9Sstevel@tonic-gate sysevent_impl_t *evp; 1803*7c478bd9Sstevel@tonic-gate char pub[MAX_PUB_LEN]; 1804*7c478bd9Sstevel@tonic-gate int pub_sz; /* includes terminating 0 */ 1805*7c478bd9Sstevel@tonic-gate int km_flags; 1806*7c478bd9Sstevel@tonic-gate size_t asz = 0; 1807*7c478bd9Sstevel@tonic-gate uint64_t attr_offset; 1808*7c478bd9Sstevel@tonic-gate caddr_t patt; 1809*7c478bd9Sstevel@tonic-gate int err; 1810*7c478bd9Sstevel@tonic-gate 1811*7c478bd9Sstevel@tonic-gate ASSERT(scp != NULL && class != NULL && subclass != NULL && 1812*7c478bd9Sstevel@tonic-gate vendor != NULL && pubs != NULL); 1813*7c478bd9Sstevel@tonic-gate 1814*7c478bd9Sstevel@tonic-gate ASSERT((flags & ~(EVCH_SLEEP | EVCH_NOSLEEP | EVCH_TRYHARD | 1815*7c478bd9Sstevel@tonic-gate EVCH_QWAIT)) == 0); 1816*7c478bd9Sstevel@tonic-gate 1817*7c478bd9Sstevel@tonic-gate km_flags = flags & (EVCH_SLEEP | EVCH_NOSLEEP | EVCH_TRYHARD); 1818*7c478bd9Sstevel@tonic-gate ASSERT(km_flags == EVCH_SLEEP || km_flags == EVCH_NOSLEEP || 1819*7c478bd9Sstevel@tonic-gate km_flags == EVCH_TRYHARD); 1820*7c478bd9Sstevel@tonic-gate 1821*7c478bd9Sstevel@tonic-gate pub_sz = snprintf(pub, MAX_PUB_LEN, "%s:kern:%s", vendor, pubs) + 1; 1822*7c478bd9Sstevel@tonic-gate if (pub_sz > MAX_PUB_LEN) 1823*7c478bd9Sstevel@tonic-gate return (EINVAL); 1824*7c478bd9Sstevel@tonic-gate 1825*7c478bd9Sstevel@tonic-gate if (attr != NULL) { 1826*7c478bd9Sstevel@tonic-gate if ((err = nvlist_size(attr, &asz, NV_ENCODE_NATIVE)) != 0) { 1827*7c478bd9Sstevel@tonic-gate return (err); 1828*7c478bd9Sstevel@tonic-gate } 1829*7c478bd9Sstevel@tonic-gate } 1830*7c478bd9Sstevel@tonic-gate evp = sysevent_evc_alloc(class, subclass, pub, pub_sz, asz, km_flags); 1831*7c478bd9Sstevel@tonic-gate if (evp == NULL) { 1832*7c478bd9Sstevel@tonic-gate return (ENOMEM); 1833*7c478bd9Sstevel@tonic-gate } 1834*7c478bd9Sstevel@tonic-gate if (attr != NULL) { 1835*7c478bd9Sstevel@tonic-gate /* 1836*7c478bd9Sstevel@tonic-gate * Pack attributes into event buffer. Event buffer already 1837*7c478bd9Sstevel@tonic-gate * has enough room for the packed nvlist. 1838*7c478bd9Sstevel@tonic-gate */ 1839*7c478bd9Sstevel@tonic-gate attr_offset = SE_ATTR_OFF(evp); 1840*7c478bd9Sstevel@tonic-gate patt = (caddr_t)evp + attr_offset; 1841*7c478bd9Sstevel@tonic-gate 1842*7c478bd9Sstevel@tonic-gate err = nvlist_pack(attr, &patt, &asz, NV_ENCODE_NATIVE, 1843*7c478bd9Sstevel@tonic-gate km_flags & EVCH_SLEEP ? KM_SLEEP : KM_NOSLEEP); 1844*7c478bd9Sstevel@tonic-gate 1845*7c478bd9Sstevel@tonic-gate ASSERT(err != ENOMEM); 1846*7c478bd9Sstevel@tonic-gate 1847*7c478bd9Sstevel@tonic-gate if (err != 0) { 1848*7c478bd9Sstevel@tonic-gate return (EINVAL); 1849*7c478bd9Sstevel@tonic-gate } 1850*7c478bd9Sstevel@tonic-gate 1851*7c478bd9Sstevel@tonic-gate evp->seh_attr_off = attr_offset; 1852*7c478bd9Sstevel@tonic-gate SE_FLAG(evp) = SE_PACKED_BUF; 1853*7c478bd9Sstevel@tonic-gate } 1854*7c478bd9Sstevel@tonic-gate return (evch_chpublish((evch_bind_t *)scp, evp, flags)); 1855*7c478bd9Sstevel@tonic-gate } 1856*7c478bd9Sstevel@tonic-gate 1857*7c478bd9Sstevel@tonic-gate int 1858*7c478bd9Sstevel@tonic-gate sysevent_evc_control(evchan_t *scp, int cmd, ...) 1859*7c478bd9Sstevel@tonic-gate { 1860*7c478bd9Sstevel@tonic-gate va_list ap; 1861*7c478bd9Sstevel@tonic-gate evch_chan_t *chp = ((evch_bind_t *)scp)->bd_channel; 1862*7c478bd9Sstevel@tonic-gate uint32_t *chlenp; 1863*7c478bd9Sstevel@tonic-gate uint32_t chlen; 1864*7c478bd9Sstevel@tonic-gate uint32_t ochlen; 1865*7c478bd9Sstevel@tonic-gate int rc = 0; 1866*7c478bd9Sstevel@tonic-gate 1867*7c478bd9Sstevel@tonic-gate if (scp == NULL) { 1868*7c478bd9Sstevel@tonic-gate return (EINVAL); 1869*7c478bd9Sstevel@tonic-gate } 1870*7c478bd9Sstevel@tonic-gate 1871*7c478bd9Sstevel@tonic-gate va_start(ap, cmd); 1872*7c478bd9Sstevel@tonic-gate mutex_enter(&chp->ch_mutex); 1873*7c478bd9Sstevel@tonic-gate switch (cmd) { 1874*7c478bd9Sstevel@tonic-gate case EVCH_GET_CHAN_LEN: 1875*7c478bd9Sstevel@tonic-gate chlenp = va_arg(ap, uint32_t *); 1876*7c478bd9Sstevel@tonic-gate *chlenp = chp->ch_maxev; 1877*7c478bd9Sstevel@tonic-gate break; 1878*7c478bd9Sstevel@tonic-gate case EVCH_SET_CHAN_LEN: 1879*7c478bd9Sstevel@tonic-gate chlen = va_arg(ap, uint32_t); 1880*7c478bd9Sstevel@tonic-gate ochlen = chp->ch_maxev; 1881*7c478bd9Sstevel@tonic-gate chp->ch_maxev = min(chlen, evch_events_max); 1882*7c478bd9Sstevel@tonic-gate if (ochlen < chp->ch_maxev) { 1883*7c478bd9Sstevel@tonic-gate cv_signal(&chp->ch_pubcv); 1884*7c478bd9Sstevel@tonic-gate } 1885*7c478bd9Sstevel@tonic-gate break; 1886*7c478bd9Sstevel@tonic-gate case EVCH_GET_CHAN_LEN_MAX: 1887*7c478bd9Sstevel@tonic-gate *va_arg(ap, uint32_t *) = evch_events_max; 1888*7c478bd9Sstevel@tonic-gate break; 1889*7c478bd9Sstevel@tonic-gate default: 1890*7c478bd9Sstevel@tonic-gate rc = EINVAL; 1891*7c478bd9Sstevel@tonic-gate } 1892*7c478bd9Sstevel@tonic-gate 1893*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_mutex); 1894*7c478bd9Sstevel@tonic-gate va_end(ap); 1895*7c478bd9Sstevel@tonic-gate return (rc); 1896*7c478bd9Sstevel@tonic-gate } 1897*7c478bd9Sstevel@tonic-gate 1898*7c478bd9Sstevel@tonic-gate /* 1899*7c478bd9Sstevel@tonic-gate * Project private interface to take a snapshot of all events of the 1900*7c478bd9Sstevel@tonic-gate * specified event channel. Argument subscr may be a subscriber id, the empty 1901*7c478bd9Sstevel@tonic-gate * string "", or NULL. The empty string indicates that no subscriber is 1902*7c478bd9Sstevel@tonic-gate * selected, for example if a previous subscriber died. sysevent_evc_walk_next() 1903*7c478bd9Sstevel@tonic-gate * will deliver events from the main event queue in this case. If subscr is 1904*7c478bd9Sstevel@tonic-gate * NULL, the subscriber with the EVCH_SUB_DUMP flag set (subd->sd_dump != 0) 1905*7c478bd9Sstevel@tonic-gate * will be selected. 1906*7c478bd9Sstevel@tonic-gate * 1907*7c478bd9Sstevel@tonic-gate * In panic case this function returns NULL. This is legal. The NULL has 1908*7c478bd9Sstevel@tonic-gate * to be delivered to sysevent_evc_walk_step() and sysevent_evc_walk_fini(). 1909*7c478bd9Sstevel@tonic-gate */ 1910*7c478bd9Sstevel@tonic-gate evchanq_t * 1911*7c478bd9Sstevel@tonic-gate sysevent_evc_walk_init(evchan_t *scp, char *subscr) 1912*7c478bd9Sstevel@tonic-gate { 1913*7c478bd9Sstevel@tonic-gate if (panicstr != NULL && scp == NULL) 1914*7c478bd9Sstevel@tonic-gate return (NULL); 1915*7c478bd9Sstevel@tonic-gate ASSERT(scp != NULL); 1916*7c478bd9Sstevel@tonic-gate return (evch_chrdevent_init(((evch_bind_t *)scp)->bd_channel, subscr)); 1917*7c478bd9Sstevel@tonic-gate } 1918*7c478bd9Sstevel@tonic-gate 1919*7c478bd9Sstevel@tonic-gate /* 1920*7c478bd9Sstevel@tonic-gate * Project private interface to read events from a previously taken 1921*7c478bd9Sstevel@tonic-gate * snapshot (with sysevent_evc_walk_init). In case of panic events 1922*7c478bd9Sstevel@tonic-gate * are retrieved directly from the channel data structures. No resources 1923*7c478bd9Sstevel@tonic-gate * are allocated and no mutexes are grabbed in panic context. 1924*7c478bd9Sstevel@tonic-gate */ 1925*7c478bd9Sstevel@tonic-gate sysevent_t * 1926*7c478bd9Sstevel@tonic-gate sysevent_evc_walk_step(evchanq_t *evcq) 1927*7c478bd9Sstevel@tonic-gate { 1928*7c478bd9Sstevel@tonic-gate return ((sysevent_t *)evch_chgetnextev(evcq)); 1929*7c478bd9Sstevel@tonic-gate } 1930*7c478bd9Sstevel@tonic-gate 1931*7c478bd9Sstevel@tonic-gate /* 1932*7c478bd9Sstevel@tonic-gate * Project private interface to free a previously taken snapshot. 1933*7c478bd9Sstevel@tonic-gate */ 1934*7c478bd9Sstevel@tonic-gate void 1935*7c478bd9Sstevel@tonic-gate sysevent_evc_walk_fini(evchanq_t *evcq) 1936*7c478bd9Sstevel@tonic-gate { 1937*7c478bd9Sstevel@tonic-gate evch_chrdevent_fini(evcq); 1938*7c478bd9Sstevel@tonic-gate } 1939*7c478bd9Sstevel@tonic-gate 1940*7c478bd9Sstevel@tonic-gate /* 1941*7c478bd9Sstevel@tonic-gate * Get address and size of an event payload. Returns NULL when no 1942*7c478bd9Sstevel@tonic-gate * payload present. 1943*7c478bd9Sstevel@tonic-gate */ 1944*7c478bd9Sstevel@tonic-gate char * 1945*7c478bd9Sstevel@tonic-gate sysevent_evc_event_attr(sysevent_t *ev, size_t *plsize) 1946*7c478bd9Sstevel@tonic-gate { 1947*7c478bd9Sstevel@tonic-gate char *attrp; 1948*7c478bd9Sstevel@tonic-gate size_t aoff; 1949*7c478bd9Sstevel@tonic-gate size_t asz; 1950*7c478bd9Sstevel@tonic-gate 1951*7c478bd9Sstevel@tonic-gate aoff = SE_ATTR_OFF(ev); 1952*7c478bd9Sstevel@tonic-gate attrp = (char *)ev + aoff; 1953*7c478bd9Sstevel@tonic-gate asz = *plsize = SE_SIZE(ev) - aoff; 1954*7c478bd9Sstevel@tonic-gate return (asz ? attrp : NULL); 1955*7c478bd9Sstevel@tonic-gate } 1956*7c478bd9Sstevel@tonic-gate 1957*7c478bd9Sstevel@tonic-gate /* 1958*7c478bd9Sstevel@tonic-gate * sysevent_get_class_name - Get class name string 1959*7c478bd9Sstevel@tonic-gate */ 1960*7c478bd9Sstevel@tonic-gate char * 1961*7c478bd9Sstevel@tonic-gate sysevent_get_class_name(sysevent_t *ev) 1962*7c478bd9Sstevel@tonic-gate { 1963*7c478bd9Sstevel@tonic-gate return (SE_CLASS_NAME(ev)); 1964*7c478bd9Sstevel@tonic-gate } 1965*7c478bd9Sstevel@tonic-gate 1966*7c478bd9Sstevel@tonic-gate /* 1967*7c478bd9Sstevel@tonic-gate * sysevent_get_subclass_name - Get subclass name string 1968*7c478bd9Sstevel@tonic-gate */ 1969*7c478bd9Sstevel@tonic-gate char * 1970*7c478bd9Sstevel@tonic-gate sysevent_get_subclass_name(sysevent_t *ev) 1971*7c478bd9Sstevel@tonic-gate { 1972*7c478bd9Sstevel@tonic-gate return (SE_SUBCLASS_NAME(ev)); 1973*7c478bd9Sstevel@tonic-gate } 1974*7c478bd9Sstevel@tonic-gate 1975*7c478bd9Sstevel@tonic-gate /* 1976*7c478bd9Sstevel@tonic-gate * sysevent_get_seq - Get event sequence id 1977*7c478bd9Sstevel@tonic-gate */ 1978*7c478bd9Sstevel@tonic-gate uint64_t 1979*7c478bd9Sstevel@tonic-gate sysevent_get_seq(sysevent_t *ev) 1980*7c478bd9Sstevel@tonic-gate { 1981*7c478bd9Sstevel@tonic-gate return (SE_SEQ(ev)); 1982*7c478bd9Sstevel@tonic-gate } 1983*7c478bd9Sstevel@tonic-gate 1984*7c478bd9Sstevel@tonic-gate /* 1985*7c478bd9Sstevel@tonic-gate * sysevent_get_time - Get event timestamp 1986*7c478bd9Sstevel@tonic-gate */ 1987*7c478bd9Sstevel@tonic-gate void 1988*7c478bd9Sstevel@tonic-gate sysevent_get_time(sysevent_t *ev, hrtime_t *etime) 1989*7c478bd9Sstevel@tonic-gate { 1990*7c478bd9Sstevel@tonic-gate *etime = SE_TIME(ev); 1991*7c478bd9Sstevel@tonic-gate } 1992*7c478bd9Sstevel@tonic-gate 1993*7c478bd9Sstevel@tonic-gate /* 1994*7c478bd9Sstevel@tonic-gate * sysevent_get_size - Get event buffer size 1995*7c478bd9Sstevel@tonic-gate */ 1996*7c478bd9Sstevel@tonic-gate size_t 1997*7c478bd9Sstevel@tonic-gate sysevent_get_size(sysevent_t *ev) 1998*7c478bd9Sstevel@tonic-gate { 1999*7c478bd9Sstevel@tonic-gate return ((size_t)SE_SIZE(ev)); 2000*7c478bd9Sstevel@tonic-gate } 2001*7c478bd9Sstevel@tonic-gate 2002*7c478bd9Sstevel@tonic-gate /* 2003*7c478bd9Sstevel@tonic-gate * sysevent_get_pub - Get publisher name string 2004*7c478bd9Sstevel@tonic-gate */ 2005*7c478bd9Sstevel@tonic-gate char * 2006*7c478bd9Sstevel@tonic-gate sysevent_get_pub(sysevent_t *ev) 2007*7c478bd9Sstevel@tonic-gate { 2008*7c478bd9Sstevel@tonic-gate return (SE_PUB_NAME(ev)); 2009*7c478bd9Sstevel@tonic-gate } 2010*7c478bd9Sstevel@tonic-gate 2011*7c478bd9Sstevel@tonic-gate /* 2012*7c478bd9Sstevel@tonic-gate * sysevent_get_attr_list - stores address of a copy of the attribute list 2013*7c478bd9Sstevel@tonic-gate * associated with the given sysevent buffer. The list must be freed by the 2014*7c478bd9Sstevel@tonic-gate * caller. 2015*7c478bd9Sstevel@tonic-gate */ 2016*7c478bd9Sstevel@tonic-gate int 2017*7c478bd9Sstevel@tonic-gate sysevent_get_attr_list(sysevent_t *ev, nvlist_t **nvlist) 2018*7c478bd9Sstevel@tonic-gate { 2019*7c478bd9Sstevel@tonic-gate int error; 2020*7c478bd9Sstevel@tonic-gate caddr_t attr; 2021*7c478bd9Sstevel@tonic-gate size_t attr_len; 2022*7c478bd9Sstevel@tonic-gate uint64_t attr_offset; 2023*7c478bd9Sstevel@tonic-gate 2024*7c478bd9Sstevel@tonic-gate *nvlist = NULL; 2025*7c478bd9Sstevel@tonic-gate if (SE_FLAG(ev) != SE_PACKED_BUF) { 2026*7c478bd9Sstevel@tonic-gate return (EINVAL); 2027*7c478bd9Sstevel@tonic-gate } 2028*7c478bd9Sstevel@tonic-gate attr_offset = SE_ATTR_OFF(ev); 2029*7c478bd9Sstevel@tonic-gate if (SE_SIZE(ev) == attr_offset) { 2030*7c478bd9Sstevel@tonic-gate return (EINVAL); 2031*7c478bd9Sstevel@tonic-gate } 2032*7c478bd9Sstevel@tonic-gate 2033*7c478bd9Sstevel@tonic-gate /* unpack nvlist */ 2034*7c478bd9Sstevel@tonic-gate attr = (caddr_t)ev + attr_offset; 2035*7c478bd9Sstevel@tonic-gate attr_len = SE_SIZE(ev) - attr_offset; 2036*7c478bd9Sstevel@tonic-gate if ((error = nvlist_unpack(attr, attr_len, nvlist, 0)) != 0) { 2037*7c478bd9Sstevel@tonic-gate error = error != ENOMEM ? EINVAL : error; 2038*7c478bd9Sstevel@tonic-gate return (error); 2039*7c478bd9Sstevel@tonic-gate } 2040*7c478bd9Sstevel@tonic-gate return (0); 2041*7c478bd9Sstevel@tonic-gate } 2042*7c478bd9Sstevel@tonic-gate 2043*7c478bd9Sstevel@tonic-gate /* 2044*7c478bd9Sstevel@tonic-gate * Functions called by the sysevent driver for general purpose event channels 2045*7c478bd9Sstevel@tonic-gate * 2046*7c478bd9Sstevel@tonic-gate * evch_usrchanopen - Create/Bind to an event channel 2047*7c478bd9Sstevel@tonic-gate * evch_usrchanclose - Unbind/Destroy event channel 2048*7c478bd9Sstevel@tonic-gate * evch_usrallocev - Allocate event data structure 2049*7c478bd9Sstevel@tonic-gate * evch_usrfreeev - Free event data structure 2050*7c478bd9Sstevel@tonic-gate * evch_usrpostevent - Publish event 2051*7c478bd9Sstevel@tonic-gate * evch_usrsubscribe - Subscribe (register callback function) 2052*7c478bd9Sstevel@tonic-gate * evch_usrunsubscribe - Unsubscribe 2053*7c478bd9Sstevel@tonic-gate * evch_usrcontrol_set - Set channel properties 2054*7c478bd9Sstevel@tonic-gate * evch_usrcontrol_get - Get channel properties 2055*7c478bd9Sstevel@tonic-gate * evch_usrgetchnames - Get list of channel names 2056*7c478bd9Sstevel@tonic-gate * evch_usrgetchdata - Get data of an event channel 2057*7c478bd9Sstevel@tonic-gate */ 2058*7c478bd9Sstevel@tonic-gate evchan_t * 2059*7c478bd9Sstevel@tonic-gate evch_usrchanopen(const char *name, uint32_t flags, int *err) 2060*7c478bd9Sstevel@tonic-gate { 2061*7c478bd9Sstevel@tonic-gate evch_bind_t *bp = NULL; 2062*7c478bd9Sstevel@tonic-gate 2063*7c478bd9Sstevel@tonic-gate *err = evch_chbind(name, &bp, flags); 2064*7c478bd9Sstevel@tonic-gate return ((evchan_t *)bp); 2065*7c478bd9Sstevel@tonic-gate } 2066*7c478bd9Sstevel@tonic-gate 2067*7c478bd9Sstevel@tonic-gate /* 2068*7c478bd9Sstevel@tonic-gate * Unbind from the channel. 2069*7c478bd9Sstevel@tonic-gate */ 2070*7c478bd9Sstevel@tonic-gate void 2071*7c478bd9Sstevel@tonic-gate evch_usrchanclose(evchan_t *cbp) 2072*7c478bd9Sstevel@tonic-gate { 2073*7c478bd9Sstevel@tonic-gate evch_chunbind((evch_bind_t *)cbp); 2074*7c478bd9Sstevel@tonic-gate } 2075*7c478bd9Sstevel@tonic-gate 2076*7c478bd9Sstevel@tonic-gate /* 2077*7c478bd9Sstevel@tonic-gate * Allocates log_evch_eventq_t structure but returns the pointer of the embedded 2078*7c478bd9Sstevel@tonic-gate * sysevent_impl_t structure as the opaque sysevent_t * data type 2079*7c478bd9Sstevel@tonic-gate */ 2080*7c478bd9Sstevel@tonic-gate sysevent_impl_t * 2081*7c478bd9Sstevel@tonic-gate evch_usrallocev(size_t evsize, uint32_t flags) 2082*7c478bd9Sstevel@tonic-gate { 2083*7c478bd9Sstevel@tonic-gate return ((sysevent_impl_t *)evch_evq_evzalloc(evsize, flags)); 2084*7c478bd9Sstevel@tonic-gate } 2085*7c478bd9Sstevel@tonic-gate 2086*7c478bd9Sstevel@tonic-gate /* 2087*7c478bd9Sstevel@tonic-gate * Free evch_eventq_t structure 2088*7c478bd9Sstevel@tonic-gate */ 2089*7c478bd9Sstevel@tonic-gate void 2090*7c478bd9Sstevel@tonic-gate evch_usrfreeev(sysevent_impl_t *ev) 2091*7c478bd9Sstevel@tonic-gate { 2092*7c478bd9Sstevel@tonic-gate evch_evq_evfree((void *)ev); 2093*7c478bd9Sstevel@tonic-gate } 2094*7c478bd9Sstevel@tonic-gate 2095*7c478bd9Sstevel@tonic-gate /* 2096*7c478bd9Sstevel@tonic-gate * Posts an event to the given channel. The event structure has to be 2097*7c478bd9Sstevel@tonic-gate * allocated by evch_usrallocev(). Returns zero on success and an error 2098*7c478bd9Sstevel@tonic-gate * code else. Attributes have to be packed and included in the event structure. 2099*7c478bd9Sstevel@tonic-gate * 2100*7c478bd9Sstevel@tonic-gate */ 2101*7c478bd9Sstevel@tonic-gate int 2102*7c478bd9Sstevel@tonic-gate evch_usrpostevent(evchan_t *bp, sysevent_impl_t *ev, uint32_t flags) 2103*7c478bd9Sstevel@tonic-gate { 2104*7c478bd9Sstevel@tonic-gate return (evch_chpublish((evch_bind_t *)bp, ev, flags)); 2105*7c478bd9Sstevel@tonic-gate } 2106*7c478bd9Sstevel@tonic-gate 2107*7c478bd9Sstevel@tonic-gate /* 2108*7c478bd9Sstevel@tonic-gate * Subscribe function for user land subscriptions 2109*7c478bd9Sstevel@tonic-gate */ 2110*7c478bd9Sstevel@tonic-gate int 2111*7c478bd9Sstevel@tonic-gate evch_usrsubscribe(evchan_t *bp, const char *sid, const char *class, 2112*7c478bd9Sstevel@tonic-gate int d, uint32_t flags) 2113*7c478bd9Sstevel@tonic-gate { 2114*7c478bd9Sstevel@tonic-gate door_handle_t dh = door_ki_lookup(d); 2115*7c478bd9Sstevel@tonic-gate int rv; 2116*7c478bd9Sstevel@tonic-gate 2117*7c478bd9Sstevel@tonic-gate if (dh == NULL) { 2118*7c478bd9Sstevel@tonic-gate return (EINVAL); 2119*7c478bd9Sstevel@tonic-gate } 2120*7c478bd9Sstevel@tonic-gate if ((rv = evch_chsubscribe((evch_bind_t *)bp, EVCH_DELDOOR, sid, class, 2121*7c478bd9Sstevel@tonic-gate (void *)dh, NULL, flags, curproc->p_pid)) != 0) { 2122*7c478bd9Sstevel@tonic-gate door_ki_rele(dh); 2123*7c478bd9Sstevel@tonic-gate } 2124*7c478bd9Sstevel@tonic-gate return (rv); 2125*7c478bd9Sstevel@tonic-gate } 2126*7c478bd9Sstevel@tonic-gate 2127*7c478bd9Sstevel@tonic-gate /* 2128*7c478bd9Sstevel@tonic-gate * Flag can be EVCH_SUB_KEEP or 0. EVCH_SUB_KEEP preserves persistent 2129*7c478bd9Sstevel@tonic-gate * subscribers 2130*7c478bd9Sstevel@tonic-gate */ 2131*7c478bd9Sstevel@tonic-gate void 2132*7c478bd9Sstevel@tonic-gate evch_usrunsubscribe(evchan_t *bp, const char *subid, uint32_t flags) 2133*7c478bd9Sstevel@tonic-gate { 2134*7c478bd9Sstevel@tonic-gate evch_chunsubscribe((evch_bind_t *)bp, subid, flags); 2135*7c478bd9Sstevel@tonic-gate } 2136*7c478bd9Sstevel@tonic-gate 2137*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2138*7c478bd9Sstevel@tonic-gate int 2139*7c478bd9Sstevel@tonic-gate evch_usrcontrol_set(evchan_t *bp, int cmd, uint32_t value) 2140*7c478bd9Sstevel@tonic-gate { 2141*7c478bd9Sstevel@tonic-gate evch_chan_t *chp = ((evch_bind_t *)bp)->bd_channel; 2142*7c478bd9Sstevel@tonic-gate uid_t uid = crgetuid(curthread->t_cred); 2143*7c478bd9Sstevel@tonic-gate int rc = 0; 2144*7c478bd9Sstevel@tonic-gate 2145*7c478bd9Sstevel@tonic-gate mutex_enter(&chp->ch_mutex); 2146*7c478bd9Sstevel@tonic-gate switch (cmd) { 2147*7c478bd9Sstevel@tonic-gate case EVCH_SET_CHAN_LEN: 2148*7c478bd9Sstevel@tonic-gate if (uid && uid != chp->ch_uid) { 2149*7c478bd9Sstevel@tonic-gate rc = EACCES; 2150*7c478bd9Sstevel@tonic-gate break; 2151*7c478bd9Sstevel@tonic-gate } 2152*7c478bd9Sstevel@tonic-gate chp->ch_maxev = min(value, evch_events_max); 2153*7c478bd9Sstevel@tonic-gate break; 2154*7c478bd9Sstevel@tonic-gate default: 2155*7c478bd9Sstevel@tonic-gate rc = EINVAL; 2156*7c478bd9Sstevel@tonic-gate } 2157*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_mutex); 2158*7c478bd9Sstevel@tonic-gate return (rc); 2159*7c478bd9Sstevel@tonic-gate } 2160*7c478bd9Sstevel@tonic-gate 2161*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2162*7c478bd9Sstevel@tonic-gate int 2163*7c478bd9Sstevel@tonic-gate evch_usrcontrol_get(evchan_t *bp, int cmd, uint32_t *value) 2164*7c478bd9Sstevel@tonic-gate { 2165*7c478bd9Sstevel@tonic-gate evch_chan_t *chp = ((evch_bind_t *)bp)->bd_channel; 2166*7c478bd9Sstevel@tonic-gate int rc = 0; 2167*7c478bd9Sstevel@tonic-gate 2168*7c478bd9Sstevel@tonic-gate mutex_enter(&chp->ch_mutex); 2169*7c478bd9Sstevel@tonic-gate switch (cmd) { 2170*7c478bd9Sstevel@tonic-gate case EVCH_GET_CHAN_LEN: 2171*7c478bd9Sstevel@tonic-gate *value = chp->ch_maxev; 2172*7c478bd9Sstevel@tonic-gate break; 2173*7c478bd9Sstevel@tonic-gate case EVCH_GET_CHAN_LEN_MAX: 2174*7c478bd9Sstevel@tonic-gate *value = evch_events_max; 2175*7c478bd9Sstevel@tonic-gate break; 2176*7c478bd9Sstevel@tonic-gate default: 2177*7c478bd9Sstevel@tonic-gate rc = EINVAL; 2178*7c478bd9Sstevel@tonic-gate } 2179*7c478bd9Sstevel@tonic-gate mutex_exit(&chp->ch_mutex); 2180*7c478bd9Sstevel@tonic-gate return (rc); 2181*7c478bd9Sstevel@tonic-gate } 2182*7c478bd9Sstevel@tonic-gate 2183*7c478bd9Sstevel@tonic-gate int 2184*7c478bd9Sstevel@tonic-gate evch_usrgetchnames(char *buf, size_t size) 2185*7c478bd9Sstevel@tonic-gate { 2186*7c478bd9Sstevel@tonic-gate return (evch_chgetnames(buf, size)); 2187*7c478bd9Sstevel@tonic-gate } 2188*7c478bd9Sstevel@tonic-gate 2189*7c478bd9Sstevel@tonic-gate int 2190*7c478bd9Sstevel@tonic-gate evch_usrgetchdata(char *chname, void *buf, size_t size) 2191*7c478bd9Sstevel@tonic-gate { 2192*7c478bd9Sstevel@tonic-gate return (evch_chgetchdata(chname, buf, size)); 2193*7c478bd9Sstevel@tonic-gate } 2194