blob: c726ece25de2381f48a7c602aa40b9a28b9adb32 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * Event loop based on Windows events and WaitForMultipleObjects
3 * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
4 *
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.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16#include <winsock2.h>
17
18#include "common.h"
19#include "eloop.h"
20
21
22struct eloop_sock {
23 int sock;
24 void *eloop_data;
25 void *user_data;
26 eloop_sock_handler handler;
27 WSAEVENT event;
28};
29
30struct eloop_event {
31 void *eloop_data;
32 void *user_data;
33 eloop_event_handler handler;
34 HANDLE event;
35};
36
37struct eloop_timeout {
38 struct os_time time;
39 void *eloop_data;
40 void *user_data;
41 eloop_timeout_handler handler;
42 struct eloop_timeout *next;
43};
44
45struct eloop_signal {
46 int sig;
47 void *user_data;
48 eloop_signal_handler handler;
49 int signaled;
50};
51
52struct eloop_data {
53 int max_sock;
54 size_t reader_count;
55 struct eloop_sock *readers;
56
57 size_t event_count;
58 struct eloop_event *events;
59
60 struct eloop_timeout *timeout;
61
62 int signal_count;
63 struct eloop_signal *signals;
64 int signaled;
65 int pending_terminate;
66
67 int terminate;
68 int reader_table_changed;
69
70 struct eloop_signal term_signal;
71 HANDLE term_event;
72
73 HANDLE *handles;
74 size_t num_handles;
75};
76
77static struct eloop_data eloop;
78
79
80int eloop_init(void)
81{
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)
87 return -1;
88
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);
94 return -1;
95 }
96
97 return 0;
98}
99
100
101static int eloop_prepare_handles(void)
102{
103 HANDLE *n;
104
105 if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8)
106 return 0;
107 n = os_realloc(eloop.handles,
108 eloop.num_handles * 2 * sizeof(eloop.handles[0]));
109 if (n == NULL)
110 return -1;
111 eloop.handles = n;
112 eloop.num_handles *= 2;
113 return 0;
114}
115
116
117int eloop_register_read_sock(int sock, eloop_sock_handler handler,
118 void *eloop_data, void *user_data)
119{
120 WSAEVENT event;
121 struct eloop_sock *tmp;
122
123 if (eloop_prepare_handles())
124 return -1;
125
126 event = WSACreateEvent();
127 if (event == WSA_INVALID_EVENT) {
128 printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
129 return -1;
130 }
131
132 if (WSAEventSelect(sock, event, FD_READ)) {
133 printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
134 WSACloseEvent(event);
135 return -1;
136 }
137 tmp = os_realloc(eloop.readers,
138 (eloop.reader_count + 1) * sizeof(struct eloop_sock));
139 if (tmp == NULL) {
140 WSAEventSelect(sock, event, 0);
141 WSACloseEvent(event);
142 return -1;
143 }
144
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++;
151 eloop.readers = tmp;
152 if (sock > eloop.max_sock)
153 eloop.max_sock = sock;
154 eloop.reader_table_changed = 1;
155
156 return 0;
157}
158
159
160void eloop_unregister_read_sock(int sock)
161{
162 size_t i;
163
164 if (eloop.readers == NULL || eloop.reader_count == 0)
165 return;
166
167 for (i = 0; i < eloop.reader_count; i++) {
168 if (eloop.readers[i].sock == sock)
169 break;
170 }
171 if (i == eloop.reader_count)
172 return;
173
174 WSAEventSelect(eloop.readers[i].sock, eloop.readers[i].event, 0);
175 WSACloseEvent(eloop.readers[i].event);
176
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));
181 }
182 eloop.reader_count--;
183 eloop.reader_table_changed = 1;
184}
185
186
187int eloop_register_event(void *event, size_t event_size,
188 eloop_event_handler handler,
189 void *eloop_data, void *user_data)
190{
191 struct eloop_event *tmp;
192 HANDLE h = event;
193
194 if (event_size != sizeof(HANDLE) || h == INVALID_HANDLE_VALUE)
195 return -1;
196
197 if (eloop_prepare_handles())
198 return -1;
199
200 tmp = os_realloc(eloop.events,
201 (eloop.event_count + 1) * sizeof(struct eloop_event));
202 if (tmp == NULL)
203 return -1;
204
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;
209 eloop.event_count++;
210 eloop.events = tmp;
211
212 return 0;
213}
214
215
216void eloop_unregister_event(void *event, size_t event_size)
217{
218 size_t i;
219 HANDLE h = event;
220
221 if (eloop.events == NULL || eloop.event_count == 0 ||
222 event_size != sizeof(HANDLE))
223 return;
224
225 for (i = 0; i < eloop.event_count; i++) {
226 if (eloop.events[i].event == h)
227 break;
228 }
229 if (i == eloop.event_count)
230 return;
231
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));
236 }
237 eloop.event_count--;
238}
239
240
241int eloop_register_timeout(unsigned int secs, unsigned int usecs,
242 eloop_timeout_handler handler,
243 void *eloop_data, void *user_data)
244{
245 struct eloop_timeout *timeout, *tmp, *prev;
246 os_time_t now_sec;
247
248 timeout = os_malloc(sizeof(*timeout));
249 if (timeout == NULL)
250 return -1;
251 os_get_time(&timeout->time);
252 now_sec = timeout->time.sec;
253 timeout->time.sec += secs;
254 if (timeout->time.sec < now_sec) {
255 /*
256 * Integer overflow - assume long enough timeout to be assumed
257 * to be infinite, i.e., the timeout would never happen.
258 */
259 wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
260 "ever happen - ignore it", secs);
261 os_free(timeout);
262 return 0;
263 }
264 timeout->time.usec += usecs;
265 while (timeout->time.usec >= 1000000) {
266 timeout->time.sec++;
267 timeout->time.usec -= 1000000;
268 }
269 timeout->eloop_data = eloop_data;
270 timeout->user_data = user_data;
271 timeout->handler = handler;
272 timeout->next = NULL;
273
274 if (eloop.timeout == NULL) {
275 eloop.timeout = timeout;
276 return 0;
277 }
278
279 prev = NULL;
280 tmp = eloop.timeout;
281 while (tmp != NULL) {
282 if (os_time_before(&timeout->time, &tmp->time))
283 break;
284 prev = tmp;
285 tmp = tmp->next;
286 }
287
288 if (prev == NULL) {
289 timeout->next = eloop.timeout;
290 eloop.timeout = timeout;
291 } else {
292 timeout->next = prev->next;
293 prev->next = timeout;
294 }
295
296 return 0;
297}
298
299
300int eloop_cancel_timeout(eloop_timeout_handler handler,
301 void *eloop_data, void *user_data)
302{
303 struct eloop_timeout *timeout, *prev, *next;
304 int removed = 0;
305
306 prev = NULL;
307 timeout = eloop.timeout;
308 while (timeout != NULL) {
309 next = timeout->next;
310
311 if (timeout->handler == handler &&
312 (timeout->eloop_data == eloop_data ||
313 eloop_data == ELOOP_ALL_CTX) &&
314 (timeout->user_data == user_data ||
315 user_data == ELOOP_ALL_CTX)) {
316 if (prev == NULL)
317 eloop.timeout = next;
318 else
319 prev->next = next;
320 os_free(timeout);
321 removed++;
322 } else
323 prev = timeout;
324
325 timeout = next;
326 }
327
328 return removed;
329}
330
331
332int eloop_is_timeout_registered(eloop_timeout_handler handler,
333 void *eloop_data, void *user_data)
334{
335 struct eloop_timeout *tmp;
336
337 tmp = eloop.timeout;
338 while (tmp != NULL) {
339 if (tmp->handler == handler &&
340 tmp->eloop_data == eloop_data &&
341 tmp->user_data == user_data)
342 return 1;
343
344 tmp = tmp->next;
345 }
346
347 return 0;
348}
349
350
351/* TODO: replace with suitable signal handler */
352#if 0
353static void eloop_handle_signal(int sig)
354{
355 int i;
356
357 eloop.signaled++;
358 for (i = 0; i < eloop.signal_count; i++) {
359 if (eloop.signals[i].sig == sig) {
360 eloop.signals[i].signaled++;
361 break;
362 }
363 }
364}
365#endif
366
367
368static void eloop_process_pending_signals(void)
369{
370 int i;
371
372 if (eloop.signaled == 0)
373 return;
374 eloop.signaled = 0;
375
376 if (eloop.pending_terminate) {
377 eloop.pending_terminate = 0;
378 }
379
380 for (i = 0; i < eloop.signal_count; i++) {
381 if (eloop.signals[i].signaled) {
382 eloop.signals[i].signaled = 0;
383 eloop.signals[i].handler(eloop.signals[i].sig,
384 eloop.signals[i].user_data);
385 }
386 }
387
388 if (eloop.term_signal.signaled) {
389 eloop.term_signal.signaled = 0;
390 eloop.term_signal.handler(eloop.term_signal.sig,
391 eloop.term_signal.user_data);
392 }
393}
394
395
396int eloop_register_signal(int sig, eloop_signal_handler handler,
397 void *user_data)
398{
399 struct eloop_signal *tmp;
400
401 tmp = os_realloc(eloop.signals,
402 (eloop.signal_count + 1) *
403 sizeof(struct eloop_signal));
404 if (tmp == NULL)
405 return -1;
406
407 tmp[eloop.signal_count].sig = sig;
408 tmp[eloop.signal_count].user_data = user_data;
409 tmp[eloop.signal_count].handler = handler;
410 tmp[eloop.signal_count].signaled = 0;
411 eloop.signal_count++;
412 eloop.signals = tmp;
413
414 /* TODO: register signal handler */
415
416 return 0;
417}
418
419
420#ifndef _WIN32_WCE
421static BOOL eloop_handle_console_ctrl(DWORD type)
422{
423 switch (type) {
424 case CTRL_C_EVENT:
425 case CTRL_BREAK_EVENT:
426 eloop.signaled++;
427 eloop.term_signal.signaled++;
428 SetEvent(eloop.term_event);
429 return TRUE;
430 default:
431 return FALSE;
432 }
433}
434#endif /* _WIN32_WCE */
435
436
437int eloop_register_signal_terminate(eloop_signal_handler handler,
438 void *user_data)
439{
440#ifndef _WIN32_WCE
441 if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl,
442 TRUE) == 0) {
443 printf("SetConsoleCtrlHandler() failed: %d\n",
444 (int) GetLastError());
445 return -1;
446 }
447#endif /* _WIN32_WCE */
448
449 eloop.term_signal.handler = handler;
450 eloop.term_signal.user_data = user_data;
451
452 return 0;
453}
454
455
456int eloop_register_signal_reconfig(eloop_signal_handler handler,
457 void *user_data)
458{
459 /* TODO */
460 return 0;
461}
462
463
464void eloop_run(void)
465{
466 struct os_time tv, now;
467 DWORD count, ret, timeout, err;
468 size_t i;
469
470 while (!eloop.terminate &&
471 (eloop.timeout || eloop.reader_count > 0 ||
472 eloop.event_count > 0)) {
473 tv.sec = tv.usec = 0;
474 if (eloop.timeout) {
475 os_get_time(&now);
476 if (os_time_before(&now, &eloop.timeout->time))
477 os_time_sub(&eloop.timeout->time, &now, &tv);
478 }
479
480 count = 0;
481 for (i = 0; i < eloop.event_count; i++)
482 eloop.handles[count++] = eloop.events[i].event;
483
484 for (i = 0; i < eloop.reader_count; i++)
485 eloop.handles[count++] = eloop.readers[i].event;
486
487 if (eloop.term_event)
488 eloop.handles[count++] = eloop.term_event;
489
490 if (eloop.timeout)
491 timeout = tv.sec * 1000 + tv.usec / 1000;
492 else
493 timeout = INFINITE;
494
495 if (count > MAXIMUM_WAIT_OBJECTS) {
496 printf("WaitForMultipleObjects: Too many events: "
497 "%d > %d (ignoring extra events)\n",
498 (int) count, MAXIMUM_WAIT_OBJECTS);
499 count = MAXIMUM_WAIT_OBJECTS;
500 }
501#ifdef _WIN32_WCE
502 ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
503 timeout);
504#else /* _WIN32_WCE */
505 ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
506 timeout, TRUE);
507#endif /* _WIN32_WCE */
508 err = GetLastError();
509
510 eloop_process_pending_signals();
511
512 /* check if some registered timeouts have occurred */
513 if (eloop.timeout) {
514 struct eloop_timeout *tmp;
515
516 os_get_time(&now);
517 if (!os_time_before(&now, &eloop.timeout->time)) {
518 tmp = eloop.timeout;
519 eloop.timeout = eloop.timeout->next;
520 tmp->handler(tmp->eloop_data,
521 tmp->user_data);
522 os_free(tmp);
523 }
524
525 }
526
527 if (ret == WAIT_FAILED) {
528 printf("WaitForMultipleObjects(count=%d) failed: %d\n",
529 (int) count, (int) err);
530 os_sleep(1, 0);
531 continue;
532 }
533
534#ifndef _WIN32_WCE
535 if (ret == WAIT_IO_COMPLETION)
536 continue;
537#endif /* _WIN32_WCE */
538
539 if (ret == WAIT_TIMEOUT)
540 continue;
541
542 while (ret >= WAIT_OBJECT_0 &&
543 ret < WAIT_OBJECT_0 + eloop.event_count) {
544 eloop.events[ret].handler(
545 eloop.events[ret].eloop_data,
546 eloop.events[ret].user_data);
547 ret = WaitForMultipleObjects(eloop.event_count,
548 eloop.handles, FALSE, 0);
549 }
550
551 eloop.reader_table_changed = 0;
552 for (i = 0; i < eloop.reader_count; i++) {
553 WSANETWORKEVENTS events;
554 if (WSAEnumNetworkEvents(eloop.readers[i].sock,
555 eloop.readers[i].event,
556 &events) == 0 &&
557 (events.lNetworkEvents & FD_READ)) {
558 eloop.readers[i].handler(
559 eloop.readers[i].sock,
560 eloop.readers[i].eloop_data,
561 eloop.readers[i].user_data);
562 if (eloop.reader_table_changed)
563 break;
564 }
565 }
566 }
567}
568
569
570void eloop_terminate(void)
571{
572 eloop.terminate = 1;
573 SetEvent(eloop.term_event);
574}
575
576
577void eloop_destroy(void)
578{
579 struct eloop_timeout *timeout, *prev;
580
581 timeout = eloop.timeout;
582 while (timeout != NULL) {
583 prev = timeout;
584 timeout = timeout->next;
585 os_free(prev);
586 }
587 os_free(eloop.readers);
588 os_free(eloop.signals);
589 if (eloop.term_event)
590 CloseHandle(eloop.term_event);
591 os_free(eloop.handles);
592 eloop.handles = NULL;
593 os_free(eloop.events);
594 eloop.events = NULL;
595}
596
597
598int eloop_terminated(void)
599{
600 return eloop.terminate;
601}
602
603
604void eloop_wait_for_read_sock(int sock)
605{
606 WSAEVENT event;
607
608 event = WSACreateEvent();
609 if (event == WSA_INVALID_EVENT) {
610 printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
611 return;
612 }
613
614 if (WSAEventSelect(sock, event, FD_READ)) {
615 printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
616 WSACloseEvent(event);
617 return ;
618 }
619
620 WaitForSingleObject(event, INFINITE);
621 WSAEventSelect(sock, event, 0);
622 WSACloseEvent(event);
623}