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