dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.lib / wpad / eloop.c
blobfd0da7c772d2fbc218fda0a35c7f1b83ae1de482
1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
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.
12 #pragma ident "%Z%%M% %I% %E% SMI"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/time.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <signal.h>
21 #include <poll.h>
23 #include "eloop.h"
25 static struct eloop_data eloop;
27 * Initialize global event loop data - must be called before any other eloop_*
28 * function. user_data is a pointer to global data structure and will be passed
29 * as eloop_ctx to signal handlers.
31 void
32 eloop_init(void *user_data)
34 (void) memset(&eloop, 0, sizeof (eloop));
35 eloop.user_data = user_data;
39 * Register handler for read event
41 int
42 eloop_register_read_sock(int sock,
43 void (*handler)(int sock, void *eloop_ctx,
44 void *sock_ctx), void *eloop_data, void *user_data)
46 struct eloop_sock *tmp;
48 tmp = reallocarray(eloop.readers, eloop.reader_count + 1,
49 sizeof(struct eloop_sock));
50 if (tmp == NULL)
51 return (-1);
53 tmp[eloop.reader_count].sock = sock;
54 tmp[eloop.reader_count].eloop_data = eloop_data;
55 tmp[eloop.reader_count].user_data = user_data;
56 tmp[eloop.reader_count].handler = handler;
57 eloop.reader_count++;
58 eloop.readers = tmp;
59 if (sock > eloop.max_sock)
60 eloop.max_sock = sock;
62 return (0);
65 void
66 eloop_unregister_read_sock(int sock)
68 int i;
70 if (eloop.readers == NULL || eloop.reader_count == 0)
71 return;
73 for (i = 0; i < eloop.reader_count; i++) {
74 if (eloop.readers[i].sock == sock)
75 break;
77 if (i == eloop.reader_count)
78 return;
79 if (i != eloop.reader_count - 1) {
80 (void) memmove(&eloop.readers[i], &eloop.readers[i + 1],
81 (eloop.reader_count - i - 1) *
82 sizeof (struct eloop_sock));
84 eloop.reader_count--;
88 * Register timeout routines
90 int
91 eloop_register_timeout(unsigned int secs, unsigned int usecs,
92 void (*handler)(void *eloop_ctx, void *timeout_ctx),
93 void *eloop_data, void *user_data)
95 struct eloop_timeout *timeout, *tmp, *prev;
97 timeout = (struct eloop_timeout *)malloc(sizeof (*timeout));
98 if (timeout == NULL)
99 return (-1);
100 (void) gettimeofday(&timeout->time, NULL);
101 timeout->time.tv_sec += secs;
102 timeout->time.tv_usec += usecs;
103 while (timeout->time.tv_usec >= 1000000) {
104 timeout->time.tv_sec++;
105 timeout->time.tv_usec -= 1000000;
107 timeout->eloop_data = eloop_data;
108 timeout->user_data = user_data;
109 timeout->handler = handler;
110 timeout->next = NULL;
112 if (eloop.timeout == NULL) {
113 eloop.timeout = timeout;
114 return (0);
117 prev = NULL;
118 tmp = eloop.timeout;
119 while (tmp != NULL) {
120 if (timercmp(&timeout->time, &tmp->time, < /* */))
121 break;
122 prev = tmp;
123 tmp = tmp->next;
126 if (prev == NULL) {
127 timeout->next = eloop.timeout;
128 eloop.timeout = timeout;
129 } else {
130 timeout->next = prev->next;
131 prev->next = timeout;
134 return (0);
138 * Cancel timeouts matching <handler,eloop_data,user_data>.
139 * ELOOP_ALL_CTX can be used as a wildcard for cancelling all timeouts
140 * regardless of eloop_data/user_data.
142 void
143 eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
144 void *eloop_data, void *user_data)
146 struct eloop_timeout *timeout, *prev, *next;
148 prev = NULL;
149 timeout = eloop.timeout;
150 while (timeout != NULL) {
151 next = timeout->next;
153 if (timeout->handler == handler &&
154 (timeout->eloop_data == eloop_data ||
155 eloop_data == ELOOP_ALL_CTX) &&
156 (timeout->user_data == user_data ||
157 user_data == ELOOP_ALL_CTX)) {
158 if (prev == NULL)
159 eloop.timeout = next;
160 else
161 prev->next = next;
162 free(timeout);
163 } else
164 prev = timeout;
166 timeout = next;
170 static void eloop_handle_signal(int sig)
172 int i;
174 eloop.signaled++;
175 for (i = 0; i < eloop.signal_count; i++) {
176 if (eloop.signals[i].sig == sig) {
177 eloop.signals[i].signaled++;
178 break;
183 static void eloop_process_pending_signals(void)
185 int i;
187 if (eloop.signaled == 0)
188 return;
189 eloop.signaled = 0;
191 for (i = 0; i < eloop.signal_count; i++) {
192 if (eloop.signals[i].signaled) {
193 eloop.signals[i].signaled = 0;
194 eloop.signals[i].handler(eloop.signals[i].sig,
195 eloop.user_data, eloop.signals[i].user_data);
201 * Register handler for signal.
202 * Note: signals are 'global' events and there is no local eloop_data pointer
203 * like with other handlers. The (global) pointer given to eloop_init() will be
204 * used as eloop_ctx for signal handlers.
207 eloop_register_signal(int sig,
208 void (*handler)(int sig, void *eloop_ctx, void *signal_ctx),
209 void *user_data)
211 struct eloop_signal *tmp;
213 tmp = (struct eloop_signal *)
214 reallocarray(eloop.signals, eloop.signal_count + 1,
215 sizeof(struct eloop_signal));
216 if (tmp == NULL)
217 return (-1);
219 tmp[eloop.signal_count].sig = sig;
220 tmp[eloop.signal_count].user_data = user_data;
221 tmp[eloop.signal_count].handler = handler;
222 tmp[eloop.signal_count].signaled = 0;
223 eloop.signal_count++;
224 eloop.signals = tmp;
225 (void) signal(sig, eloop_handle_signal);
227 return (0);
231 * Start event loop and continue running as long as there are any registered
232 * event handlers.
234 void
235 eloop_run(void)
237 struct pollfd pfds[MAX_POLLFDS]; /* array of polled fd */
238 int i, res;
239 int default_t, t;
240 struct timeval tv, now;
242 default_t = 5 * 1000; /* 5 seconds */
243 while (!eloop.terminate &&
244 (eloop.timeout || eloop.reader_count > 0)) {
245 if (eloop.timeout) {
246 (void) gettimeofday(&now, NULL);
247 if (timercmp(&now, &eloop.timeout->time, < /* */))
248 timersub(&eloop.timeout->time, &now, &tv);
249 else
250 tv.tv_sec = tv.tv_usec = 0;
253 t = (eloop.timeout == NULL ?
254 default_t : (tv.tv_sec * 1000 + tv.tv_usec / 1000));
255 for (i = 0; i < eloop.reader_count; i++) {
256 pfds[i].fd = eloop.readers[i].sock;
257 pfds[i].events = POLLIN | POLLPRI;
259 res = poll(pfds, eloop.reader_count, t);
260 if (res < 0 && errno != EINTR)
261 return;
263 eloop_process_pending_signals();
265 /* check if some registered timeouts have occurred */
266 if (eloop.timeout) {
267 struct eloop_timeout *tmp;
269 (void) gettimeofday(&now, NULL);
270 if (!timercmp(&now, &eloop.timeout->time, < /* */)) {
271 tmp = eloop.timeout;
272 eloop.timeout = eloop.timeout->next;
273 tmp->handler(tmp->eloop_data, tmp->user_data);
274 free(tmp);
279 if (res <= 0)
280 continue;
282 for (i = 0; i < eloop.reader_count; i++) {
283 if (pfds[i].revents) {
284 eloop.readers[i].handler(
285 eloop.readers[i].sock,
286 eloop.readers[i].eloop_data,
287 eloop.readers[i].user_data);
294 * Terminate event loop even if there are registered events.
296 void
297 eloop_terminate(void)
299 eloop.terminate = 1;
304 * Free any reserved resources. After calling eloop_destoy(), other eloop_*
305 * functions must not be called before re-running eloop_init().
307 void
308 eloop_destroy(void)
310 struct eloop_timeout *timeout, *prev;
312 timeout = eloop.timeout;
313 while (timeout != NULL) {
314 prev = timeout;
315 timeout = timeout->next;
316 free(prev);
318 free(eloop.readers);
319 free(eloop.signals);