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