Home | History | Annotate | Download | only in utils
      1 /*
      2  * Event loop based on select() loop
      3  * Copyright (c) 2002-2009, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 
     11 #include "common.h"
     12 #include "trace.h"
     13 #include "list.h"
     14 #include "eloop.h"
     15 
     16 #ifdef CONFIG_ELOOP_POLL
     17 #include <assert.h>
     18 #include <poll.h>
     19 #endif /* CONFIG_ELOOP_POLL */
     20 
     21 
     22 struct eloop_sock {
     23 	int sock;
     24 	void *eloop_data;
     25 	void *user_data;
     26 	eloop_sock_handler handler;
     27 	WPA_TRACE_REF(eloop);
     28 	WPA_TRACE_REF(user);
     29 	WPA_TRACE_INFO
     30 };
     31 
     32 struct eloop_timeout {
     33 	struct dl_list list;
     34 	struct os_time time;
     35 	void *eloop_data;
     36 	void *user_data;
     37 	eloop_timeout_handler handler;
     38 	WPA_TRACE_REF(eloop);
     39 	WPA_TRACE_REF(user);
     40 	WPA_TRACE_INFO
     41 };
     42 
     43 struct eloop_signal {
     44 	int sig;
     45 	void *user_data;
     46 	eloop_signal_handler handler;
     47 	int signaled;
     48 };
     49 
     50 struct eloop_sock_table {
     51 	int count;
     52 	struct eloop_sock *table;
     53 	int changed;
     54 };
     55 
     56 struct eloop_data {
     57 	int max_sock;
     58 
     59 	int count; /* sum of all table counts */
     60 #ifdef CONFIG_ELOOP_POLL
     61 	int max_pollfd_map; /* number of pollfds_map currently allocated */
     62 	int max_poll_fds; /* number of pollfds currently allocated */
     63 	struct pollfd *pollfds;
     64 	struct pollfd **pollfds_map;
     65 #endif /* CONFIG_ELOOP_POLL */
     66 	struct eloop_sock_table readers;
     67 	struct eloop_sock_table writers;
     68 	struct eloop_sock_table exceptions;
     69 
     70 	struct dl_list timeout;
     71 
     72 	int signal_count;
     73 	struct eloop_signal *signals;
     74 	int signaled;
     75 	int pending_terminate;
     76 
     77 	int terminate;
     78 	int reader_table_changed;
     79 };
     80 
     81 static struct eloop_data eloop;
     82 
     83 
     84 #ifdef WPA_TRACE
     85 
     86 static void eloop_sigsegv_handler(int sig)
     87 {
     88 	wpa_trace_show("eloop SIGSEGV");
     89 	abort();
     90 }
     91 
     92 static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
     93 {
     94 	int i;
     95 	if (table == NULL || table->table == NULL)
     96 		return;
     97 	for (i = 0; i < table->count; i++) {
     98 		wpa_trace_add_ref(&table->table[i], eloop,
     99 				  table->table[i].eloop_data);
    100 		wpa_trace_add_ref(&table->table[i], user,
    101 				  table->table[i].user_data);
    102 	}
    103 }
    104 
    105 
    106 static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
    107 {
    108 	int i;
    109 	if (table == NULL || table->table == NULL)
    110 		return;
    111 	for (i = 0; i < table->count; i++) {
    112 		wpa_trace_remove_ref(&table->table[i], eloop,
    113 				     table->table[i].eloop_data);
    114 		wpa_trace_remove_ref(&table->table[i], user,
    115 				     table->table[i].user_data);
    116 	}
    117 }
    118 
    119 #else /* WPA_TRACE */
    120 
    121 #define eloop_trace_sock_add_ref(table) do { } while (0)
    122 #define eloop_trace_sock_remove_ref(table) do { } while (0)
    123 
    124 #endif /* WPA_TRACE */
    125 
    126 
    127 int eloop_init(void)
    128 {
    129 	os_memset(&eloop, 0, sizeof(eloop));
    130 	dl_list_init(&eloop.timeout);
    131 #ifdef WPA_TRACE
    132 	signal(SIGSEGV, eloop_sigsegv_handler);
    133 #endif /* WPA_TRACE */
    134 	return 0;
    135 }
    136 
    137 
    138 static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
    139                                      int sock, eloop_sock_handler handler,
    140                                      void *eloop_data, void *user_data)
    141 {
    142 	struct eloop_sock *tmp;
    143 	int new_max_sock;
    144 
    145 	if (sock > eloop.max_sock)
    146 		new_max_sock = sock;
    147 	else
    148 		new_max_sock = eloop.max_sock;
    149 
    150 	if (table == NULL)
    151 		return -1;
    152 
    153 #ifdef CONFIG_ELOOP_POLL
    154 	if (new_max_sock >= eloop.max_pollfd_map) {
    155 		struct pollfd **nmap;
    156 		nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
    157 					sizeof(struct pollfd *));
    158 		if (nmap == NULL)
    159 			return -1;
    160 
    161 		eloop.max_pollfd_map = new_max_sock + 50;
    162 		eloop.pollfds_map = nmap;
    163 	}
    164 
    165 	if (eloop.count + 1 > eloop.max_poll_fds) {
    166 		struct pollfd *n;
    167 		int nmax = eloop.count + 1 + 50;
    168 		n = os_realloc_array(eloop.pollfds, nmax,
    169 				     sizeof(struct pollfd));
    170 		if (n == NULL)
    171 			return -1;
    172 
    173 		eloop.max_poll_fds = nmax;
    174 		eloop.pollfds = n;
    175 	}
    176 #endif /* CONFIG_ELOOP_POLL */
    177 
    178 	eloop_trace_sock_remove_ref(table);
    179 	tmp = os_realloc_array(table->table, table->count + 1,
    180 			       sizeof(struct eloop_sock));
    181 	if (tmp == NULL)
    182 		return -1;
    183 
    184 	tmp[table->count].sock = sock;
    185 	tmp[table->count].eloop_data = eloop_data;
    186 	tmp[table->count].user_data = user_data;
    187 	tmp[table->count].handler = handler;
    188 	wpa_trace_record(&tmp[table->count]);
    189 	table->count++;
    190 	table->table = tmp;
    191 	eloop.max_sock = new_max_sock;
    192 	eloop.count++;
    193 	table->changed = 1;
    194 	eloop_trace_sock_add_ref(table);
    195 
    196 	return 0;
    197 }
    198 
    199 
    200 static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
    201                                          int sock)
    202 {
    203 	int i;
    204 
    205 	if (table == NULL || table->table == NULL || table->count == 0)
    206 		return;
    207 
    208 	for (i = 0; i < table->count; i++) {
    209 		if (table->table[i].sock == sock)
    210 			break;
    211 	}
    212 	if (i == table->count)
    213 		return;
    214 	eloop_trace_sock_remove_ref(table);
    215 	if (i != table->count - 1) {
    216 		os_memmove(&table->table[i], &table->table[i + 1],
    217 			   (table->count - i - 1) *
    218 			   sizeof(struct eloop_sock));
    219 	}
    220 	table->count--;
    221 	eloop.count--;
    222 	table->changed = 1;
    223 	eloop_trace_sock_add_ref(table);
    224 }
    225 
    226 
    227 #ifdef CONFIG_ELOOP_POLL
    228 
    229 static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
    230 {
    231 	if (fd < mx && fd >= 0)
    232 		return pollfds_map[fd];
    233 	return NULL;
    234 }
    235 
    236 
    237 static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
    238 				    struct eloop_sock_table *writers,
    239 				    struct eloop_sock_table *exceptions,
    240 				    struct pollfd *pollfds,
    241 				    struct pollfd **pollfds_map,
    242 				    int max_pollfd_map)
    243 {
    244 	int i;
    245 	int nxt = 0;
    246 	int fd;
    247 	struct pollfd *pfd;
    248 
    249 	/* Clear pollfd lookup map. It will be re-populated below. */
    250 	os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
    251 
    252 	if (readers && readers->table) {
    253 		for (i = 0; i < readers->count; i++) {
    254 			fd = readers->table[i].sock;
    255 			assert(fd >= 0 && fd < max_pollfd_map);
    256 			pollfds[nxt].fd = fd;
    257 			pollfds[nxt].events = POLLIN;
    258 			pollfds[nxt].revents = 0;
    259 			pollfds_map[fd] = &(pollfds[nxt]);
    260 			nxt++;
    261 		}
    262 	}
    263 
    264 	if (writers && writers->table) {
    265 		for (i = 0; i < writers->count; i++) {
    266 			/*
    267 			 * See if we already added this descriptor, update it
    268 			 * if so.
    269 			 */
    270 			fd = writers->table[i].sock;
    271 			assert(fd >= 0 && fd < max_pollfd_map);
    272 			pfd = pollfds_map[fd];
    273 			if (!pfd) {
    274 				pfd = &(pollfds[nxt]);
    275 				pfd->events = 0;
    276 				pfd->fd = fd;
    277 				pollfds[i].revents = 0;
    278 				pollfds_map[fd] = pfd;
    279 				nxt++;
    280 			}
    281 			pfd->events |= POLLOUT;
    282 		}
    283 	}
    284 
    285 	/*
    286 	 * Exceptions are always checked when using poll, but I suppose it's
    287 	 * possible that someone registered a socket *only* for exception
    288 	 * handling. Set the POLLIN bit in this case.
    289 	 */
    290 	if (exceptions && exceptions->table) {
    291 		for (i = 0; i < exceptions->count; i++) {
    292 			/*
    293 			 * See if we already added this descriptor, just use it
    294 			 * if so.
    295 			 */
    296 			fd = exceptions->table[i].sock;
    297 			assert(fd >= 0 && fd < max_pollfd_map);
    298 			pfd = pollfds_map[fd];
    299 			if (!pfd) {
    300 				pfd = &(pollfds[nxt]);
    301 				pfd->events = POLLIN;
    302 				pfd->fd = fd;
    303 				pollfds[i].revents = 0;
    304 				pollfds_map[fd] = pfd;
    305 				nxt++;
    306 			}
    307 		}
    308 	}
    309 
    310 	return nxt;
    311 }
    312 
    313 
    314 static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
    315 					   struct pollfd **pollfds_map,
    316 					   int max_pollfd_map,
    317 					   short int revents)
    318 {
    319 	int i;
    320 	struct pollfd *pfd;
    321 
    322 	if (!table || !table->table)
    323 		return 0;
    324 
    325 	table->changed = 0;
    326 	for (i = 0; i < table->count; i++) {
    327 		pfd = find_pollfd(pollfds_map, table->table[i].sock,
    328 				  max_pollfd_map);
    329 		if (!pfd)
    330 			continue;
    331 
    332 		if (!(pfd->revents & revents))
    333 			continue;
    334 
    335 		table->table[i].handler(table->table[i].sock,
    336 					table->table[i].eloop_data,
    337 					table->table[i].user_data);
    338 		if (table->changed)
    339 			return 1;
    340 	}
    341 
    342 	return 0;
    343 }
    344 
    345 
    346 static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
    347 				      struct eloop_sock_table *writers,
    348 				      struct eloop_sock_table *exceptions,
    349 				      struct pollfd **pollfds_map,
    350 				      int max_pollfd_map)
    351 {
    352 	if (eloop_sock_table_dispatch_table(readers, pollfds_map,
    353 					    max_pollfd_map, POLLIN | POLLERR |
    354 					    POLLHUP))
    355 		return; /* pollfds may be invalid at this point */
    356 
    357 	if (eloop_sock_table_dispatch_table(writers, pollfds_map,
    358 					    max_pollfd_map, POLLOUT))
    359 		return; /* pollfds may be invalid at this point */
    360 
    361 	eloop_sock_table_dispatch_table(exceptions, pollfds_map,
    362 					max_pollfd_map, POLLERR | POLLHUP);
    363 }
    364 
    365 #else /* CONFIG_ELOOP_POLL */
    366 
    367 static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
    368 				     fd_set *fds)
    369 {
    370 	int i;
    371 
    372 	FD_ZERO(fds);
    373 
    374 	if (table->table == NULL)
    375 		return;
    376 
    377 	for (i = 0; i < table->count; i++)
    378 		FD_SET(table->table[i].sock, fds);
    379 }
    380 
    381 
    382 static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
    383 				      fd_set *fds)
    384 {
    385 	int i;
    386 
    387 	if (table == NULL || table->table == NULL)
    388 		return;
    389 
    390 	table->changed = 0;
    391 	for (i = 0; i < table->count; i++) {
    392 		if (FD_ISSET(table->table[i].sock, fds)) {
    393 			table->table[i].handler(table->table[i].sock,
    394 						table->table[i].eloop_data,
    395 						table->table[i].user_data);
    396 			if (table->changed)
    397 				break;
    398 		}
    399 	}
    400 }
    401 
    402 #endif /* CONFIG_ELOOP_POLL */
    403 
    404 
    405 static void eloop_sock_table_destroy(struct eloop_sock_table *table)
    406 {
    407 	if (table) {
    408 		int i;
    409 		for (i = 0; i < table->count && table->table; i++) {
    410 			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
    411 				   "sock=%d eloop_data=%p user_data=%p "
    412 				   "handler=%p",
    413 				   table->table[i].sock,
    414 				   table->table[i].eloop_data,
    415 				   table->table[i].user_data,
    416 				   table->table[i].handler);
    417 			wpa_trace_dump_funcname("eloop unregistered socket "
    418 						"handler",
    419 						table->table[i].handler);
    420 			wpa_trace_dump("eloop sock", &table->table[i]);
    421 		}
    422 		os_free(table->table);
    423 	}
    424 }
    425 
    426 
    427 int eloop_register_read_sock(int sock, eloop_sock_handler handler,
    428 			     void *eloop_data, void *user_data)
    429 {
    430 	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
    431 				   eloop_data, user_data);
    432 }
    433 
    434 
    435 void eloop_unregister_read_sock(int sock)
    436 {
    437 	eloop_unregister_sock(sock, EVENT_TYPE_READ);
    438 }
    439 
    440 
    441 static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
    442 {
    443 	switch (type) {
    444 	case EVENT_TYPE_READ:
    445 		return &eloop.readers;
    446 	case EVENT_TYPE_WRITE:
    447 		return &eloop.writers;
    448 	case EVENT_TYPE_EXCEPTION:
    449 		return &eloop.exceptions;
    450 	}
    451 
    452 	return NULL;
    453 }
    454 
    455 
    456 int eloop_register_sock(int sock, eloop_event_type type,
    457 			eloop_sock_handler handler,
    458 			void *eloop_data, void *user_data)
    459 {
    460 	struct eloop_sock_table *table;
    461 
    462 	table = eloop_get_sock_table(type);
    463 	return eloop_sock_table_add_sock(table, sock, handler,
    464 					 eloop_data, user_data);
    465 }
    466 
    467 
    468 void eloop_unregister_sock(int sock, eloop_event_type type)
    469 {
    470 	struct eloop_sock_table *table;
    471 
    472 	table = eloop_get_sock_table(type);
    473 	eloop_sock_table_remove_sock(table, sock);
    474 }
    475 
    476 
    477 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
    478 			   eloop_timeout_handler handler,
    479 			   void *eloop_data, void *user_data)
    480 {
    481 	struct eloop_timeout *timeout, *tmp;
    482 	os_time_t now_sec;
    483 
    484 	timeout = os_zalloc(sizeof(*timeout));
    485 	if (timeout == NULL)
    486 		return -1;
    487 	if (os_get_time(&timeout->time) < 0) {
    488 		os_free(timeout);
    489 		return -1;
    490 	}
    491 	now_sec = timeout->time.sec;
    492 	timeout->time.sec += secs;
    493 	if (timeout->time.sec < now_sec) {
    494 		/*
    495 		 * Integer overflow - assume long enough timeout to be assumed
    496 		 * to be infinite, i.e., the timeout would never happen.
    497 		 */
    498 		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
    499 			   "ever happen - ignore it", secs);
    500 		os_free(timeout);
    501 		return 0;
    502 	}
    503 	timeout->time.usec += usecs;
    504 	while (timeout->time.usec >= 1000000) {
    505 		timeout->time.sec++;
    506 		timeout->time.usec -= 1000000;
    507 	}
    508 	timeout->eloop_data = eloop_data;
    509 	timeout->user_data = user_data;
    510 	timeout->handler = handler;
    511 	wpa_trace_add_ref(timeout, eloop, eloop_data);
    512 	wpa_trace_add_ref(timeout, user, user_data);
    513 	wpa_trace_record(timeout);
    514 
    515 	/* Maintain timeouts in order of increasing time */
    516 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
    517 		if (os_time_before(&timeout->time, &tmp->time)) {
    518 			dl_list_add(tmp->list.prev, &timeout->list);
    519 			return 0;
    520 		}
    521 	}
    522 	dl_list_add_tail(&eloop.timeout, &timeout->list);
    523 
    524 	return 0;
    525 }
    526 
    527 
    528 static void eloop_remove_timeout(struct eloop_timeout *timeout)
    529 {
    530 	dl_list_del(&timeout->list);
    531 	wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
    532 	wpa_trace_remove_ref(timeout, user, timeout->user_data);
    533 	os_free(timeout);
    534 }
    535 
    536 
    537 int eloop_cancel_timeout(eloop_timeout_handler handler,
    538 			 void *eloop_data, void *user_data)
    539 {
    540 	struct eloop_timeout *timeout, *prev;
    541 	int removed = 0;
    542 
    543 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
    544 			      struct eloop_timeout, list) {
    545 		if (timeout->handler == handler &&
    546 		    (timeout->eloop_data == eloop_data ||
    547 		     eloop_data == ELOOP_ALL_CTX) &&
    548 		    (timeout->user_data == user_data ||
    549 		     user_data == ELOOP_ALL_CTX)) {
    550 			eloop_remove_timeout(timeout);
    551 			removed++;
    552 		}
    553 	}
    554 
    555 	return removed;
    556 }
    557 
    558 
    559 int eloop_cancel_timeout_one(eloop_timeout_handler handler,
    560 			     void *eloop_data, void *user_data,
    561 			     struct os_time *remaining)
    562 {
    563 	struct eloop_timeout *timeout, *prev;
    564 	int removed = 0;
    565 	struct os_time now;
    566 
    567 	os_get_time(&now);
    568 	remaining->sec = remaining->usec = 0;
    569 
    570 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
    571 			      struct eloop_timeout, list) {
    572 		if (timeout->handler == handler &&
    573 		    (timeout->eloop_data == eloop_data) &&
    574 		    (timeout->user_data == user_data)) {
    575 			removed = 1;
    576 			if (os_time_before(&now, &timeout->time))
    577 				os_time_sub(&timeout->time, &now, remaining);
    578 			eloop_remove_timeout(timeout);
    579 			break;
    580 		}
    581 	}
    582 	return removed;
    583 }
    584 
    585 
    586 int eloop_is_timeout_registered(eloop_timeout_handler handler,
    587 				void *eloop_data, void *user_data)
    588 {
    589 	struct eloop_timeout *tmp;
    590 
    591 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
    592 		if (tmp->handler == handler &&
    593 		    tmp->eloop_data == eloop_data &&
    594 		    tmp->user_data == user_data)
    595 			return 1;
    596 	}
    597 
    598 	return 0;
    599 }
    600 
    601 
    602 #ifndef CONFIG_NATIVE_WINDOWS
    603 static void eloop_handle_alarm(int sig)
    604 {
    605 	wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
    606 		   "two seconds. Looks like there\n"
    607 		   "is a bug that ends up in a busy loop that "
    608 		   "prevents clean shutdown.\n"
    609 		   "Killing program forcefully.\n");
    610 	exit(1);
    611 }
    612 #endif /* CONFIG_NATIVE_WINDOWS */
    613 
    614 
    615 static void eloop_handle_signal(int sig)
    616 {
    617 	int i;
    618 
    619 #ifndef CONFIG_NATIVE_WINDOWS
    620 	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
    621 		/* Use SIGALRM to break out from potential busy loops that
    622 		 * would not allow the program to be killed. */
    623 		eloop.pending_terminate = 1;
    624 		signal(SIGALRM, eloop_handle_alarm);
    625 		alarm(2);
    626 	}
    627 #endif /* CONFIG_NATIVE_WINDOWS */
    628 
    629 	eloop.signaled++;
    630 	for (i = 0; i < eloop.signal_count; i++) {
    631 		if (eloop.signals[i].sig == sig) {
    632 			eloop.signals[i].signaled++;
    633 			break;
    634 		}
    635 	}
    636 }
    637 
    638 
    639 static void eloop_process_pending_signals(void)
    640 {
    641 	int i;
    642 
    643 	if (eloop.signaled == 0)
    644 		return;
    645 	eloop.signaled = 0;
    646 
    647 	if (eloop.pending_terminate) {
    648 #ifndef CONFIG_NATIVE_WINDOWS
    649 		alarm(0);
    650 #endif /* CONFIG_NATIVE_WINDOWS */
    651 		eloop.pending_terminate = 0;
    652 	}
    653 
    654 	for (i = 0; i < eloop.signal_count; i++) {
    655 		if (eloop.signals[i].signaled) {
    656 			eloop.signals[i].signaled = 0;
    657 			eloop.signals[i].handler(eloop.signals[i].sig,
    658 						 eloop.signals[i].user_data);
    659 		}
    660 	}
    661 }
    662 
    663 
    664 int eloop_register_signal(int sig, eloop_signal_handler handler,
    665 			  void *user_data)
    666 {
    667 	struct eloop_signal *tmp;
    668 
    669 	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
    670 			       sizeof(struct eloop_signal));
    671 	if (tmp == NULL)
    672 		return -1;
    673 
    674 	tmp[eloop.signal_count].sig = sig;
    675 	tmp[eloop.signal_count].user_data = user_data;
    676 	tmp[eloop.signal_count].handler = handler;
    677 	tmp[eloop.signal_count].signaled = 0;
    678 	eloop.signal_count++;
    679 	eloop.signals = tmp;
    680 	signal(sig, eloop_handle_signal);
    681 
    682 	return 0;
    683 }
    684 
    685 
    686 int eloop_register_signal_terminate(eloop_signal_handler handler,
    687 				    void *user_data)
    688 {
    689 	int ret = eloop_register_signal(SIGINT, handler, user_data);
    690 	if (ret == 0)
    691 		ret = eloop_register_signal(SIGTERM, handler, user_data);
    692 	return ret;
    693 }
    694 
    695 
    696 int eloop_register_signal_reconfig(eloop_signal_handler handler,
    697 				   void *user_data)
    698 {
    699 #ifdef CONFIG_NATIVE_WINDOWS
    700 	return 0;
    701 #else /* CONFIG_NATIVE_WINDOWS */
    702 	return eloop_register_signal(SIGHUP, handler, user_data);
    703 #endif /* CONFIG_NATIVE_WINDOWS */
    704 }
    705 
    706 
    707 void eloop_run(void)
    708 {
    709 #ifdef CONFIG_ELOOP_POLL
    710 	int num_poll_fds;
    711 	int timeout_ms = 0;
    712 #else /* CONFIG_ELOOP_POLL */
    713 	fd_set *rfds, *wfds, *efds;
    714 	struct timeval _tv;
    715 #endif /* CONFIG_ELOOP_POLL */
    716 	int res;
    717 	struct os_time tv, now;
    718 
    719 #ifndef CONFIG_ELOOP_POLL
    720 	rfds = os_malloc(sizeof(*rfds));
    721 	wfds = os_malloc(sizeof(*wfds));
    722 	efds = os_malloc(sizeof(*efds));
    723 	if (rfds == NULL || wfds == NULL || efds == NULL)
    724 		goto out;
    725 #endif /* CONFIG_ELOOP_POLL */
    726 
    727 	while (!eloop.terminate &&
    728 	       (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
    729 		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
    730 		struct eloop_timeout *timeout;
    731 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
    732 					list);
    733 		if (timeout) {
    734 			os_get_time(&now);
    735 			if (os_time_before(&now, &timeout->time))
    736 				os_time_sub(&timeout->time, &now, &tv);
    737 			else
    738 				tv.sec = tv.usec = 0;
    739 #ifdef CONFIG_ELOOP_POLL
    740 			timeout_ms = tv.sec * 1000 + tv.usec / 1000;
    741 #else /* CONFIG_ELOOP_POLL */
    742 			_tv.tv_sec = tv.sec;
    743 			_tv.tv_usec = tv.usec;
    744 #endif /* CONFIG_ELOOP_POLL */
    745 		}
    746 
    747 #ifdef CONFIG_ELOOP_POLL
    748 		num_poll_fds = eloop_sock_table_set_fds(
    749 			&eloop.readers, &eloop.writers, &eloop.exceptions,
    750 			eloop.pollfds, eloop.pollfds_map,
    751 			eloop.max_pollfd_map);
    752 		res = poll(eloop.pollfds, num_poll_fds,
    753 			   timeout ? timeout_ms : -1);
    754 
    755 		if (res < 0 && errno != EINTR && errno != 0) {
    756 			perror("poll");
    757 			goto out;
    758 		}
    759 #else /* CONFIG_ELOOP_POLL */
    760 		eloop_sock_table_set_fds(&eloop.readers, rfds);
    761 		eloop_sock_table_set_fds(&eloop.writers, wfds);
    762 		eloop_sock_table_set_fds(&eloop.exceptions, efds);
    763 		res = select(eloop.max_sock + 1, rfds, wfds, efds,
    764 			     timeout ? &_tv : NULL);
    765 		if (res < 0 && errno != EINTR && errno != 0) {
    766 			perror("select");
    767 			goto out;
    768 		}
    769 #endif /* CONFIG_ELOOP_POLL */
    770 		eloop_process_pending_signals();
    771 
    772 		/* check if some registered timeouts have occurred */
    773 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
    774 					list);
    775 		if (timeout) {
    776 			os_get_time(&now);
    777 			if (!os_time_before(&now, &timeout->time)) {
    778 				void *eloop_data = timeout->eloop_data;
    779 				void *user_data = timeout->user_data;
    780 				eloop_timeout_handler handler =
    781 					timeout->handler;
    782 				eloop_remove_timeout(timeout);
    783 				handler(eloop_data, user_data);
    784 			}
    785 
    786 		}
    787 
    788 		if (res <= 0)
    789 			continue;
    790 
    791 #ifdef CONFIG_ELOOP_POLL
    792 		eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
    793 					  &eloop.exceptions, eloop.pollfds_map,
    794 					  eloop.max_pollfd_map);
    795 #else /* CONFIG_ELOOP_POLL */
    796 		eloop_sock_table_dispatch(&eloop.readers, rfds);
    797 		eloop_sock_table_dispatch(&eloop.writers, wfds);
    798 		eloop_sock_table_dispatch(&eloop.exceptions, efds);
    799 #endif /* CONFIG_ELOOP_POLL */
    800 	}
    801 
    802 	eloop.terminate = 0;
    803 out:
    804 #ifndef CONFIG_ELOOP_POLL
    805 	os_free(rfds);
    806 	os_free(wfds);
    807 	os_free(efds);
    808 #endif /* CONFIG_ELOOP_POLL */
    809 	return;
    810 }
    811 
    812 
    813 void eloop_terminate(void)
    814 {
    815 	eloop.terminate = 1;
    816 }
    817 
    818 
    819 void eloop_destroy(void)
    820 {
    821 	struct eloop_timeout *timeout, *prev;
    822 	struct os_time now;
    823 
    824 	os_get_time(&now);
    825 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
    826 			      struct eloop_timeout, list) {
    827 		int sec, usec;
    828 		sec = timeout->time.sec - now.sec;
    829 		usec = timeout->time.usec - now.usec;
    830 		if (timeout->time.usec < now.usec) {
    831 			sec--;
    832 			usec += 1000000;
    833 		}
    834 		wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
    835 			   "eloop_data=%p user_data=%p handler=%p",
    836 			   sec, usec, timeout->eloop_data, timeout->user_data,
    837 			   timeout->handler);
    838 		wpa_trace_dump_funcname("eloop unregistered timeout handler",
    839 					timeout->handler);
    840 		wpa_trace_dump("eloop timeout", timeout);
    841 		eloop_remove_timeout(timeout);
    842 	}
    843 	eloop_sock_table_destroy(&eloop.readers);
    844 	eloop_sock_table_destroy(&eloop.writers);
    845 	eloop_sock_table_destroy(&eloop.exceptions);
    846 	os_free(eloop.signals);
    847 
    848 #ifdef CONFIG_ELOOP_POLL
    849 	os_free(eloop.pollfds);
    850 	os_free(eloop.pollfds_map);
    851 #endif /* CONFIG_ELOOP_POLL */
    852 }
    853 
    854 
    855 int eloop_terminated(void)
    856 {
    857 	return eloop.terminate;
    858 }
    859 
    860 
    861 void eloop_wait_for_read_sock(int sock)
    862 {
    863 #ifdef CONFIG_ELOOP_POLL
    864 	struct pollfd pfd;
    865 
    866 	if (sock < 0)
    867 		return;
    868 
    869 	os_memset(&pfd, 0, sizeof(pfd));
    870 	pfd.fd = sock;
    871 	pfd.events = POLLIN;
    872 
    873 	poll(&pfd, 1, -1);
    874 #else /* CONFIG_ELOOP_POLL */
    875 	fd_set rfds;
    876 
    877 	if (sock < 0)
    878 		return;
    879 
    880 	FD_ZERO(&rfds);
    881 	FD_SET(sock, &rfds);
    882 	select(sock + 1, &rfds, NULL, NULL, NULL);
    883 #endif /* CONFIG_ELOOP_POLL */
    884 }
    885