2 * Event loop based on select() loop
3 * Copyright (c) 2002-2009, 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.
27 eloop_sock_handler handler
;
33 struct eloop_timeout
{
38 eloop_timeout_handler handler
;
47 eloop_signal_handler handler
;
51 struct eloop_sock_table
{
53 struct eloop_sock
*table
;
60 struct eloop_sock_table readers
;
61 struct eloop_sock_table writers
;
62 struct eloop_sock_table exceptions
;
64 struct dl_list timeout
;
67 struct eloop_signal
*signals
;
69 int pending_terminate
;
72 int reader_table_changed
;
75 static struct eloop_data eloop
;
80 static void eloop_sigsegv_handler(int sig
)
82 wpa_trace_show("eloop SIGSEGV");
86 static void eloop_trace_sock_add_ref(struct eloop_sock_table
*table
)
89 if (table
== NULL
|| table
->table
== NULL
)
91 for (i
= 0; i
< table
->count
; i
++) {
92 wpa_trace_add_ref(&table
->table
[i
], eloop
,
93 table
->table
[i
].eloop_data
);
94 wpa_trace_add_ref(&table
->table
[i
], user
,
95 table
->table
[i
].user_data
);
100 static void eloop_trace_sock_remove_ref(struct eloop_sock_table
*table
)
103 if (table
== NULL
|| table
->table
== NULL
)
105 for (i
= 0; i
< table
->count
; i
++) {
106 wpa_trace_remove_ref(&table
->table
[i
], eloop
,
107 table
->table
[i
].eloop_data
);
108 wpa_trace_remove_ref(&table
->table
[i
], user
,
109 table
->table
[i
].user_data
);
113 #else /* WPA_TRACE */
115 #define eloop_trace_sock_add_ref(table) do { } while (0)
116 #define eloop_trace_sock_remove_ref(table) do { } while (0)
118 #endif /* WPA_TRACE */
123 os_memset(&eloop
, 0, sizeof(eloop
));
124 dl_list_init(&eloop
.timeout
);
126 signal(SIGSEGV
, eloop_sigsegv_handler
);
127 #endif /* WPA_TRACE */
132 static int eloop_sock_table_add_sock(struct eloop_sock_table
*table
,
133 int sock
, eloop_sock_handler handler
,
134 void *eloop_data
, void *user_data
)
136 struct eloop_sock
*tmp
;
141 eloop_trace_sock_remove_ref(table
);
142 tmp
= (struct eloop_sock
*)
143 os_realloc(table
->table
,
144 (table
->count
+ 1) * sizeof(struct eloop_sock
));
148 tmp
[table
->count
].sock
= sock
;
149 tmp
[table
->count
].eloop_data
= eloop_data
;
150 tmp
[table
->count
].user_data
= user_data
;
151 tmp
[table
->count
].handler
= handler
;
152 wpa_trace_record(&tmp
[table
->count
]);
155 if (sock
> eloop
.max_sock
)
156 eloop
.max_sock
= sock
;
158 eloop_trace_sock_add_ref(table
);
164 static void eloop_sock_table_remove_sock(struct eloop_sock_table
*table
,
169 if (table
== NULL
|| table
->table
== NULL
|| table
->count
== 0)
172 for (i
= 0; i
< table
->count
; i
++) {
173 if (table
->table
[i
].sock
== sock
)
176 if (i
== table
->count
)
178 eloop_trace_sock_remove_ref(table
);
179 if (i
!= table
->count
- 1) {
180 os_memmove(&table
->table
[i
], &table
->table
[i
+ 1],
181 (table
->count
- i
- 1) *
182 sizeof(struct eloop_sock
));
186 eloop_trace_sock_add_ref(table
);
190 static void eloop_sock_table_set_fds(struct eloop_sock_table
*table
,
197 if (table
->table
== NULL
)
200 for (i
= 0; i
< table
->count
; i
++)
201 FD_SET(table
->table
[i
].sock
, fds
);
205 static void eloop_sock_table_dispatch(struct eloop_sock_table
*table
,
210 if (table
== NULL
|| table
->table
== NULL
)
214 for (i
= 0; i
< table
->count
; i
++) {
215 if (FD_ISSET(table
->table
[i
].sock
, fds
)) {
216 table
->table
[i
].handler(table
->table
[i
].sock
,
217 table
->table
[i
].eloop_data
,
218 table
->table
[i
].user_data
);
226 static void eloop_sock_table_destroy(struct eloop_sock_table
*table
)
230 for (i
= 0; i
< table
->count
&& table
->table
; i
++) {
231 wpa_printf(MSG_INFO
, "ELOOP: remaining socket: "
232 "sock=%d eloop_data=%p user_data=%p "
234 table
->table
[i
].sock
,
235 table
->table
[i
].eloop_data
,
236 table
->table
[i
].user_data
,
237 table
->table
[i
].handler
);
238 wpa_trace_dump_funcname("eloop unregistered socket "
240 table
->table
[i
].handler
);
241 wpa_trace_dump("eloop sock", &table
->table
[i
]);
243 os_free(table
->table
);
248 int eloop_register_read_sock(int sock
, eloop_sock_handler handler
,
249 void *eloop_data
, void *user_data
)
251 return eloop_register_sock(sock
, EVENT_TYPE_READ
, handler
,
252 eloop_data
, user_data
);
256 void eloop_unregister_read_sock(int sock
)
258 eloop_unregister_sock(sock
, EVENT_TYPE_READ
);
262 static struct eloop_sock_table
*eloop_get_sock_table(eloop_event_type type
)
265 case EVENT_TYPE_READ
:
266 return &eloop
.readers
;
267 case EVENT_TYPE_WRITE
:
268 return &eloop
.writers
;
269 case EVENT_TYPE_EXCEPTION
:
270 return &eloop
.exceptions
;
277 int eloop_register_sock(int sock
, eloop_event_type type
,
278 eloop_sock_handler handler
,
279 void *eloop_data
, void *user_data
)
281 struct eloop_sock_table
*table
;
283 table
= eloop_get_sock_table(type
);
284 return eloop_sock_table_add_sock(table
, sock
, handler
,
285 eloop_data
, user_data
);
289 void eloop_unregister_sock(int sock
, eloop_event_type type
)
291 struct eloop_sock_table
*table
;
293 table
= eloop_get_sock_table(type
);
294 eloop_sock_table_remove_sock(table
, sock
);
298 int eloop_register_timeout(unsigned int secs
, unsigned int usecs
,
299 eloop_timeout_handler handler
,
300 void *eloop_data
, void *user_data
)
302 struct eloop_timeout
*timeout
, *tmp
;
304 timeout
= os_malloc(sizeof(*timeout
));
307 if (os_get_time(&timeout
->time
) < 0) {
311 timeout
->time
.sec
+= secs
;
312 timeout
->time
.usec
+= usecs
;
313 while (timeout
->time
.usec
>= 1000000) {
315 timeout
->time
.usec
-= 1000000;
317 timeout
->eloop_data
= eloop_data
;
318 timeout
->user_data
= user_data
;
319 timeout
->handler
= handler
;
320 wpa_trace_add_ref(timeout
, eloop
, eloop_data
);
321 wpa_trace_add_ref(timeout
, user
, user_data
);
322 wpa_trace_record(timeout
);
324 /* Maintain timeouts in order of increasing time */
325 dl_list_for_each(tmp
, &eloop
.timeout
, struct eloop_timeout
, list
) {
326 if (os_time_before(&timeout
->time
, &tmp
->time
)) {
327 dl_list_add(tmp
->list
.prev
, &timeout
->list
);
331 dl_list_add_tail(&eloop
.timeout
, &timeout
->list
);
337 static void eloop_remove_timeout(struct eloop_timeout
*timeout
)
339 dl_list_del(&timeout
->list
);
340 wpa_trace_remove_ref(timeout
, eloop
, timeout
->eloop_data
);
341 wpa_trace_remove_ref(timeout
, user
, timeout
->user_data
);
346 int eloop_cancel_timeout(eloop_timeout_handler handler
,
347 void *eloop_data
, void *user_data
)
349 struct eloop_timeout
*timeout
, *prev
;
352 dl_list_for_each_safe(timeout
, prev
, &eloop
.timeout
,
353 struct eloop_timeout
, list
) {
354 if (timeout
->handler
== handler
&&
355 (timeout
->eloop_data
== eloop_data
||
356 eloop_data
== ELOOP_ALL_CTX
) &&
357 (timeout
->user_data
== user_data
||
358 user_data
== ELOOP_ALL_CTX
)) {
359 eloop_remove_timeout(timeout
);
368 int eloop_is_timeout_registered(eloop_timeout_handler handler
,
369 void *eloop_data
, void *user_data
)
371 struct eloop_timeout
*tmp
;
373 dl_list_for_each(tmp
, &eloop
.timeout
, struct eloop_timeout
, list
) {
374 if (tmp
->handler
== handler
&&
375 tmp
->eloop_data
== eloop_data
&&
376 tmp
->user_data
== user_data
)
384 #ifndef CONFIG_NATIVE_WINDOWS
385 static void eloop_handle_alarm(int sig
)
387 wpa_printf(MSG_ERROR
, "eloop: could not process SIGINT or SIGTERM in "
388 "two seconds. Looks like there\n"
389 "is a bug that ends up in a busy loop that "
390 "prevents clean shutdown.\n"
391 "Killing program forcefully.\n");
394 #endif /* CONFIG_NATIVE_WINDOWS */
397 static void eloop_handle_signal(int sig
)
401 #ifndef CONFIG_NATIVE_WINDOWS
402 if ((sig
== SIGINT
|| sig
== SIGTERM
) && !eloop
.pending_terminate
) {
403 /* Use SIGALRM to break out from potential busy loops that
404 * would not allow the program to be killed. */
405 eloop
.pending_terminate
= 1;
406 signal(SIGALRM
, eloop_handle_alarm
);
409 #endif /* CONFIG_NATIVE_WINDOWS */
412 for (i
= 0; i
< eloop
.signal_count
; i
++) {
413 if (eloop
.signals
[i
].sig
== sig
) {
414 eloop
.signals
[i
].signaled
++;
421 static void eloop_process_pending_signals(void)
425 if (eloop
.signaled
== 0)
429 if (eloop
.pending_terminate
) {
430 #ifndef CONFIG_NATIVE_WINDOWS
432 #endif /* CONFIG_NATIVE_WINDOWS */
433 eloop
.pending_terminate
= 0;
436 for (i
= 0; i
< eloop
.signal_count
; i
++) {
437 if (eloop
.signals
[i
].signaled
) {
438 eloop
.signals
[i
].signaled
= 0;
439 eloop
.signals
[i
].handler(eloop
.signals
[i
].sig
,
440 eloop
.signals
[i
].user_data
);
446 int eloop_register_signal(int sig
, eloop_signal_handler handler
,
449 struct eloop_signal
*tmp
;
451 tmp
= (struct eloop_signal
*)
452 os_realloc(eloop
.signals
,
453 (eloop
.signal_count
+ 1) *
454 sizeof(struct eloop_signal
));
458 tmp
[eloop
.signal_count
].sig
= sig
;
459 tmp
[eloop
.signal_count
].user_data
= user_data
;
460 tmp
[eloop
.signal_count
].handler
= handler
;
461 tmp
[eloop
.signal_count
].signaled
= 0;
462 eloop
.signal_count
++;
464 signal(sig
, eloop_handle_signal
);
470 int eloop_register_signal_terminate(eloop_signal_handler handler
,
473 int ret
= eloop_register_signal(SIGINT
, handler
, user_data
);
475 ret
= eloop_register_signal(SIGTERM
, handler
, user_data
);
480 int eloop_register_signal_reconfig(eloop_signal_handler handler
,
483 #ifdef CONFIG_NATIVE_WINDOWS
485 #else /* CONFIG_NATIVE_WINDOWS */
486 return eloop_register_signal(SIGHUP
, handler
, user_data
);
487 #endif /* CONFIG_NATIVE_WINDOWS */
493 fd_set
*rfds
, *wfds
, *efds
;
496 struct os_time tv
, now
;
498 rfds
= os_malloc(sizeof(*rfds
));
499 wfds
= os_malloc(sizeof(*wfds
));
500 efds
= os_malloc(sizeof(*efds
));
501 if (rfds
== NULL
|| wfds
== NULL
|| efds
== NULL
)
504 while (!eloop
.terminate
&&
505 (!dl_list_empty(&eloop
.timeout
) || eloop
.readers
.count
> 0 ||
506 eloop
.writers
.count
> 0 || eloop
.exceptions
.count
> 0)) {
507 struct eloop_timeout
*timeout
;
508 timeout
= dl_list_first(&eloop
.timeout
, struct eloop_timeout
,
512 if (os_time_before(&now
, &timeout
->time
))
513 os_time_sub(&timeout
->time
, &now
, &tv
);
515 tv
.sec
= tv
.usec
= 0;
517 _tv
.tv_usec
= tv
.usec
;
520 eloop_sock_table_set_fds(&eloop
.readers
, rfds
);
521 eloop_sock_table_set_fds(&eloop
.writers
, wfds
);
522 eloop_sock_table_set_fds(&eloop
.exceptions
, efds
);
523 res
= select(eloop
.max_sock
+ 1, rfds
, wfds
, efds
,
524 timeout
? &_tv
: NULL
);
525 if (res
< 0 && errno
!= EINTR
&& errno
!= 0) {
529 eloop_process_pending_signals();
531 /* check if some registered timeouts have occurred */
534 if (!os_time_before(&now
, &timeout
->time
)) {
535 void *eloop_data
= timeout
->eloop_data
;
536 void *user_data
= timeout
->user_data
;
537 eloop_timeout_handler handler
=
539 eloop_remove_timeout(timeout
);
540 handler(eloop_data
, user_data
);
548 eloop_sock_table_dispatch(&eloop
.readers
, rfds
);
549 eloop_sock_table_dispatch(&eloop
.writers
, wfds
);
550 eloop_sock_table_dispatch(&eloop
.exceptions
, efds
);
560 void eloop_terminate(void)
566 void eloop_destroy(void)
568 struct eloop_timeout
*timeout
, *prev
;
572 dl_list_for_each_safe(timeout
, prev
, &eloop
.timeout
,
573 struct eloop_timeout
, list
) {
575 sec
= timeout
->time
.sec
- now
.sec
;
576 usec
= timeout
->time
.usec
- now
.usec
;
577 if (timeout
->time
.usec
< now
.usec
) {
581 wpa_printf(MSG_INFO
, "ELOOP: remaining timeout: %d.%06d "
582 "eloop_data=%p user_data=%p handler=%p",
583 sec
, usec
, timeout
->eloop_data
, timeout
->user_data
,
585 wpa_trace_dump_funcname("eloop unregistered timeout handler",
587 wpa_trace_dump("eloop timeout", timeout
);
588 eloop_remove_timeout(timeout
);
590 eloop_sock_table_destroy(&eloop
.readers
);
591 eloop_sock_table_destroy(&eloop
.writers
);
592 eloop_sock_table_destroy(&eloop
.exceptions
);
593 os_free(eloop
.signals
);
597 int eloop_terminated(void)
599 return eloop
.terminate
;
603 void eloop_wait_for_read_sock(int sock
)
612 select(sock
+ 1, &rfds
, NULL
, NULL
, NULL
);