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