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