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
12
* See README and COPYING for more details.
25
eloop_sock_handler handler;
28
struct eloop_timeout {
32
eloop_timeout_handler handler;
33
struct eloop_timeout *next;
39
eloop_signal_handler handler;
43
struct eloop_sock_table {
45
struct eloop_sock *table;
54
struct eloop_sock_table readers;
55
struct eloop_sock_table writers;
56
struct eloop_sock_table exceptions;
58
struct eloop_timeout *timeout;
61
struct eloop_signal *signals;
63
int pending_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;
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;
89
tmp = (struct eloop_sock *)
90
os_realloc(table->table,
91
(table->count + 1) * sizeof(struct eloop_sock));
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;
101
if (sock > eloop.max_sock)
102
eloop.max_sock = sock;
109
static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
114
if (table == NULL || table->table == NULL || table->count == 0)
117
for (i = 0; i < table->count; i++) {
118
if (table->table[i].sock == sock)
121
if (i == table->count)
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));
133
static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
140
if (table->table == NULL)
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,
153
if (table == NULL || table->table == NULL)
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);
169
static void eloop_sock_table_destroy(struct eloop_sock_table *table)
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)
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;
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));
245
os_get_time(&timeout->time);
246
timeout->time.sec += secs;
247
timeout->time.usec += usecs;
248
while (timeout->time.usec >= 1000000) {
250
timeout->time.usec -= 1000000;
252
timeout->eloop_data = eloop_data;
253
timeout->user_data = user_data;
254
timeout->handler = handler;
255
timeout->next = NULL;
257
if (eloop.timeout == NULL) {
258
eloop.timeout = timeout;
264
while (tmp != NULL) {
265
if (os_time_before(&timeout->time, &tmp->time))
272
timeout->next = eloop.timeout;
273
eloop.timeout = timeout;
275
timeout->next = prev->next;
276
prev->next = timeout;
283
int eloop_cancel_timeout(eloop_timeout_handler handler,
284
void *eloop_data, void *user_data)
286
struct eloop_timeout *timeout, *prev, *next;
290
timeout = eloop.timeout;
291
while (timeout != NULL) {
292
next = timeout->next;
294
if (timeout->handler == handler &&
295
(timeout->eloop_data == eloop_data ||
296
eloop_data == ELOOP_ALL_CTX) &&
297
(timeout->user_data == user_data ||
298
user_data == ELOOP_ALL_CTX)) {
300
eloop.timeout = next;
315
#ifndef CONFIG_NATIVE_WINDOWS
316
static void eloop_handle_alarm(int sig)
318
fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
319
"seconds. Looks like there\n"
320
"is a bug that ends up in a busy loop that "
321
"prevents clean shutdown.\n"
322
"Killing program forcefully.\n");
325
#endif /* CONFIG_NATIVE_WINDOWS */
328
static void eloop_handle_signal(int sig)
332
#ifndef CONFIG_NATIVE_WINDOWS
333
if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
334
/* Use SIGALRM to break out from potential busy loops that
335
* would not allow the program to be killed. */
336
eloop.pending_terminate = 1;
337
signal(SIGALRM, eloop_handle_alarm);
340
#endif /* CONFIG_NATIVE_WINDOWS */
343
for (i = 0; i < eloop.signal_count; i++) {
344
if (eloop.signals[i].sig == sig) {
345
eloop.signals[i].signaled++;
352
static void eloop_process_pending_signals(void)
356
if (eloop.signaled == 0)
360
if (eloop.pending_terminate) {
361
#ifndef CONFIG_NATIVE_WINDOWS
363
#endif /* CONFIG_NATIVE_WINDOWS */
364
eloop.pending_terminate = 0;
367
for (i = 0; i < eloop.signal_count; i++) {
368
if (eloop.signals[i].signaled) {
369
eloop.signals[i].signaled = 0;
370
eloop.signals[i].handler(eloop.signals[i].sig,
372
eloop.signals[i].user_data);
378
int eloop_register_signal(int sig, eloop_signal_handler handler,
381
struct eloop_signal *tmp;
383
tmp = (struct eloop_signal *)
384
os_realloc(eloop.signals,
385
(eloop.signal_count + 1) *
386
sizeof(struct eloop_signal));
390
tmp[eloop.signal_count].sig = sig;
391
tmp[eloop.signal_count].user_data = user_data;
392
tmp[eloop.signal_count].handler = handler;
393
tmp[eloop.signal_count].signaled = 0;
394
eloop.signal_count++;
396
signal(sig, eloop_handle_signal);
402
int eloop_register_signal_terminate(eloop_signal_handler handler,
405
int ret = eloop_register_signal(SIGINT, handler, user_data);
407
ret = eloop_register_signal(SIGTERM, handler, user_data);
412
int eloop_register_signal_reconfig(eloop_signal_handler handler,
415
#ifdef CONFIG_NATIVE_WINDOWS
417
#else /* CONFIG_NATIVE_WINDOWS */
418
return eloop_register_signal(SIGHUP, handler, user_data);
419
#endif /* CONFIG_NATIVE_WINDOWS */
425
fd_set *rfds, *wfds, *efds;
428
struct os_time tv, now;
430
rfds = os_malloc(sizeof(*rfds));
431
wfds = os_malloc(sizeof(*wfds));
432
efds = os_malloc(sizeof(*efds));
433
if (rfds == NULL || wfds == NULL || efds == NULL) {
434
printf("eloop_run - malloc failed\n");
438
while (!eloop.terminate &&
439
(eloop.timeout || eloop.readers.count > 0 ||
440
eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
443
if (os_time_before(&now, &eloop.timeout->time))
444
os_time_sub(&eloop.timeout->time, &now, &tv);
446
tv.sec = tv.usec = 0;
448
printf("next timeout in %lu.%06lu sec\n",
452
_tv.tv_usec = tv.usec;
455
eloop_sock_table_set_fds(&eloop.readers, rfds);
456
eloop_sock_table_set_fds(&eloop.writers, wfds);
457
eloop_sock_table_set_fds(&eloop.exceptions, efds);
458
res = select(eloop.max_sock + 1, rfds, wfds, efds,
459
eloop.timeout ? &_tv : NULL);
460
if (res < 0 && errno != EINTR && errno != 0) {
464
eloop_process_pending_signals();
466
/* check if some registered timeouts have occurred */
468
struct eloop_timeout *tmp;
471
if (!os_time_before(&now, &eloop.timeout->time)) {
473
eloop.timeout = eloop.timeout->next;
474
tmp->handler(tmp->eloop_data,
484
eloop_sock_table_dispatch(&eloop.readers, rfds);
485
eloop_sock_table_dispatch(&eloop.writers, wfds);
486
eloop_sock_table_dispatch(&eloop.exceptions, efds);
496
void eloop_terminate(void)
502
void eloop_destroy(void)
504
struct eloop_timeout *timeout, *prev;
507
timeout = eloop.timeout;
510
while (timeout != NULL) {
513
timeout = timeout->next;
514
sec = prev->time.sec - now.sec;
515
usec = prev->time.usec - now.usec;
516
if (prev->time.usec < now.usec) {
520
printf("ELOOP: remaining timeout: %d.%06d eloop_data=%p "
521
"user_data=%p handler=%p\n",
522
sec, usec, prev->eloop_data, prev->user_data,
526
eloop_sock_table_destroy(&eloop.readers);
527
eloop_sock_table_destroy(&eloop.writers);
528
eloop_sock_table_destroy(&eloop.exceptions);
529
os_free(eloop.signals);
533
int eloop_terminated(void)
535
return eloop.terminate;
539
void eloop_wait_for_read_sock(int sock)
548
select(sock + 1, &rfds, NULL, NULL, NULL);
552
void * eloop_get_user_data(void)
554
return eloop.user_data;