xref: /titanic_41/usr/src/lib/libinetutil/common/eh.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
30*7c478bd9Sstevel@tonic-gate #include <errno.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>	/* INFTIM */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <libinetutil.h>
35*7c478bd9Sstevel@tonic-gate #include "libinetutil_impl.h"
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate static int	grow_fds(iu_eh_t *, int);
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate /*
40*7c478bd9Sstevel@tonic-gate  * signal_to_eh[] is pretty much useless, since the event handler is
41*7c478bd9Sstevel@tonic-gate  * really a singleton (we pass iu_eh_t *'s around to maintain an
42*7c478bd9Sstevel@tonic-gate  * abstraction, not to allow multiple event handlers to exist).  we
43*7c478bd9Sstevel@tonic-gate  * need some way to get back our event handler in post_signal(),
44*7c478bd9Sstevel@tonic-gate  * and since the signal model is too lame to provide opaque pointers,
45*7c478bd9Sstevel@tonic-gate  * we have to resort to global variables.
46*7c478bd9Sstevel@tonic-gate  */
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate static iu_eh_t *signal_to_eh[NSIG];
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate /*
51*7c478bd9Sstevel@tonic-gate  * iu_eh_create(): creates, initializes, and returns an event handler for use
52*7c478bd9Sstevel@tonic-gate  *
53*7c478bd9Sstevel@tonic-gate  *   input: void
54*7c478bd9Sstevel@tonic-gate  *  output: iu_eh_t *: the new event handler
55*7c478bd9Sstevel@tonic-gate  */
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate iu_eh_t *
iu_eh_create(void)58*7c478bd9Sstevel@tonic-gate iu_eh_create(void)
59*7c478bd9Sstevel@tonic-gate {
60*7c478bd9Sstevel@tonic-gate 	iu_eh_t	*eh = malloc(sizeof (iu_eh_t));
61*7c478bd9Sstevel@tonic-gate 	int	sig;
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate 	if (eh == NULL)
64*7c478bd9Sstevel@tonic-gate 		return (NULL);
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate 	eh->iueh_pollfds	= NULL;
67*7c478bd9Sstevel@tonic-gate 	eh->iueh_events		= NULL;
68*7c478bd9Sstevel@tonic-gate 	eh->iueh_shutdown	= NULL;
69*7c478bd9Sstevel@tonic-gate 	eh->iueh_num_fds	= 0;
70*7c478bd9Sstevel@tonic-gate 	eh->iueh_stop		= B_FALSE;
71*7c478bd9Sstevel@tonic-gate 	eh->iueh_reason		= 0;
72*7c478bd9Sstevel@tonic-gate 	eh->iueh_shutdown_arg	= NULL;
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&eh->iueh_sig_regset);
75*7c478bd9Sstevel@tonic-gate 	for (sig = 0; sig < NSIG; sig++) {
76*7c478bd9Sstevel@tonic-gate 		eh->iueh_sig_info[sig].iues_pending = B_FALSE;
77*7c478bd9Sstevel@tonic-gate 		eh->iueh_sig_info[sig].iues_handler = NULL;
78*7c478bd9Sstevel@tonic-gate 		eh->iueh_sig_info[sig].iues_data = NULL;
79*7c478bd9Sstevel@tonic-gate 	}
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 	return (eh);
82*7c478bd9Sstevel@tonic-gate }
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate /*
85*7c478bd9Sstevel@tonic-gate  * iu_eh_destroy(): destroys an existing event handler
86*7c478bd9Sstevel@tonic-gate  *
87*7c478bd9Sstevel@tonic-gate  *   input: iu_eh_t *: the event handler to destroy
88*7c478bd9Sstevel@tonic-gate  *  output: void
89*7c478bd9Sstevel@tonic-gate  *   notes: it is assumed all events related to this eh have been unregistered
90*7c478bd9Sstevel@tonic-gate  *          prior to calling iu_eh_destroy()
91*7c478bd9Sstevel@tonic-gate  */
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate void
iu_eh_destroy(iu_eh_t * eh)94*7c478bd9Sstevel@tonic-gate iu_eh_destroy(iu_eh_t *eh)
95*7c478bd9Sstevel@tonic-gate {
96*7c478bd9Sstevel@tonic-gate 	int	sig;
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate 	for (sig = 0; sig < NSIG; sig++)
99*7c478bd9Sstevel@tonic-gate 		if (signal_to_eh[sig] == eh)
100*7c478bd9Sstevel@tonic-gate 			(void) iu_eh_unregister_signal(eh, sig, NULL);
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate 	free(eh->iueh_pollfds);
103*7c478bd9Sstevel@tonic-gate 	free(eh->iueh_events);
104*7c478bd9Sstevel@tonic-gate 	free(eh);
105*7c478bd9Sstevel@tonic-gate }
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate /*
108*7c478bd9Sstevel@tonic-gate  * iu_stop_handling_events(): informs the event handler to stop handling events
109*7c478bd9Sstevel@tonic-gate  *
110*7c478bd9Sstevel@tonic-gate  *   input: iu_eh_t *: the event handler to stop.
111*7c478bd9Sstevel@tonic-gate  *	    unsigned int: the (user-defined) reason why
112*7c478bd9Sstevel@tonic-gate  *          iu_eh_shutdown_t *: the shutdown callback. if it is NULL,
113*7c478bd9Sstevel@tonic-gate  *				the event handler will stop right away;
114*7c478bd9Sstevel@tonic-gate  *				otherwise, the event handler will not
115*7c478bd9Sstevel@tonic-gate  *				stop until the callback returns B_TRUE
116*7c478bd9Sstevel@tonic-gate  *	    void *: data for the shutdown callback. it may be NULL
117*7c478bd9Sstevel@tonic-gate  *  output: void
118*7c478bd9Sstevel@tonic-gate  *   notes: the event handler in question must be in iu_handle_events()
119*7c478bd9Sstevel@tonic-gate  */
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate void
iu_stop_handling_events(iu_eh_t * eh,unsigned int reason,iu_eh_shutdown_t * shutdown,void * arg)122*7c478bd9Sstevel@tonic-gate iu_stop_handling_events(iu_eh_t *eh, unsigned int reason,
123*7c478bd9Sstevel@tonic-gate     iu_eh_shutdown_t *shutdown, void *arg)
124*7c478bd9Sstevel@tonic-gate {
125*7c478bd9Sstevel@tonic-gate 	eh->iueh_stop   = B_TRUE;
126*7c478bd9Sstevel@tonic-gate 	eh->iueh_reason = reason;
127*7c478bd9Sstevel@tonic-gate 	eh->iueh_shutdown = shutdown;
128*7c478bd9Sstevel@tonic-gate 	eh->iueh_shutdown_arg = arg;
129*7c478bd9Sstevel@tonic-gate }
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate /*
132*7c478bd9Sstevel@tonic-gate  * grow_fds(): grows the internal file descriptor set used by the event
133*7c478bd9Sstevel@tonic-gate  *		  handler
134*7c478bd9Sstevel@tonic-gate  *
135*7c478bd9Sstevel@tonic-gate  *   input: iu_eh_t *: the event handler whose descriptor set needs to be grown
136*7c478bd9Sstevel@tonic-gate  *          int: the new total number of descriptors needed in the set
137*7c478bd9Sstevel@tonic-gate  *  output: int: zero on failure, success otherwise
138*7c478bd9Sstevel@tonic-gate  */
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate static int
grow_fds(iu_eh_t * eh,int total_fds)141*7c478bd9Sstevel@tonic-gate grow_fds(iu_eh_t *eh, int total_fds)
142*7c478bd9Sstevel@tonic-gate {
143*7c478bd9Sstevel@tonic-gate 	unsigned int	i;
144*7c478bd9Sstevel@tonic-gate 	struct pollfd	*new_pollfds;
145*7c478bd9Sstevel@tonic-gate 	iu_event_node_t	*new_events;
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	if (total_fds <= eh->iueh_num_fds)
148*7c478bd9Sstevel@tonic-gate 		return (1);
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	new_pollfds = realloc(eh->iueh_pollfds,
151*7c478bd9Sstevel@tonic-gate 	    total_fds * sizeof (struct pollfd));
152*7c478bd9Sstevel@tonic-gate 	if (new_pollfds == NULL)
153*7c478bd9Sstevel@tonic-gate 		return (0);
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	eh->iueh_pollfds = new_pollfds;
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	new_events = realloc(eh->iueh_events,
158*7c478bd9Sstevel@tonic-gate 	    total_fds * sizeof (iu_event_node_t));
159*7c478bd9Sstevel@tonic-gate 	if (new_events == NULL) {
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 		/*
162*7c478bd9Sstevel@tonic-gate 		 * yow.  one realloc failed, but the other succeeded.
163*7c478bd9Sstevel@tonic-gate 		 * we will just leave the descriptor size at the
164*7c478bd9Sstevel@tonic-gate 		 * original size.  if the caller tries again, then the
165*7c478bd9Sstevel@tonic-gate 		 * first realloc() will do nothing since the requested
166*7c478bd9Sstevel@tonic-gate 		 * number of descriptors is already allocated.
167*7c478bd9Sstevel@tonic-gate 		 */
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 		return (0);
170*7c478bd9Sstevel@tonic-gate 	}
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	for (i = eh->iueh_num_fds; i < total_fds; i++)
173*7c478bd9Sstevel@tonic-gate 		eh->iueh_pollfds[i].fd = -1;
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	eh->iueh_events  = new_events;
176*7c478bd9Sstevel@tonic-gate 	eh->iueh_num_fds = total_fds;
177*7c478bd9Sstevel@tonic-gate 	return (1);
178*7c478bd9Sstevel@tonic-gate }
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate /*
181*7c478bd9Sstevel@tonic-gate  * when increasing the file descriptor set size, how much to increase by:
182*7c478bd9Sstevel@tonic-gate  */
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate #define	EH_FD_SLACK	10
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate /*
187*7c478bd9Sstevel@tonic-gate  * iu_register_event(): adds an event to the set managed by an event handler
188*7c478bd9Sstevel@tonic-gate  *
189*7c478bd9Sstevel@tonic-gate  *   input: iu_eh_t *: the event handler to add the event to
190*7c478bd9Sstevel@tonic-gate  *          int: the descriptor on which to listen for events.  must be
191*7c478bd9Sstevel@tonic-gate  *		 a descriptor which has not yet been registered.
192*7c478bd9Sstevel@tonic-gate  *          short: the events to listen for on that descriptor
193*7c478bd9Sstevel@tonic-gate  *          iu_eh_callback_t: the callback to execute when the event happens
194*7c478bd9Sstevel@tonic-gate  *          void *: the argument to pass to the callback function
195*7c478bd9Sstevel@tonic-gate  *  output: iu_event_id_t: -1 on failure, the new event id otherwise
196*7c478bd9Sstevel@tonic-gate  */
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate iu_event_id_t
iu_register_event(iu_eh_t * eh,int fd,short events,iu_eh_callback_t * callback,void * arg)199*7c478bd9Sstevel@tonic-gate iu_register_event(iu_eh_t *eh, int fd, short events, iu_eh_callback_t *callback,
200*7c478bd9Sstevel@tonic-gate     void *arg)
201*7c478bd9Sstevel@tonic-gate {
202*7c478bd9Sstevel@tonic-gate 	if (eh->iueh_num_fds <= fd)
203*7c478bd9Sstevel@tonic-gate 		if (grow_fds(eh, fd + EH_FD_SLACK) == 0)
204*7c478bd9Sstevel@tonic-gate 			return (-1);
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	/*
207*7c478bd9Sstevel@tonic-gate 	 * the current implementation uses the file descriptor itself
208*7c478bd9Sstevel@tonic-gate 	 * as the iu_event_id_t, since we know the kernel's gonna be
209*7c478bd9Sstevel@tonic-gate 	 * pretty smart about managing file descriptors and we know
210*7c478bd9Sstevel@tonic-gate 	 * that they're per-process unique.  however, it does mean
211*7c478bd9Sstevel@tonic-gate 	 * that the same descriptor cannot be registered multiple
212*7c478bd9Sstevel@tonic-gate 	 * times for different callbacks depending on its events.  if
213*7c478bd9Sstevel@tonic-gate 	 * this behavior is desired, either use dup(2) to get a unique
214*7c478bd9Sstevel@tonic-gate 	 * descriptor, or demultiplex in the callback function based
215*7c478bd9Sstevel@tonic-gate 	 * on `events'.
216*7c478bd9Sstevel@tonic-gate 	 */
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	if (eh->iueh_pollfds[fd].fd != -1)
219*7c478bd9Sstevel@tonic-gate 		return (-1);
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	eh->iueh_pollfds[fd].fd 		= fd;
222*7c478bd9Sstevel@tonic-gate 	eh->iueh_pollfds[fd].events		= events;
223*7c478bd9Sstevel@tonic-gate 	eh->iueh_events[fd].iuen_callback	= callback;
224*7c478bd9Sstevel@tonic-gate 	eh->iueh_events[fd].iuen_arg		= arg;
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	return (fd);
227*7c478bd9Sstevel@tonic-gate }
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate /*
230*7c478bd9Sstevel@tonic-gate  * iu_unregister_event(): removes an event from the set managed by an event
231*7c478bd9Sstevel@tonic-gate  *			  handler
232*7c478bd9Sstevel@tonic-gate  *
233*7c478bd9Sstevel@tonic-gate  *   input: iu_eh_t *: the event handler to remove the event from
234*7c478bd9Sstevel@tonic-gate  *          iu_event_id_t: the event to remove (from iu_register_event())
235*7c478bd9Sstevel@tonic-gate  *          void **: if non-NULL, will be set to point to the argument passed
236*7c478bd9Sstevel@tonic-gate  *                   into iu_register_event()
237*7c478bd9Sstevel@tonic-gate  *  output: int: zero on failure, success otherwise
238*7c478bd9Sstevel@tonic-gate  */
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate int
iu_unregister_event(iu_eh_t * eh,iu_event_id_t event_id,void ** arg)241*7c478bd9Sstevel@tonic-gate iu_unregister_event(iu_eh_t *eh, iu_event_id_t event_id, void **arg)
242*7c478bd9Sstevel@tonic-gate {
243*7c478bd9Sstevel@tonic-gate 	if (event_id < 0 || event_id >= eh->iueh_num_fds ||
244*7c478bd9Sstevel@tonic-gate 	    eh->iueh_pollfds[event_id].fd == -1)
245*7c478bd9Sstevel@tonic-gate 		return (0);
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	/*
248*7c478bd9Sstevel@tonic-gate 	 * fringe condition: in case this event was about to be called
249*7c478bd9Sstevel@tonic-gate 	 * back in iu_handle_events(), zero revents to prevent it.
250*7c478bd9Sstevel@tonic-gate 	 * (having an unregistered event get called back could be
251*7c478bd9Sstevel@tonic-gate 	 * disastrous depending on if `arg' is reference counted).
252*7c478bd9Sstevel@tonic-gate 	 */
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 	eh->iueh_pollfds[event_id].revents = 0;
255*7c478bd9Sstevel@tonic-gate 	eh->iueh_pollfds[event_id].fd = -1;
256*7c478bd9Sstevel@tonic-gate 	if (arg != NULL)
257*7c478bd9Sstevel@tonic-gate 		*arg = eh->iueh_events[event_id].iuen_arg;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	return (1);
260*7c478bd9Sstevel@tonic-gate }
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate /*
263*7c478bd9Sstevel@tonic-gate  * iu_handle_events(): begins handling events on an event handler
264*7c478bd9Sstevel@tonic-gate  *
265*7c478bd9Sstevel@tonic-gate  *   input: iu_eh_t *: the event handler to begin event handling on
266*7c478bd9Sstevel@tonic-gate  *          tq_t *: a timer queue of timers to process while handling events
267*7c478bd9Sstevel@tonic-gate  *                  (see timer_queue.h for details)
268*7c478bd9Sstevel@tonic-gate  *  output: int: the reason why we stopped, -1 if due to internal failure
269*7c478bd9Sstevel@tonic-gate  */
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate int
iu_handle_events(iu_eh_t * eh,iu_tq_t * tq)272*7c478bd9Sstevel@tonic-gate iu_handle_events(iu_eh_t *eh, iu_tq_t *tq)
273*7c478bd9Sstevel@tonic-gate {
274*7c478bd9Sstevel@tonic-gate 	int		n_lit, timeout, sig, saved_errno;
275*7c478bd9Sstevel@tonic-gate 	unsigned int	i;
276*7c478bd9Sstevel@tonic-gate 	sigset_t	oset;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	eh->iueh_stop = B_FALSE;
279*7c478bd9Sstevel@tonic-gate 	do {
280*7c478bd9Sstevel@tonic-gate 		timeout = tq ? iu_earliest_timer(tq) : INFTIM;
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 		/*
283*7c478bd9Sstevel@tonic-gate 		 * we only unblock registered signals around poll(); this
284*7c478bd9Sstevel@tonic-gate 		 * way other parts of the code don't have to worry about
285*7c478bd9Sstevel@tonic-gate 		 * restarting "non-restartable" system calls and so forth.
286*7c478bd9Sstevel@tonic-gate 		 */
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_UNBLOCK, &eh->iueh_sig_regset, &oset);
289*7c478bd9Sstevel@tonic-gate 		n_lit = poll(eh->iueh_pollfds, eh->iueh_num_fds, timeout);
290*7c478bd9Sstevel@tonic-gate 		saved_errno = errno;
291*7c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_SETMASK, &oset, NULL);
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 		switch (n_lit) {
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 		case -1:
296*7c478bd9Sstevel@tonic-gate 			if (saved_errno != EINTR)
297*7c478bd9Sstevel@tonic-gate 				return (-1);
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 			for (sig = 0; sig < NSIG; sig++) {
300*7c478bd9Sstevel@tonic-gate 				if (eh->iueh_sig_info[sig].iues_pending) {
301*7c478bd9Sstevel@tonic-gate 					eh->iueh_sig_info[sig].iues_pending =
302*7c478bd9Sstevel@tonic-gate 					    B_FALSE;
303*7c478bd9Sstevel@tonic-gate 					eh->iueh_sig_info[sig].iues_handler(eh,
304*7c478bd9Sstevel@tonic-gate 					    sig,
305*7c478bd9Sstevel@tonic-gate 					    eh->iueh_sig_info[sig].iues_data);
306*7c478bd9Sstevel@tonic-gate 				}
307*7c478bd9Sstevel@tonic-gate 			}
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 			if (eh->iueh_shutdown != NULL)
310*7c478bd9Sstevel@tonic-gate 				break;
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 			continue;
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 		case  0:
315*7c478bd9Sstevel@tonic-gate 			/*
316*7c478bd9Sstevel@tonic-gate 			 * timeout occurred.  we must have a valid tq pointer
317*7c478bd9Sstevel@tonic-gate 			 * since that's the only way a timeout can happen.
318*7c478bd9Sstevel@tonic-gate 			 */
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 			(void) iu_expire_timers(tq);
321*7c478bd9Sstevel@tonic-gate 			continue;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 		default:
324*7c478bd9Sstevel@tonic-gate 			break;
325*7c478bd9Sstevel@tonic-gate 		}
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 		/* file descriptors are lit; call 'em back */
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < eh->iueh_num_fds && n_lit > 0; i++) {
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 			if (eh->iueh_pollfds[i].revents == 0)
332*7c478bd9Sstevel@tonic-gate 				continue;
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 			n_lit--;
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 			/*
337*7c478bd9Sstevel@tonic-gate 			 * turn off any descriptors that have gone
338*7c478bd9Sstevel@tonic-gate 			 * bad.  shouldn't happen, but...
339*7c478bd9Sstevel@tonic-gate 			 */
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 			if (eh->iueh_pollfds[i].revents & (POLLNVAL|POLLERR)) {
342*7c478bd9Sstevel@tonic-gate 				/* TODO: issue a warning here - but how? */
343*7c478bd9Sstevel@tonic-gate 				(void) iu_unregister_event(eh, i, NULL);
344*7c478bd9Sstevel@tonic-gate 				continue;
345*7c478bd9Sstevel@tonic-gate 			}
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 			eh->iueh_events[i].iuen_callback(eh, i,
348*7c478bd9Sstevel@tonic-gate 			    eh->iueh_pollfds[i].revents, i,
349*7c478bd9Sstevel@tonic-gate 			    eh->iueh_events[i].iuen_arg);
350*7c478bd9Sstevel@tonic-gate 		}
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	} while (eh->iueh_stop == B_FALSE || (eh->iueh_shutdown != NULL &&
353*7c478bd9Sstevel@tonic-gate 	    eh->iueh_shutdown(eh, eh->iueh_shutdown_arg) == B_FALSE));
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	return (eh->iueh_reason);
356*7c478bd9Sstevel@tonic-gate }
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate /*
359*7c478bd9Sstevel@tonic-gate  * post_signal(): posts a signal for later consumption in iu_handle_events()
360*7c478bd9Sstevel@tonic-gate  *
361*7c478bd9Sstevel@tonic-gate  *   input: int: the signal that's been received
362*7c478bd9Sstevel@tonic-gate  *  output: void
363*7c478bd9Sstevel@tonic-gate  */
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate static void
post_signal(int sig)366*7c478bd9Sstevel@tonic-gate post_signal(int sig)
367*7c478bd9Sstevel@tonic-gate {
368*7c478bd9Sstevel@tonic-gate 	if (signal_to_eh[sig] != NULL)
369*7c478bd9Sstevel@tonic-gate 		signal_to_eh[sig]->iueh_sig_info[sig].iues_pending = B_TRUE;
370*7c478bd9Sstevel@tonic-gate }
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate /*
373*7c478bd9Sstevel@tonic-gate  * iu_eh_register_signal(): registers a signal handler with an event handler
374*7c478bd9Sstevel@tonic-gate  *
375*7c478bd9Sstevel@tonic-gate  *   input: iu_eh_t *: the event handler to register the signal handler with
376*7c478bd9Sstevel@tonic-gate  *	    int: the signal to register
377*7c478bd9Sstevel@tonic-gate  *	    iu_eh_sighandler_t *: the signal handler to call back
378*7c478bd9Sstevel@tonic-gate  *	    void *: the argument to pass to the signal handler function
379*7c478bd9Sstevel@tonic-gate  *   output: int: zero on failure, success otherwise
380*7c478bd9Sstevel@tonic-gate  */
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate int
iu_eh_register_signal(iu_eh_t * eh,int sig,iu_eh_sighandler_t * handler,void * data)383*7c478bd9Sstevel@tonic-gate iu_eh_register_signal(iu_eh_t *eh, int sig, iu_eh_sighandler_t *handler,
384*7c478bd9Sstevel@tonic-gate     void *data)
385*7c478bd9Sstevel@tonic-gate {
386*7c478bd9Sstevel@tonic-gate 	struct sigaction	act;
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	if (sig < 0 || sig >= NSIG || signal_to_eh[sig] != NULL)
389*7c478bd9Sstevel@tonic-gate 		return (0);
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	act.sa_flags = 0;
392*7c478bd9Sstevel@tonic-gate 	act.sa_handler = &post_signal;
393*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
394*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, sig); /* used for sigprocmask() */
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	if (sigaction(sig, &act, NULL) == -1)
397*7c478bd9Sstevel@tonic-gate 		return (0);
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &act.sa_mask, NULL);
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	eh->iueh_sig_info[sig].iues_data = data;
402*7c478bd9Sstevel@tonic-gate 	eh->iueh_sig_info[sig].iues_handler = handler;
403*7c478bd9Sstevel@tonic-gate 	signal_to_eh[sig] = eh;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&eh->iueh_sig_regset, sig);
406*7c478bd9Sstevel@tonic-gate 	return (0);
407*7c478bd9Sstevel@tonic-gate }
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate /*
410*7c478bd9Sstevel@tonic-gate  * iu_eh_unregister_signal(): unregisters a signal handler from an event handler
411*7c478bd9Sstevel@tonic-gate  *
412*7c478bd9Sstevel@tonic-gate  *   input: iu_eh_t *: the event handler to unregister the signal handler from
413*7c478bd9Sstevel@tonic-gate  *	    int: the signal to unregister
414*7c478bd9Sstevel@tonic-gate  *	    void **: if non-NULL, will be set to point to the argument passed
415*7c478bd9Sstevel@tonic-gate  *		     into iu_eh_register_signal()
416*7c478bd9Sstevel@tonic-gate  *  output: int: zero on failure, success otherwise
417*7c478bd9Sstevel@tonic-gate  */
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate int
iu_eh_unregister_signal(iu_eh_t * eh,int sig,void ** datap)420*7c478bd9Sstevel@tonic-gate iu_eh_unregister_signal(iu_eh_t *eh, int sig, void **datap)
421*7c478bd9Sstevel@tonic-gate {
422*7c478bd9Sstevel@tonic-gate 	sigset_t	set;
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	if (sig < 0 || sig >= NSIG || signal_to_eh[sig] != eh)
425*7c478bd9Sstevel@tonic-gate 		return (0);
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	if (signal(sig, SIG_DFL) == SIG_ERR)
428*7c478bd9Sstevel@tonic-gate 		return (0);
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	if (datap != NULL)
431*7c478bd9Sstevel@tonic-gate 		*datap = eh->iueh_sig_info[sig].iues_data;
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&set);
434*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&set, sig);
435*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_UNBLOCK, &set, NULL);
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	eh->iueh_sig_info[sig].iues_data = NULL;
438*7c478bd9Sstevel@tonic-gate 	eh->iueh_sig_info[sig].iues_handler = NULL;
439*7c478bd9Sstevel@tonic-gate 	eh->iueh_sig_info[sig].iues_pending = B_FALSE;
440*7c478bd9Sstevel@tonic-gate 	signal_to_eh[sig] = NULL;
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	(void) sigdelset(&eh->iueh_sig_regset, sig);
443*7c478bd9Sstevel@tonic-gate 	return (1);
444*7c478bd9Sstevel@tonic-gate }
445