2 * Event loop based on Windows events and WaitForMultipleObjects
3 * Copyright (c) 2002-2006, 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.
26 eloop_sock_handler handler
;
33 eloop_event_handler handler
;
37 struct eloop_timeout
{
41 eloop_timeout_handler handler
;
42 struct eloop_timeout
*next
;
48 eloop_signal_handler handler
;
55 struct eloop_sock
*readers
;
58 struct eloop_event
*events
;
60 struct eloop_timeout
*timeout
;
63 struct eloop_signal
*signals
;
65 int pending_terminate
;
68 int reader_table_changed
;
70 struct eloop_signal term_signal
;
77 static struct eloop_data eloop
;
82 os_memset(&eloop
, 0, sizeof(eloop
));
83 eloop
.num_handles
= 1;
84 eloop
.handles
= os_malloc(eloop
.num_handles
*
85 sizeof(eloop
.handles
[0]));
86 if (eloop
.handles
== NULL
)
89 eloop
.term_event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
90 if (eloop
.term_event
== NULL
) {
91 printf("CreateEvent() failed: %d\n",
92 (int) GetLastError());
93 os_free(eloop
.handles
);
101 static int eloop_prepare_handles(void)
105 if (eloop
.num_handles
> eloop
.reader_count
+ eloop
.event_count
+ 8)
107 n
= os_realloc(eloop
.handles
,
108 eloop
.num_handles
* 2 * sizeof(eloop
.handles
[0]));
112 eloop
.num_handles
*= 2;
117 int eloop_register_read_sock(int sock
, eloop_sock_handler handler
,
118 void *eloop_data
, void *user_data
)
121 struct eloop_sock
*tmp
;
123 if (eloop_prepare_handles())
126 event
= WSACreateEvent();
127 if (event
== WSA_INVALID_EVENT
) {
128 printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
132 if (WSAEventSelect(sock
, event
, FD_READ
)) {
133 printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
134 WSACloseEvent(event
);
137 tmp
= os_realloc(eloop
.readers
,
138 (eloop
.reader_count
+ 1) * sizeof(struct eloop_sock
));
140 WSAEventSelect(sock
, event
, 0);
141 WSACloseEvent(event
);
145 tmp
[eloop
.reader_count
].sock
= sock
;
146 tmp
[eloop
.reader_count
].eloop_data
= eloop_data
;
147 tmp
[eloop
.reader_count
].user_data
= user_data
;
148 tmp
[eloop
.reader_count
].handler
= handler
;
149 tmp
[eloop
.reader_count
].event
= event
;
150 eloop
.reader_count
++;
152 if (sock
> eloop
.max_sock
)
153 eloop
.max_sock
= sock
;
154 eloop
.reader_table_changed
= 1;
160 void eloop_unregister_read_sock(int sock
)
164 if (eloop
.readers
== NULL
|| eloop
.reader_count
== 0)
167 for (i
= 0; i
< eloop
.reader_count
; i
++) {
168 if (eloop
.readers
[i
].sock
== sock
)
171 if (i
== eloop
.reader_count
)
174 WSAEventSelect(eloop
.readers
[i
].sock
, eloop
.readers
[i
].event
, 0);
175 WSACloseEvent(eloop
.readers
[i
].event
);
177 if (i
!= eloop
.reader_count
- 1) {
178 os_memmove(&eloop
.readers
[i
], &eloop
.readers
[i
+ 1],
179 (eloop
.reader_count
- i
- 1) *
180 sizeof(struct eloop_sock
));
182 eloop
.reader_count
--;
183 eloop
.reader_table_changed
= 1;
187 int eloop_register_event(void *event
, size_t event_size
,
188 eloop_event_handler handler
,
189 void *eloop_data
, void *user_data
)
191 struct eloop_event
*tmp
;
194 if (event_size
!= sizeof(HANDLE
) || h
== INVALID_HANDLE_VALUE
)
197 if (eloop_prepare_handles())
200 tmp
= os_realloc(eloop
.events
,
201 (eloop
.event_count
+ 1) * sizeof(struct eloop_event
));
205 tmp
[eloop
.event_count
].eloop_data
= eloop_data
;
206 tmp
[eloop
.event_count
].user_data
= user_data
;
207 tmp
[eloop
.event_count
].handler
= handler
;
208 tmp
[eloop
.event_count
].event
= h
;
216 void eloop_unregister_event(void *event
, size_t event_size
)
221 if (eloop
.events
== NULL
|| eloop
.event_count
== 0 ||
222 event_size
!= sizeof(HANDLE
))
225 for (i
= 0; i
< eloop
.event_count
; i
++) {
226 if (eloop
.events
[i
].event
== h
)
229 if (i
== eloop
.event_count
)
232 if (i
!= eloop
.event_count
- 1) {
233 os_memmove(&eloop
.events
[i
], &eloop
.events
[i
+ 1],
234 (eloop
.event_count
- i
- 1) *
235 sizeof(struct eloop_event
));
241 int eloop_register_timeout(unsigned int secs
, unsigned int usecs
,
242 eloop_timeout_handler handler
,
243 void *eloop_data
, void *user_data
)
245 struct eloop_timeout
*timeout
, *tmp
, *prev
;
247 timeout
= os_malloc(sizeof(*timeout
));
250 os_get_time(&timeout
->time
);
251 timeout
->time
.sec
+= secs
;
252 timeout
->time
.usec
+= usecs
;
253 while (timeout
->time
.usec
>= 1000000) {
255 timeout
->time
.usec
-= 1000000;
257 timeout
->eloop_data
= eloop_data
;
258 timeout
->user_data
= user_data
;
259 timeout
->handler
= handler
;
260 timeout
->next
= NULL
;
262 if (eloop
.timeout
== NULL
) {
263 eloop
.timeout
= timeout
;
269 while (tmp
!= NULL
) {
270 if (os_time_before(&timeout
->time
, &tmp
->time
))
277 timeout
->next
= eloop
.timeout
;
278 eloop
.timeout
= timeout
;
280 timeout
->next
= prev
->next
;
281 prev
->next
= timeout
;
288 int eloop_cancel_timeout(eloop_timeout_handler handler
,
289 void *eloop_data
, void *user_data
)
291 struct eloop_timeout
*timeout
, *prev
, *next
;
295 timeout
= eloop
.timeout
;
296 while (timeout
!= NULL
) {
297 next
= timeout
->next
;
299 if (timeout
->handler
== handler
&&
300 (timeout
->eloop_data
== eloop_data
||
301 eloop_data
== ELOOP_ALL_CTX
) &&
302 (timeout
->user_data
== user_data
||
303 user_data
== ELOOP_ALL_CTX
)) {
305 eloop
.timeout
= next
;
320 int eloop_is_timeout_registered(eloop_timeout_handler handler
,
321 void *eloop_data
, void *user_data
)
323 struct eloop_timeout
*tmp
;
326 while (tmp
!= NULL
) {
327 if (tmp
->handler
== handler
&&
328 tmp
->eloop_data
== eloop_data
&&
329 tmp
->user_data
== user_data
)
339 /* TODO: replace with suitable signal handler */
341 static void eloop_handle_signal(int sig
)
346 for (i
= 0; i
< eloop
.signal_count
; i
++) {
347 if (eloop
.signals
[i
].sig
== sig
) {
348 eloop
.signals
[i
].signaled
++;
356 static void eloop_process_pending_signals(void)
360 if (eloop
.signaled
== 0)
364 if (eloop
.pending_terminate
) {
365 eloop
.pending_terminate
= 0;
368 for (i
= 0; i
< eloop
.signal_count
; i
++) {
369 if (eloop
.signals
[i
].signaled
) {
370 eloop
.signals
[i
].signaled
= 0;
371 eloop
.signals
[i
].handler(eloop
.signals
[i
].sig
,
372 eloop
.signals
[i
].user_data
);
376 if (eloop
.term_signal
.signaled
) {
377 eloop
.term_signal
.signaled
= 0;
378 eloop
.term_signal
.handler(eloop
.term_signal
.sig
,
379 eloop
.term_signal
.user_data
);
384 int eloop_register_signal(int sig
, eloop_signal_handler handler
,
387 struct eloop_signal
*tmp
;
389 tmp
= os_realloc(eloop
.signals
,
390 (eloop
.signal_count
+ 1) *
391 sizeof(struct eloop_signal
));
395 tmp
[eloop
.signal_count
].sig
= sig
;
396 tmp
[eloop
.signal_count
].user_data
= user_data
;
397 tmp
[eloop
.signal_count
].handler
= handler
;
398 tmp
[eloop
.signal_count
].signaled
= 0;
399 eloop
.signal_count
++;
402 /* TODO: register signal handler */
409 static BOOL
eloop_handle_console_ctrl(DWORD type
)
413 case CTRL_BREAK_EVENT
:
415 eloop
.term_signal
.signaled
++;
416 SetEvent(eloop
.term_event
);
422 #endif /* _WIN32_WCE */
425 int eloop_register_signal_terminate(eloop_signal_handler handler
,
429 if (SetConsoleCtrlHandler((PHANDLER_ROUTINE
) eloop_handle_console_ctrl
,
431 printf("SetConsoleCtrlHandler() failed: %d\n",
432 (int) GetLastError());
435 #endif /* _WIN32_WCE */
437 eloop
.term_signal
.handler
= handler
;
438 eloop
.term_signal
.user_data
= user_data
;
444 int eloop_register_signal_reconfig(eloop_signal_handler handler
,
454 struct os_time tv
, now
;
455 DWORD count
, ret
, timeout
, err
;
458 while (!eloop
.terminate
&&
459 (eloop
.timeout
|| eloop
.reader_count
> 0 ||
460 eloop
.event_count
> 0)) {
461 tv
.sec
= tv
.usec
= 0;
464 if (os_time_before(&now
, &eloop
.timeout
->time
))
465 os_time_sub(&eloop
.timeout
->time
, &now
, &tv
);
469 for (i
= 0; i
< eloop
.event_count
; i
++)
470 eloop
.handles
[count
++] = eloop
.events
[i
].event
;
472 for (i
= 0; i
< eloop
.reader_count
; i
++)
473 eloop
.handles
[count
++] = eloop
.readers
[i
].event
;
475 if (eloop
.term_event
)
476 eloop
.handles
[count
++] = eloop
.term_event
;
479 timeout
= tv
.sec
* 1000 + tv
.usec
/ 1000;
483 if (count
> MAXIMUM_WAIT_OBJECTS
) {
484 printf("WaitForMultipleObjects: Too many events: "
485 "%d > %d (ignoring extra events)\n",
486 (int) count
, MAXIMUM_WAIT_OBJECTS
);
487 count
= MAXIMUM_WAIT_OBJECTS
;
490 ret
= WaitForMultipleObjects(count
, eloop
.handles
, FALSE
,
492 #else /* _WIN32_WCE */
493 ret
= WaitForMultipleObjectsEx(count
, eloop
.handles
, FALSE
,
495 #endif /* _WIN32_WCE */
496 err
= GetLastError();
498 eloop_process_pending_signals();
500 /* check if some registered timeouts have occurred */
502 struct eloop_timeout
*tmp
;
505 if (!os_time_before(&now
, &eloop
.timeout
->time
)) {
507 eloop
.timeout
= eloop
.timeout
->next
;
508 tmp
->handler(tmp
->eloop_data
,
515 if (ret
== WAIT_FAILED
) {
516 printf("WaitForMultipleObjects(count=%d) failed: %d\n",
517 (int) count
, (int) err
);
523 if (ret
== WAIT_IO_COMPLETION
)
525 #endif /* _WIN32_WCE */
527 if (ret
== WAIT_TIMEOUT
)
530 while (ret
>= WAIT_OBJECT_0
&&
531 ret
< WAIT_OBJECT_0
+ eloop
.event_count
) {
532 eloop
.events
[ret
].handler(
533 eloop
.events
[ret
].eloop_data
,
534 eloop
.events
[ret
].user_data
);
535 ret
= WaitForMultipleObjects(eloop
.event_count
,
536 eloop
.handles
, FALSE
, 0);
539 eloop
.reader_table_changed
= 0;
540 for (i
= 0; i
< eloop
.reader_count
; i
++) {
541 WSANETWORKEVENTS events
;
542 if (WSAEnumNetworkEvents(eloop
.readers
[i
].sock
,
543 eloop
.readers
[i
].event
,
545 (events
.lNetworkEvents
& FD_READ
)) {
546 eloop
.readers
[i
].handler(
547 eloop
.readers
[i
].sock
,
548 eloop
.readers
[i
].eloop_data
,
549 eloop
.readers
[i
].user_data
);
550 if (eloop
.reader_table_changed
)
558 void eloop_terminate(void)
561 SetEvent(eloop
.term_event
);
565 void eloop_destroy(void)
567 struct eloop_timeout
*timeout
, *prev
;
569 timeout
= eloop
.timeout
;
570 while (timeout
!= NULL
) {
572 timeout
= timeout
->next
;
575 os_free(eloop
.readers
);
576 os_free(eloop
.signals
);
577 if (eloop
.term_event
)
578 CloseHandle(eloop
.term_event
);
579 os_free(eloop
.handles
);
580 eloop
.handles
= NULL
;
581 os_free(eloop
.events
);
586 int eloop_terminated(void)
588 return eloop
.terminate
;
592 void eloop_wait_for_read_sock(int sock
)
596 event
= WSACreateEvent();
597 if (event
== WSA_INVALID_EVENT
) {
598 printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
602 if (WSAEventSelect(sock
, event
, FD_READ
)) {
603 printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
604 WSACloseEvent(event
);
608 WaitForSingleObject(event
, INFINITE
);
609 WSAEventSelect(sock
, event
, 0);
610 WSACloseEvent(event
);