xref: /illumos-gate/usr/src/uts/common/os/evchannels.c (revision 074e084f68dd0b08686612bec695a0cfe249da6d)
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