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
)
172 os_free(table
->table
);
176 int eloop_register_read_sock(int sock
, eloop_sock_handler handler
,
177 void *eloop_data
, void *user_data
)
179 return eloop_register_sock(sock
, EVENT_TYPE_READ
, handler
,
180 eloop_data
, user_data
);
184 void eloop_unregister_read_sock(int sock
)
186 eloop_unregister_sock(sock
, EVENT_TYPE_READ
);
190 static struct eloop_sock_table
*eloop_get_sock_table(eloop_event_type type
)
193 case EVENT_TYPE_READ
:
194 return &eloop
.readers
;
195 case EVENT_TYPE_WRITE
:
196 return &eloop
.writers
;
197 case EVENT_TYPE_EXCEPTION
:
198 return &eloop
.exceptions
;
205 int eloop_register_sock(int sock
, eloop_event_type type
,
206 eloop_sock_handler handler
,
207 void *eloop_data
, void *user_data
)
209 struct eloop_sock_table
*table
;
211 table
= eloop_get_sock_table(type
);
212 return eloop_sock_table_add_sock(table
, sock
, handler
,
213 eloop_data
, user_data
);
217 void eloop_unregister_sock(int sock
, eloop_event_type type
)
219 struct eloop_sock_table
*table
;
221 table
= eloop_get_sock_table(type
);
222 eloop_sock_table_remove_sock(table
, sock
);
226 int eloop_register_timeout(unsigned int secs
, unsigned int usecs
,
227 eloop_timeout_handler handler
,
228 void *eloop_data
, void *user_data
)
230 struct eloop_timeout
*timeout
, *tmp
, *prev
;
232 timeout
= os_malloc(sizeof(*timeout
));
235 os_get_time(&timeout
->time
);
236 timeout
->time
.sec
+= secs
;
237 timeout
->time
.usec
+= usecs
;
238 while (timeout
->time
.usec
>= 1000000) {
240 timeout
->time
.usec
-= 1000000;
242 timeout
->eloop_data
= eloop_data
;
243 timeout
->user_data
= user_data
;
244 timeout
->handler
= handler
;
245 timeout
->next
= NULL
;
247 if (eloop
.timeout
== NULL
) {
248 eloop
.timeout
= timeout
;
254 while (tmp
!= NULL
) {
255 if (os_time_before(&timeout
->time
, &tmp
->time
))
262 timeout
->next
= eloop
.timeout
;
263 eloop
.timeout
= timeout
;
265 timeout
->next
= prev
->next
;
266 prev
->next
= timeout
;
273 int eloop_cancel_timeout(eloop_timeout_handler handler
,
274 void *eloop_data
, void *user_data
)
276 struct eloop_timeout
*timeout
, *prev
, *next
;
280 timeout
= eloop
.timeout
;
281 while (timeout
!= NULL
) {
282 next
= timeout
->next
;
284 if (timeout
->handler
== handler
&&
285 (timeout
->eloop_data
== eloop_data
||
286 eloop_data
== ELOOP_ALL_CTX
) &&
287 (timeout
->user_data
== user_data
||
288 user_data
== ELOOP_ALL_CTX
)) {
290 eloop
.timeout
= next
;
305 #ifndef CONFIG_NATIVE_WINDOWS
306 static void eloop_handle_alarm(int sig
)
308 fprintf(stderr
, "eloop: could not process SIGINT or SIGTERM in two "
309 "seconds. Looks like there\n"
310 "is a bug that ends up in a busy loop that "
311 "prevents clean shutdown.\n"
312 "Killing program forcefully.\n");
315 #endif /* CONFIG_NATIVE_WINDOWS */
318 static void eloop_handle_signal(int sig
)
322 #ifndef CONFIG_NATIVE_WINDOWS
323 if ((sig
== SIGINT
|| sig
== SIGTERM
) && !eloop
.pending_terminate
) {
324 /* Use SIGALRM to break out from potential busy loops that
325 * would not allow the program to be killed. */
326 eloop
.pending_terminate
= 1;
327 signal(SIGALRM
, eloop_handle_alarm
);
330 #endif /* CONFIG_NATIVE_WINDOWS */
333 for (i
= 0; i
< eloop
.signal_count
; i
++) {
334 if (eloop
.signals
[i
].sig
== sig
) {
335 eloop
.signals
[i
].signaled
++;
342 static void eloop_process_pending_signals(void)
346 if (eloop
.signaled
== 0)
350 if (eloop
.pending_terminate
) {
351 #ifndef CONFIG_NATIVE_WINDOWS
353 #endif /* CONFIG_NATIVE_WINDOWS */
354 eloop
.pending_terminate
= 0;
357 for (i
= 0; i
< eloop
.signal_count
; i
++) {
358 if (eloop
.signals
[i
].signaled
) {
359 eloop
.signals
[i
].signaled
= 0;
360 eloop
.signals
[i
].handler(eloop
.signals
[i
].sig
,
362 eloop
.signals
[i
].user_data
);
368 int eloop_register_signal(int sig
, eloop_signal_handler handler
,
371 struct eloop_signal
*tmp
;
373 tmp
= (struct eloop_signal
*)
374 os_realloc(eloop
.signals
,
375 (eloop
.signal_count
+ 1) *
376 sizeof(struct eloop_signal
));
380 tmp
[eloop
.signal_count
].sig
= sig
;
381 tmp
[eloop
.signal_count
].user_data
= user_data
;
382 tmp
[eloop
.signal_count
].handler
= handler
;
383 tmp
[eloop
.signal_count
].signaled
= 0;
384 eloop
.signal_count
++;
386 signal(sig
, eloop_handle_signal
);
392 int eloop_register_signal_terminate(eloop_signal_handler handler
,
395 int ret
= eloop_register_signal(SIGINT
, handler
, user_data
);
397 ret
= eloop_register_signal(SIGTERM
, handler
, user_data
);
402 int eloop_register_signal_reconfig(eloop_signal_handler handler
,
405 #ifdef CONFIG_NATIVE_WINDOWS
407 #else /* CONFIG_NATIVE_WINDOWS */
408 return eloop_register_signal(SIGHUP
, handler
, user_data
);
409 #endif /* CONFIG_NATIVE_WINDOWS */
415 fd_set
*rfds
, *wfds
, *efds
;
418 struct os_time tv
, now
;
420 rfds
= os_malloc(sizeof(*rfds
));
421 wfds
= os_malloc(sizeof(*wfds
));
422 efds
= os_malloc(sizeof(*efds
));
423 if (rfds
== NULL
|| wfds
== NULL
|| efds
== NULL
) {
424 printf("eloop_run - malloc failed\n");
428 while (!eloop
.terminate
&&
429 (eloop
.timeout
|| eloop
.readers
.count
> 0 ||
430 eloop
.writers
.count
> 0 || eloop
.exceptions
.count
> 0)) {
433 if (os_time_before(&now
, &eloop
.timeout
->time
))
434 os_time_sub(&eloop
.timeout
->time
, &now
, &tv
);
436 tv
.sec
= tv
.usec
= 0;
438 printf("next timeout in %lu.%06lu sec\n",
442 _tv
.tv_usec
= tv
.usec
;
445 eloop_sock_table_set_fds(&eloop
.readers
, rfds
);
446 eloop_sock_table_set_fds(&eloop
.writers
, wfds
);
447 eloop_sock_table_set_fds(&eloop
.exceptions
, efds
);
448 res
= select(eloop
.max_sock
+ 1, rfds
, wfds
, efds
,
449 eloop
.timeout
? &_tv
: NULL
);
450 if (res
< 0 && errno
!= EINTR
&& errno
!= 0) {
454 eloop_process_pending_signals();
456 /* check if some registered timeouts have occurred */
458 struct eloop_timeout
*tmp
;
461 if (!os_time_before(&now
, &eloop
.timeout
->time
)) {
463 eloop
.timeout
= eloop
.timeout
->next
;
464 tmp
->handler(tmp
->eloop_data
,
474 eloop_sock_table_dispatch(&eloop
.readers
, rfds
);
475 eloop_sock_table_dispatch(&eloop
.writers
, wfds
);
476 eloop_sock_table_dispatch(&eloop
.exceptions
, efds
);
486 void eloop_terminate(void)
492 void eloop_destroy(void)
494 struct eloop_timeout
*timeout
, *prev
;
496 timeout
= eloop
.timeout
;
497 while (timeout
!= NULL
) {
499 timeout
= timeout
->next
;
502 eloop_sock_table_destroy(&eloop
.readers
);
503 eloop_sock_table_destroy(&eloop
.writers
);
504 eloop_sock_table_destroy(&eloop
.exceptions
);
505 os_free(eloop
.signals
);
509 int eloop_terminated(void)
511 return eloop
.terminate
;
515 void eloop_wait_for_read_sock(int sock
)
524 select(sock
+ 1, &rfds
, NULL
, NULL
, NULL
);
528 void * eloop_get_user_data(void)
530 return eloop
.user_data
;