xref: /freebsd/contrib/wpa/src/utils/eloop.c (revision 325151a32e114f02699a301c1e74080e7c1f1a26)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * Event loop based on select() loop
3e28a4053SRui Paulo  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
105b9c547cSRui Paulo #include <assert.h>
1139beb93cSSam Leffler 
1239beb93cSSam Leffler #include "common.h"
13e28a4053SRui Paulo #include "trace.h"
14e28a4053SRui Paulo #include "list.h"
1539beb93cSSam Leffler #include "eloop.h"
1639beb93cSSam Leffler 
175b9c547cSRui Paulo #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL)
185b9c547cSRui Paulo #error Do not define both of poll and epoll
195b9c547cSRui Paulo #endif
205b9c547cSRui Paulo 
215b9c547cSRui Paulo #if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL)
225b9c547cSRui Paulo #define CONFIG_ELOOP_SELECT
235b9c547cSRui Paulo #endif
245b9c547cSRui Paulo 
25f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
26f05cddf9SRui Paulo #include <poll.h>
27f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
28f05cddf9SRui Paulo 
295b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
305b9c547cSRui Paulo #include <sys/epoll.h>
315b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
3239beb93cSSam Leffler 
3339beb93cSSam Leffler struct eloop_sock {
3439beb93cSSam Leffler 	int sock;
3539beb93cSSam Leffler 	void *eloop_data;
3639beb93cSSam Leffler 	void *user_data;
3739beb93cSSam Leffler 	eloop_sock_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_timeout {
44e28a4053SRui Paulo 	struct dl_list list;
455b9c547cSRui Paulo 	struct os_reltime time;
4639beb93cSSam Leffler 	void *eloop_data;
4739beb93cSSam Leffler 	void *user_data;
4839beb93cSSam Leffler 	eloop_timeout_handler handler;
49e28a4053SRui Paulo 	WPA_TRACE_REF(eloop);
50e28a4053SRui Paulo 	WPA_TRACE_REF(user);
51e28a4053SRui Paulo 	WPA_TRACE_INFO
5239beb93cSSam Leffler };
5339beb93cSSam Leffler 
5439beb93cSSam Leffler struct eloop_signal {
5539beb93cSSam Leffler 	int sig;
5639beb93cSSam Leffler 	void *user_data;
5739beb93cSSam Leffler 	eloop_signal_handler handler;
5839beb93cSSam Leffler 	int signaled;
5939beb93cSSam Leffler };
6039beb93cSSam Leffler 
6139beb93cSSam Leffler struct eloop_sock_table {
6239beb93cSSam Leffler 	int count;
6339beb93cSSam Leffler 	struct eloop_sock *table;
645b9c547cSRui Paulo 	eloop_event_type type;
6539beb93cSSam Leffler 	int changed;
6639beb93cSSam Leffler };
6739beb93cSSam Leffler 
6839beb93cSSam Leffler struct eloop_data {
6939beb93cSSam Leffler 	int max_sock;
7039beb93cSSam Leffler 
71f05cddf9SRui Paulo 	int count; /* sum of all table counts */
72f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
73f05cddf9SRui Paulo 	int max_pollfd_map; /* number of pollfds_map currently allocated */
74f05cddf9SRui Paulo 	int max_poll_fds; /* number of pollfds currently allocated */
75f05cddf9SRui Paulo 	struct pollfd *pollfds;
76f05cddf9SRui Paulo 	struct pollfd **pollfds_map;
77f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
785b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
795b9c547cSRui Paulo 	int epollfd;
805b9c547cSRui Paulo 	int epoll_max_event_num;
815b9c547cSRui Paulo 	int epoll_max_fd;
825b9c547cSRui Paulo 	struct eloop_sock *epoll_table;
835b9c547cSRui Paulo 	struct epoll_event *epoll_events;
845b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
8539beb93cSSam Leffler 	struct eloop_sock_table readers;
8639beb93cSSam Leffler 	struct eloop_sock_table writers;
8739beb93cSSam Leffler 	struct eloop_sock_table exceptions;
8839beb93cSSam Leffler 
89e28a4053SRui Paulo 	struct dl_list timeout;
9039beb93cSSam Leffler 
9139beb93cSSam Leffler 	int signal_count;
9239beb93cSSam Leffler 	struct eloop_signal *signals;
9339beb93cSSam Leffler 	int signaled;
9439beb93cSSam Leffler 	int pending_terminate;
9539beb93cSSam Leffler 
9639beb93cSSam Leffler 	int terminate;
9739beb93cSSam Leffler };
9839beb93cSSam Leffler 
9939beb93cSSam Leffler static struct eloop_data eloop;
10039beb93cSSam Leffler 
10139beb93cSSam Leffler 
102e28a4053SRui Paulo #ifdef WPA_TRACE
103e28a4053SRui Paulo 
104e28a4053SRui Paulo static void eloop_sigsegv_handler(int sig)
105e28a4053SRui Paulo {
106e28a4053SRui Paulo 	wpa_trace_show("eloop SIGSEGV");
107e28a4053SRui Paulo 	abort();
108e28a4053SRui Paulo }
109e28a4053SRui Paulo 
110e28a4053SRui Paulo static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
111e28a4053SRui Paulo {
112e28a4053SRui Paulo 	int i;
113e28a4053SRui Paulo 	if (table == NULL || table->table == NULL)
114e28a4053SRui Paulo 		return;
115e28a4053SRui Paulo 	for (i = 0; i < table->count; i++) {
116e28a4053SRui Paulo 		wpa_trace_add_ref(&table->table[i], eloop,
117e28a4053SRui Paulo 				  table->table[i].eloop_data);
118e28a4053SRui Paulo 		wpa_trace_add_ref(&table->table[i], user,
119e28a4053SRui Paulo 				  table->table[i].user_data);
120e28a4053SRui Paulo 	}
121e28a4053SRui Paulo }
122e28a4053SRui Paulo 
123e28a4053SRui Paulo 
124e28a4053SRui Paulo static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
125e28a4053SRui Paulo {
126e28a4053SRui Paulo 	int i;
127e28a4053SRui Paulo 	if (table == NULL || table->table == NULL)
128e28a4053SRui Paulo 		return;
129e28a4053SRui Paulo 	for (i = 0; i < table->count; i++) {
130e28a4053SRui Paulo 		wpa_trace_remove_ref(&table->table[i], eloop,
131e28a4053SRui Paulo 				     table->table[i].eloop_data);
132e28a4053SRui Paulo 		wpa_trace_remove_ref(&table->table[i], user,
133e28a4053SRui Paulo 				     table->table[i].user_data);
134e28a4053SRui Paulo 	}
135e28a4053SRui Paulo }
136e28a4053SRui Paulo 
137e28a4053SRui Paulo #else /* WPA_TRACE */
138e28a4053SRui Paulo 
139e28a4053SRui Paulo #define eloop_trace_sock_add_ref(table) do { } while (0)
140e28a4053SRui Paulo #define eloop_trace_sock_remove_ref(table) do { } while (0)
141e28a4053SRui Paulo 
142e28a4053SRui Paulo #endif /* WPA_TRACE */
143e28a4053SRui Paulo 
144e28a4053SRui Paulo 
145e28a4053SRui Paulo int eloop_init(void)
14639beb93cSSam Leffler {
14739beb93cSSam Leffler 	os_memset(&eloop, 0, sizeof(eloop));
148e28a4053SRui Paulo 	dl_list_init(&eloop.timeout);
1495b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
1505b9c547cSRui Paulo 	eloop.epollfd = epoll_create1(0);
1515b9c547cSRui Paulo 	if (eloop.epollfd < 0) {
1525b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s\n",
1535b9c547cSRui Paulo 			   __func__, strerror(errno));
1545b9c547cSRui Paulo 		return -1;
1555b9c547cSRui Paulo 	}
1565b9c547cSRui Paulo 	eloop.readers.type = EVENT_TYPE_READ;
1575b9c547cSRui Paulo 	eloop.writers.type = EVENT_TYPE_WRITE;
1585b9c547cSRui Paulo 	eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
1595b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
160e28a4053SRui Paulo #ifdef WPA_TRACE
161e28a4053SRui Paulo 	signal(SIGSEGV, eloop_sigsegv_handler);
162e28a4053SRui Paulo #endif /* WPA_TRACE */
16339beb93cSSam Leffler 	return 0;
16439beb93cSSam Leffler }
16539beb93cSSam Leffler 
16639beb93cSSam Leffler 
16739beb93cSSam Leffler static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
16839beb93cSSam Leffler                                      int sock, eloop_sock_handler handler,
16939beb93cSSam Leffler                                      void *eloop_data, void *user_data)
17039beb93cSSam Leffler {
1715b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
1725b9c547cSRui Paulo 	struct eloop_sock *temp_table;
1735b9c547cSRui Paulo 	struct epoll_event ev, *temp_events;
1745b9c547cSRui Paulo 	int next;
1755b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
17639beb93cSSam Leffler 	struct eloop_sock *tmp;
177f05cddf9SRui Paulo 	int new_max_sock;
178f05cddf9SRui Paulo 
179f05cddf9SRui Paulo 	if (sock > eloop.max_sock)
180f05cddf9SRui Paulo 		new_max_sock = sock;
181f05cddf9SRui Paulo 	else
182f05cddf9SRui Paulo 		new_max_sock = eloop.max_sock;
18339beb93cSSam Leffler 
18439beb93cSSam Leffler 	if (table == NULL)
18539beb93cSSam Leffler 		return -1;
18639beb93cSSam Leffler 
187f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
188f05cddf9SRui Paulo 	if (new_max_sock >= eloop.max_pollfd_map) {
189f05cddf9SRui Paulo 		struct pollfd **nmap;
190f05cddf9SRui Paulo 		nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
191f05cddf9SRui Paulo 					sizeof(struct pollfd *));
192f05cddf9SRui Paulo 		if (nmap == NULL)
193f05cddf9SRui Paulo 			return -1;
194f05cddf9SRui Paulo 
195f05cddf9SRui Paulo 		eloop.max_pollfd_map = new_max_sock + 50;
196f05cddf9SRui Paulo 		eloop.pollfds_map = nmap;
197f05cddf9SRui Paulo 	}
198f05cddf9SRui Paulo 
199f05cddf9SRui Paulo 	if (eloop.count + 1 > eloop.max_poll_fds) {
200f05cddf9SRui Paulo 		struct pollfd *n;
201f05cddf9SRui Paulo 		int nmax = eloop.count + 1 + 50;
202f05cddf9SRui Paulo 		n = os_realloc_array(eloop.pollfds, nmax,
203f05cddf9SRui Paulo 				     sizeof(struct pollfd));
204f05cddf9SRui Paulo 		if (n == NULL)
205f05cddf9SRui Paulo 			return -1;
206f05cddf9SRui Paulo 
207f05cddf9SRui Paulo 		eloop.max_poll_fds = nmax;
208f05cddf9SRui Paulo 		eloop.pollfds = n;
209f05cddf9SRui Paulo 	}
210f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
2115b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
2125b9c547cSRui Paulo 	if (new_max_sock >= eloop.epoll_max_fd) {
2135b9c547cSRui Paulo 		next = eloop.epoll_max_fd == 0 ? 16 : eloop.epoll_max_fd * 2;
2145b9c547cSRui Paulo 		temp_table = os_realloc_array(eloop.epoll_table, next,
2155b9c547cSRui Paulo 					      sizeof(struct eloop_sock));
2165b9c547cSRui Paulo 		if (temp_table == NULL)
2175b9c547cSRui Paulo 			return -1;
2185b9c547cSRui Paulo 
2195b9c547cSRui Paulo 		eloop.epoll_max_fd = next;
2205b9c547cSRui Paulo 		eloop.epoll_table = temp_table;
2215b9c547cSRui Paulo 	}
2225b9c547cSRui Paulo 
2235b9c547cSRui Paulo 	if (eloop.count + 1 > eloop.epoll_max_event_num) {
2245b9c547cSRui Paulo 		next = eloop.epoll_max_event_num == 0 ? 8 :
2255b9c547cSRui Paulo 			eloop.epoll_max_event_num * 2;
2265b9c547cSRui Paulo 		temp_events = os_realloc_array(eloop.epoll_events, next,
2275b9c547cSRui Paulo 					       sizeof(struct epoll_event));
2285b9c547cSRui Paulo 		if (temp_events == NULL) {
2295b9c547cSRui Paulo 			wpa_printf(MSG_ERROR, "%s: malloc for epoll failed. "
2305b9c547cSRui Paulo 				   "%s\n", __func__, strerror(errno));
2315b9c547cSRui Paulo 			return -1;
2325b9c547cSRui Paulo 		}
2335b9c547cSRui Paulo 
2345b9c547cSRui Paulo 		eloop.epoll_max_event_num = next;
2355b9c547cSRui Paulo 		eloop.epoll_events = temp_events;
2365b9c547cSRui Paulo 	}
2375b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
238f05cddf9SRui Paulo 
239e28a4053SRui Paulo 	eloop_trace_sock_remove_ref(table);
240f05cddf9SRui Paulo 	tmp = os_realloc_array(table->table, table->count + 1,
241f05cddf9SRui Paulo 			       sizeof(struct eloop_sock));
2425b9c547cSRui Paulo 	if (tmp == NULL) {
2435b9c547cSRui Paulo 		eloop_trace_sock_add_ref(table);
24439beb93cSSam Leffler 		return -1;
2455b9c547cSRui Paulo 	}
24639beb93cSSam Leffler 
24739beb93cSSam Leffler 	tmp[table->count].sock = sock;
24839beb93cSSam Leffler 	tmp[table->count].eloop_data = eloop_data;
24939beb93cSSam Leffler 	tmp[table->count].user_data = user_data;
25039beb93cSSam Leffler 	tmp[table->count].handler = handler;
251e28a4053SRui Paulo 	wpa_trace_record(&tmp[table->count]);
25239beb93cSSam Leffler 	table->count++;
25339beb93cSSam Leffler 	table->table = tmp;
254f05cddf9SRui Paulo 	eloop.max_sock = new_max_sock;
255f05cddf9SRui Paulo 	eloop.count++;
25639beb93cSSam Leffler 	table->changed = 1;
257e28a4053SRui Paulo 	eloop_trace_sock_add_ref(table);
25839beb93cSSam Leffler 
2595b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
2605b9c547cSRui Paulo 	os_memset(&ev, 0, sizeof(ev));
2615b9c547cSRui Paulo 	switch (table->type) {
2625b9c547cSRui Paulo 	case EVENT_TYPE_READ:
2635b9c547cSRui Paulo 		ev.events = EPOLLIN;
2645b9c547cSRui Paulo 		break;
2655b9c547cSRui Paulo 	case EVENT_TYPE_WRITE:
2665b9c547cSRui Paulo 		ev.events = EPOLLOUT;
2675b9c547cSRui Paulo 		break;
2685b9c547cSRui Paulo 	/*
2695b9c547cSRui Paulo 	 * Exceptions are always checked when using epoll, but I suppose it's
2705b9c547cSRui Paulo 	 * possible that someone registered a socket *only* for exception
2715b9c547cSRui Paulo 	 * handling.
2725b9c547cSRui Paulo 	 */
2735b9c547cSRui Paulo 	case EVENT_TYPE_EXCEPTION:
2745b9c547cSRui Paulo 		ev.events = EPOLLERR | EPOLLHUP;
2755b9c547cSRui Paulo 		break;
2765b9c547cSRui Paulo 	}
2775b9c547cSRui Paulo 	ev.data.fd = sock;
2785b9c547cSRui Paulo 	if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
2795b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d "
2805b9c547cSRui Paulo 			   "failed. %s\n", __func__, sock, strerror(errno));
2815b9c547cSRui Paulo 		return -1;
2825b9c547cSRui Paulo 	}
2835b9c547cSRui Paulo 	os_memcpy(&eloop.epoll_table[sock], &table->table[table->count - 1],
2845b9c547cSRui Paulo 		  sizeof(struct eloop_sock));
2855b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
28639beb93cSSam Leffler 	return 0;
28739beb93cSSam Leffler }
28839beb93cSSam Leffler 
28939beb93cSSam Leffler 
29039beb93cSSam Leffler static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
29139beb93cSSam Leffler                                          int sock)
29239beb93cSSam Leffler {
29339beb93cSSam Leffler 	int i;
29439beb93cSSam Leffler 
29539beb93cSSam Leffler 	if (table == NULL || table->table == NULL || table->count == 0)
29639beb93cSSam Leffler 		return;
29739beb93cSSam Leffler 
29839beb93cSSam Leffler 	for (i = 0; i < table->count; i++) {
29939beb93cSSam Leffler 		if (table->table[i].sock == sock)
30039beb93cSSam Leffler 			break;
30139beb93cSSam Leffler 	}
30239beb93cSSam Leffler 	if (i == table->count)
30339beb93cSSam Leffler 		return;
304e28a4053SRui Paulo 	eloop_trace_sock_remove_ref(table);
30539beb93cSSam Leffler 	if (i != table->count - 1) {
30639beb93cSSam Leffler 		os_memmove(&table->table[i], &table->table[i + 1],
30739beb93cSSam Leffler 			   (table->count - i - 1) *
30839beb93cSSam Leffler 			   sizeof(struct eloop_sock));
30939beb93cSSam Leffler 	}
31039beb93cSSam Leffler 	table->count--;
311f05cddf9SRui Paulo 	eloop.count--;
31239beb93cSSam Leffler 	table->changed = 1;
313e28a4053SRui Paulo 	eloop_trace_sock_add_ref(table);
3145b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
3155b9c547cSRui Paulo 	if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
3165b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d "
3175b9c547cSRui Paulo 			   "failed. %s\n", __func__, sock, strerror(errno));
3185b9c547cSRui Paulo 		return;
3195b9c547cSRui Paulo 	}
3205b9c547cSRui Paulo 	os_memset(&eloop.epoll_table[sock], 0, sizeof(struct eloop_sock));
3215b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
32239beb93cSSam Leffler }
32339beb93cSSam Leffler 
32439beb93cSSam Leffler 
325f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
326f05cddf9SRui Paulo 
327f05cddf9SRui Paulo static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
328f05cddf9SRui Paulo {
329f05cddf9SRui Paulo 	if (fd < mx && fd >= 0)
330f05cddf9SRui Paulo 		return pollfds_map[fd];
331f05cddf9SRui Paulo 	return NULL;
332f05cddf9SRui Paulo }
333f05cddf9SRui Paulo 
334f05cddf9SRui Paulo 
335f05cddf9SRui Paulo static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
336f05cddf9SRui Paulo 				    struct eloop_sock_table *writers,
337f05cddf9SRui Paulo 				    struct eloop_sock_table *exceptions,
338f05cddf9SRui Paulo 				    struct pollfd *pollfds,
339f05cddf9SRui Paulo 				    struct pollfd **pollfds_map,
340f05cddf9SRui Paulo 				    int max_pollfd_map)
341f05cddf9SRui Paulo {
342f05cddf9SRui Paulo 	int i;
343f05cddf9SRui Paulo 	int nxt = 0;
344f05cddf9SRui Paulo 	int fd;
345f05cddf9SRui Paulo 	struct pollfd *pfd;
346f05cddf9SRui Paulo 
347f05cddf9SRui Paulo 	/* Clear pollfd lookup map. It will be re-populated below. */
348f05cddf9SRui Paulo 	os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
349f05cddf9SRui Paulo 
350f05cddf9SRui Paulo 	if (readers && readers->table) {
351f05cddf9SRui Paulo 		for (i = 0; i < readers->count; i++) {
352f05cddf9SRui Paulo 			fd = readers->table[i].sock;
353f05cddf9SRui Paulo 			assert(fd >= 0 && fd < max_pollfd_map);
354f05cddf9SRui Paulo 			pollfds[nxt].fd = fd;
355f05cddf9SRui Paulo 			pollfds[nxt].events = POLLIN;
356f05cddf9SRui Paulo 			pollfds[nxt].revents = 0;
357f05cddf9SRui Paulo 			pollfds_map[fd] = &(pollfds[nxt]);
358f05cddf9SRui Paulo 			nxt++;
359f05cddf9SRui Paulo 		}
360f05cddf9SRui Paulo 	}
361f05cddf9SRui Paulo 
362f05cddf9SRui Paulo 	if (writers && writers->table) {
363f05cddf9SRui Paulo 		for (i = 0; i < writers->count; i++) {
364f05cddf9SRui Paulo 			/*
365f05cddf9SRui Paulo 			 * See if we already added this descriptor, update it
366f05cddf9SRui Paulo 			 * if so.
367f05cddf9SRui Paulo 			 */
368f05cddf9SRui Paulo 			fd = writers->table[i].sock;
369f05cddf9SRui Paulo 			assert(fd >= 0 && fd < max_pollfd_map);
370f05cddf9SRui Paulo 			pfd = pollfds_map[fd];
371f05cddf9SRui Paulo 			if (!pfd) {
372f05cddf9SRui Paulo 				pfd = &(pollfds[nxt]);
373f05cddf9SRui Paulo 				pfd->events = 0;
374f05cddf9SRui Paulo 				pfd->fd = fd;
375f05cddf9SRui Paulo 				pollfds[i].revents = 0;
376f05cddf9SRui Paulo 				pollfds_map[fd] = pfd;
377f05cddf9SRui Paulo 				nxt++;
378f05cddf9SRui Paulo 			}
379f05cddf9SRui Paulo 			pfd->events |= POLLOUT;
380f05cddf9SRui Paulo 		}
381f05cddf9SRui Paulo 	}
382f05cddf9SRui Paulo 
383f05cddf9SRui Paulo 	/*
384f05cddf9SRui Paulo 	 * Exceptions are always checked when using poll, but I suppose it's
385f05cddf9SRui Paulo 	 * possible that someone registered a socket *only* for exception
386f05cddf9SRui Paulo 	 * handling. Set the POLLIN bit in this case.
387f05cddf9SRui Paulo 	 */
388f05cddf9SRui Paulo 	if (exceptions && exceptions->table) {
389f05cddf9SRui Paulo 		for (i = 0; i < exceptions->count; i++) {
390f05cddf9SRui Paulo 			/*
391f05cddf9SRui Paulo 			 * See if we already added this descriptor, just use it
392f05cddf9SRui Paulo 			 * if so.
393f05cddf9SRui Paulo 			 */
394f05cddf9SRui Paulo 			fd = exceptions->table[i].sock;
395f05cddf9SRui Paulo 			assert(fd >= 0 && fd < max_pollfd_map);
396f05cddf9SRui Paulo 			pfd = pollfds_map[fd];
397f05cddf9SRui Paulo 			if (!pfd) {
398f05cddf9SRui Paulo 				pfd = &(pollfds[nxt]);
399f05cddf9SRui Paulo 				pfd->events = POLLIN;
400f05cddf9SRui Paulo 				pfd->fd = fd;
401f05cddf9SRui Paulo 				pollfds[i].revents = 0;
402f05cddf9SRui Paulo 				pollfds_map[fd] = pfd;
403f05cddf9SRui Paulo 				nxt++;
404f05cddf9SRui Paulo 			}
405f05cddf9SRui Paulo 		}
406f05cddf9SRui Paulo 	}
407f05cddf9SRui Paulo 
408f05cddf9SRui Paulo 	return nxt;
409f05cddf9SRui Paulo }
410f05cddf9SRui Paulo 
411f05cddf9SRui Paulo 
412f05cddf9SRui Paulo static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
413f05cddf9SRui Paulo 					   struct pollfd **pollfds_map,
414f05cddf9SRui Paulo 					   int max_pollfd_map,
415f05cddf9SRui Paulo 					   short int revents)
416f05cddf9SRui Paulo {
417f05cddf9SRui Paulo 	int i;
418f05cddf9SRui Paulo 	struct pollfd *pfd;
419f05cddf9SRui Paulo 
420f05cddf9SRui Paulo 	if (!table || !table->table)
421f05cddf9SRui Paulo 		return 0;
422f05cddf9SRui Paulo 
423f05cddf9SRui Paulo 	table->changed = 0;
424f05cddf9SRui Paulo 	for (i = 0; i < table->count; i++) {
425f05cddf9SRui Paulo 		pfd = find_pollfd(pollfds_map, table->table[i].sock,
426f05cddf9SRui Paulo 				  max_pollfd_map);
427f05cddf9SRui Paulo 		if (!pfd)
428f05cddf9SRui Paulo 			continue;
429f05cddf9SRui Paulo 
430f05cddf9SRui Paulo 		if (!(pfd->revents & revents))
431f05cddf9SRui Paulo 			continue;
432f05cddf9SRui Paulo 
433f05cddf9SRui Paulo 		table->table[i].handler(table->table[i].sock,
434f05cddf9SRui Paulo 					table->table[i].eloop_data,
435f05cddf9SRui Paulo 					table->table[i].user_data);
436f05cddf9SRui Paulo 		if (table->changed)
437f05cddf9SRui Paulo 			return 1;
438f05cddf9SRui Paulo 	}
439f05cddf9SRui Paulo 
440f05cddf9SRui Paulo 	return 0;
441f05cddf9SRui Paulo }
442f05cddf9SRui Paulo 
443f05cddf9SRui Paulo 
444f05cddf9SRui Paulo static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
445f05cddf9SRui Paulo 				      struct eloop_sock_table *writers,
446f05cddf9SRui Paulo 				      struct eloop_sock_table *exceptions,
447f05cddf9SRui Paulo 				      struct pollfd **pollfds_map,
448f05cddf9SRui Paulo 				      int max_pollfd_map)
449f05cddf9SRui Paulo {
450f05cddf9SRui Paulo 	if (eloop_sock_table_dispatch_table(readers, pollfds_map,
451f05cddf9SRui Paulo 					    max_pollfd_map, POLLIN | POLLERR |
452f05cddf9SRui Paulo 					    POLLHUP))
453f05cddf9SRui Paulo 		return; /* pollfds may be invalid at this point */
454f05cddf9SRui Paulo 
455f05cddf9SRui Paulo 	if (eloop_sock_table_dispatch_table(writers, pollfds_map,
456f05cddf9SRui Paulo 					    max_pollfd_map, POLLOUT))
457f05cddf9SRui Paulo 		return; /* pollfds may be invalid at this point */
458f05cddf9SRui Paulo 
459f05cddf9SRui Paulo 	eloop_sock_table_dispatch_table(exceptions, pollfds_map,
460f05cddf9SRui Paulo 					max_pollfd_map, POLLERR | POLLHUP);
461f05cddf9SRui Paulo }
462f05cddf9SRui Paulo 
4635b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */
4645b9c547cSRui Paulo 
4655b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
466f05cddf9SRui Paulo 
46739beb93cSSam Leffler static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
46839beb93cSSam Leffler 				     fd_set *fds)
46939beb93cSSam Leffler {
47039beb93cSSam Leffler 	int i;
47139beb93cSSam Leffler 
47239beb93cSSam Leffler 	FD_ZERO(fds);
47339beb93cSSam Leffler 
47439beb93cSSam Leffler 	if (table->table == NULL)
47539beb93cSSam Leffler 		return;
47639beb93cSSam Leffler 
4775b9c547cSRui Paulo 	for (i = 0; i < table->count; i++) {
4785b9c547cSRui Paulo 		assert(table->table[i].sock >= 0);
47939beb93cSSam Leffler 		FD_SET(table->table[i].sock, fds);
48039beb93cSSam Leffler 	}
4815b9c547cSRui Paulo }
48239beb93cSSam Leffler 
48339beb93cSSam Leffler 
48439beb93cSSam Leffler static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
48539beb93cSSam Leffler 				      fd_set *fds)
48639beb93cSSam Leffler {
48739beb93cSSam Leffler 	int i;
48839beb93cSSam Leffler 
48939beb93cSSam Leffler 	if (table == NULL || table->table == NULL)
49039beb93cSSam Leffler 		return;
49139beb93cSSam Leffler 
49239beb93cSSam Leffler 	table->changed = 0;
49339beb93cSSam Leffler 	for (i = 0; i < table->count; i++) {
49439beb93cSSam Leffler 		if (FD_ISSET(table->table[i].sock, fds)) {
49539beb93cSSam Leffler 			table->table[i].handler(table->table[i].sock,
49639beb93cSSam Leffler 						table->table[i].eloop_data,
49739beb93cSSam Leffler 						table->table[i].user_data);
49839beb93cSSam Leffler 			if (table->changed)
49939beb93cSSam Leffler 				break;
50039beb93cSSam Leffler 		}
50139beb93cSSam Leffler 	}
50239beb93cSSam Leffler }
50339beb93cSSam Leffler 
5045b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
5055b9c547cSRui Paulo 
5065b9c547cSRui Paulo 
5075b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
5085b9c547cSRui Paulo static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
5095b9c547cSRui Paulo {
5105b9c547cSRui Paulo 	struct eloop_sock *table;
5115b9c547cSRui Paulo 	int i;
5125b9c547cSRui Paulo 
5135b9c547cSRui Paulo 	for (i = 0; i < nfds; i++) {
5145b9c547cSRui Paulo 		table = &eloop.epoll_table[events[i].data.fd];
5155b9c547cSRui Paulo 		if (table->handler == NULL)
5165b9c547cSRui Paulo 			continue;
5175b9c547cSRui Paulo 		table->handler(table->sock, table->eloop_data,
5185b9c547cSRui Paulo 			       table->user_data);
519*325151a3SRui Paulo 		if (eloop.readers.changed ||
520*325151a3SRui Paulo 		    eloop.writers.changed ||
521*325151a3SRui Paulo 		    eloop.exceptions.changed)
522*325151a3SRui Paulo 			break;
5235b9c547cSRui Paulo 	}
5245b9c547cSRui Paulo }
5255b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
526f05cddf9SRui Paulo 
52739beb93cSSam Leffler 
52839beb93cSSam Leffler static void eloop_sock_table_destroy(struct eloop_sock_table *table)
52939beb93cSSam Leffler {
53039beb93cSSam Leffler 	if (table) {
53139beb93cSSam Leffler 		int i;
53239beb93cSSam Leffler 		for (i = 0; i < table->count && table->table; i++) {
533e28a4053SRui Paulo 			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
534e28a4053SRui Paulo 				   "sock=%d eloop_data=%p user_data=%p "
535e28a4053SRui Paulo 				   "handler=%p",
53639beb93cSSam Leffler 				   table->table[i].sock,
53739beb93cSSam Leffler 				   table->table[i].eloop_data,
53839beb93cSSam Leffler 				   table->table[i].user_data,
53939beb93cSSam Leffler 				   table->table[i].handler);
540e28a4053SRui Paulo 			wpa_trace_dump_funcname("eloop unregistered socket "
541e28a4053SRui Paulo 						"handler",
542e28a4053SRui Paulo 						table->table[i].handler);
543e28a4053SRui Paulo 			wpa_trace_dump("eloop sock", &table->table[i]);
54439beb93cSSam Leffler 		}
54539beb93cSSam Leffler 		os_free(table->table);
54639beb93cSSam Leffler 	}
54739beb93cSSam Leffler }
54839beb93cSSam Leffler 
54939beb93cSSam Leffler 
55039beb93cSSam Leffler int eloop_register_read_sock(int sock, eloop_sock_handler handler,
55139beb93cSSam Leffler 			     void *eloop_data, void *user_data)
55239beb93cSSam Leffler {
55339beb93cSSam Leffler 	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
55439beb93cSSam Leffler 				   eloop_data, user_data);
55539beb93cSSam Leffler }
55639beb93cSSam Leffler 
55739beb93cSSam Leffler 
55839beb93cSSam Leffler void eloop_unregister_read_sock(int sock)
55939beb93cSSam Leffler {
56039beb93cSSam Leffler 	eloop_unregister_sock(sock, EVENT_TYPE_READ);
56139beb93cSSam Leffler }
56239beb93cSSam Leffler 
56339beb93cSSam Leffler 
56439beb93cSSam Leffler static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
56539beb93cSSam Leffler {
56639beb93cSSam Leffler 	switch (type) {
56739beb93cSSam Leffler 	case EVENT_TYPE_READ:
56839beb93cSSam Leffler 		return &eloop.readers;
56939beb93cSSam Leffler 	case EVENT_TYPE_WRITE:
57039beb93cSSam Leffler 		return &eloop.writers;
57139beb93cSSam Leffler 	case EVENT_TYPE_EXCEPTION:
57239beb93cSSam Leffler 		return &eloop.exceptions;
57339beb93cSSam Leffler 	}
57439beb93cSSam Leffler 
57539beb93cSSam Leffler 	return NULL;
57639beb93cSSam Leffler }
57739beb93cSSam Leffler 
57839beb93cSSam Leffler 
57939beb93cSSam Leffler int eloop_register_sock(int sock, eloop_event_type type,
58039beb93cSSam Leffler 			eloop_sock_handler handler,
58139beb93cSSam Leffler 			void *eloop_data, void *user_data)
58239beb93cSSam Leffler {
58339beb93cSSam Leffler 	struct eloop_sock_table *table;
58439beb93cSSam Leffler 
5855b9c547cSRui Paulo 	assert(sock >= 0);
58639beb93cSSam Leffler 	table = eloop_get_sock_table(type);
58739beb93cSSam Leffler 	return eloop_sock_table_add_sock(table, sock, handler,
58839beb93cSSam Leffler 					 eloop_data, user_data);
58939beb93cSSam Leffler }
59039beb93cSSam Leffler 
59139beb93cSSam Leffler 
59239beb93cSSam Leffler void eloop_unregister_sock(int sock, eloop_event_type type)
59339beb93cSSam Leffler {
59439beb93cSSam Leffler 	struct eloop_sock_table *table;
59539beb93cSSam Leffler 
59639beb93cSSam Leffler 	table = eloop_get_sock_table(type);
59739beb93cSSam Leffler 	eloop_sock_table_remove_sock(table, sock);
59839beb93cSSam Leffler }
59939beb93cSSam Leffler 
60039beb93cSSam Leffler 
60139beb93cSSam Leffler int eloop_register_timeout(unsigned int secs, unsigned int usecs,
60239beb93cSSam Leffler 			   eloop_timeout_handler handler,
60339beb93cSSam Leffler 			   void *eloop_data, void *user_data)
60439beb93cSSam Leffler {
605e28a4053SRui Paulo 	struct eloop_timeout *timeout, *tmp;
606f05cddf9SRui Paulo 	os_time_t now_sec;
60739beb93cSSam Leffler 
608e28a4053SRui Paulo 	timeout = os_zalloc(sizeof(*timeout));
60939beb93cSSam Leffler 	if (timeout == NULL)
61039beb93cSSam Leffler 		return -1;
6115b9c547cSRui Paulo 	if (os_get_reltime(&timeout->time) < 0) {
61239beb93cSSam Leffler 		os_free(timeout);
61339beb93cSSam Leffler 		return -1;
61439beb93cSSam Leffler 	}
615f05cddf9SRui Paulo 	now_sec = timeout->time.sec;
61639beb93cSSam Leffler 	timeout->time.sec += secs;
617f05cddf9SRui Paulo 	if (timeout->time.sec < now_sec) {
618f05cddf9SRui Paulo 		/*
619f05cddf9SRui Paulo 		 * Integer overflow - assume long enough timeout to be assumed
620f05cddf9SRui Paulo 		 * to be infinite, i.e., the timeout would never happen.
621f05cddf9SRui Paulo 		 */
622f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
623f05cddf9SRui Paulo 			   "ever happen - ignore it", secs);
624f05cddf9SRui Paulo 		os_free(timeout);
625f05cddf9SRui Paulo 		return 0;
626f05cddf9SRui Paulo 	}
62739beb93cSSam Leffler 	timeout->time.usec += usecs;
62839beb93cSSam Leffler 	while (timeout->time.usec >= 1000000) {
62939beb93cSSam Leffler 		timeout->time.sec++;
63039beb93cSSam Leffler 		timeout->time.usec -= 1000000;
63139beb93cSSam Leffler 	}
63239beb93cSSam Leffler 	timeout->eloop_data = eloop_data;
63339beb93cSSam Leffler 	timeout->user_data = user_data;
63439beb93cSSam Leffler 	timeout->handler = handler;
635e28a4053SRui Paulo 	wpa_trace_add_ref(timeout, eloop, eloop_data);
636e28a4053SRui Paulo 	wpa_trace_add_ref(timeout, user, user_data);
637e28a4053SRui Paulo 	wpa_trace_record(timeout);
63839beb93cSSam Leffler 
639e28a4053SRui Paulo 	/* Maintain timeouts in order of increasing time */
640e28a4053SRui Paulo 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
6415b9c547cSRui Paulo 		if (os_reltime_before(&timeout->time, &tmp->time)) {
642e28a4053SRui Paulo 			dl_list_add(tmp->list.prev, &timeout->list);
643e28a4053SRui Paulo 			return 0;
644e28a4053SRui Paulo 		}
645e28a4053SRui Paulo 	}
646e28a4053SRui Paulo 	dl_list_add_tail(&eloop.timeout, &timeout->list);
647e28a4053SRui Paulo 
64839beb93cSSam Leffler 	return 0;
64939beb93cSSam Leffler }
65039beb93cSSam Leffler 
65139beb93cSSam Leffler 
652e28a4053SRui Paulo static void eloop_remove_timeout(struct eloop_timeout *timeout)
653e28a4053SRui Paulo {
654e28a4053SRui Paulo 	dl_list_del(&timeout->list);
655e28a4053SRui Paulo 	wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
656e28a4053SRui Paulo 	wpa_trace_remove_ref(timeout, user, timeout->user_data);
657e28a4053SRui Paulo 	os_free(timeout);
65839beb93cSSam Leffler }
65939beb93cSSam Leffler 
66039beb93cSSam Leffler 
66139beb93cSSam Leffler int eloop_cancel_timeout(eloop_timeout_handler handler,
66239beb93cSSam Leffler 			 void *eloop_data, void *user_data)
66339beb93cSSam Leffler {
664e28a4053SRui Paulo 	struct eloop_timeout *timeout, *prev;
66539beb93cSSam Leffler 	int removed = 0;
66639beb93cSSam Leffler 
667e28a4053SRui Paulo 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
668e28a4053SRui Paulo 			      struct eloop_timeout, list) {
66939beb93cSSam Leffler 		if (timeout->handler == handler &&
67039beb93cSSam Leffler 		    (timeout->eloop_data == eloop_data ||
67139beb93cSSam Leffler 		     eloop_data == ELOOP_ALL_CTX) &&
67239beb93cSSam Leffler 		    (timeout->user_data == user_data ||
67339beb93cSSam Leffler 		     user_data == ELOOP_ALL_CTX)) {
674e28a4053SRui Paulo 			eloop_remove_timeout(timeout);
67539beb93cSSam Leffler 			removed++;
676e28a4053SRui Paulo 		}
67739beb93cSSam Leffler 	}
67839beb93cSSam Leffler 
67939beb93cSSam Leffler 	return removed;
68039beb93cSSam Leffler }
68139beb93cSSam Leffler 
68239beb93cSSam Leffler 
6835b9c547cSRui Paulo int eloop_cancel_timeout_one(eloop_timeout_handler handler,
6845b9c547cSRui Paulo 			     void *eloop_data, void *user_data,
6855b9c547cSRui Paulo 			     struct os_reltime *remaining)
6865b9c547cSRui Paulo {
6875b9c547cSRui Paulo 	struct eloop_timeout *timeout, *prev;
6885b9c547cSRui Paulo 	int removed = 0;
6895b9c547cSRui Paulo 	struct os_reltime now;
6905b9c547cSRui Paulo 
6915b9c547cSRui Paulo 	os_get_reltime(&now);
6925b9c547cSRui Paulo 	remaining->sec = remaining->usec = 0;
6935b9c547cSRui Paulo 
6945b9c547cSRui Paulo 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
6955b9c547cSRui Paulo 			      struct eloop_timeout, list) {
6965b9c547cSRui Paulo 		if (timeout->handler == handler &&
6975b9c547cSRui Paulo 		    (timeout->eloop_data == eloop_data) &&
6985b9c547cSRui Paulo 		    (timeout->user_data == user_data)) {
6995b9c547cSRui Paulo 			removed = 1;
7005b9c547cSRui Paulo 			if (os_reltime_before(&now, &timeout->time))
7015b9c547cSRui Paulo 				os_reltime_sub(&timeout->time, &now, remaining);
7025b9c547cSRui Paulo 			eloop_remove_timeout(timeout);
7035b9c547cSRui Paulo 			break;
7045b9c547cSRui Paulo 		}
7055b9c547cSRui Paulo 	}
7065b9c547cSRui Paulo 	return removed;
7075b9c547cSRui Paulo }
7085b9c547cSRui Paulo 
7095b9c547cSRui Paulo 
71039beb93cSSam Leffler int eloop_is_timeout_registered(eloop_timeout_handler handler,
71139beb93cSSam Leffler 				void *eloop_data, void *user_data)
71239beb93cSSam Leffler {
71339beb93cSSam Leffler 	struct eloop_timeout *tmp;
71439beb93cSSam Leffler 
715e28a4053SRui Paulo 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
71639beb93cSSam Leffler 		if (tmp->handler == handler &&
71739beb93cSSam Leffler 		    tmp->eloop_data == eloop_data &&
71839beb93cSSam Leffler 		    tmp->user_data == user_data)
71939beb93cSSam Leffler 			return 1;
72039beb93cSSam Leffler 	}
72139beb93cSSam Leffler 
72239beb93cSSam Leffler 	return 0;
72339beb93cSSam Leffler }
72439beb93cSSam Leffler 
72539beb93cSSam Leffler 
7265b9c547cSRui Paulo int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
7275b9c547cSRui Paulo 			  eloop_timeout_handler handler, void *eloop_data,
7285b9c547cSRui Paulo 			  void *user_data)
7295b9c547cSRui Paulo {
7305b9c547cSRui Paulo 	struct os_reltime now, requested, remaining;
7315b9c547cSRui Paulo 	struct eloop_timeout *tmp;
7325b9c547cSRui Paulo 
7335b9c547cSRui Paulo 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
7345b9c547cSRui Paulo 		if (tmp->handler == handler &&
7355b9c547cSRui Paulo 		    tmp->eloop_data == eloop_data &&
7365b9c547cSRui Paulo 		    tmp->user_data == user_data) {
7375b9c547cSRui Paulo 			requested.sec = req_secs;
7385b9c547cSRui Paulo 			requested.usec = req_usecs;
7395b9c547cSRui Paulo 			os_get_reltime(&now);
7405b9c547cSRui Paulo 			os_reltime_sub(&tmp->time, &now, &remaining);
7415b9c547cSRui Paulo 			if (os_reltime_before(&requested, &remaining)) {
7425b9c547cSRui Paulo 				eloop_cancel_timeout(handler, eloop_data,
7435b9c547cSRui Paulo 						     user_data);
7445b9c547cSRui Paulo 				eloop_register_timeout(requested.sec,
7455b9c547cSRui Paulo 						       requested.usec,
7465b9c547cSRui Paulo 						       handler, eloop_data,
7475b9c547cSRui Paulo 						       user_data);
7485b9c547cSRui Paulo 				return 1;
7495b9c547cSRui Paulo 			}
7505b9c547cSRui Paulo 			return 0;
7515b9c547cSRui Paulo 		}
7525b9c547cSRui Paulo 	}
7535b9c547cSRui Paulo 
7545b9c547cSRui Paulo 	return -1;
7555b9c547cSRui Paulo }
7565b9c547cSRui Paulo 
7575b9c547cSRui Paulo 
7585b9c547cSRui Paulo int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
7595b9c547cSRui Paulo 			    eloop_timeout_handler handler, void *eloop_data,
7605b9c547cSRui Paulo 			    void *user_data)
7615b9c547cSRui Paulo {
7625b9c547cSRui Paulo 	struct os_reltime now, requested, remaining;
7635b9c547cSRui Paulo 	struct eloop_timeout *tmp;
7645b9c547cSRui Paulo 
7655b9c547cSRui Paulo 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
7665b9c547cSRui Paulo 		if (tmp->handler == handler &&
7675b9c547cSRui Paulo 		    tmp->eloop_data == eloop_data &&
7685b9c547cSRui Paulo 		    tmp->user_data == user_data) {
7695b9c547cSRui Paulo 			requested.sec = req_secs;
7705b9c547cSRui Paulo 			requested.usec = req_usecs;
7715b9c547cSRui Paulo 			os_get_reltime(&now);
7725b9c547cSRui Paulo 			os_reltime_sub(&tmp->time, &now, &remaining);
7735b9c547cSRui Paulo 			if (os_reltime_before(&remaining, &requested)) {
7745b9c547cSRui Paulo 				eloop_cancel_timeout(handler, eloop_data,
7755b9c547cSRui Paulo 						     user_data);
7765b9c547cSRui Paulo 				eloop_register_timeout(requested.sec,
7775b9c547cSRui Paulo 						       requested.usec,
7785b9c547cSRui Paulo 						       handler, eloop_data,
7795b9c547cSRui Paulo 						       user_data);
7805b9c547cSRui Paulo 				return 1;
7815b9c547cSRui Paulo 			}
7825b9c547cSRui Paulo 			return 0;
7835b9c547cSRui Paulo 		}
7845b9c547cSRui Paulo 	}
7855b9c547cSRui Paulo 
7865b9c547cSRui Paulo 	return -1;
7875b9c547cSRui Paulo }
7885b9c547cSRui Paulo 
7895b9c547cSRui Paulo 
79039beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
79139beb93cSSam Leffler static void eloop_handle_alarm(int sig)
79239beb93cSSam Leffler {
793e28a4053SRui Paulo 	wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
794e28a4053SRui Paulo 		   "two seconds. Looks like there\n"
79539beb93cSSam Leffler 		   "is a bug that ends up in a busy loop that "
79639beb93cSSam Leffler 		   "prevents clean shutdown.\n"
79739beb93cSSam Leffler 		   "Killing program forcefully.\n");
79839beb93cSSam Leffler 	exit(1);
79939beb93cSSam Leffler }
80039beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
80139beb93cSSam Leffler 
80239beb93cSSam Leffler 
80339beb93cSSam Leffler static void eloop_handle_signal(int sig)
80439beb93cSSam Leffler {
80539beb93cSSam Leffler 	int i;
80639beb93cSSam Leffler 
80739beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
80839beb93cSSam Leffler 	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
80939beb93cSSam Leffler 		/* Use SIGALRM to break out from potential busy loops that
81039beb93cSSam Leffler 		 * would not allow the program to be killed. */
81139beb93cSSam Leffler 		eloop.pending_terminate = 1;
81239beb93cSSam Leffler 		signal(SIGALRM, eloop_handle_alarm);
81339beb93cSSam Leffler 		alarm(2);
81439beb93cSSam Leffler 	}
81539beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
81639beb93cSSam Leffler 
81739beb93cSSam Leffler 	eloop.signaled++;
81839beb93cSSam Leffler 	for (i = 0; i < eloop.signal_count; i++) {
81939beb93cSSam Leffler 		if (eloop.signals[i].sig == sig) {
82039beb93cSSam Leffler 			eloop.signals[i].signaled++;
82139beb93cSSam Leffler 			break;
82239beb93cSSam Leffler 		}
82339beb93cSSam Leffler 	}
82439beb93cSSam Leffler }
82539beb93cSSam Leffler 
82639beb93cSSam Leffler 
82739beb93cSSam Leffler static void eloop_process_pending_signals(void)
82839beb93cSSam Leffler {
82939beb93cSSam Leffler 	int i;
83039beb93cSSam Leffler 
83139beb93cSSam Leffler 	if (eloop.signaled == 0)
83239beb93cSSam Leffler 		return;
83339beb93cSSam Leffler 	eloop.signaled = 0;
83439beb93cSSam Leffler 
83539beb93cSSam Leffler 	if (eloop.pending_terminate) {
83639beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
83739beb93cSSam Leffler 		alarm(0);
83839beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
83939beb93cSSam Leffler 		eloop.pending_terminate = 0;
84039beb93cSSam Leffler 	}
84139beb93cSSam Leffler 
84239beb93cSSam Leffler 	for (i = 0; i < eloop.signal_count; i++) {
84339beb93cSSam Leffler 		if (eloop.signals[i].signaled) {
84439beb93cSSam Leffler 			eloop.signals[i].signaled = 0;
84539beb93cSSam Leffler 			eloop.signals[i].handler(eloop.signals[i].sig,
84639beb93cSSam Leffler 						 eloop.signals[i].user_data);
84739beb93cSSam Leffler 		}
84839beb93cSSam Leffler 	}
84939beb93cSSam Leffler }
85039beb93cSSam Leffler 
85139beb93cSSam Leffler 
85239beb93cSSam Leffler int eloop_register_signal(int sig, eloop_signal_handler handler,
85339beb93cSSam Leffler 			  void *user_data)
85439beb93cSSam Leffler {
85539beb93cSSam Leffler 	struct eloop_signal *tmp;
85639beb93cSSam Leffler 
857f05cddf9SRui Paulo 	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
85839beb93cSSam Leffler 			       sizeof(struct eloop_signal));
85939beb93cSSam Leffler 	if (tmp == NULL)
86039beb93cSSam Leffler 		return -1;
86139beb93cSSam Leffler 
86239beb93cSSam Leffler 	tmp[eloop.signal_count].sig = sig;
86339beb93cSSam Leffler 	tmp[eloop.signal_count].user_data = user_data;
86439beb93cSSam Leffler 	tmp[eloop.signal_count].handler = handler;
86539beb93cSSam Leffler 	tmp[eloop.signal_count].signaled = 0;
86639beb93cSSam Leffler 	eloop.signal_count++;
86739beb93cSSam Leffler 	eloop.signals = tmp;
86839beb93cSSam Leffler 	signal(sig, eloop_handle_signal);
86939beb93cSSam Leffler 
87039beb93cSSam Leffler 	return 0;
87139beb93cSSam Leffler }
87239beb93cSSam Leffler 
87339beb93cSSam Leffler 
87439beb93cSSam Leffler int eloop_register_signal_terminate(eloop_signal_handler handler,
87539beb93cSSam Leffler 				    void *user_data)
87639beb93cSSam Leffler {
87739beb93cSSam Leffler 	int ret = eloop_register_signal(SIGINT, handler, user_data);
87839beb93cSSam Leffler 	if (ret == 0)
87939beb93cSSam Leffler 		ret = eloop_register_signal(SIGTERM, handler, user_data);
88039beb93cSSam Leffler 	return ret;
88139beb93cSSam Leffler }
88239beb93cSSam Leffler 
88339beb93cSSam Leffler 
88439beb93cSSam Leffler int eloop_register_signal_reconfig(eloop_signal_handler handler,
88539beb93cSSam Leffler 				   void *user_data)
88639beb93cSSam Leffler {
88739beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
88839beb93cSSam Leffler 	return 0;
88939beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */
89039beb93cSSam Leffler 	return eloop_register_signal(SIGHUP, handler, user_data);
89139beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
89239beb93cSSam Leffler }
89339beb93cSSam Leffler 
89439beb93cSSam Leffler 
89539beb93cSSam Leffler void eloop_run(void)
89639beb93cSSam Leffler {
897f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
898f05cddf9SRui Paulo 	int num_poll_fds;
899f05cddf9SRui Paulo 	int timeout_ms = 0;
9005b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */
9015b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
90239beb93cSSam Leffler 	fd_set *rfds, *wfds, *efds;
90339beb93cSSam Leffler 	struct timeval _tv;
9045b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
9055b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
9065b9c547cSRui Paulo 	int timeout_ms = -1;
9075b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
908f05cddf9SRui Paulo 	int res;
9095b9c547cSRui Paulo 	struct os_reltime tv, now;
91039beb93cSSam Leffler 
9115b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
91239beb93cSSam Leffler 	rfds = os_malloc(sizeof(*rfds));
91339beb93cSSam Leffler 	wfds = os_malloc(sizeof(*wfds));
91439beb93cSSam Leffler 	efds = os_malloc(sizeof(*efds));
915e28a4053SRui Paulo 	if (rfds == NULL || wfds == NULL || efds == NULL)
91639beb93cSSam Leffler 		goto out;
9175b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
91839beb93cSSam Leffler 
91939beb93cSSam Leffler 	while (!eloop.terminate &&
920e28a4053SRui Paulo 	       (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
92139beb93cSSam Leffler 		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
922e28a4053SRui Paulo 		struct eloop_timeout *timeout;
923*325151a3SRui Paulo 
924*325151a3SRui Paulo 		if (eloop.pending_terminate) {
925*325151a3SRui Paulo 			/*
926*325151a3SRui Paulo 			 * This may happen in some corner cases where a signal
927*325151a3SRui Paulo 			 * is received during a blocking operation. We need to
928*325151a3SRui Paulo 			 * process the pending signals and exit if requested to
929*325151a3SRui Paulo 			 * avoid hitting the SIGALRM limit if the blocking
930*325151a3SRui Paulo 			 * operation took more than two seconds.
931*325151a3SRui Paulo 			 */
932*325151a3SRui Paulo 			eloop_process_pending_signals();
933*325151a3SRui Paulo 			if (eloop.terminate)
934*325151a3SRui Paulo 				break;
935*325151a3SRui Paulo 		}
936*325151a3SRui Paulo 
937e28a4053SRui Paulo 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
938e28a4053SRui Paulo 					list);
939e28a4053SRui Paulo 		if (timeout) {
9405b9c547cSRui Paulo 			os_get_reltime(&now);
9415b9c547cSRui Paulo 			if (os_reltime_before(&now, &timeout->time))
9425b9c547cSRui Paulo 				os_reltime_sub(&timeout->time, &now, &tv);
94339beb93cSSam Leffler 			else
94439beb93cSSam Leffler 				tv.sec = tv.usec = 0;
9455b9c547cSRui Paulo #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
946f05cddf9SRui Paulo 			timeout_ms = tv.sec * 1000 + tv.usec / 1000;
9475b9c547cSRui Paulo #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
9485b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
94939beb93cSSam Leffler 			_tv.tv_sec = tv.sec;
95039beb93cSSam Leffler 			_tv.tv_usec = tv.usec;
9515b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
95239beb93cSSam Leffler 		}
95339beb93cSSam Leffler 
954f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
955f05cddf9SRui Paulo 		num_poll_fds = eloop_sock_table_set_fds(
956f05cddf9SRui Paulo 			&eloop.readers, &eloop.writers, &eloop.exceptions,
957f05cddf9SRui Paulo 			eloop.pollfds, eloop.pollfds_map,
958f05cddf9SRui Paulo 			eloop.max_pollfd_map);
959f05cddf9SRui Paulo 		res = poll(eloop.pollfds, num_poll_fds,
960f05cddf9SRui Paulo 			   timeout ? timeout_ms : -1);
9615b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */
9625b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
96339beb93cSSam Leffler 		eloop_sock_table_set_fds(&eloop.readers, rfds);
96439beb93cSSam Leffler 		eloop_sock_table_set_fds(&eloop.writers, wfds);
96539beb93cSSam Leffler 		eloop_sock_table_set_fds(&eloop.exceptions, efds);
96639beb93cSSam Leffler 		res = select(eloop.max_sock + 1, rfds, wfds, efds,
967e28a4053SRui Paulo 			     timeout ? &_tv : NULL);
9685b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
9695b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
9705b9c547cSRui Paulo 		if (eloop.count == 0) {
9715b9c547cSRui Paulo 			res = 0;
9725b9c547cSRui Paulo 		} else {
9735b9c547cSRui Paulo 			res = epoll_wait(eloop.epollfd, eloop.epoll_events,
9745b9c547cSRui Paulo 					 eloop.count, timeout_ms);
9755b9c547cSRui Paulo 		}
9765b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
97739beb93cSSam Leffler 		if (res < 0 && errno != EINTR && errno != 0) {
9785b9c547cSRui Paulo 			wpa_printf(MSG_ERROR, "eloop: %s: %s",
9795b9c547cSRui Paulo #ifdef CONFIG_ELOOP_POLL
9805b9c547cSRui Paulo 				   "poll"
9815b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */
9825b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
9835b9c547cSRui Paulo 				   "select"
9845b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
9855b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
9865b9c547cSRui Paulo 				   "epoll"
9875b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
9885b9c547cSRui Paulo 				   , strerror(errno));
98939beb93cSSam Leffler 			goto out;
99039beb93cSSam Leffler 		}
991*325151a3SRui Paulo 
992*325151a3SRui Paulo 		eloop.readers.changed = 0;
993*325151a3SRui Paulo 		eloop.writers.changed = 0;
994*325151a3SRui Paulo 		eloop.exceptions.changed = 0;
995*325151a3SRui Paulo 
99639beb93cSSam Leffler 		eloop_process_pending_signals();
99739beb93cSSam Leffler 
99839beb93cSSam Leffler 		/* check if some registered timeouts have occurred */
999e28a4053SRui Paulo 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
1000e28a4053SRui Paulo 					list);
1001e28a4053SRui Paulo 		if (timeout) {
10025b9c547cSRui Paulo 			os_get_reltime(&now);
10035b9c547cSRui Paulo 			if (!os_reltime_before(&now, &timeout->time)) {
1004e28a4053SRui Paulo 				void *eloop_data = timeout->eloop_data;
1005e28a4053SRui Paulo 				void *user_data = timeout->user_data;
1006e28a4053SRui Paulo 				eloop_timeout_handler handler =
1007e28a4053SRui Paulo 					timeout->handler;
1008e28a4053SRui Paulo 				eloop_remove_timeout(timeout);
1009e28a4053SRui Paulo 				handler(eloop_data, user_data);
101039beb93cSSam Leffler 			}
101139beb93cSSam Leffler 
101239beb93cSSam Leffler 		}
101339beb93cSSam Leffler 
101439beb93cSSam Leffler 		if (res <= 0)
101539beb93cSSam Leffler 			continue;
101639beb93cSSam Leffler 
1017*325151a3SRui Paulo 		if (eloop.readers.changed ||
1018*325151a3SRui Paulo 		    eloop.writers.changed ||
1019*325151a3SRui Paulo 		    eloop.exceptions.changed) {
1020*325151a3SRui Paulo 			 /*
1021*325151a3SRui Paulo 			  * Sockets may have been closed and reopened with the
1022*325151a3SRui Paulo 			  * same FD in the signal or timeout handlers, so we
1023*325151a3SRui Paulo 			  * must skip the previous results and check again
1024*325151a3SRui Paulo 			  * whether any of the currently registered sockets have
1025*325151a3SRui Paulo 			  * events.
1026*325151a3SRui Paulo 			  */
1027*325151a3SRui Paulo 			continue;
1028*325151a3SRui Paulo 		}
1029*325151a3SRui Paulo 
1030f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
1031f05cddf9SRui Paulo 		eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
1032f05cddf9SRui Paulo 					  &eloop.exceptions, eloop.pollfds_map,
1033f05cddf9SRui Paulo 					  eloop.max_pollfd_map);
10345b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */
10355b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
103639beb93cSSam Leffler 		eloop_sock_table_dispatch(&eloop.readers, rfds);
103739beb93cSSam Leffler 		eloop_sock_table_dispatch(&eloop.writers, wfds);
103839beb93cSSam Leffler 		eloop_sock_table_dispatch(&eloop.exceptions, efds);
10395b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
10405b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
10415b9c547cSRui Paulo 		eloop_sock_table_dispatch(eloop.epoll_events, res);
10425b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
104339beb93cSSam Leffler 	}
104439beb93cSSam Leffler 
10455b9c547cSRui Paulo 	eloop.terminate = 0;
104639beb93cSSam Leffler out:
10475b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
104839beb93cSSam Leffler 	os_free(rfds);
104939beb93cSSam Leffler 	os_free(wfds);
105039beb93cSSam Leffler 	os_free(efds);
10515b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
1052f05cddf9SRui Paulo 	return;
105339beb93cSSam Leffler }
105439beb93cSSam Leffler 
105539beb93cSSam Leffler 
105639beb93cSSam Leffler void eloop_terminate(void)
105739beb93cSSam Leffler {
105839beb93cSSam Leffler 	eloop.terminate = 1;
105939beb93cSSam Leffler }
106039beb93cSSam Leffler 
106139beb93cSSam Leffler 
106239beb93cSSam Leffler void eloop_destroy(void)
106339beb93cSSam Leffler {
106439beb93cSSam Leffler 	struct eloop_timeout *timeout, *prev;
10655b9c547cSRui Paulo 	struct os_reltime now;
106639beb93cSSam Leffler 
10675b9c547cSRui Paulo 	os_get_reltime(&now);
1068e28a4053SRui Paulo 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
1069e28a4053SRui Paulo 			      struct eloop_timeout, list) {
107039beb93cSSam Leffler 		int sec, usec;
1071e28a4053SRui Paulo 		sec = timeout->time.sec - now.sec;
1072e28a4053SRui Paulo 		usec = timeout->time.usec - now.usec;
1073e28a4053SRui Paulo 		if (timeout->time.usec < now.usec) {
107439beb93cSSam Leffler 			sec--;
107539beb93cSSam Leffler 			usec += 1000000;
107639beb93cSSam Leffler 		}
1077e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
1078e28a4053SRui Paulo 			   "eloop_data=%p user_data=%p handler=%p",
1079e28a4053SRui Paulo 			   sec, usec, timeout->eloop_data, timeout->user_data,
1080e28a4053SRui Paulo 			   timeout->handler);
1081e28a4053SRui Paulo 		wpa_trace_dump_funcname("eloop unregistered timeout handler",
1082e28a4053SRui Paulo 					timeout->handler);
1083e28a4053SRui Paulo 		wpa_trace_dump("eloop timeout", timeout);
1084e28a4053SRui Paulo 		eloop_remove_timeout(timeout);
108539beb93cSSam Leffler 	}
108639beb93cSSam Leffler 	eloop_sock_table_destroy(&eloop.readers);
108739beb93cSSam Leffler 	eloop_sock_table_destroy(&eloop.writers);
108839beb93cSSam Leffler 	eloop_sock_table_destroy(&eloop.exceptions);
108939beb93cSSam Leffler 	os_free(eloop.signals);
1090f05cddf9SRui Paulo 
1091f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
1092f05cddf9SRui Paulo 	os_free(eloop.pollfds);
1093f05cddf9SRui Paulo 	os_free(eloop.pollfds_map);
1094f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
10955b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
10965b9c547cSRui Paulo 	os_free(eloop.epoll_table);
10975b9c547cSRui Paulo 	os_free(eloop.epoll_events);
10985b9c547cSRui Paulo 	close(eloop.epollfd);
10995b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
110039beb93cSSam Leffler }
110139beb93cSSam Leffler 
110239beb93cSSam Leffler 
110339beb93cSSam Leffler int eloop_terminated(void)
110439beb93cSSam Leffler {
1105*325151a3SRui Paulo 	return eloop.terminate || eloop.pending_terminate;
110639beb93cSSam Leffler }
110739beb93cSSam Leffler 
110839beb93cSSam Leffler 
110939beb93cSSam Leffler void eloop_wait_for_read_sock(int sock)
111039beb93cSSam Leffler {
1111f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
1112f05cddf9SRui Paulo 	struct pollfd pfd;
1113f05cddf9SRui Paulo 
1114f05cddf9SRui Paulo 	if (sock < 0)
1115f05cddf9SRui Paulo 		return;
1116f05cddf9SRui Paulo 
1117f05cddf9SRui Paulo 	os_memset(&pfd, 0, sizeof(pfd));
1118f05cddf9SRui Paulo 	pfd.fd = sock;
1119f05cddf9SRui Paulo 	pfd.events = POLLIN;
1120f05cddf9SRui Paulo 
1121f05cddf9SRui Paulo 	poll(&pfd, 1, -1);
11225b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */
11235b9c547cSRui Paulo #if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL)
11245b9c547cSRui Paulo 	/*
11255b9c547cSRui Paulo 	 * We can use epoll() here. But epoll() requres 4 system calls.
11265b9c547cSRui Paulo 	 * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for
11275b9c547cSRui Paulo 	 * epoll fd. So select() is better for performance here.
11285b9c547cSRui Paulo 	 */
112939beb93cSSam Leffler 	fd_set rfds;
113039beb93cSSam Leffler 
113139beb93cSSam Leffler 	if (sock < 0)
113239beb93cSSam Leffler 		return;
113339beb93cSSam Leffler 
113439beb93cSSam Leffler 	FD_ZERO(&rfds);
113539beb93cSSam Leffler 	FD_SET(sock, &rfds);
113639beb93cSSam Leffler 	select(sock + 1, &rfds, NULL, NULL, NULL);
11375b9c547cSRui Paulo #endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */
113839beb93cSSam Leffler }
11395b9c547cSRui Paulo 
11405b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
11415b9c547cSRui Paulo #undef CONFIG_ELOOP_SELECT
11425b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
1143