2 * Event loop based on select() loop
3 * Copyright (c) 2002-2005, 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.
25 eloop_sock_handler handler;
28 struct eloop_timeout {
32 eloop_timeout_handler handler;
33 struct eloop_timeout *next;
39 eloop_signal_handler handler;
43 struct eloop_sock_table {
45 struct eloop_sock *table;
54 struct eloop_sock_table readers;
55 struct eloop_sock_table writers;
56 struct eloop_sock_table exceptions;
58 struct eloop_timeout *timeout;
61 struct eloop_signal *signals;
63 int pending_terminate;
66 int reader_table_changed;
69 static struct eloop_data eloop;
72 int eloop_init(void *user_data)
74 os_memset(&eloop, 0, sizeof(eloop));
75 eloop.user_data = user_data;
80 static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
81 int sock, eloop_sock_handler handler,
82 void *eloop_data, void *user_data)
84 struct eloop_sock *tmp;
89 tmp = (struct eloop_sock *)
90 os_realloc(table->table,
91 (table->count + 1) * sizeof(struct eloop_sock));
95 tmp[table->count].sock = sock;
96 tmp[table->count].eloop_data = eloop_data;
97 tmp[table->count].user_data = user_data;
98 tmp[table->count].handler = handler;
101 if (sock > eloop.max_sock)
102 eloop.max_sock = sock;
109 static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
114 if (table == NULL || table->table == NULL || table->count == 0)
117 for (i = 0; i < table->count; i++) {
118 if (table->table[i].sock == sock)
121 if (i == table->count)
123 if (i != table->count - 1) {
124 os_memmove(&table->table[i], &table->table[i + 1],
125 (table->count - i - 1) *
126 sizeof(struct eloop_sock));
133 static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
140 if (table->table == NULL)
143 for (i = 0; i < table->count; i++)
144 FD_SET(table->table[i].sock, fds);
148 static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
153 if (table == NULL || table->table == NULL)
157 for (i = 0; i < table->count; i++) {
158 if (FD_ISSET(table->table[i].sock, fds)) {
159 table->table[i].handler(table->table[i].sock,
160 table->table[i].eloop_data,
161 table->table[i].user_data);
169 static void eloop_sock_table_destroy(struct eloop_sock_table *table)
172 os_free(table->table);
176 int eloop_register_read_sock(int sock, eloop_sock_handler handler,
177 void *eloop_data, void *user_data)
179 return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
180 eloop_data, user_data);
184 void eloop_unregister_read_sock(int sock)
186 eloop_unregister_sock(sock, EVENT_TYPE_READ);
190 static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
193 case EVENT_TYPE_READ:
194 return &eloop.readers;
195 case EVENT_TYPE_WRITE:
196 return &eloop.writers;
197 case EVENT_TYPE_EXCEPTION:
198 return &eloop.exceptions;
205 int eloop_register_sock(int sock, eloop_event_type type,
206 eloop_sock_handler handler,
207 void *eloop_data, void *user_data)
209 struct eloop_sock_table *table;
211 table = eloop_get_sock_table(type);
212 return eloop_sock_table_add_sock(table, sock, handler,
213 eloop_data, user_data);
217 void eloop_unregister_sock(int sock, eloop_event_type type)
219 struct eloop_sock_table *table;
221 table = eloop_get_sock_table(type);
222 eloop_sock_table_remove_sock(table, sock);
226 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
227 eloop_timeout_handler handler,
228 void *eloop_data, void *user_data)
230 struct eloop_timeout *timeout, *tmp, *prev;
232 timeout = os_malloc(sizeof(*timeout));
235 os_get_time(&timeout->time);
236 timeout->time.sec += secs;
237 timeout->time.usec += usecs;
238 while (timeout->time.usec >= 1000000) {
240 timeout->time.usec -= 1000000;
242 timeout->eloop_data = eloop_data;
243 timeout->user_data = user_data;
244 timeout->handler = handler;
245 timeout->next = NULL;
247 if (eloop.timeout == NULL) {
248 eloop.timeout = timeout;
254 while (tmp != NULL) {
255 if (os_time_before(&timeout->time, &tmp->time))
262 timeout->next = eloop.timeout;
263 eloop.timeout = timeout;
265 timeout->next = prev->next;
266 prev->next = timeout;
273 int eloop_cancel_timeout(eloop_timeout_handler handler,
274 void *eloop_data, void *user_data)
276 struct eloop_timeout *timeout, *prev, *next;
280 timeout = eloop.timeout;
281 while (timeout != NULL) {
282 next = timeout->next;
284 if (timeout->handler == handler &&
285 (timeout->eloop_data == eloop_data ||
286 eloop_data == ELOOP_ALL_CTX) &&
287 (timeout->user_data == user_data ||
288 user_data == ELOOP_ALL_CTX)) {
290 eloop.timeout = next;
305 #ifndef CONFIG_NATIVE_WINDOWS
306 static void eloop_handle_alarm(int sig)
308 fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
309 "seconds. Looks like there\n"
310 "is a bug that ends up in a busy loop that "
311 "prevents clean shutdown.\n"
312 "Killing program forcefully.\n");
315 #endif /* CONFIG_NATIVE_WINDOWS */
318 static void eloop_handle_signal(int sig)
322 #ifndef CONFIG_NATIVE_WINDOWS
323 if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
324 /* Use SIGALRM to break out from potential busy loops that
325 * would not allow the program to be killed. */
326 eloop.pending_terminate = 1;
327 signal(SIGALRM, eloop_handle_alarm);
330 #endif /* CONFIG_NATIVE_WINDOWS */
333 for (i = 0; i < eloop.signal_count; i++) {
334 if (eloop.signals[i].sig == sig) {
335 eloop.signals[i].signaled++;
342 static void eloop_process_pending_signals(void)
346 if (eloop.signaled == 0)
350 if (eloop.pending_terminate) {
351 #ifndef CONFIG_NATIVE_WINDOWS
353 #endif /* CONFIG_NATIVE_WINDOWS */
354 eloop.pending_terminate = 0;
357 for (i = 0; i < eloop.signal_count; i++) {
358 if (eloop.signals[i].signaled) {
359 eloop.signals[i].signaled = 0;
360 eloop.signals[i].handler(eloop.signals[i].sig,
362 eloop.signals[i].user_data);
368 int eloop_register_signal(int sig, eloop_signal_handler handler,
371 struct eloop_signal *tmp;
373 tmp = (struct eloop_signal *)
374 os_realloc(eloop.signals,
375 (eloop.signal_count + 1) *
376 sizeof(struct eloop_signal));
380 tmp[eloop.signal_count].sig = sig;
381 tmp[eloop.signal_count].user_data = user_data;
382 tmp[eloop.signal_count].handler = handler;
383 tmp[eloop.signal_count].signaled = 0;
384 eloop.signal_count++;
386 signal(sig, eloop_handle_signal);
392 int eloop_register_signal_terminate(eloop_signal_handler handler,
395 int ret = eloop_register_signal(SIGINT, handler, user_data);
397 ret = eloop_register_signal(SIGTERM, handler, user_data);
402 int eloop_register_signal_reconfig(eloop_signal_handler handler,
405 #ifdef CONFIG_NATIVE_WINDOWS
407 #else /* CONFIG_NATIVE_WINDOWS */
408 return eloop_register_signal(SIGHUP, handler, user_data);
409 #endif /* CONFIG_NATIVE_WINDOWS */
415 fd_set *rfds, *wfds, *efds;
418 struct os_time tv, now;
420 rfds = os_malloc(sizeof(*rfds));
421 wfds = os_malloc(sizeof(*wfds));
422 efds = os_malloc(sizeof(*efds));
423 if (rfds == NULL || wfds == NULL || efds == NULL) {
424 printf("eloop_run - malloc failed\n");
428 while (!eloop.terminate &&
429 (eloop.timeout || eloop.readers.count > 0 ||
430 eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
433 if (os_time_before(&now, &eloop.timeout->time))
434 os_time_sub(&eloop.timeout->time, &now, &tv);
436 tv.sec = tv.usec = 0;
438 printf("next timeout in %lu.%06lu sec\n",
442 _tv.tv_usec = tv.usec;
445 eloop_sock_table_set_fds(&eloop.readers, rfds);
446 eloop_sock_table_set_fds(&eloop.writers, wfds);
447 eloop_sock_table_set_fds(&eloop.exceptions, efds);
448 res = select(eloop.max_sock + 1, rfds, wfds, efds,
449 eloop.timeout ? &_tv : NULL);
450 if (res < 0 && errno != EINTR && errno != 0) {
454 eloop_process_pending_signals();
456 /* check if some registered timeouts have occurred */
458 struct eloop_timeout *tmp;
461 if (!os_time_before(&now, &eloop.timeout->time)) {
463 eloop.timeout = eloop.timeout->next;
464 tmp->handler(tmp->eloop_data,
474 eloop_sock_table_dispatch(&eloop.readers, rfds);
475 eloop_sock_table_dispatch(&eloop.writers, wfds);
476 eloop_sock_table_dispatch(&eloop.exceptions, efds);
486 void eloop_terminate(void)
492 void eloop_destroy(void)
494 struct eloop_timeout *timeout, *prev;
496 timeout = eloop.timeout;
497 while (timeout != NULL) {
499 timeout = timeout->next;
502 eloop_sock_table_destroy(&eloop.readers);
503 eloop_sock_table_destroy(&eloop.writers);
504 eloop_sock_table_destroy(&eloop.exceptions);
505 os_free(eloop.signals);
509 int eloop_terminated(void)
511 return eloop.terminate;
515 void eloop_wait_for_read_sock(int sock)
524 select(sock + 1, &rfds, NULL, NULL, NULL);
528 void * eloop_get_user_data(void)
530 return eloop.user_data;