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);