Reduce amount of macro magic. Use the same special characters as nroff
[netbsd-mini2440.git] / dist / wpa / src / utils / eloop.c
blob4edb2a7033964d2479e53fefd910ac3b6f1e36a1
1 /*
2 * Event loop based on select() loop
3 * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include "includes.h"
17 #include "common.h"
18 #include "eloop.h"
21 struct eloop_sock {
22 int sock;
23 void *eloop_data;
24 void *user_data;
25 eloop_sock_handler handler;
28 struct eloop_timeout {
29 struct os_time time;
30 void *eloop_data;
31 void *user_data;
32 eloop_timeout_handler handler;
33 struct eloop_timeout *next;
36 struct eloop_signal {
37 int sig;
38 void *user_data;
39 eloop_signal_handler handler;
40 int signaled;
43 struct eloop_sock_table {
44 int count;
45 struct eloop_sock *table;
46 int changed;
49 struct eloop_data {
50 void *user_data;
52 int max_sock;
54 struct eloop_sock_table readers;
55 struct eloop_sock_table writers;
56 struct eloop_sock_table exceptions;
58 struct eloop_timeout *timeout;
60 int signal_count;
61 struct eloop_signal *signals;
62 int signaled;
63 int pending_terminate;
65 int terminate;
66 int reader_table_changed;
69 static struct eloop_data eloop;
72 int eloop_init(void *user_data)
74 os_memset(&eloop, 0, sizeof(eloop));
75 eloop.user_data = user_data;
76 return 0;
80 static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
81 int sock, eloop_sock_handler handler,
82 void *eloop_data, void *user_data)
84 struct eloop_sock *tmp;
86 if (table == NULL)
87 return -1;
89 tmp = (struct eloop_sock *)
90 os_realloc(table->table,
91 (table->count + 1) * sizeof(struct eloop_sock));
92 if (tmp == NULL)
93 return -1;
95 tmp[table->count].sock = sock;
96 tmp[table->count].eloop_data = eloop_data;
97 tmp[table->count].user_data = user_data;
98 tmp[table->count].handler = handler;
99 table->count++;
100 table->table = tmp;
101 if (sock > eloop.max_sock)
102 eloop.max_sock = sock;
103 table->changed = 1;
105 return 0;
109 static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
110 int sock)
112 int i;
114 if (table == NULL || table->table == NULL || table->count == 0)
115 return;
117 for (i = 0; i < table->count; i++) {
118 if (table->table[i].sock == sock)
119 break;
121 if (i == table->count)
122 return;
123 if (i != table->count - 1) {
124 os_memmove(&table->table[i], &table->table[i + 1],
125 (table->count - i - 1) *
126 sizeof(struct eloop_sock));
128 table->count--;
129 table->changed = 1;
133 static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
134 fd_set *fds)
136 int i;
138 FD_ZERO(fds);
140 if (table->table == NULL)
141 return;
143 for (i = 0; i < table->count; i++)
144 FD_SET(table->table[i].sock, fds);
148 static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
149 fd_set *fds)
151 int i;
153 if (table == NULL || table->table == NULL)
154 return;
156 table->changed = 0;
157 for (i = 0; i < table->count; i++) {
158 if (FD_ISSET(table->table[i].sock, fds)) {
159 table->table[i].handler(table->table[i].sock,
160 table->table[i].eloop_data,
161 table->table[i].user_data);
162 if (table->changed)
163 break;
169 static void eloop_sock_table_destroy(struct eloop_sock_table *table)
171 if (table) {
172 int i;
173 for (i = 0; i < table->count && table->table; i++) {
174 printf("ELOOP: remaining socket: sock=%d "
175 "eloop_data=%p user_data=%p handler=%p\n",
176 table->table[i].sock,
177 table->table[i].eloop_data,
178 table->table[i].user_data,
179 table->table[i].handler);
181 os_free(table->table);
186 int eloop_register_read_sock(int sock, eloop_sock_handler handler,
187 void *eloop_data, void *user_data)
189 return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
190 eloop_data, user_data);
194 void eloop_unregister_read_sock(int sock)
196 eloop_unregister_sock(sock, EVENT_TYPE_READ);
200 static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
202 switch (type) {
203 case EVENT_TYPE_READ:
204 return &eloop.readers;
205 case EVENT_TYPE_WRITE:
206 return &eloop.writers;
207 case EVENT_TYPE_EXCEPTION:
208 return &eloop.exceptions;
211 return NULL;
215 int eloop_register_sock(int sock, eloop_event_type type,
216 eloop_sock_handler handler,
217 void *eloop_data, void *user_data)
219 struct eloop_sock_table *table;
221 table = eloop_get_sock_table(type);
222 return eloop_sock_table_add_sock(table, sock, handler,
223 eloop_data, user_data);
227 void eloop_unregister_sock(int sock, eloop_event_type type)
229 struct eloop_sock_table *table;
231 table = eloop_get_sock_table(type);
232 eloop_sock_table_remove_sock(table, sock);
236 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
237 eloop_timeout_handler handler,
238 void *eloop_data, void *user_data)
240 struct eloop_timeout *timeout, *tmp, *prev;
242 timeout = os_malloc(sizeof(*timeout));
243 if (timeout == NULL)
244 return -1;
245 if (os_get_time(&timeout->time) < 0) {
246 os_free(timeout);
247 return -1;
249 timeout->time.sec += secs;
250 timeout->time.usec += usecs;
251 while (timeout->time.usec >= 1000000) {
252 timeout->time.sec++;
253 timeout->time.usec -= 1000000;
255 timeout->eloop_data = eloop_data;
256 timeout->user_data = user_data;
257 timeout->handler = handler;
258 timeout->next = NULL;
260 if (eloop.timeout == NULL) {
261 eloop.timeout = timeout;
262 return 0;
265 prev = NULL;
266 tmp = eloop.timeout;
267 while (tmp != NULL) {
268 if (os_time_before(&timeout->time, &tmp->time))
269 break;
270 prev = tmp;
271 tmp = tmp->next;
274 if (prev == NULL) {
275 timeout->next = eloop.timeout;
276 eloop.timeout = timeout;
277 } else {
278 timeout->next = prev->next;
279 prev->next = timeout;
282 return 0;
286 int eloop_cancel_timeout(eloop_timeout_handler handler,
287 void *eloop_data, void *user_data)
289 struct eloop_timeout *timeout, *prev, *next;
290 int removed = 0;
292 prev = NULL;
293 timeout = eloop.timeout;
294 while (timeout != NULL) {
295 next = timeout->next;
297 if (timeout->handler == handler &&
298 (timeout->eloop_data == eloop_data ||
299 eloop_data == ELOOP_ALL_CTX) &&
300 (timeout->user_data == user_data ||
301 user_data == ELOOP_ALL_CTX)) {
302 if (prev == NULL)
303 eloop.timeout = next;
304 else
305 prev->next = next;
306 os_free(timeout);
307 removed++;
308 } else
309 prev = timeout;
311 timeout = next;
314 return removed;
318 int eloop_is_timeout_registered(eloop_timeout_handler handler,
319 void *eloop_data, void *user_data)
321 struct eloop_timeout *tmp;
323 tmp = eloop.timeout;
324 while (tmp != NULL) {
325 if (tmp->handler == handler &&
326 tmp->eloop_data == eloop_data &&
327 tmp->user_data == user_data)
328 return 1;
330 tmp = tmp->next;
333 return 0;
337 #ifndef CONFIG_NATIVE_WINDOWS
338 static void eloop_handle_alarm(int sig)
340 fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
341 "seconds. Looks like there\n"
342 "is a bug that ends up in a busy loop that "
343 "prevents clean shutdown.\n"
344 "Killing program forcefully.\n");
345 exit(1);
347 #endif /* CONFIG_NATIVE_WINDOWS */
350 static void eloop_handle_signal(int sig)
352 int i;
354 #ifndef CONFIG_NATIVE_WINDOWS
355 if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
356 /* Use SIGALRM to break out from potential busy loops that
357 * would not allow the program to be killed. */
358 eloop.pending_terminate = 1;
359 signal(SIGALRM, eloop_handle_alarm);
360 alarm(2);
362 #endif /* CONFIG_NATIVE_WINDOWS */
364 eloop.signaled++;
365 for (i = 0; i < eloop.signal_count; i++) {
366 if (eloop.signals[i].sig == sig) {
367 eloop.signals[i].signaled++;
368 break;
374 static void eloop_process_pending_signals(void)
376 int i;
378 if (eloop.signaled == 0)
379 return;
380 eloop.signaled = 0;
382 if (eloop.pending_terminate) {
383 #ifndef CONFIG_NATIVE_WINDOWS
384 alarm(0);
385 #endif /* CONFIG_NATIVE_WINDOWS */
386 eloop.pending_terminate = 0;
389 for (i = 0; i < eloop.signal_count; i++) {
390 if (eloop.signals[i].signaled) {
391 eloop.signals[i].signaled = 0;
392 eloop.signals[i].handler(eloop.signals[i].sig,
393 eloop.user_data,
394 eloop.signals[i].user_data);
400 int eloop_register_signal(int sig, eloop_signal_handler handler,
401 void *user_data)
403 struct eloop_signal *tmp;
405 tmp = (struct eloop_signal *)
406 os_realloc(eloop.signals,
407 (eloop.signal_count + 1) *
408 sizeof(struct eloop_signal));
409 if (tmp == NULL)
410 return -1;
412 tmp[eloop.signal_count].sig = sig;
413 tmp[eloop.signal_count].user_data = user_data;
414 tmp[eloop.signal_count].handler = handler;
415 tmp[eloop.signal_count].signaled = 0;
416 eloop.signal_count++;
417 eloop.signals = tmp;
418 signal(sig, eloop_handle_signal);
420 return 0;
424 int eloop_register_signal_terminate(eloop_signal_handler handler,
425 void *user_data)
427 int ret = eloop_register_signal(SIGINT, handler, user_data);
428 if (ret == 0)
429 ret = eloop_register_signal(SIGTERM, handler, user_data);
430 return ret;
434 int eloop_register_signal_reconfig(eloop_signal_handler handler,
435 void *user_data)
437 #ifdef CONFIG_NATIVE_WINDOWS
438 return 0;
439 #else /* CONFIG_NATIVE_WINDOWS */
440 return eloop_register_signal(SIGHUP, handler, user_data);
441 #endif /* CONFIG_NATIVE_WINDOWS */
445 void eloop_run(void)
447 fd_set *rfds, *wfds, *efds;
448 int res;
449 struct timeval _tv;
450 struct os_time tv, now;
452 rfds = os_malloc(sizeof(*rfds));
453 wfds = os_malloc(sizeof(*wfds));
454 efds = os_malloc(sizeof(*efds));
455 if (rfds == NULL || wfds == NULL || efds == NULL) {
456 printf("eloop_run - malloc failed\n");
457 goto out;
460 while (!eloop.terminate &&
461 (eloop.timeout || eloop.readers.count > 0 ||
462 eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
463 if (eloop.timeout) {
464 os_get_time(&now);
465 if (os_time_before(&now, &eloop.timeout->time))
466 os_time_sub(&eloop.timeout->time, &now, &tv);
467 else
468 tv.sec = tv.usec = 0;
469 #if 0
470 printf("next timeout in %lu.%06lu sec\n",
471 tv.sec, tv.usec);
472 #endif
473 _tv.tv_sec = tv.sec;
474 _tv.tv_usec = tv.usec;
477 eloop_sock_table_set_fds(&eloop.readers, rfds);
478 eloop_sock_table_set_fds(&eloop.writers, wfds);
479 eloop_sock_table_set_fds(&eloop.exceptions, efds);
480 res = select(eloop.max_sock + 1, rfds, wfds, efds,
481 eloop.timeout ? &_tv : NULL);
482 if (res < 0 && errno != EINTR && errno != 0) {
483 perror("select");
484 goto out;
486 eloop_process_pending_signals();
488 /* check if some registered timeouts have occurred */
489 if (eloop.timeout) {
490 struct eloop_timeout *tmp;
492 os_get_time(&now);
493 if (!os_time_before(&now, &eloop.timeout->time)) {
494 tmp = eloop.timeout;
495 eloop.timeout = eloop.timeout->next;
496 tmp->handler(tmp->eloop_data,
497 tmp->user_data);
498 os_free(tmp);
503 if (res <= 0)
504 continue;
506 eloop_sock_table_dispatch(&eloop.readers, rfds);
507 eloop_sock_table_dispatch(&eloop.writers, wfds);
508 eloop_sock_table_dispatch(&eloop.exceptions, efds);
511 out:
512 os_free(rfds);
513 os_free(wfds);
514 os_free(efds);
518 void eloop_terminate(void)
520 eloop.terminate = 1;
524 void eloop_destroy(void)
526 struct eloop_timeout *timeout, *prev;
527 struct os_time now;
529 timeout = eloop.timeout;
530 if (timeout)
531 os_get_time(&now);
532 while (timeout != NULL) {
533 int sec, usec;
534 prev = timeout;
535 timeout = timeout->next;
536 sec = prev->time.sec - now.sec;
537 usec = prev->time.usec - now.usec;
538 if (prev->time.usec < now.usec) {
539 sec--;
540 usec += 1000000;
542 printf("ELOOP: remaining timeout: %d.%06d eloop_data=%p "
543 "user_data=%p handler=%p\n",
544 sec, usec, prev->eloop_data, prev->user_data,
545 prev->handler);
546 os_free(prev);
548 eloop_sock_table_destroy(&eloop.readers);
549 eloop_sock_table_destroy(&eloop.writers);
550 eloop_sock_table_destroy(&eloop.exceptions);
551 os_free(eloop.signals);
555 int eloop_terminated(void)
557 return eloop.terminate;
561 void eloop_wait_for_read_sock(int sock)
563 fd_set rfds;
565 if (sock < 0)
566 return;
568 FD_ZERO(&rfds);
569 FD_SET(sock, &rfds);
570 select(sock + 1, &rfds, NULL, NULL, NULL);
574 void * eloop_get_user_data(void)
576 return eloop.user_data;