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
;
57 struct eloop_sock
*readers
;
60 struct eloop_event
*events
;
62 struct eloop_timeout
*timeout
;
65 struct eloop_signal
*signals
;
67 int pending_terminate
;
70 int reader_table_changed
;
72 struct eloop_signal term_signal
;
79 static struct eloop_data eloop
;
82 int eloop_init(void *user_data
)
84 os_memset(&eloop
, 0, sizeof(eloop
));
85 eloop
.user_data
= user_data
;
86 eloop
.num_handles
= 1;
87 eloop
.handles
= os_malloc(eloop
.num_handles
*
88 sizeof(eloop
.handles
[0]));
89 if (eloop
.handles
== NULL
)
92 eloop
.term_event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
93 if (eloop
.term_event
== NULL
) {
94 printf("CreateEvent() failed: %d\n",
95 (int) GetLastError());
96 os_free(eloop
.handles
);
104 static int eloop_prepare_handles(void)
108 if (eloop
.num_handles
> eloop
.reader_count
+ eloop
.event_count
+ 8)
110 n
= os_realloc(eloop
.handles
,
111 eloop
.num_handles
* 2 * sizeof(eloop
.handles
[0]));
115 eloop
.num_handles
*= 2;
120 int eloop_register_read_sock(int sock
, eloop_sock_handler handler
,
121 void *eloop_data
, void *user_data
)
124 struct eloop_sock
*tmp
;
126 if (eloop_prepare_handles())
129 event
= WSACreateEvent();
130 if (event
== WSA_INVALID_EVENT
) {
131 printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
135 if (WSAEventSelect(sock
, event
, FD_READ
)) {
136 printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
137 WSACloseEvent(event
);
140 tmp
= os_realloc(eloop
.readers
,
141 (eloop
.reader_count
+ 1) * sizeof(struct eloop_sock
));
143 WSAEventSelect(sock
, event
, 0);
144 WSACloseEvent(event
);
148 tmp
[eloop
.reader_count
].sock
= sock
;
149 tmp
[eloop
.reader_count
].eloop_data
= eloop_data
;
150 tmp
[eloop
.reader_count
].user_data
= user_data
;
151 tmp
[eloop
.reader_count
].handler
= handler
;
152 tmp
[eloop
.reader_count
].event
= event
;
153 eloop
.reader_count
++;
155 if (sock
> eloop
.max_sock
)
156 eloop
.max_sock
= sock
;
157 eloop
.reader_table_changed
= 1;
163 void eloop_unregister_read_sock(int sock
)
167 if (eloop
.readers
== NULL
|| eloop
.reader_count
== 0)
170 for (i
= 0; i
< eloop
.reader_count
; i
++) {
171 if (eloop
.readers
[i
].sock
== sock
)
174 if (i
== eloop
.reader_count
)
177 WSAEventSelect(eloop
.readers
[i
].sock
, eloop
.readers
[i
].event
, 0);
178 WSACloseEvent(eloop
.readers
[i
].event
);
180 if (i
!= eloop
.reader_count
- 1) {
181 os_memmove(&eloop
.readers
[i
], &eloop
.readers
[i
+ 1],
182 (eloop
.reader_count
- i
- 1) *
183 sizeof(struct eloop_sock
));
185 eloop
.reader_count
--;
186 eloop
.reader_table_changed
= 1;
190 int eloop_register_event(void *event
, size_t event_size
,
191 eloop_event_handler handler
,
192 void *eloop_data
, void *user_data
)
194 struct eloop_event
*tmp
;
197 if (event_size
!= sizeof(HANDLE
) || h
== INVALID_HANDLE_VALUE
)
200 if (eloop_prepare_handles())
203 tmp
= os_realloc(eloop
.events
,
204 (eloop
.event_count
+ 1) * sizeof(struct eloop_event
));
208 tmp
[eloop
.event_count
].eloop_data
= eloop_data
;
209 tmp
[eloop
.event_count
].user_data
= user_data
;
210 tmp
[eloop
.event_count
].handler
= handler
;
211 tmp
[eloop
.event_count
].event
= h
;
219 void eloop_unregister_event(void *event
, size_t event_size
)
224 if (eloop
.events
== NULL
|| eloop
.event_count
== 0 ||
225 event_size
!= sizeof(HANDLE
))
228 for (i
= 0; i
< eloop
.event_count
; i
++) {
229 if (eloop
.events
[i
].event
== h
)
232 if (i
== eloop
.event_count
)
235 if (i
!= eloop
.event_count
- 1) {
236 os_memmove(&eloop
.events
[i
], &eloop
.events
[i
+ 1],
237 (eloop
.event_count
- i
- 1) *
238 sizeof(struct eloop_event
));
244 int eloop_register_timeout(unsigned int secs
, unsigned int usecs
,
245 eloop_timeout_handler handler
,
246 void *eloop_data
, void *user_data
)
248 struct eloop_timeout
*timeout
, *tmp
, *prev
;
250 timeout
= os_malloc(sizeof(*timeout
));
253 os_get_time(&timeout
->time
);
254 timeout
->time
.sec
+= secs
;
255 timeout
->time
.usec
+= usecs
;
256 while (timeout
->time
.usec
>= 1000000) {
258 timeout
->time
.usec
-= 1000000;
260 timeout
->eloop_data
= eloop_data
;
261 timeout
->user_data
= user_data
;
262 timeout
->handler
= handler
;
263 timeout
->next
= NULL
;
265 if (eloop
.timeout
== NULL
) {
266 eloop
.timeout
= timeout
;
272 while (tmp
!= NULL
) {
273 if (os_time_before(&timeout
->time
, &tmp
->time
))
280 timeout
->next
= eloop
.timeout
;
281 eloop
.timeout
= timeout
;
283 timeout
->next
= prev
->next
;
284 prev
->next
= timeout
;
291 int eloop_cancel_timeout(eloop_timeout_handler handler
,
292 void *eloop_data
, void *user_data
)
294 struct eloop_timeout
*timeout
, *prev
, *next
;
298 timeout
= eloop
.timeout
;
299 while (timeout
!= NULL
) {
300 next
= timeout
->next
;
302 if (timeout
->handler
== handler
&&
303 (timeout
->eloop_data
== eloop_data
||
304 eloop_data
== ELOOP_ALL_CTX
) &&
305 (timeout
->user_data
== user_data
||
306 user_data
== ELOOP_ALL_CTX
)) {
308 eloop
.timeout
= next
;
323 /* TODO: replace with suitable signal handler */
325 static void eloop_handle_signal(int sig
)
330 for (i
= 0; i
< eloop
.signal_count
; i
++) {
331 if (eloop
.signals
[i
].sig
== sig
) {
332 eloop
.signals
[i
].signaled
++;
340 static void eloop_process_pending_signals(void)
344 if (eloop
.signaled
== 0)
348 if (eloop
.pending_terminate
) {
349 eloop
.pending_terminate
= 0;
352 for (i
= 0; i
< eloop
.signal_count
; i
++) {
353 if (eloop
.signals
[i
].signaled
) {
354 eloop
.signals
[i
].signaled
= 0;
355 eloop
.signals
[i
].handler(eloop
.signals
[i
].sig
,
357 eloop
.signals
[i
].user_data
);
361 if (eloop
.term_signal
.signaled
) {
362 eloop
.term_signal
.signaled
= 0;
363 eloop
.term_signal
.handler(eloop
.term_signal
.sig
,
365 eloop
.term_signal
.user_data
);
370 int eloop_register_signal(int sig
, eloop_signal_handler handler
,
373 struct eloop_signal
*tmp
;
375 tmp
= os_realloc(eloop
.signals
,
376 (eloop
.signal_count
+ 1) *
377 sizeof(struct eloop_signal
));
381 tmp
[eloop
.signal_count
].sig
= sig
;
382 tmp
[eloop
.signal_count
].user_data
= user_data
;
383 tmp
[eloop
.signal_count
].handler
= handler
;
384 tmp
[eloop
.signal_count
].signaled
= 0;
385 eloop
.signal_count
++;
388 /* TODO: register signal handler */
395 static BOOL
eloop_handle_console_ctrl(DWORD type
)
399 case CTRL_BREAK_EVENT
:
401 eloop
.term_signal
.signaled
++;
402 SetEvent(eloop
.term_event
);
408 #endif /* _WIN32_WCE */
411 int eloop_register_signal_terminate(eloop_signal_handler handler
,
415 if (SetConsoleCtrlHandler((PHANDLER_ROUTINE
) eloop_handle_console_ctrl
,
417 printf("SetConsoleCtrlHandler() failed: %d\n",
418 (int) GetLastError());
421 #endif /* _WIN32_WCE */
423 eloop
.term_signal
.handler
= handler
;
424 eloop
.term_signal
.user_data
= user_data
;
430 int eloop_register_signal_reconfig(eloop_signal_handler handler
,
440 struct os_time tv
, now
;
441 DWORD count
, ret
, timeout
, err
;
444 while (!eloop
.terminate
&&
445 (eloop
.timeout
|| eloop
.reader_count
> 0 ||
446 eloop
.event_count
> 0)) {
449 if (os_time_before(&now
, &eloop
.timeout
->time
))
450 os_time_sub(&eloop
.timeout
->time
, &now
, &tv
);
452 tv
.sec
= tv
.usec
= 0;
456 for (i
= 0; i
< eloop
.event_count
; i
++)
457 eloop
.handles
[count
++] = eloop
.events
[i
].event
;
459 for (i
= 0; i
< eloop
.reader_count
; i
++)
460 eloop
.handles
[count
++] = eloop
.readers
[i
].event
;
462 if (eloop
.term_event
)
463 eloop
.handles
[count
++] = eloop
.term_event
;
466 timeout
= tv
.sec
* 1000 + tv
.usec
/ 1000;
470 if (count
> MAXIMUM_WAIT_OBJECTS
) {
471 printf("WaitForMultipleObjects: Too many events: "
472 "%d > %d (ignoring extra events)\n",
473 (int) count
, MAXIMUM_WAIT_OBJECTS
);
474 count
= MAXIMUM_WAIT_OBJECTS
;
477 ret
= WaitForMultipleObjects(count
, eloop
.handles
, FALSE
,
479 #else /* _WIN32_WCE */
480 ret
= WaitForMultipleObjectsEx(count
, eloop
.handles
, FALSE
,
482 #endif /* _WIN32_WCE */
483 err
= GetLastError();
485 eloop_process_pending_signals();
487 /* check if some registered timeouts have occurred */
489 struct eloop_timeout
*tmp
;
492 if (!os_time_before(&now
, &eloop
.timeout
->time
)) {
494 eloop
.timeout
= eloop
.timeout
->next
;
495 tmp
->handler(tmp
->eloop_data
,
502 if (ret
== WAIT_FAILED
) {
503 printf("WaitForMultipleObjects(count=%d) failed: %d\n",
504 (int) count
, (int) err
);
510 if (ret
== WAIT_IO_COMPLETION
)
512 #endif /* _WIN32_WCE */
514 if (ret
== WAIT_TIMEOUT
)
517 while (ret
>= WAIT_OBJECT_0
&&
518 ret
< WAIT_OBJECT_0
+ eloop
.event_count
) {
519 eloop
.events
[ret
].handler(
520 eloop
.events
[ret
].eloop_data
,
521 eloop
.events
[ret
].user_data
);
522 ret
= WaitForMultipleObjects(eloop
.event_count
,
523 eloop
.handles
, FALSE
, 0);
526 eloop
.reader_table_changed
= 0;
527 for (i
= 0; i
< eloop
.reader_count
; i
++) {
528 WSANETWORKEVENTS events
;
529 if (WSAEnumNetworkEvents(eloop
.readers
[i
].sock
,
530 eloop
.readers
[i
].event
,
532 (events
.lNetworkEvents
& FD_READ
)) {
533 eloop
.readers
[i
].handler(
534 eloop
.readers
[i
].sock
,
535 eloop
.readers
[i
].eloop_data
,
536 eloop
.readers
[i
].user_data
);
537 if (eloop
.reader_table_changed
)
545 void eloop_terminate(void)
548 SetEvent(eloop
.term_event
);
552 void eloop_destroy(void)
554 struct eloop_timeout
*timeout
, *prev
;
556 timeout
= eloop
.timeout
;
557 while (timeout
!= NULL
) {
559 timeout
= timeout
->next
;
562 os_free(eloop
.readers
);
563 os_free(eloop
.signals
);
564 if (eloop
.term_event
)
565 CloseHandle(eloop
.term_event
);
566 os_free(eloop
.handles
);
567 eloop
.handles
= NULL
;
568 os_free(eloop
.events
);
573 int eloop_terminated(void)
575 return eloop
.terminate
;
579 void eloop_wait_for_read_sock(int sock
)
583 event
= WSACreateEvent();
584 if (event
== WSA_INVALID_EVENT
) {
585 printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
589 if (WSAEventSelect(sock
, event
, FD_READ
)) {
590 printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
591 WSACloseEvent(event
);
595 WaitForSingleObject(event
, INFINITE
);
596 WSAEventSelect(sock
, event
, 0);
597 WSACloseEvent(event
);
601 void * eloop_get_user_data(void)
603 return eloop
.user_data
;