1*4126Szf162725 /*
2*4126Szf162725  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3*4126Szf162725  * Use is subject to license terms.
4*4126Szf162725  */
5*4126Szf162725 
6*4126Szf162725 /*
7*4126Szf162725  * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
8*4126Szf162725  * Sun elects to license this software under the BSD license.
9*4126Szf162725  * See README for more details.
10*4126Szf162725  */
11*4126Szf162725 
12*4126Szf162725 #pragma ident	"%Z%%M%	%I%	%E% SMI"
13*4126Szf162725 
14*4126Szf162725 #include <stdio.h>
15*4126Szf162725 #include <stdlib.h>
16*4126Szf162725 #include <string.h>
17*4126Szf162725 #include <sys/time.h>
18*4126Szf162725 #include <unistd.h>
19*4126Szf162725 #include <errno.h>
20*4126Szf162725 #include <signal.h>
21*4126Szf162725 #include <poll.h>
22*4126Szf162725 
23*4126Szf162725 #include "eloop.h"
24*4126Szf162725 
25*4126Szf162725 static struct eloop_data eloop;
26*4126Szf162725 /*
27*4126Szf162725  * Initialize global event loop data - must be called before any other eloop_*
28*4126Szf162725  * function. user_data is a pointer to global data structure and will be passed
29*4126Szf162725  * as eloop_ctx to signal handlers.
30*4126Szf162725  */
31*4126Szf162725 void
32*4126Szf162725 eloop_init(void *user_data)
33*4126Szf162725 {
34*4126Szf162725 	(void) memset(&eloop, 0, sizeof (eloop));
35*4126Szf162725 	eloop.user_data = user_data;
36*4126Szf162725 }
37*4126Szf162725 
38*4126Szf162725 /*
39*4126Szf162725  * Register handler for read event
40*4126Szf162725  */
41*4126Szf162725 int
42*4126Szf162725 eloop_register_read_sock(int sock,
43*4126Szf162725     void (*handler)(int sock, void *eloop_ctx,
44*4126Szf162725     void *sock_ctx), void *eloop_data, void *user_data)
45*4126Szf162725 {
46*4126Szf162725 	struct eloop_sock *tmp;
47*4126Szf162725 
48*4126Szf162725 	tmp = (struct eloop_sock *)realloc(eloop.readers,
49*4126Szf162725 	    (eloop.reader_count + 1) * sizeof (struct eloop_sock));
50*4126Szf162725 	if (tmp == NULL)
51*4126Szf162725 		return (-1);
52*4126Szf162725 
53*4126Szf162725 	tmp[eloop.reader_count].sock = sock;
54*4126Szf162725 	tmp[eloop.reader_count].eloop_data = eloop_data;
55*4126Szf162725 	tmp[eloop.reader_count].user_data = user_data;
56*4126Szf162725 	tmp[eloop.reader_count].handler = handler;
57*4126Szf162725 	eloop.reader_count++;
58*4126Szf162725 	eloop.readers = tmp;
59*4126Szf162725 	if (sock > eloop.max_sock)
60*4126Szf162725 		eloop.max_sock = sock;
61*4126Szf162725 
62*4126Szf162725 	return (0);
63*4126Szf162725 }
64*4126Szf162725 
65*4126Szf162725 void
66*4126Szf162725 eloop_unregister_read_sock(int sock)
67*4126Szf162725 {
68*4126Szf162725 	int i;
69*4126Szf162725 
70*4126Szf162725 	if (eloop.readers == NULL || eloop.reader_count == 0)
71*4126Szf162725 		return;
72*4126Szf162725 
73*4126Szf162725 	for (i = 0; i < eloop.reader_count; i++) {
74*4126Szf162725 		if (eloop.readers[i].sock == sock)
75*4126Szf162725 			break;
76*4126Szf162725 	}
77*4126Szf162725 	if (i == eloop.reader_count)
78*4126Szf162725 		return;
79*4126Szf162725 	if (i != eloop.reader_count - 1) {
80*4126Szf162725 		(void) memmove(&eloop.readers[i], &eloop.readers[i + 1],
81*4126Szf162725 		    (eloop.reader_count - i - 1) *
82*4126Szf162725 		    sizeof (struct eloop_sock));
83*4126Szf162725 	}
84*4126Szf162725 	eloop.reader_count--;
85*4126Szf162725 }
86*4126Szf162725 
87*4126Szf162725 /*
88*4126Szf162725  * Register timeout routines
89*4126Szf162725  */
90*4126Szf162725 int
91*4126Szf162725 eloop_register_timeout(unsigned int secs, unsigned int usecs,
92*4126Szf162725     void (*handler)(void *eloop_ctx, void *timeout_ctx),
93*4126Szf162725     void *eloop_data, void *user_data)
94*4126Szf162725 {
95*4126Szf162725 	struct eloop_timeout *timeout, *tmp, *prev;
96*4126Szf162725 
97*4126Szf162725 	timeout = (struct eloop_timeout *)malloc(sizeof (*timeout));
98*4126Szf162725 	if (timeout == NULL)
99*4126Szf162725 		return (-1);
100*4126Szf162725 	(void) gettimeofday(&timeout->time, NULL);
101*4126Szf162725 	timeout->time.tv_sec += secs;
102*4126Szf162725 	timeout->time.tv_usec += usecs;
103*4126Szf162725 	while (timeout->time.tv_usec >= 1000000) {
104*4126Szf162725 		timeout->time.tv_sec++;
105*4126Szf162725 		timeout->time.tv_usec -= 1000000;
106*4126Szf162725 	}
107*4126Szf162725 	timeout->eloop_data = eloop_data;
108*4126Szf162725 	timeout->user_data = user_data;
109*4126Szf162725 	timeout->handler = handler;
110*4126Szf162725 	timeout->next = NULL;
111*4126Szf162725 
112*4126Szf162725 	if (eloop.timeout == NULL) {
113*4126Szf162725 		eloop.timeout = timeout;
114*4126Szf162725 		return (0);
115*4126Szf162725 	}
116*4126Szf162725 
117*4126Szf162725 	prev = NULL;
118*4126Szf162725 	tmp = eloop.timeout;
119*4126Szf162725 	while (tmp != NULL) {
120*4126Szf162725 		if (timercmp(&timeout->time, &tmp->time, < /* */))
121*4126Szf162725 			break;
122*4126Szf162725 		prev = tmp;
123*4126Szf162725 		tmp = tmp->next;
124*4126Szf162725 	}
125*4126Szf162725 
126*4126Szf162725 	if (prev == NULL) {
127*4126Szf162725 		timeout->next = eloop.timeout;
128*4126Szf162725 		eloop.timeout = timeout;
129*4126Szf162725 	} else {
130*4126Szf162725 		timeout->next = prev->next;
131*4126Szf162725 		prev->next = timeout;
132*4126Szf162725 	}
133*4126Szf162725 
134*4126Szf162725 	return (0);
135*4126Szf162725 }
136*4126Szf162725 
137*4126Szf162725 /*
138*4126Szf162725  * Cancel timeouts matching <handler,eloop_data,user_data>.
139*4126Szf162725  * ELOOP_ALL_CTX can be used as a wildcard for cancelling all timeouts
140*4126Szf162725  * regardless of eloop_data/user_data.
141*4126Szf162725  */
142*4126Szf162725 void
143*4126Szf162725 eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
144*4126Szf162725     void *eloop_data, void *user_data)
145*4126Szf162725 {
146*4126Szf162725 	struct eloop_timeout *timeout, *prev, *next;
147*4126Szf162725 
148*4126Szf162725 	prev = NULL;
149*4126Szf162725 	timeout = eloop.timeout;
150*4126Szf162725 	while (timeout != NULL) {
151*4126Szf162725 		next = timeout->next;
152*4126Szf162725 
153*4126Szf162725 		if (timeout->handler == handler &&
154*4126Szf162725 		    (timeout->eloop_data == eloop_data ||
155*4126Szf162725 		    eloop_data == ELOOP_ALL_CTX) &&
156*4126Szf162725 		    (timeout->user_data == user_data ||
157*4126Szf162725 		    user_data == ELOOP_ALL_CTX)) {
158*4126Szf162725 			if (prev == NULL)
159*4126Szf162725 				eloop.timeout = next;
160*4126Szf162725 			else
161*4126Szf162725 				prev->next = next;
162*4126Szf162725 			free(timeout);
163*4126Szf162725 		} else
164*4126Szf162725 			prev = timeout;
165*4126Szf162725 
166*4126Szf162725 		timeout = next;
167*4126Szf162725 	}
168*4126Szf162725 }
169*4126Szf162725 
170*4126Szf162725 static void eloop_handle_signal(int sig)
171*4126Szf162725 {
172*4126Szf162725 	int i;
173*4126Szf162725 
174*4126Szf162725 	eloop.signaled++;
175*4126Szf162725 	for (i = 0; i < eloop.signal_count; i++) {
176*4126Szf162725 		if (eloop.signals[i].sig == sig) {
177*4126Szf162725 			eloop.signals[i].signaled++;
178*4126Szf162725 			break;
179*4126Szf162725 		}
180*4126Szf162725 	}
181*4126Szf162725 }
182*4126Szf162725 
183*4126Szf162725 static void eloop_process_pending_signals(void)
184*4126Szf162725 {
185*4126Szf162725 	int i;
186*4126Szf162725 
187*4126Szf162725 	if (eloop.signaled == 0)
188*4126Szf162725 		return;
189*4126Szf162725 	eloop.signaled = 0;
190*4126Szf162725 
191*4126Szf162725 	for (i = 0; i < eloop.signal_count; i++) {
192*4126Szf162725 		if (eloop.signals[i].signaled) {
193*4126Szf162725 			eloop.signals[i].signaled = 0;
194*4126Szf162725 			eloop.signals[i].handler(eloop.signals[i].sig,
195*4126Szf162725 			    eloop.user_data, eloop.signals[i].user_data);
196*4126Szf162725 		}
197*4126Szf162725 	}
198*4126Szf162725 }
199*4126Szf162725 
200*4126Szf162725 /*
201*4126Szf162725  * Register handler for signal.
202*4126Szf162725  * Note: signals are 'global' events and there is no local eloop_data pointer
203*4126Szf162725  * like with other handlers. The (global) pointer given to eloop_init() will be
204*4126Szf162725  * used as eloop_ctx for signal handlers.
205*4126Szf162725  */
206*4126Szf162725 int
207*4126Szf162725 eloop_register_signal(int sig,
208*4126Szf162725     void (*handler)(int sig, void *eloop_ctx, void *signal_ctx),
209*4126Szf162725     void *user_data)
210*4126Szf162725 {
211*4126Szf162725 	struct eloop_signal *tmp;
212*4126Szf162725 
213*4126Szf162725 	tmp = (struct eloop_signal *)
214*4126Szf162725 	    realloc(eloop.signals,
215*4126Szf162725 	    (eloop.signal_count + 1) *
216*4126Szf162725 	    sizeof (struct eloop_signal));
217*4126Szf162725 	if (tmp == NULL)
218*4126Szf162725 		return (-1);
219*4126Szf162725 
220*4126Szf162725 	tmp[eloop.signal_count].sig = sig;
221*4126Szf162725 	tmp[eloop.signal_count].user_data = user_data;
222*4126Szf162725 	tmp[eloop.signal_count].handler = handler;
223*4126Szf162725 	tmp[eloop.signal_count].signaled = 0;
224*4126Szf162725 	eloop.signal_count++;
225*4126Szf162725 	eloop.signals = tmp;
226*4126Szf162725 	(void) signal(sig, eloop_handle_signal);
227*4126Szf162725 
228*4126Szf162725 	return (0);
229*4126Szf162725 }
230*4126Szf162725 
231*4126Szf162725 /*
232*4126Szf162725  * Start event loop and continue running as long as there are any registered
233*4126Szf162725  * event handlers.
234*4126Szf162725  */
235*4126Szf162725 void
236*4126Szf162725 eloop_run(void)
237*4126Szf162725 {
238*4126Szf162725 	struct pollfd pfds[MAX_POLLFDS];	/* array of polled fd */
239*4126Szf162725 	int i, res;
240*4126Szf162725 	int default_t, t;
241*4126Szf162725 	struct timeval tv, now;
242*4126Szf162725 
243*4126Szf162725 	default_t = 5 * 1000;	/* 5 seconds */
244*4126Szf162725 	while (!eloop.terminate &&
245*4126Szf162725 		(eloop.timeout || eloop.reader_count > 0)) {
246*4126Szf162725 		if (eloop.timeout) {
247*4126Szf162725 			(void) gettimeofday(&now, NULL);
248*4126Szf162725 			if (timercmp(&now, &eloop.timeout->time, < /* */))
249*4126Szf162725 				/* LINTED E_CONSTANT_CONDITION */
250*4126Szf162725 				timersub(&eloop.timeout->time, &now, &tv);
251*4126Szf162725 			else
252*4126Szf162725 				tv.tv_sec = tv.tv_usec = 0;
253*4126Szf162725 		}
254*4126Szf162725 
255*4126Szf162725 		t = (eloop.timeout == NULL ?
256*4126Szf162725 		    default_t : (tv.tv_sec * 1000 + tv.tv_usec / 1000));
257*4126Szf162725 		for (i = 0; i < eloop.reader_count; i++) {
258*4126Szf162725 			pfds[i].fd = eloop.readers[i].sock;
259*4126Szf162725 			pfds[i].events = POLLIN | POLLPRI;
260*4126Szf162725 		}
261*4126Szf162725 		res = poll(pfds, eloop.reader_count, t);
262*4126Szf162725 		if (res < 0 && errno != EINTR)
263*4126Szf162725 			return;
264*4126Szf162725 
265*4126Szf162725 		eloop_process_pending_signals();
266*4126Szf162725 
267*4126Szf162725 		/* check if some registered timeouts have occurred */
268*4126Szf162725 		if (eloop.timeout) {
269*4126Szf162725 			struct eloop_timeout *tmp;
270*4126Szf162725 
271*4126Szf162725 			(void) gettimeofday(&now, NULL);
272*4126Szf162725 			if (!timercmp(&now, &eloop.timeout->time, < /* */)) {
273*4126Szf162725 				tmp = eloop.timeout;
274*4126Szf162725 				eloop.timeout = eloop.timeout->next;
275*4126Szf162725 				tmp->handler(tmp->eloop_data, tmp->user_data);
276*4126Szf162725 				free(tmp);
277*4126Szf162725 			}
278*4126Szf162725 
279*4126Szf162725 		}
280*4126Szf162725 
281*4126Szf162725 		if (res <= 0)
282*4126Szf162725 			continue;
283*4126Szf162725 
284*4126Szf162725 		for (i = 0; i < eloop.reader_count; i++) {
285*4126Szf162725 			if (pfds[i].revents) {
286*4126Szf162725 				eloop.readers[i].handler(
287*4126Szf162725 				    eloop.readers[i].sock,
288*4126Szf162725 				    eloop.readers[i].eloop_data,
289*4126Szf162725 				    eloop.readers[i].user_data);
290*4126Szf162725 			}
291*4126Szf162725 		}
292*4126Szf162725 	}
293*4126Szf162725 }
294*4126Szf162725 
295*4126Szf162725 /*
296*4126Szf162725  * Terminate event loop even if there are registered events.
297*4126Szf162725  */
298*4126Szf162725 void
299*4126Szf162725 eloop_terminate(void)
300*4126Szf162725 {
301*4126Szf162725 	eloop.terminate = 1;
302*4126Szf162725 }
303*4126Szf162725 
304*4126Szf162725 
305*4126Szf162725 /*
306*4126Szf162725  * Free any reserved resources. After calling eloop_destoy(), other eloop_*
307*4126Szf162725  * functions must not be called before re-running eloop_init().
308*4126Szf162725  */
309*4126Szf162725 void
310*4126Szf162725 eloop_destroy(void)
311*4126Szf162725 {
312*4126Szf162725 	struct eloop_timeout *timeout, *prev;
313*4126Szf162725 
314*4126Szf162725 	timeout = eloop.timeout;
315*4126Szf162725 	while (timeout != NULL) {
316*4126Szf162725 		prev = timeout;
317*4126Szf162725 		timeout = timeout->next;
318*4126Szf162725 		free(prev);
319*4126Szf162725 	}
320*4126Szf162725 	free(eloop.readers);
321*4126Szf162725 	free(eloop.signals);
322*4126Szf162725 }
323