xref: /freebsd/contrib/wpa/src/utils/eloop.c (revision f05cddf940dbfc5b657f5e9beb9de2c31e509e5b)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * Event loop based on select() loop
3e28a4053SRui Paulo  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5*f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6*f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
12e28a4053SRui Paulo #include "trace.h"
13e28a4053SRui Paulo #include "list.h"
1439beb93cSSam Leffler #include "eloop.h"
1539beb93cSSam Leffler 
16*f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
17*f05cddf9SRui Paulo #include <assert.h>
18*f05cddf9SRui Paulo #include <poll.h>
19*f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
20*f05cddf9SRui Paulo 
2139beb93cSSam Leffler 
2239beb93cSSam Leffler struct eloop_sock {
2339beb93cSSam Leffler 	int sock;
2439beb93cSSam Leffler 	void *eloop_data;
2539beb93cSSam Leffler 	void *user_data;
2639beb93cSSam Leffler 	eloop_sock_handler handler;
27e28a4053SRui Paulo 	WPA_TRACE_REF(eloop);
28e28a4053SRui Paulo 	WPA_TRACE_REF(user);
29e28a4053SRui Paulo 	WPA_TRACE_INFO
3039beb93cSSam Leffler };
3139beb93cSSam Leffler 
3239beb93cSSam Leffler struct eloop_timeout {
33e28a4053SRui Paulo 	struct dl_list list;
3439beb93cSSam Leffler 	struct os_time time;
3539beb93cSSam Leffler 	void *eloop_data;
3639beb93cSSam Leffler 	void *user_data;
3739beb93cSSam Leffler 	eloop_timeout_handler handler;
38e28a4053SRui Paulo 	WPA_TRACE_REF(eloop);
39e28a4053SRui Paulo 	WPA_TRACE_REF(user);
40e28a4053SRui Paulo 	WPA_TRACE_INFO
4139beb93cSSam Leffler };
4239beb93cSSam Leffler 
4339beb93cSSam Leffler struct eloop_signal {
4439beb93cSSam Leffler 	int sig;
4539beb93cSSam Leffler 	void *user_data;
4639beb93cSSam Leffler 	eloop_signal_handler handler;
4739beb93cSSam Leffler 	int signaled;
4839beb93cSSam Leffler };
4939beb93cSSam Leffler 
5039beb93cSSam Leffler struct eloop_sock_table {
5139beb93cSSam Leffler 	int count;
5239beb93cSSam Leffler 	struct eloop_sock *table;
5339beb93cSSam Leffler 	int changed;
5439beb93cSSam Leffler };
5539beb93cSSam Leffler 
5639beb93cSSam Leffler struct eloop_data {
5739beb93cSSam Leffler 	int max_sock;
5839beb93cSSam Leffler 
59*f05cddf9SRui Paulo 	int count; /* sum of all table counts */
60*f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
61*f05cddf9SRui Paulo 	int max_pollfd_map; /* number of pollfds_map currently allocated */
62*f05cddf9SRui Paulo 	int max_poll_fds; /* number of pollfds currently allocated */
63*f05cddf9SRui Paulo 	struct pollfd *pollfds;
64*f05cddf9SRui Paulo 	struct pollfd **pollfds_map;
65*f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
6639beb93cSSam Leffler 	struct eloop_sock_table readers;
6739beb93cSSam Leffler 	struct eloop_sock_table writers;
6839beb93cSSam Leffler 	struct eloop_sock_table exceptions;
6939beb93cSSam Leffler 
70e28a4053SRui Paulo 	struct dl_list timeout;
7139beb93cSSam Leffler 
7239beb93cSSam Leffler 	int signal_count;
7339beb93cSSam Leffler 	struct eloop_signal *signals;
7439beb93cSSam Leffler 	int signaled;
7539beb93cSSam Leffler 	int pending_terminate;
7639beb93cSSam Leffler 
7739beb93cSSam Leffler 	int terminate;
7839beb93cSSam Leffler 	int reader_table_changed;
7939beb93cSSam Leffler };
8039beb93cSSam Leffler 
8139beb93cSSam Leffler static struct eloop_data eloop;
8239beb93cSSam Leffler 
8339beb93cSSam Leffler 
84e28a4053SRui Paulo #ifdef WPA_TRACE
85e28a4053SRui Paulo 
86e28a4053SRui Paulo static void eloop_sigsegv_handler(int sig)
87e28a4053SRui Paulo {
88e28a4053SRui Paulo 	wpa_trace_show("eloop SIGSEGV");
89e28a4053SRui Paulo 	abort();
90e28a4053SRui Paulo }
91e28a4053SRui Paulo 
92e28a4053SRui Paulo static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
93e28a4053SRui Paulo {
94e28a4053SRui Paulo 	int i;
95e28a4053SRui Paulo 	if (table == NULL || table->table == NULL)
96e28a4053SRui Paulo 		return;
97e28a4053SRui Paulo 	for (i = 0; i < table->count; i++) {
98e28a4053SRui Paulo 		wpa_trace_add_ref(&table->table[i], eloop,
99e28a4053SRui Paulo 				  table->table[i].eloop_data);
100e28a4053SRui Paulo 		wpa_trace_add_ref(&table->table[i], user,
101e28a4053SRui Paulo 				  table->table[i].user_data);
102e28a4053SRui Paulo 	}
103e28a4053SRui Paulo }
104e28a4053SRui Paulo 
105e28a4053SRui Paulo 
106e28a4053SRui Paulo static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
107e28a4053SRui Paulo {
108e28a4053SRui Paulo 	int i;
109e28a4053SRui Paulo 	if (table == NULL || table->table == NULL)
110e28a4053SRui Paulo 		return;
111e28a4053SRui Paulo 	for (i = 0; i < table->count; i++) {
112e28a4053SRui Paulo 		wpa_trace_remove_ref(&table->table[i], eloop,
113e28a4053SRui Paulo 				     table->table[i].eloop_data);
114e28a4053SRui Paulo 		wpa_trace_remove_ref(&table->table[i], user,
115e28a4053SRui Paulo 				     table->table[i].user_data);
116e28a4053SRui Paulo 	}
117e28a4053SRui Paulo }
118e28a4053SRui Paulo 
119e28a4053SRui Paulo #else /* WPA_TRACE */
120e28a4053SRui Paulo 
121e28a4053SRui Paulo #define eloop_trace_sock_add_ref(table) do { } while (0)
122e28a4053SRui Paulo #define eloop_trace_sock_remove_ref(table) do { } while (0)
123e28a4053SRui Paulo 
124e28a4053SRui Paulo #endif /* WPA_TRACE */
125e28a4053SRui Paulo 
126e28a4053SRui Paulo 
127e28a4053SRui Paulo int eloop_init(void)
12839beb93cSSam Leffler {
12939beb93cSSam Leffler 	os_memset(&eloop, 0, sizeof(eloop));
130e28a4053SRui Paulo 	dl_list_init(&eloop.timeout);
131e28a4053SRui Paulo #ifdef WPA_TRACE
132e28a4053SRui Paulo 	signal(SIGSEGV, eloop_sigsegv_handler);
133e28a4053SRui Paulo #endif /* WPA_TRACE */
13439beb93cSSam Leffler 	return 0;
13539beb93cSSam Leffler }
13639beb93cSSam Leffler 
13739beb93cSSam Leffler 
13839beb93cSSam Leffler static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
13939beb93cSSam Leffler                                      int sock, eloop_sock_handler handler,
14039beb93cSSam Leffler                                      void *eloop_data, void *user_data)
14139beb93cSSam Leffler {
14239beb93cSSam Leffler 	struct eloop_sock *tmp;
143*f05cddf9SRui Paulo 	int new_max_sock;
144*f05cddf9SRui Paulo 
145*f05cddf9SRui Paulo 	if (sock > eloop.max_sock)
146*f05cddf9SRui Paulo 		new_max_sock = sock;
147*f05cddf9SRui Paulo 	else
148*f05cddf9SRui Paulo 		new_max_sock = eloop.max_sock;
14939beb93cSSam Leffler 
15039beb93cSSam Leffler 	if (table == NULL)
15139beb93cSSam Leffler 		return -1;
15239beb93cSSam Leffler 
153*f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
154*f05cddf9SRui Paulo 	if (new_max_sock >= eloop.max_pollfd_map) {
155*f05cddf9SRui Paulo 		struct pollfd **nmap;
156*f05cddf9SRui Paulo 		nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
157*f05cddf9SRui Paulo 					sizeof(struct pollfd *));
158*f05cddf9SRui Paulo 		if (nmap == NULL)
159*f05cddf9SRui Paulo 			return -1;
160*f05cddf9SRui Paulo 
161*f05cddf9SRui Paulo 		eloop.max_pollfd_map = new_max_sock + 50;
162*f05cddf9SRui Paulo 		eloop.pollfds_map = nmap;
163*f05cddf9SRui Paulo 	}
164*f05cddf9SRui Paulo 
165*f05cddf9SRui Paulo 	if (eloop.count + 1 > eloop.max_poll_fds) {
166*f05cddf9SRui Paulo 		struct pollfd *n;
167*f05cddf9SRui Paulo 		int nmax = eloop.count + 1 + 50;
168*f05cddf9SRui Paulo 		n = os_realloc_array(eloop.pollfds, nmax,
169*f05cddf9SRui Paulo 				     sizeof(struct pollfd));
170*f05cddf9SRui Paulo 		if (n == NULL)
171*f05cddf9SRui Paulo 			return -1;
172*f05cddf9SRui Paulo 
173*f05cddf9SRui Paulo 		eloop.max_poll_fds = nmax;
174*f05cddf9SRui Paulo 		eloop.pollfds = n;
175*f05cddf9SRui Paulo 	}
176*f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
177*f05cddf9SRui Paulo 
178e28a4053SRui Paulo 	eloop_trace_sock_remove_ref(table);
179*f05cddf9SRui Paulo 	tmp = os_realloc_array(table->table, table->count + 1,
180*f05cddf9SRui Paulo 			       sizeof(struct eloop_sock));
18139beb93cSSam Leffler 	if (tmp == NULL)
18239beb93cSSam Leffler 		return -1;
18339beb93cSSam Leffler 
18439beb93cSSam Leffler 	tmp[table->count].sock = sock;
18539beb93cSSam Leffler 	tmp[table->count].eloop_data = eloop_data;
18639beb93cSSam Leffler 	tmp[table->count].user_data = user_data;
18739beb93cSSam Leffler 	tmp[table->count].handler = handler;
188e28a4053SRui Paulo 	wpa_trace_record(&tmp[table->count]);
18939beb93cSSam Leffler 	table->count++;
19039beb93cSSam Leffler 	table->table = tmp;
191*f05cddf9SRui Paulo 	eloop.max_sock = new_max_sock;
192*f05cddf9SRui Paulo 	eloop.count++;
19339beb93cSSam Leffler 	table->changed = 1;
194e28a4053SRui Paulo 	eloop_trace_sock_add_ref(table);
19539beb93cSSam Leffler 
19639beb93cSSam Leffler 	return 0;
19739beb93cSSam Leffler }
19839beb93cSSam Leffler 
19939beb93cSSam Leffler 
20039beb93cSSam Leffler static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
20139beb93cSSam Leffler                                          int sock)
20239beb93cSSam Leffler {
20339beb93cSSam Leffler 	int i;
20439beb93cSSam Leffler 
20539beb93cSSam Leffler 	if (table == NULL || table->table == NULL || table->count == 0)
20639beb93cSSam Leffler 		return;
20739beb93cSSam Leffler 
20839beb93cSSam Leffler 	for (i = 0; i < table->count; i++) {
20939beb93cSSam Leffler 		if (table->table[i].sock == sock)
21039beb93cSSam Leffler 			break;
21139beb93cSSam Leffler 	}
21239beb93cSSam Leffler 	if (i == table->count)
21339beb93cSSam Leffler 		return;
214e28a4053SRui Paulo 	eloop_trace_sock_remove_ref(table);
21539beb93cSSam Leffler 	if (i != table->count - 1) {
21639beb93cSSam Leffler 		os_memmove(&table->table[i], &table->table[i + 1],
21739beb93cSSam Leffler 			   (table->count - i - 1) *
21839beb93cSSam Leffler 			   sizeof(struct eloop_sock));
21939beb93cSSam Leffler 	}
22039beb93cSSam Leffler 	table->count--;
221*f05cddf9SRui Paulo 	eloop.count--;
22239beb93cSSam Leffler 	table->changed = 1;
223e28a4053SRui Paulo 	eloop_trace_sock_add_ref(table);
22439beb93cSSam Leffler }
22539beb93cSSam Leffler 
22639beb93cSSam Leffler 
227*f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
228*f05cddf9SRui Paulo 
229*f05cddf9SRui Paulo static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
230*f05cddf9SRui Paulo {
231*f05cddf9SRui Paulo 	if (fd < mx && fd >= 0)
232*f05cddf9SRui Paulo 		return pollfds_map[fd];
233*f05cddf9SRui Paulo 	return NULL;
234*f05cddf9SRui Paulo }
235*f05cddf9SRui Paulo 
236*f05cddf9SRui Paulo 
237*f05cddf9SRui Paulo static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
238*f05cddf9SRui Paulo 				    struct eloop_sock_table *writers,
239*f05cddf9SRui Paulo 				    struct eloop_sock_table *exceptions,
240*f05cddf9SRui Paulo 				    struct pollfd *pollfds,
241*f05cddf9SRui Paulo 				    struct pollfd **pollfds_map,
242*f05cddf9SRui Paulo 				    int max_pollfd_map)
243*f05cddf9SRui Paulo {
244*f05cddf9SRui Paulo 	int i;
245*f05cddf9SRui Paulo 	int nxt = 0;
246*f05cddf9SRui Paulo 	int fd;
247*f05cddf9SRui Paulo 	struct pollfd *pfd;
248*f05cddf9SRui Paulo 
249*f05cddf9SRui Paulo 	/* Clear pollfd lookup map. It will be re-populated below. */
250*f05cddf9SRui Paulo 	os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
251*f05cddf9SRui Paulo 
252*f05cddf9SRui Paulo 	if (readers && readers->table) {
253*f05cddf9SRui Paulo 		for (i = 0; i < readers->count; i++) {
254*f05cddf9SRui Paulo 			fd = readers->table[i].sock;
255*f05cddf9SRui Paulo 			assert(fd >= 0 && fd < max_pollfd_map);
256*f05cddf9SRui Paulo 			pollfds[nxt].fd = fd;
257*f05cddf9SRui Paulo 			pollfds[nxt].events = POLLIN;
258*f05cddf9SRui Paulo 			pollfds[nxt].revents = 0;
259*f05cddf9SRui Paulo 			pollfds_map[fd] = &(pollfds[nxt]);
260*f05cddf9SRui Paulo 			nxt++;
261*f05cddf9SRui Paulo 		}
262*f05cddf9SRui Paulo 	}
263*f05cddf9SRui Paulo 
264*f05cddf9SRui Paulo 	if (writers && writers->table) {
265*f05cddf9SRui Paulo 		for (i = 0; i < writers->count; i++) {
266*f05cddf9SRui Paulo 			/*
267*f05cddf9SRui Paulo 			 * See if we already added this descriptor, update it
268*f05cddf9SRui Paulo 			 * if so.
269*f05cddf9SRui Paulo 			 */
270*f05cddf9SRui Paulo 			fd = writers->table[i].sock;
271*f05cddf9SRui Paulo 			assert(fd >= 0 && fd < max_pollfd_map);
272*f05cddf9SRui Paulo 			pfd = pollfds_map[fd];
273*f05cddf9SRui Paulo 			if (!pfd) {
274*f05cddf9SRui Paulo 				pfd = &(pollfds[nxt]);
275*f05cddf9SRui Paulo 				pfd->events = 0;
276*f05cddf9SRui Paulo 				pfd->fd = fd;
277*f05cddf9SRui Paulo 				pollfds[i].revents = 0;
278*f05cddf9SRui Paulo 				pollfds_map[fd] = pfd;
279*f05cddf9SRui Paulo 				nxt++;
280*f05cddf9SRui Paulo 			}
281*f05cddf9SRui Paulo 			pfd->events |= POLLOUT;
282*f05cddf9SRui Paulo 		}
283*f05cddf9SRui Paulo 	}
284*f05cddf9SRui Paulo 
285*f05cddf9SRui Paulo 	/*
286*f05cddf9SRui Paulo 	 * Exceptions are always checked when using poll, but I suppose it's
287*f05cddf9SRui Paulo 	 * possible that someone registered a socket *only* for exception
288*f05cddf9SRui Paulo 	 * handling. Set the POLLIN bit in this case.
289*f05cddf9SRui Paulo 	 */
290*f05cddf9SRui Paulo 	if (exceptions && exceptions->table) {
291*f05cddf9SRui Paulo 		for (i = 0; i < exceptions->count; i++) {
292*f05cddf9SRui Paulo 			/*
293*f05cddf9SRui Paulo 			 * See if we already added this descriptor, just use it
294*f05cddf9SRui Paulo 			 * if so.
295*f05cddf9SRui Paulo 			 */
296*f05cddf9SRui Paulo 			fd = exceptions->table[i].sock;
297*f05cddf9SRui Paulo 			assert(fd >= 0 && fd < max_pollfd_map);
298*f05cddf9SRui Paulo 			pfd = pollfds_map[fd];
299*f05cddf9SRui Paulo 			if (!pfd) {
300*f05cddf9SRui Paulo 				pfd = &(pollfds[nxt]);
301*f05cddf9SRui Paulo 				pfd->events = POLLIN;
302*f05cddf9SRui Paulo 				pfd->fd = fd;
303*f05cddf9SRui Paulo 				pollfds[i].revents = 0;
304*f05cddf9SRui Paulo 				pollfds_map[fd] = pfd;
305*f05cddf9SRui Paulo 				nxt++;
306*f05cddf9SRui Paulo 			}
307*f05cddf9SRui Paulo 		}
308*f05cddf9SRui Paulo 	}
309*f05cddf9SRui Paulo 
310*f05cddf9SRui Paulo 	return nxt;
311*f05cddf9SRui Paulo }
312*f05cddf9SRui Paulo 
313*f05cddf9SRui Paulo 
314*f05cddf9SRui Paulo static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
315*f05cddf9SRui Paulo 					   struct pollfd **pollfds_map,
316*f05cddf9SRui Paulo 					   int max_pollfd_map,
317*f05cddf9SRui Paulo 					   short int revents)
318*f05cddf9SRui Paulo {
319*f05cddf9SRui Paulo 	int i;
320*f05cddf9SRui Paulo 	struct pollfd *pfd;
321*f05cddf9SRui Paulo 
322*f05cddf9SRui Paulo 	if (!table || !table->table)
323*f05cddf9SRui Paulo 		return 0;
324*f05cddf9SRui Paulo 
325*f05cddf9SRui Paulo 	table->changed = 0;
326*f05cddf9SRui Paulo 	for (i = 0; i < table->count; i++) {
327*f05cddf9SRui Paulo 		pfd = find_pollfd(pollfds_map, table->table[i].sock,
328*f05cddf9SRui Paulo 				  max_pollfd_map);
329*f05cddf9SRui Paulo 		if (!pfd)
330*f05cddf9SRui Paulo 			continue;
331*f05cddf9SRui Paulo 
332*f05cddf9SRui Paulo 		if (!(pfd->revents & revents))
333*f05cddf9SRui Paulo 			continue;
334*f05cddf9SRui Paulo 
335*f05cddf9SRui Paulo 		table->table[i].handler(table->table[i].sock,
336*f05cddf9SRui Paulo 					table->table[i].eloop_data,
337*f05cddf9SRui Paulo 					table->table[i].user_data);
338*f05cddf9SRui Paulo 		if (table->changed)
339*f05cddf9SRui Paulo 			return 1;
340*f05cddf9SRui Paulo 	}
341*f05cddf9SRui Paulo 
342*f05cddf9SRui Paulo 	return 0;
343*f05cddf9SRui Paulo }
344*f05cddf9SRui Paulo 
345*f05cddf9SRui Paulo 
346*f05cddf9SRui Paulo static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
347*f05cddf9SRui Paulo 				      struct eloop_sock_table *writers,
348*f05cddf9SRui Paulo 				      struct eloop_sock_table *exceptions,
349*f05cddf9SRui Paulo 				      struct pollfd **pollfds_map,
350*f05cddf9SRui Paulo 				      int max_pollfd_map)
351*f05cddf9SRui Paulo {
352*f05cddf9SRui Paulo 	if (eloop_sock_table_dispatch_table(readers, pollfds_map,
353*f05cddf9SRui Paulo 					    max_pollfd_map, POLLIN | POLLERR |
354*f05cddf9SRui Paulo 					    POLLHUP))
355*f05cddf9SRui Paulo 		return; /* pollfds may be invalid at this point */
356*f05cddf9SRui Paulo 
357*f05cddf9SRui Paulo 	if (eloop_sock_table_dispatch_table(writers, pollfds_map,
358*f05cddf9SRui Paulo 					    max_pollfd_map, POLLOUT))
359*f05cddf9SRui Paulo 		return; /* pollfds may be invalid at this point */
360*f05cddf9SRui Paulo 
361*f05cddf9SRui Paulo 	eloop_sock_table_dispatch_table(exceptions, pollfds_map,
362*f05cddf9SRui Paulo 					max_pollfd_map, POLLERR | POLLHUP);
363*f05cddf9SRui Paulo }
364*f05cddf9SRui Paulo 
365*f05cddf9SRui Paulo #else /* CONFIG_ELOOP_POLL */
366*f05cddf9SRui Paulo 
36739beb93cSSam Leffler static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
36839beb93cSSam Leffler 				     fd_set *fds)
36939beb93cSSam Leffler {
37039beb93cSSam Leffler 	int i;
37139beb93cSSam Leffler 
37239beb93cSSam Leffler 	FD_ZERO(fds);
37339beb93cSSam Leffler 
37439beb93cSSam Leffler 	if (table->table == NULL)
37539beb93cSSam Leffler 		return;
37639beb93cSSam Leffler 
37739beb93cSSam Leffler 	for (i = 0; i < table->count; i++)
37839beb93cSSam Leffler 		FD_SET(table->table[i].sock, fds);
37939beb93cSSam Leffler }
38039beb93cSSam Leffler 
38139beb93cSSam Leffler 
38239beb93cSSam Leffler static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
38339beb93cSSam Leffler 				      fd_set *fds)
38439beb93cSSam Leffler {
38539beb93cSSam Leffler 	int i;
38639beb93cSSam Leffler 
38739beb93cSSam Leffler 	if (table == NULL || table->table == NULL)
38839beb93cSSam Leffler 		return;
38939beb93cSSam Leffler 
39039beb93cSSam Leffler 	table->changed = 0;
39139beb93cSSam Leffler 	for (i = 0; i < table->count; i++) {
39239beb93cSSam Leffler 		if (FD_ISSET(table->table[i].sock, fds)) {
39339beb93cSSam Leffler 			table->table[i].handler(table->table[i].sock,
39439beb93cSSam Leffler 						table->table[i].eloop_data,
39539beb93cSSam Leffler 						table->table[i].user_data);
39639beb93cSSam Leffler 			if (table->changed)
39739beb93cSSam Leffler 				break;
39839beb93cSSam Leffler 		}
39939beb93cSSam Leffler 	}
40039beb93cSSam Leffler }
40139beb93cSSam Leffler 
402*f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
403*f05cddf9SRui Paulo 
40439beb93cSSam Leffler 
40539beb93cSSam Leffler static void eloop_sock_table_destroy(struct eloop_sock_table *table)
40639beb93cSSam Leffler {
40739beb93cSSam Leffler 	if (table) {
40839beb93cSSam Leffler 		int i;
40939beb93cSSam Leffler 		for (i = 0; i < table->count && table->table; i++) {
410e28a4053SRui Paulo 			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
411e28a4053SRui Paulo 				   "sock=%d eloop_data=%p user_data=%p "
412e28a4053SRui Paulo 				   "handler=%p",
41339beb93cSSam Leffler 				   table->table[i].sock,
41439beb93cSSam Leffler 				   table->table[i].eloop_data,
41539beb93cSSam Leffler 				   table->table[i].user_data,
41639beb93cSSam Leffler 				   table->table[i].handler);
417e28a4053SRui Paulo 			wpa_trace_dump_funcname("eloop unregistered socket "
418e28a4053SRui Paulo 						"handler",
419e28a4053SRui Paulo 						table->table[i].handler);
420e28a4053SRui Paulo 			wpa_trace_dump("eloop sock", &table->table[i]);
42139beb93cSSam Leffler 		}
42239beb93cSSam Leffler 		os_free(table->table);
42339beb93cSSam Leffler 	}
42439beb93cSSam Leffler }
42539beb93cSSam Leffler 
42639beb93cSSam Leffler 
42739beb93cSSam Leffler int eloop_register_read_sock(int sock, eloop_sock_handler handler,
42839beb93cSSam Leffler 			     void *eloop_data, void *user_data)
42939beb93cSSam Leffler {
43039beb93cSSam Leffler 	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
43139beb93cSSam Leffler 				   eloop_data, user_data);
43239beb93cSSam Leffler }
43339beb93cSSam Leffler 
43439beb93cSSam Leffler 
43539beb93cSSam Leffler void eloop_unregister_read_sock(int sock)
43639beb93cSSam Leffler {
43739beb93cSSam Leffler 	eloop_unregister_sock(sock, EVENT_TYPE_READ);
43839beb93cSSam Leffler }
43939beb93cSSam Leffler 
44039beb93cSSam Leffler 
44139beb93cSSam Leffler static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
44239beb93cSSam Leffler {
44339beb93cSSam Leffler 	switch (type) {
44439beb93cSSam Leffler 	case EVENT_TYPE_READ:
44539beb93cSSam Leffler 		return &eloop.readers;
44639beb93cSSam Leffler 	case EVENT_TYPE_WRITE:
44739beb93cSSam Leffler 		return &eloop.writers;
44839beb93cSSam Leffler 	case EVENT_TYPE_EXCEPTION:
44939beb93cSSam Leffler 		return &eloop.exceptions;
45039beb93cSSam Leffler 	}
45139beb93cSSam Leffler 
45239beb93cSSam Leffler 	return NULL;
45339beb93cSSam Leffler }
45439beb93cSSam Leffler 
45539beb93cSSam Leffler 
45639beb93cSSam Leffler int eloop_register_sock(int sock, eloop_event_type type,
45739beb93cSSam Leffler 			eloop_sock_handler handler,
45839beb93cSSam Leffler 			void *eloop_data, void *user_data)
45939beb93cSSam Leffler {
46039beb93cSSam Leffler 	struct eloop_sock_table *table;
46139beb93cSSam Leffler 
46239beb93cSSam Leffler 	table = eloop_get_sock_table(type);
46339beb93cSSam Leffler 	return eloop_sock_table_add_sock(table, sock, handler,
46439beb93cSSam Leffler 					 eloop_data, user_data);
46539beb93cSSam Leffler }
46639beb93cSSam Leffler 
46739beb93cSSam Leffler 
46839beb93cSSam Leffler void eloop_unregister_sock(int sock, eloop_event_type type)
46939beb93cSSam Leffler {
47039beb93cSSam Leffler 	struct eloop_sock_table *table;
47139beb93cSSam Leffler 
47239beb93cSSam Leffler 	table = eloop_get_sock_table(type);
47339beb93cSSam Leffler 	eloop_sock_table_remove_sock(table, sock);
47439beb93cSSam Leffler }
47539beb93cSSam Leffler 
47639beb93cSSam Leffler 
47739beb93cSSam Leffler int eloop_register_timeout(unsigned int secs, unsigned int usecs,
47839beb93cSSam Leffler 			   eloop_timeout_handler handler,
47939beb93cSSam Leffler 			   void *eloop_data, void *user_data)
48039beb93cSSam Leffler {
481e28a4053SRui Paulo 	struct eloop_timeout *timeout, *tmp;
482*f05cddf9SRui Paulo 	os_time_t now_sec;
48339beb93cSSam Leffler 
484e28a4053SRui Paulo 	timeout = os_zalloc(sizeof(*timeout));
48539beb93cSSam Leffler 	if (timeout == NULL)
48639beb93cSSam Leffler 		return -1;
48739beb93cSSam Leffler 	if (os_get_time(&timeout->time) < 0) {
48839beb93cSSam Leffler 		os_free(timeout);
48939beb93cSSam Leffler 		return -1;
49039beb93cSSam Leffler 	}
491*f05cddf9SRui Paulo 	now_sec = timeout->time.sec;
49239beb93cSSam Leffler 	timeout->time.sec += secs;
493*f05cddf9SRui Paulo 	if (timeout->time.sec < now_sec) {
494*f05cddf9SRui Paulo 		/*
495*f05cddf9SRui Paulo 		 * Integer overflow - assume long enough timeout to be assumed
496*f05cddf9SRui Paulo 		 * to be infinite, i.e., the timeout would never happen.
497*f05cddf9SRui Paulo 		 */
498*f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
499*f05cddf9SRui Paulo 			   "ever happen - ignore it", secs);
500*f05cddf9SRui Paulo 		os_free(timeout);
501*f05cddf9SRui Paulo 		return 0;
502*f05cddf9SRui Paulo 	}
50339beb93cSSam Leffler 	timeout->time.usec += usecs;
50439beb93cSSam Leffler 	while (timeout->time.usec >= 1000000) {
50539beb93cSSam Leffler 		timeout->time.sec++;
50639beb93cSSam Leffler 		timeout->time.usec -= 1000000;
50739beb93cSSam Leffler 	}
50839beb93cSSam Leffler 	timeout->eloop_data = eloop_data;
50939beb93cSSam Leffler 	timeout->user_data = user_data;
51039beb93cSSam Leffler 	timeout->handler = handler;
511e28a4053SRui Paulo 	wpa_trace_add_ref(timeout, eloop, eloop_data);
512e28a4053SRui Paulo 	wpa_trace_add_ref(timeout, user, user_data);
513e28a4053SRui Paulo 	wpa_trace_record(timeout);
51439beb93cSSam Leffler 
515e28a4053SRui Paulo 	/* Maintain timeouts in order of increasing time */
516e28a4053SRui Paulo 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
517e28a4053SRui Paulo 		if (os_time_before(&timeout->time, &tmp->time)) {
518e28a4053SRui Paulo 			dl_list_add(tmp->list.prev, &timeout->list);
519e28a4053SRui Paulo 			return 0;
520e28a4053SRui Paulo 		}
521e28a4053SRui Paulo 	}
522e28a4053SRui Paulo 	dl_list_add_tail(&eloop.timeout, &timeout->list);
523e28a4053SRui Paulo 
52439beb93cSSam Leffler 	return 0;
52539beb93cSSam Leffler }
52639beb93cSSam Leffler 
52739beb93cSSam Leffler 
528e28a4053SRui Paulo static void eloop_remove_timeout(struct eloop_timeout *timeout)
529e28a4053SRui Paulo {
530e28a4053SRui Paulo 	dl_list_del(&timeout->list);
531e28a4053SRui Paulo 	wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
532e28a4053SRui Paulo 	wpa_trace_remove_ref(timeout, user, timeout->user_data);
533e28a4053SRui Paulo 	os_free(timeout);
53439beb93cSSam Leffler }
53539beb93cSSam Leffler 
53639beb93cSSam Leffler 
53739beb93cSSam Leffler int eloop_cancel_timeout(eloop_timeout_handler handler,
53839beb93cSSam Leffler 			 void *eloop_data, void *user_data)
53939beb93cSSam Leffler {
540e28a4053SRui Paulo 	struct eloop_timeout *timeout, *prev;
54139beb93cSSam Leffler 	int removed = 0;
54239beb93cSSam Leffler 
543e28a4053SRui Paulo 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
544e28a4053SRui Paulo 			      struct eloop_timeout, list) {
54539beb93cSSam Leffler 		if (timeout->handler == handler &&
54639beb93cSSam Leffler 		    (timeout->eloop_data == eloop_data ||
54739beb93cSSam Leffler 		     eloop_data == ELOOP_ALL_CTX) &&
54839beb93cSSam Leffler 		    (timeout->user_data == user_data ||
54939beb93cSSam Leffler 		     user_data == ELOOP_ALL_CTX)) {
550e28a4053SRui Paulo 			eloop_remove_timeout(timeout);
55139beb93cSSam Leffler 			removed++;
552e28a4053SRui Paulo 		}
55339beb93cSSam Leffler 	}
55439beb93cSSam Leffler 
55539beb93cSSam Leffler 	return removed;
55639beb93cSSam Leffler }
55739beb93cSSam Leffler 
55839beb93cSSam Leffler 
55939beb93cSSam Leffler int eloop_is_timeout_registered(eloop_timeout_handler handler,
56039beb93cSSam Leffler 				void *eloop_data, void *user_data)
56139beb93cSSam Leffler {
56239beb93cSSam Leffler 	struct eloop_timeout *tmp;
56339beb93cSSam Leffler 
564e28a4053SRui Paulo 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
56539beb93cSSam Leffler 		if (tmp->handler == handler &&
56639beb93cSSam Leffler 		    tmp->eloop_data == eloop_data &&
56739beb93cSSam Leffler 		    tmp->user_data == user_data)
56839beb93cSSam Leffler 			return 1;
56939beb93cSSam Leffler 	}
57039beb93cSSam Leffler 
57139beb93cSSam Leffler 	return 0;
57239beb93cSSam Leffler }
57339beb93cSSam Leffler 
57439beb93cSSam Leffler 
57539beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
57639beb93cSSam Leffler static void eloop_handle_alarm(int sig)
57739beb93cSSam Leffler {
578e28a4053SRui Paulo 	wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
579e28a4053SRui Paulo 		   "two seconds. Looks like there\n"
58039beb93cSSam Leffler 		   "is a bug that ends up in a busy loop that "
58139beb93cSSam Leffler 		   "prevents clean shutdown.\n"
58239beb93cSSam Leffler 		   "Killing program forcefully.\n");
58339beb93cSSam Leffler 	exit(1);
58439beb93cSSam Leffler }
58539beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
58639beb93cSSam Leffler 
58739beb93cSSam Leffler 
58839beb93cSSam Leffler static void eloop_handle_signal(int sig)
58939beb93cSSam Leffler {
59039beb93cSSam Leffler 	int i;
59139beb93cSSam Leffler 
59239beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
59339beb93cSSam Leffler 	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
59439beb93cSSam Leffler 		/* Use SIGALRM to break out from potential busy loops that
59539beb93cSSam Leffler 		 * would not allow the program to be killed. */
59639beb93cSSam Leffler 		eloop.pending_terminate = 1;
59739beb93cSSam Leffler 		signal(SIGALRM, eloop_handle_alarm);
59839beb93cSSam Leffler 		alarm(2);
59939beb93cSSam Leffler 	}
60039beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
60139beb93cSSam Leffler 
60239beb93cSSam Leffler 	eloop.signaled++;
60339beb93cSSam Leffler 	for (i = 0; i < eloop.signal_count; i++) {
60439beb93cSSam Leffler 		if (eloop.signals[i].sig == sig) {
60539beb93cSSam Leffler 			eloop.signals[i].signaled++;
60639beb93cSSam Leffler 			break;
60739beb93cSSam Leffler 		}
60839beb93cSSam Leffler 	}
60939beb93cSSam Leffler }
61039beb93cSSam Leffler 
61139beb93cSSam Leffler 
61239beb93cSSam Leffler static void eloop_process_pending_signals(void)
61339beb93cSSam Leffler {
61439beb93cSSam Leffler 	int i;
61539beb93cSSam Leffler 
61639beb93cSSam Leffler 	if (eloop.signaled == 0)
61739beb93cSSam Leffler 		return;
61839beb93cSSam Leffler 	eloop.signaled = 0;
61939beb93cSSam Leffler 
62039beb93cSSam Leffler 	if (eloop.pending_terminate) {
62139beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
62239beb93cSSam Leffler 		alarm(0);
62339beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
62439beb93cSSam Leffler 		eloop.pending_terminate = 0;
62539beb93cSSam Leffler 	}
62639beb93cSSam Leffler 
62739beb93cSSam Leffler 	for (i = 0; i < eloop.signal_count; i++) {
62839beb93cSSam Leffler 		if (eloop.signals[i].signaled) {
62939beb93cSSam Leffler 			eloop.signals[i].signaled = 0;
63039beb93cSSam Leffler 			eloop.signals[i].handler(eloop.signals[i].sig,
63139beb93cSSam Leffler 						 eloop.signals[i].user_data);
63239beb93cSSam Leffler 		}
63339beb93cSSam Leffler 	}
63439beb93cSSam Leffler }
63539beb93cSSam Leffler 
63639beb93cSSam Leffler 
63739beb93cSSam Leffler int eloop_register_signal(int sig, eloop_signal_handler handler,
63839beb93cSSam Leffler 			  void *user_data)
63939beb93cSSam Leffler {
64039beb93cSSam Leffler 	struct eloop_signal *tmp;
64139beb93cSSam Leffler 
642*f05cddf9SRui Paulo 	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
64339beb93cSSam Leffler 			       sizeof(struct eloop_signal));
64439beb93cSSam Leffler 	if (tmp == NULL)
64539beb93cSSam Leffler 		return -1;
64639beb93cSSam Leffler 
64739beb93cSSam Leffler 	tmp[eloop.signal_count].sig = sig;
64839beb93cSSam Leffler 	tmp[eloop.signal_count].user_data = user_data;
64939beb93cSSam Leffler 	tmp[eloop.signal_count].handler = handler;
65039beb93cSSam Leffler 	tmp[eloop.signal_count].signaled = 0;
65139beb93cSSam Leffler 	eloop.signal_count++;
65239beb93cSSam Leffler 	eloop.signals = tmp;
65339beb93cSSam Leffler 	signal(sig, eloop_handle_signal);
65439beb93cSSam Leffler 
65539beb93cSSam Leffler 	return 0;
65639beb93cSSam Leffler }
65739beb93cSSam Leffler 
65839beb93cSSam Leffler 
65939beb93cSSam Leffler int eloop_register_signal_terminate(eloop_signal_handler handler,
66039beb93cSSam Leffler 				    void *user_data)
66139beb93cSSam Leffler {
66239beb93cSSam Leffler 	int ret = eloop_register_signal(SIGINT, handler, user_data);
66339beb93cSSam Leffler 	if (ret == 0)
66439beb93cSSam Leffler 		ret = eloop_register_signal(SIGTERM, handler, user_data);
66539beb93cSSam Leffler 	return ret;
66639beb93cSSam Leffler }
66739beb93cSSam Leffler 
66839beb93cSSam Leffler 
66939beb93cSSam Leffler int eloop_register_signal_reconfig(eloop_signal_handler handler,
67039beb93cSSam Leffler 				   void *user_data)
67139beb93cSSam Leffler {
67239beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
67339beb93cSSam Leffler 	return 0;
67439beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */
67539beb93cSSam Leffler 	return eloop_register_signal(SIGHUP, handler, user_data);
67639beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
67739beb93cSSam Leffler }
67839beb93cSSam Leffler 
67939beb93cSSam Leffler 
68039beb93cSSam Leffler void eloop_run(void)
68139beb93cSSam Leffler {
682*f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
683*f05cddf9SRui Paulo 	int num_poll_fds;
684*f05cddf9SRui Paulo 	int timeout_ms = 0;
685*f05cddf9SRui Paulo #else /* CONFIG_ELOOP_POLL */
68639beb93cSSam Leffler 	fd_set *rfds, *wfds, *efds;
68739beb93cSSam Leffler 	struct timeval _tv;
688*f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
689*f05cddf9SRui Paulo 	int res;
69039beb93cSSam Leffler 	struct os_time tv, now;
69139beb93cSSam Leffler 
692*f05cddf9SRui Paulo #ifndef CONFIG_ELOOP_POLL
69339beb93cSSam Leffler 	rfds = os_malloc(sizeof(*rfds));
69439beb93cSSam Leffler 	wfds = os_malloc(sizeof(*wfds));
69539beb93cSSam Leffler 	efds = os_malloc(sizeof(*efds));
696e28a4053SRui Paulo 	if (rfds == NULL || wfds == NULL || efds == NULL)
69739beb93cSSam Leffler 		goto out;
698*f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
69939beb93cSSam Leffler 
70039beb93cSSam Leffler 	while (!eloop.terminate &&
701e28a4053SRui Paulo 	       (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
70239beb93cSSam Leffler 		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
703e28a4053SRui Paulo 		struct eloop_timeout *timeout;
704e28a4053SRui Paulo 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
705e28a4053SRui Paulo 					list);
706e28a4053SRui Paulo 		if (timeout) {
70739beb93cSSam Leffler 			os_get_time(&now);
708e28a4053SRui Paulo 			if (os_time_before(&now, &timeout->time))
709e28a4053SRui Paulo 				os_time_sub(&timeout->time, &now, &tv);
71039beb93cSSam Leffler 			else
71139beb93cSSam Leffler 				tv.sec = tv.usec = 0;
712*f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
713*f05cddf9SRui Paulo 			timeout_ms = tv.sec * 1000 + tv.usec / 1000;
714*f05cddf9SRui Paulo #else /* CONFIG_ELOOP_POLL */
71539beb93cSSam Leffler 			_tv.tv_sec = tv.sec;
71639beb93cSSam Leffler 			_tv.tv_usec = tv.usec;
717*f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
71839beb93cSSam Leffler 		}
71939beb93cSSam Leffler 
720*f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
721*f05cddf9SRui Paulo 		num_poll_fds = eloop_sock_table_set_fds(
722*f05cddf9SRui Paulo 			&eloop.readers, &eloop.writers, &eloop.exceptions,
723*f05cddf9SRui Paulo 			eloop.pollfds, eloop.pollfds_map,
724*f05cddf9SRui Paulo 			eloop.max_pollfd_map);
725*f05cddf9SRui Paulo 		res = poll(eloop.pollfds, num_poll_fds,
726*f05cddf9SRui Paulo 			   timeout ? timeout_ms : -1);
727*f05cddf9SRui Paulo 
728*f05cddf9SRui Paulo 		if (res < 0 && errno != EINTR && errno != 0) {
729*f05cddf9SRui Paulo 			perror("poll");
730*f05cddf9SRui Paulo 			goto out;
731*f05cddf9SRui Paulo 		}
732*f05cddf9SRui Paulo #else /* CONFIG_ELOOP_POLL */
73339beb93cSSam Leffler 		eloop_sock_table_set_fds(&eloop.readers, rfds);
73439beb93cSSam Leffler 		eloop_sock_table_set_fds(&eloop.writers, wfds);
73539beb93cSSam Leffler 		eloop_sock_table_set_fds(&eloop.exceptions, efds);
73639beb93cSSam Leffler 		res = select(eloop.max_sock + 1, rfds, wfds, efds,
737e28a4053SRui Paulo 			     timeout ? &_tv : NULL);
73839beb93cSSam Leffler 		if (res < 0 && errno != EINTR && errno != 0) {
73939beb93cSSam Leffler 			perror("select");
74039beb93cSSam Leffler 			goto out;
74139beb93cSSam Leffler 		}
742*f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
74339beb93cSSam Leffler 		eloop_process_pending_signals();
74439beb93cSSam Leffler 
74539beb93cSSam Leffler 		/* check if some registered timeouts have occurred */
746e28a4053SRui Paulo 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
747e28a4053SRui Paulo 					list);
748e28a4053SRui Paulo 		if (timeout) {
74939beb93cSSam Leffler 			os_get_time(&now);
750e28a4053SRui Paulo 			if (!os_time_before(&now, &timeout->time)) {
751e28a4053SRui Paulo 				void *eloop_data = timeout->eloop_data;
752e28a4053SRui Paulo 				void *user_data = timeout->user_data;
753e28a4053SRui Paulo 				eloop_timeout_handler handler =
754e28a4053SRui Paulo 					timeout->handler;
755e28a4053SRui Paulo 				eloop_remove_timeout(timeout);
756e28a4053SRui Paulo 				handler(eloop_data, user_data);
75739beb93cSSam Leffler 			}
75839beb93cSSam Leffler 
75939beb93cSSam Leffler 		}
76039beb93cSSam Leffler 
76139beb93cSSam Leffler 		if (res <= 0)
76239beb93cSSam Leffler 			continue;
76339beb93cSSam Leffler 
764*f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
765*f05cddf9SRui Paulo 		eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
766*f05cddf9SRui Paulo 					  &eloop.exceptions, eloop.pollfds_map,
767*f05cddf9SRui Paulo 					  eloop.max_pollfd_map);
768*f05cddf9SRui Paulo #else /* CONFIG_ELOOP_POLL */
76939beb93cSSam Leffler 		eloop_sock_table_dispatch(&eloop.readers, rfds);
77039beb93cSSam Leffler 		eloop_sock_table_dispatch(&eloop.writers, wfds);
77139beb93cSSam Leffler 		eloop_sock_table_dispatch(&eloop.exceptions, efds);
772*f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
77339beb93cSSam Leffler 	}
77439beb93cSSam Leffler 
77539beb93cSSam Leffler out:
776*f05cddf9SRui Paulo #ifndef CONFIG_ELOOP_POLL
77739beb93cSSam Leffler 	os_free(rfds);
77839beb93cSSam Leffler 	os_free(wfds);
77939beb93cSSam Leffler 	os_free(efds);
780*f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
781*f05cddf9SRui Paulo 	return;
78239beb93cSSam Leffler }
78339beb93cSSam Leffler 
78439beb93cSSam Leffler 
78539beb93cSSam Leffler void eloop_terminate(void)
78639beb93cSSam Leffler {
78739beb93cSSam Leffler 	eloop.terminate = 1;
78839beb93cSSam Leffler }
78939beb93cSSam Leffler 
79039beb93cSSam Leffler 
79139beb93cSSam Leffler void eloop_destroy(void)
79239beb93cSSam Leffler {
79339beb93cSSam Leffler 	struct eloop_timeout *timeout, *prev;
79439beb93cSSam Leffler 	struct os_time now;
79539beb93cSSam Leffler 
79639beb93cSSam Leffler 	os_get_time(&now);
797e28a4053SRui Paulo 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
798e28a4053SRui Paulo 			      struct eloop_timeout, list) {
79939beb93cSSam Leffler 		int sec, usec;
800e28a4053SRui Paulo 		sec = timeout->time.sec - now.sec;
801e28a4053SRui Paulo 		usec = timeout->time.usec - now.usec;
802e28a4053SRui Paulo 		if (timeout->time.usec < now.usec) {
80339beb93cSSam Leffler 			sec--;
80439beb93cSSam Leffler 			usec += 1000000;
80539beb93cSSam Leffler 		}
806e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
807e28a4053SRui Paulo 			   "eloop_data=%p user_data=%p handler=%p",
808e28a4053SRui Paulo 			   sec, usec, timeout->eloop_data, timeout->user_data,
809e28a4053SRui Paulo 			   timeout->handler);
810e28a4053SRui Paulo 		wpa_trace_dump_funcname("eloop unregistered timeout handler",
811e28a4053SRui Paulo 					timeout->handler);
812e28a4053SRui Paulo 		wpa_trace_dump("eloop timeout", timeout);
813e28a4053SRui Paulo 		eloop_remove_timeout(timeout);
81439beb93cSSam Leffler 	}
81539beb93cSSam Leffler 	eloop_sock_table_destroy(&eloop.readers);
81639beb93cSSam Leffler 	eloop_sock_table_destroy(&eloop.writers);
81739beb93cSSam Leffler 	eloop_sock_table_destroy(&eloop.exceptions);
81839beb93cSSam Leffler 	os_free(eloop.signals);
819*f05cddf9SRui Paulo 
820*f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
821*f05cddf9SRui Paulo 	os_free(eloop.pollfds);
822*f05cddf9SRui Paulo 	os_free(eloop.pollfds_map);
823*f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
82439beb93cSSam Leffler }
82539beb93cSSam Leffler 
82639beb93cSSam Leffler 
82739beb93cSSam Leffler int eloop_terminated(void)
82839beb93cSSam Leffler {
82939beb93cSSam Leffler 	return eloop.terminate;
83039beb93cSSam Leffler }
83139beb93cSSam Leffler 
83239beb93cSSam Leffler 
83339beb93cSSam Leffler void eloop_wait_for_read_sock(int sock)
83439beb93cSSam Leffler {
835*f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
836*f05cddf9SRui Paulo 	struct pollfd pfd;
837*f05cddf9SRui Paulo 
838*f05cddf9SRui Paulo 	if (sock < 0)
839*f05cddf9SRui Paulo 		return;
840*f05cddf9SRui Paulo 
841*f05cddf9SRui Paulo 	os_memset(&pfd, 0, sizeof(pfd));
842*f05cddf9SRui Paulo 	pfd.fd = sock;
843*f05cddf9SRui Paulo 	pfd.events = POLLIN;
844*f05cddf9SRui Paulo 
845*f05cddf9SRui Paulo 	poll(&pfd, 1, -1);
846*f05cddf9SRui Paulo #else /* CONFIG_ELOOP_POLL */
84739beb93cSSam Leffler 	fd_set rfds;
84839beb93cSSam Leffler 
84939beb93cSSam Leffler 	if (sock < 0)
85039beb93cSSam Leffler 		return;
85139beb93cSSam Leffler 
85239beb93cSSam Leffler 	FD_ZERO(&rfds);
85339beb93cSSam Leffler 	FD_SET(sock, &rfds);
85439beb93cSSam Leffler 	select(sock + 1, &rfds, NULL, NULL, NULL);
855*f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
85639beb93cSSam Leffler }
857