xref: /netbsd-src/external/bsd/wpa/dist/src/utils/eloop.c (revision 45d3cc13f775755ee348416d64536fb30df46e06)
18dbcf02cSchristos /*
28dbcf02cSchristos  * Event loop based on select() loop
38dbcf02cSchristos  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
48dbcf02cSchristos  *
5316ee512Schristos  * This software may be distributed under the terms of the BSD license.
6316ee512Schristos  * See README for more details.
78dbcf02cSchristos  */
88dbcf02cSchristos 
98dbcf02cSchristos #include "includes.h"
103c5783d3Schristos #include <assert.h>
118dbcf02cSchristos 
128dbcf02cSchristos #include "common.h"
138dbcf02cSchristos #include "trace.h"
148dbcf02cSchristos #include "list.h"
158dbcf02cSchristos #include "eloop.h"
168dbcf02cSchristos 
173c5783d3Schristos #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL)
183c5783d3Schristos #error Do not define both of poll and epoll
193c5783d3Schristos #endif
203c5783d3Schristos 
216da92e7fSroy #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_KQUEUE)
226da92e7fSroy #error Do not define both of poll and kqueue
236da92e7fSroy #endif
246da92e7fSroy 
256da92e7fSroy #if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) && \
266da92e7fSroy     !defined(CONFIG_ELOOP_KQUEUE)
273c5783d3Schristos #define CONFIG_ELOOP_SELECT
283c5783d3Schristos #endif
293c5783d3Schristos 
30316ee512Schristos #ifdef CONFIG_ELOOP_POLL
31316ee512Schristos #include <poll.h>
32316ee512Schristos #endif /* CONFIG_ELOOP_POLL */
33316ee512Schristos 
343c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL
353c5783d3Schristos #include <sys/epoll.h>
363c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */
378dbcf02cSchristos 
386da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
396da92e7fSroy #include <sys/event.h>
406da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */
416da92e7fSroy 
428dbcf02cSchristos struct eloop_sock {
438dbcf02cSchristos 	int sock;
448dbcf02cSchristos 	void *eloop_data;
458dbcf02cSchristos 	void *user_data;
468dbcf02cSchristos 	eloop_sock_handler handler;
47042b6b47Sroy 	WPA_TRACE_REF(eloop);
48042b6b47Sroy 	WPA_TRACE_REF(user);
498dbcf02cSchristos 	WPA_TRACE_INFO
508dbcf02cSchristos };
518dbcf02cSchristos 
528dbcf02cSchristos struct eloop_timeout {
538dbcf02cSchristos 	struct dl_list list;
543c5783d3Schristos 	struct os_reltime time;
558dbcf02cSchristos 	void *eloop_data;
568dbcf02cSchristos 	void *user_data;
578dbcf02cSchristos 	eloop_timeout_handler handler;
58042b6b47Sroy 	WPA_TRACE_REF(eloop);
59042b6b47Sroy 	WPA_TRACE_REF(user);
608dbcf02cSchristos 	WPA_TRACE_INFO
618dbcf02cSchristos };
628dbcf02cSchristos 
638dbcf02cSchristos struct eloop_signal {
648dbcf02cSchristos 	int sig;
658dbcf02cSchristos 	void *user_data;
668dbcf02cSchristos 	eloop_signal_handler handler;
678dbcf02cSchristos 	int signaled;
688dbcf02cSchristos };
698dbcf02cSchristos 
708dbcf02cSchristos struct eloop_sock_table {
71*45d3cc13Schristos 	size_t count;
728dbcf02cSchristos 	struct eloop_sock *table;
733c5783d3Schristos 	eloop_event_type type;
748dbcf02cSchristos 	int changed;
758dbcf02cSchristos };
768dbcf02cSchristos 
778dbcf02cSchristos struct eloop_data {
788dbcf02cSchristos 	int max_sock;
798dbcf02cSchristos 
80*45d3cc13Schristos 	size_t count; /* sum of all table counts */
81316ee512Schristos #ifdef CONFIG_ELOOP_POLL
82*45d3cc13Schristos 	size_t max_pollfd_map; /* number of pollfds_map currently allocated */
83*45d3cc13Schristos 	size_t max_poll_fds; /* number of pollfds currently allocated */
84316ee512Schristos 	struct pollfd *pollfds;
85316ee512Schristos 	struct pollfd **pollfds_map;
86316ee512Schristos #endif /* CONFIG_ELOOP_POLL */
876da92e7fSroy #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
886da92e7fSroy 	int max_fd;
896da92e7fSroy 	struct eloop_sock *fd_table;
90ecc36642Schristos #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
913c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL
923c5783d3Schristos 	int epollfd;
93*45d3cc13Schristos 	size_t epoll_max_event_num;
943c5783d3Schristos 	struct epoll_event *epoll_events;
953c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */
966da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
976da92e7fSroy 	int kqueuefd;
98*45d3cc13Schristos 	size_t kqueue_nevents;
996da92e7fSroy 	struct kevent *kqueue_events;
1006da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */
1018dbcf02cSchristos 	struct eloop_sock_table readers;
1028dbcf02cSchristos 	struct eloop_sock_table writers;
1038dbcf02cSchristos 	struct eloop_sock_table exceptions;
1048dbcf02cSchristos 
1058dbcf02cSchristos 	struct dl_list timeout;
1068dbcf02cSchristos 
107*45d3cc13Schristos 	size_t signal_count;
1088dbcf02cSchristos 	struct eloop_signal *signals;
1098dbcf02cSchristos 	int signaled;
1108dbcf02cSchristos 	int pending_terminate;
1118dbcf02cSchristos 
1128dbcf02cSchristos 	int terminate;
1138dbcf02cSchristos };
1148dbcf02cSchristos 
1158dbcf02cSchristos static struct eloop_data eloop;
1168dbcf02cSchristos 
1178dbcf02cSchristos 
1188dbcf02cSchristos #ifdef WPA_TRACE
1198dbcf02cSchristos 
1208dbcf02cSchristos static void eloop_sigsegv_handler(int sig)
1218dbcf02cSchristos {
1228dbcf02cSchristos 	wpa_trace_show("eloop SIGSEGV");
1238dbcf02cSchristos 	abort();
1248dbcf02cSchristos }
1258dbcf02cSchristos 
1268dbcf02cSchristos static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
1278dbcf02cSchristos {
128*45d3cc13Schristos 	size_t i;
129*45d3cc13Schristos 
1308dbcf02cSchristos 	if (table == NULL || table->table == NULL)
1318dbcf02cSchristos 		return;
1328dbcf02cSchristos 	for (i = 0; i < table->count; i++) {
1338dbcf02cSchristos 		wpa_trace_add_ref(&table->table[i], eloop,
1348dbcf02cSchristos 				  table->table[i].eloop_data);
1358dbcf02cSchristos 		wpa_trace_add_ref(&table->table[i], user,
1368dbcf02cSchristos 				  table->table[i].user_data);
1378dbcf02cSchristos 	}
1388dbcf02cSchristos }
1398dbcf02cSchristos 
1408dbcf02cSchristos 
1418dbcf02cSchristos static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
1428dbcf02cSchristos {
143*45d3cc13Schristos 	size_t i;
144*45d3cc13Schristos 
1458dbcf02cSchristos 	if (table == NULL || table->table == NULL)
1468dbcf02cSchristos 		return;
1478dbcf02cSchristos 	for (i = 0; i < table->count; i++) {
1488dbcf02cSchristos 		wpa_trace_remove_ref(&table->table[i], eloop,
1498dbcf02cSchristos 				     table->table[i].eloop_data);
1508dbcf02cSchristos 		wpa_trace_remove_ref(&table->table[i], user,
1518dbcf02cSchristos 				     table->table[i].user_data);
1528dbcf02cSchristos 	}
1538dbcf02cSchristos }
1548dbcf02cSchristos 
1558dbcf02cSchristos #else /* WPA_TRACE */
1568dbcf02cSchristos 
1578dbcf02cSchristos #define eloop_trace_sock_add_ref(table) do { } while (0)
1588dbcf02cSchristos #define eloop_trace_sock_remove_ref(table) do { } while (0)
1598dbcf02cSchristos 
1608dbcf02cSchristos #endif /* WPA_TRACE */
1618dbcf02cSchristos 
1628dbcf02cSchristos 
1638dbcf02cSchristos int eloop_init(void)
1648dbcf02cSchristos {
1658dbcf02cSchristos 	os_memset(&eloop, 0, sizeof(eloop));
1668dbcf02cSchristos 	dl_list_init(&eloop.timeout);
1673c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL
1683c5783d3Schristos 	eloop.epollfd = epoll_create1(0);
1693c5783d3Schristos 	if (eloop.epollfd < 0) {
170ecc36642Schristos 		wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s",
1713c5783d3Schristos 			   __func__, strerror(errno));
1723c5783d3Schristos 		return -1;
1733c5783d3Schristos 	}
1743c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */
1756da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
1766da92e7fSroy 	eloop.kqueuefd = kqueue();
1776da92e7fSroy 	if (eloop.kqueuefd < 0) {
178ecc36642Schristos 		wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
1796da92e7fSroy 			   __func__, strerror(errno));
1806da92e7fSroy 		return -1;
1816da92e7fSroy 	}
1826da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */
183d2b81c07Sroy #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
184d2b81c07Sroy 	eloop.readers.type = EVENT_TYPE_READ;
185d2b81c07Sroy 	eloop.writers.type = EVENT_TYPE_WRITE;
186d2b81c07Sroy 	eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
187ecc36642Schristos #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
1888dbcf02cSchristos #ifdef WPA_TRACE
1898dbcf02cSchristos 	signal(SIGSEGV, eloop_sigsegv_handler);
1908dbcf02cSchristos #endif /* WPA_TRACE */
1918dbcf02cSchristos 	return 0;
1928dbcf02cSchristos }
1938dbcf02cSchristos 
194ecc36642Schristos 
195d2b81c07Sroy #ifdef CONFIG_ELOOP_EPOLL
196d2b81c07Sroy static int eloop_sock_queue(int sock, eloop_event_type type)
197d2b81c07Sroy {
198d2b81c07Sroy 	struct epoll_event ev;
199d2b81c07Sroy 
200d2b81c07Sroy 	os_memset(&ev, 0, sizeof(ev));
201d2b81c07Sroy 	switch (type) {
202d2b81c07Sroy 	case EVENT_TYPE_READ:
203d2b81c07Sroy 		ev.events = EPOLLIN;
204d2b81c07Sroy 		break;
205d2b81c07Sroy 	case EVENT_TYPE_WRITE:
206d2b81c07Sroy 		ev.events = EPOLLOUT;
207d2b81c07Sroy 		break;
208d2b81c07Sroy 	/*
209d2b81c07Sroy 	 * Exceptions are always checked when using epoll, but I suppose it's
210d2b81c07Sroy 	 * possible that someone registered a socket *only* for exception
211d2b81c07Sroy 	 * handling.
212d2b81c07Sroy 	 */
213d2b81c07Sroy 	case EVENT_TYPE_EXCEPTION:
214d2b81c07Sroy 		ev.events = EPOLLERR | EPOLLHUP;
215d2b81c07Sroy 		break;
216d2b81c07Sroy 	}
217d2b81c07Sroy 	ev.data.fd = sock;
218d2b81c07Sroy 	if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
219ecc36642Schristos 		wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d failed: %s",
220ecc36642Schristos 			   __func__, sock, strerror(errno));
221d2b81c07Sroy 		return -1;
222d2b81c07Sroy 	}
223d2b81c07Sroy 	return 0;
224d2b81c07Sroy }
225d2b81c07Sroy #endif /* CONFIG_ELOOP_EPOLL */
226d2b81c07Sroy 
227ecc36642Schristos 
228d2b81c07Sroy #ifdef CONFIG_ELOOP_KQUEUE
229d2b81c07Sroy 
230460bb4fcSchristos static short event_type_kevent_filter(eloop_event_type type)
231460bb4fcSchristos {
232d2b81c07Sroy 	switch (type) {
233d2b81c07Sroy 	case EVENT_TYPE_READ:
234460bb4fcSchristos 		return EVFILT_READ;
235d2b81c07Sroy 	case EVENT_TYPE_WRITE:
236460bb4fcSchristos 		return EVFILT_WRITE;
237d2b81c07Sroy 	default:
238460bb4fcSchristos 		return 0;
239d2b81c07Sroy 	}
240460bb4fcSchristos }
241460bb4fcSchristos 
242460bb4fcSchristos 
243460bb4fcSchristos static int eloop_sock_queue(int sock, eloop_event_type type)
244460bb4fcSchristos {
245460bb4fcSchristos 	struct kevent ke;
246460bb4fcSchristos 
247460bb4fcSchristos 	EV_SET(&ke, sock, event_type_kevent_filter(type), EV_ADD, 0, 0, 0);
248d2b81c07Sroy 	if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) {
249ecc36642Schristos 		wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s",
250ecc36642Schristos 			   __func__, sock, strerror(errno));
251d2b81c07Sroy 		return -1;
252d2b81c07Sroy 	}
253d2b81c07Sroy 	return 0;
254d2b81c07Sroy }
255460bb4fcSchristos 
256d2b81c07Sroy #endif /* CONFIG_ELOOP_KQUEUE */
2578dbcf02cSchristos 
258ecc36642Schristos 
2598dbcf02cSchristos static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
2608dbcf02cSchristos                                      int sock, eloop_sock_handler handler,
2618dbcf02cSchristos                                      void *eloop_data, void *user_data)
2628dbcf02cSchristos {
2633c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL
264d2b81c07Sroy 	struct epoll_event *temp_events;
2653c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */
266fbb8252eSroy #ifdef CONFIG_ELOOP_KQUEUE
267fbb8252eSroy 	struct kevent *temp_events;
268fbb8252eSroy #endif /* CONFIG_ELOOP_EPOLL */
269d2b81c07Sroy #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
2706da92e7fSroy 	struct eloop_sock *temp_table;
271*45d3cc13Schristos 	size_t next;
272ecc36642Schristos #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
2738dbcf02cSchristos 	struct eloop_sock *tmp;
274316ee512Schristos 	int new_max_sock;
275316ee512Schristos 
276316ee512Schristos 	if (sock > eloop.max_sock)
277316ee512Schristos 		new_max_sock = sock;
278316ee512Schristos 	else
279316ee512Schristos 		new_max_sock = eloop.max_sock;
2808dbcf02cSchristos 
2818dbcf02cSchristos 	if (table == NULL)
2828dbcf02cSchristos 		return -1;
2838dbcf02cSchristos 
284316ee512Schristos #ifdef CONFIG_ELOOP_POLL
285*45d3cc13Schristos 	if ((size_t) new_max_sock >= eloop.max_pollfd_map) {
286316ee512Schristos 		struct pollfd **nmap;
287316ee512Schristos 		nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
288316ee512Schristos 					sizeof(struct pollfd *));
289316ee512Schristos 		if (nmap == NULL)
290316ee512Schristos 			return -1;
291316ee512Schristos 
292316ee512Schristos 		eloop.max_pollfd_map = new_max_sock + 50;
293316ee512Schristos 		eloop.pollfds_map = nmap;
294316ee512Schristos 	}
295316ee512Schristos 
296316ee512Schristos 	if (eloop.count + 1 > eloop.max_poll_fds) {
297316ee512Schristos 		struct pollfd *n;
298*45d3cc13Schristos 		size_t nmax = eloop.count + 1 + 50;
299*45d3cc13Schristos 
300316ee512Schristos 		n = os_realloc_array(eloop.pollfds, nmax,
301316ee512Schristos 				     sizeof(struct pollfd));
302316ee512Schristos 		if (n == NULL)
303316ee512Schristos 			return -1;
304316ee512Schristos 
305316ee512Schristos 		eloop.max_poll_fds = nmax;
306316ee512Schristos 		eloop.pollfds = n;
307316ee512Schristos 	}
308316ee512Schristos #endif /* CONFIG_ELOOP_POLL */
3096da92e7fSroy #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
3106da92e7fSroy 	if (new_max_sock >= eloop.max_fd) {
311460bb4fcSchristos 		next = new_max_sock + 16;
3126da92e7fSroy 		temp_table = os_realloc_array(eloop.fd_table, next,
3133c5783d3Schristos 					      sizeof(struct eloop_sock));
3143c5783d3Schristos 		if (temp_table == NULL)
3153c5783d3Schristos 			return -1;
3163c5783d3Schristos 
3176da92e7fSroy 		eloop.max_fd = next;
3186da92e7fSroy 		eloop.fd_table = temp_table;
3193c5783d3Schristos 	}
320ecc36642Schristos #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
3213c5783d3Schristos 
3226da92e7fSroy #ifdef CONFIG_ELOOP_EPOLL
3233c5783d3Schristos 	if (eloop.count + 1 > eloop.epoll_max_event_num) {
3243c5783d3Schristos 		next = eloop.epoll_max_event_num == 0 ? 8 :
3253c5783d3Schristos 			eloop.epoll_max_event_num * 2;
3263c5783d3Schristos 		temp_events = os_realloc_array(eloop.epoll_events, next,
3273c5783d3Schristos 					       sizeof(struct epoll_event));
3283c5783d3Schristos 		if (temp_events == NULL) {
329ecc36642Schristos 			wpa_printf(MSG_ERROR, "%s: malloc for epoll failed: %s",
330ecc36642Schristos 				   __func__, strerror(errno));
3313c5783d3Schristos 			return -1;
3323c5783d3Schristos 		}
3333c5783d3Schristos 
3343c5783d3Schristos 		eloop.epoll_max_event_num = next;
3353c5783d3Schristos 		eloop.epoll_events = temp_events;
3363c5783d3Schristos 	}
3373c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */
3386da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
3396da92e7fSroy 	if (eloop.count + 1 > eloop.kqueue_nevents) {
3406da92e7fSroy 		next = eloop.kqueue_nevents == 0 ? 8 : eloop.kqueue_nevents * 2;
341fbb8252eSroy 		temp_events = os_malloc(next * sizeof(*temp_events));
342ecc36642Schristos 		if (!temp_events) {
343ecc36642Schristos 			wpa_printf(MSG_ERROR,
344ecc36642Schristos 				   "%s: malloc for kqueue failed: %s",
345ecc36642Schristos 				   __func__, strerror(errno));
3466da92e7fSroy 			return -1;
3476da92e7fSroy 		}
3486da92e7fSroy 
349fbb8252eSroy 		os_free(eloop.kqueue_events);
350fbb8252eSroy 		eloop.kqueue_events = temp_events;
3516da92e7fSroy 		eloop.kqueue_nevents = next;
3526da92e7fSroy 	}
3536da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */
354316ee512Schristos 
3558dbcf02cSchristos 	eloop_trace_sock_remove_ref(table);
356316ee512Schristos 	tmp = os_realloc_array(table->table, table->count + 1,
357316ee512Schristos 			       sizeof(struct eloop_sock));
358299bbf24Schristos 	if (tmp == NULL) {
359299bbf24Schristos 		eloop_trace_sock_add_ref(table);
3608dbcf02cSchristos 		return -1;
361299bbf24Schristos 	}
3628dbcf02cSchristos 
3638dbcf02cSchristos 	tmp[table->count].sock = sock;
3648dbcf02cSchristos 	tmp[table->count].eloop_data = eloop_data;
3658dbcf02cSchristos 	tmp[table->count].user_data = user_data;
3668dbcf02cSchristos 	tmp[table->count].handler = handler;
3678dbcf02cSchristos 	wpa_trace_record(&tmp[table->count]);
3688dbcf02cSchristos 	table->count++;
3698dbcf02cSchristos 	table->table = tmp;
370316ee512Schristos 	eloop.max_sock = new_max_sock;
371316ee512Schristos 	eloop.count++;
3728dbcf02cSchristos 	table->changed = 1;
3738dbcf02cSchristos 	eloop_trace_sock_add_ref(table);
3748dbcf02cSchristos 
375d2b81c07Sroy #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
376ecc36642Schristos 	if (eloop_sock_queue(sock, table->type) < 0)
3773c5783d3Schristos 		return -1;
3786da92e7fSroy 	os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1],
3793c5783d3Schristos 		  sizeof(struct eloop_sock));
380ecc36642Schristos #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
3818dbcf02cSchristos 	return 0;
3828dbcf02cSchristos }
3838dbcf02cSchristos 
3848dbcf02cSchristos 
3858dbcf02cSchristos static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
3868dbcf02cSchristos                                          int sock)
3878dbcf02cSchristos {
3886da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
3896da92e7fSroy 	struct kevent ke;
390ecc36642Schristos #endif /* CONFIG_ELOOP_KQUEUE */
391*45d3cc13Schristos 	size_t i;
3928dbcf02cSchristos 
3938dbcf02cSchristos 	if (table == NULL || table->table == NULL || table->count == 0)
3948dbcf02cSchristos 		return;
3958dbcf02cSchristos 
3968dbcf02cSchristos 	for (i = 0; i < table->count; i++) {
3978dbcf02cSchristos 		if (table->table[i].sock == sock)
3988dbcf02cSchristos 			break;
3998dbcf02cSchristos 	}
4008dbcf02cSchristos 	if (i == table->count)
4018dbcf02cSchristos 		return;
4028dbcf02cSchristos 	eloop_trace_sock_remove_ref(table);
4038dbcf02cSchristos 	if (i != table->count - 1) {
4048dbcf02cSchristos 		os_memmove(&table->table[i], &table->table[i + 1],
4058dbcf02cSchristos 			   (table->count - i - 1) *
4068dbcf02cSchristos 			   sizeof(struct eloop_sock));
4078dbcf02cSchristos 	}
4088dbcf02cSchristos 	table->count--;
409316ee512Schristos 	eloop.count--;
4108dbcf02cSchristos 	table->changed = 1;
4118dbcf02cSchristos 	eloop_trace_sock_add_ref(table);
4123c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL
4133c5783d3Schristos 	if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
414ecc36642Schristos 		wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d failed: %s",
415ecc36642Schristos 			   __func__, sock, strerror(errno));
4163c5783d3Schristos 		return;
4173c5783d3Schristos 	}
4186da92e7fSroy 	os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
4193c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */
4206da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
421460bb4fcSchristos 	EV_SET(&ke, sock, event_type_kevent_filter(table->type), EV_DELETE, 0,
422460bb4fcSchristos 	       0, 0);
423ecc36642Schristos 	if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) {
424ecc36642Schristos 		wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s",
425ecc36642Schristos 			   __func__, sock, strerror(errno));
4266da92e7fSroy 		return;
4276da92e7fSroy 	}
4286da92e7fSroy 	os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
4296da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */
4308dbcf02cSchristos }
4318dbcf02cSchristos 
4328dbcf02cSchristos 
433316ee512Schristos #ifdef CONFIG_ELOOP_POLL
434316ee512Schristos 
435316ee512Schristos static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
436316ee512Schristos {
437316ee512Schristos 	if (fd < mx && fd >= 0)
438316ee512Schristos 		return pollfds_map[fd];
439316ee512Schristos 	return NULL;
440316ee512Schristos }
441316ee512Schristos 
442316ee512Schristos 
443316ee512Schristos static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
444316ee512Schristos 				    struct eloop_sock_table *writers,
445316ee512Schristos 				    struct eloop_sock_table *exceptions,
446316ee512Schristos 				    struct pollfd *pollfds,
447316ee512Schristos 				    struct pollfd **pollfds_map,
448316ee512Schristos 				    int max_pollfd_map)
449316ee512Schristos {
450*45d3cc13Schristos 	size_t i;
451316ee512Schristos 	int nxt = 0;
452316ee512Schristos 	int fd;
453316ee512Schristos 	struct pollfd *pfd;
454316ee512Schristos 
455316ee512Schristos 	/* Clear pollfd lookup map. It will be re-populated below. */
456316ee512Schristos 	os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
457316ee512Schristos 
458316ee512Schristos 	if (readers && readers->table) {
459316ee512Schristos 		for (i = 0; i < readers->count; i++) {
460316ee512Schristos 			fd = readers->table[i].sock;
461316ee512Schristos 			assert(fd >= 0 && fd < max_pollfd_map);
462316ee512Schristos 			pollfds[nxt].fd = fd;
463316ee512Schristos 			pollfds[nxt].events = POLLIN;
464316ee512Schristos 			pollfds[nxt].revents = 0;
465316ee512Schristos 			pollfds_map[fd] = &(pollfds[nxt]);
466316ee512Schristos 			nxt++;
467316ee512Schristos 		}
468316ee512Schristos 	}
469316ee512Schristos 
470316ee512Schristos 	if (writers && writers->table) {
471316ee512Schristos 		for (i = 0; i < writers->count; i++) {
472316ee512Schristos 			/*
473316ee512Schristos 			 * See if we already added this descriptor, update it
474316ee512Schristos 			 * if so.
475316ee512Schristos 			 */
476316ee512Schristos 			fd = writers->table[i].sock;
477316ee512Schristos 			assert(fd >= 0 && fd < max_pollfd_map);
478316ee512Schristos 			pfd = pollfds_map[fd];
479316ee512Schristos 			if (!pfd) {
480316ee512Schristos 				pfd = &(pollfds[nxt]);
481316ee512Schristos 				pfd->events = 0;
482316ee512Schristos 				pfd->fd = fd;
483316ee512Schristos 				pollfds[i].revents = 0;
484316ee512Schristos 				pollfds_map[fd] = pfd;
485316ee512Schristos 				nxt++;
486316ee512Schristos 			}
487316ee512Schristos 			pfd->events |= POLLOUT;
488316ee512Schristos 		}
489316ee512Schristos 	}
490316ee512Schristos 
491316ee512Schristos 	/*
492316ee512Schristos 	 * Exceptions are always checked when using poll, but I suppose it's
493316ee512Schristos 	 * possible that someone registered a socket *only* for exception
494316ee512Schristos 	 * handling. Set the POLLIN bit in this case.
495316ee512Schristos 	 */
496316ee512Schristos 	if (exceptions && exceptions->table) {
497316ee512Schristos 		for (i = 0; i < exceptions->count; i++) {
498316ee512Schristos 			/*
499316ee512Schristos 			 * See if we already added this descriptor, just use it
500316ee512Schristos 			 * if so.
501316ee512Schristos 			 */
502316ee512Schristos 			fd = exceptions->table[i].sock;
503316ee512Schristos 			assert(fd >= 0 && fd < max_pollfd_map);
504316ee512Schristos 			pfd = pollfds_map[fd];
505316ee512Schristos 			if (!pfd) {
506316ee512Schristos 				pfd = &(pollfds[nxt]);
507316ee512Schristos 				pfd->events = POLLIN;
508316ee512Schristos 				pfd->fd = fd;
509316ee512Schristos 				pollfds[i].revents = 0;
510316ee512Schristos 				pollfds_map[fd] = pfd;
511316ee512Schristos 				nxt++;
512316ee512Schristos 			}
513316ee512Schristos 		}
514316ee512Schristos 	}
515316ee512Schristos 
516316ee512Schristos 	return nxt;
517316ee512Schristos }
518316ee512Schristos 
519316ee512Schristos 
520316ee512Schristos static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
521316ee512Schristos 					   struct pollfd **pollfds_map,
522316ee512Schristos 					   int max_pollfd_map,
523316ee512Schristos 					   short int revents)
524316ee512Schristos {
525*45d3cc13Schristos 	size_t i;
526316ee512Schristos 	struct pollfd *pfd;
527316ee512Schristos 
528316ee512Schristos 	if (!table || !table->table)
529316ee512Schristos 		return 0;
530316ee512Schristos 
531316ee512Schristos 	table->changed = 0;
532316ee512Schristos 	for (i = 0; i < table->count; i++) {
533316ee512Schristos 		pfd = find_pollfd(pollfds_map, table->table[i].sock,
534316ee512Schristos 				  max_pollfd_map);
535316ee512Schristos 		if (!pfd)
536316ee512Schristos 			continue;
537316ee512Schristos 
538316ee512Schristos 		if (!(pfd->revents & revents))
539316ee512Schristos 			continue;
540316ee512Schristos 
541316ee512Schristos 		table->table[i].handler(table->table[i].sock,
542316ee512Schristos 					table->table[i].eloop_data,
543316ee512Schristos 					table->table[i].user_data);
544316ee512Schristos 		if (table->changed)
545316ee512Schristos 			return 1;
546316ee512Schristos 	}
547316ee512Schristos 
548316ee512Schristos 	return 0;
549316ee512Schristos }
550316ee512Schristos 
551316ee512Schristos 
552316ee512Schristos static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
553316ee512Schristos 				      struct eloop_sock_table *writers,
554316ee512Schristos 				      struct eloop_sock_table *exceptions,
555316ee512Schristos 				      struct pollfd **pollfds_map,
556316ee512Schristos 				      int max_pollfd_map)
557316ee512Schristos {
558316ee512Schristos 	if (eloop_sock_table_dispatch_table(readers, pollfds_map,
559316ee512Schristos 					    max_pollfd_map, POLLIN | POLLERR |
560316ee512Schristos 					    POLLHUP))
561316ee512Schristos 		return; /* pollfds may be invalid at this point */
562316ee512Schristos 
563316ee512Schristos 	if (eloop_sock_table_dispatch_table(writers, pollfds_map,
564316ee512Schristos 					    max_pollfd_map, POLLOUT))
565316ee512Schristos 		return; /* pollfds may be invalid at this point */
566316ee512Schristos 
567316ee512Schristos 	eloop_sock_table_dispatch_table(exceptions, pollfds_map,
568316ee512Schristos 					max_pollfd_map, POLLERR | POLLHUP);
569316ee512Schristos }
570316ee512Schristos 
5713c5783d3Schristos #endif /* CONFIG_ELOOP_POLL */
5723c5783d3Schristos 
5733c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT
574316ee512Schristos 
5758dbcf02cSchristos static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
5768dbcf02cSchristos 				     fd_set *fds)
5778dbcf02cSchristos {
578*45d3cc13Schristos 	size_t i;
5798dbcf02cSchristos 
5808dbcf02cSchristos 	FD_ZERO(fds);
5818dbcf02cSchristos 
5828dbcf02cSchristos 	if (table->table == NULL)
5838dbcf02cSchristos 		return;
5848dbcf02cSchristos 
5853c5783d3Schristos 	for (i = 0; i < table->count; i++) {
5863c5783d3Schristos 		assert(table->table[i].sock >= 0);
5878dbcf02cSchristos 		FD_SET(table->table[i].sock, fds);
5888dbcf02cSchristos 	}
5893c5783d3Schristos }
5908dbcf02cSchristos 
5918dbcf02cSchristos 
5928dbcf02cSchristos static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
5938dbcf02cSchristos 				      fd_set *fds)
5948dbcf02cSchristos {
595*45d3cc13Schristos 	size_t i;
5968dbcf02cSchristos 
5978dbcf02cSchristos 	if (table == NULL || table->table == NULL)
5988dbcf02cSchristos 		return;
5998dbcf02cSchristos 
6008dbcf02cSchristos 	table->changed = 0;
6018dbcf02cSchristos 	for (i = 0; i < table->count; i++) {
6028dbcf02cSchristos 		if (FD_ISSET(table->table[i].sock, fds)) {
6038dbcf02cSchristos 			table->table[i].handler(table->table[i].sock,
6048dbcf02cSchristos 						table->table[i].eloop_data,
6058dbcf02cSchristos 						table->table[i].user_data);
6068dbcf02cSchristos 			if (table->changed)
6078dbcf02cSchristos 				break;
6088dbcf02cSchristos 		}
6098dbcf02cSchristos 	}
6108dbcf02cSchristos }
6118dbcf02cSchristos 
6123c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */
6133c5783d3Schristos 
6143c5783d3Schristos 
6153c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL
6163c5783d3Schristos static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
6173c5783d3Schristos {
6183c5783d3Schristos 	struct eloop_sock *table;
6193c5783d3Schristos 	int i;
6203c5783d3Schristos 
6213c5783d3Schristos 	for (i = 0; i < nfds; i++) {
6226da92e7fSroy 		table = &eloop.fd_table[events[i].data.fd];
6233c5783d3Schristos 		if (table->handler == NULL)
6243c5783d3Schristos 			continue;
6253c5783d3Schristos 		table->handler(table->sock, table->eloop_data,
6263c5783d3Schristos 			       table->user_data);
627042b6b47Sroy 		if (eloop.readers.changed ||
628042b6b47Sroy 		    eloop.writers.changed ||
629042b6b47Sroy 		    eloop.exceptions.changed)
630042b6b47Sroy 			break;
6313c5783d3Schristos 	}
6323c5783d3Schristos }
6333c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */
634316ee512Schristos 
6358dbcf02cSchristos 
6366da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
637ecc36642Schristos 
6386da92e7fSroy static void eloop_sock_table_dispatch(struct kevent *events, int nfds)
6396da92e7fSroy {
6406da92e7fSroy 	struct eloop_sock *table;
6416da92e7fSroy 	int i;
6426da92e7fSroy 
6436da92e7fSroy 	for (i = 0; i < nfds; i++) {
6446da92e7fSroy 		table = &eloop.fd_table[events[i].ident];
6456da92e7fSroy 		if (table->handler == NULL)
6466da92e7fSroy 			continue;
6476da92e7fSroy 		table->handler(table->sock, table->eloop_data,
6486da92e7fSroy 			       table->user_data);
649042b6b47Sroy 		if (eloop.readers.changed ||
650042b6b47Sroy 		    eloop.writers.changed ||
651042b6b47Sroy 		    eloop.exceptions.changed)
652042b6b47Sroy 			break;
6536da92e7fSroy 	}
6546da92e7fSroy }
655d2b81c07Sroy 
656ecc36642Schristos 
657d2b81c07Sroy static int eloop_sock_table_requeue(struct eloop_sock_table *table)
658d2b81c07Sroy {
659*45d3cc13Schristos 	size_t i;
660*45d3cc13Schristos 	int r;
661d2b81c07Sroy 
662d2b81c07Sroy 	r = 0;
663d2b81c07Sroy 	for (i = 0; i < table->count && table->table; i++) {
664d2b81c07Sroy 		if (eloop_sock_queue(table->table[i].sock, table->type) == -1)
665d2b81c07Sroy 			r = -1;
666d2b81c07Sroy 	}
667d2b81c07Sroy 	return r;
668d2b81c07Sroy }
669d2b81c07Sroy 
670ecc36642Schristos #endif /* CONFIG_ELOOP_KQUEUE */
671ecc36642Schristos 
672ecc36642Schristos 
673d2b81c07Sroy int eloop_sock_requeue(void)
674d2b81c07Sroy {
675d2b81c07Sroy 	int r = 0;
676d2b81c07Sroy 
677ecc36642Schristos #ifdef CONFIG_ELOOP_KQUEUE
678d2b81c07Sroy 	close(eloop.kqueuefd);
679d2b81c07Sroy 	eloop.kqueuefd = kqueue();
680d2b81c07Sroy 	if (eloop.kqueuefd < 0) {
681ecc36642Schristos 		wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
682d2b81c07Sroy 			   __func__, strerror(errno));
683d2b81c07Sroy 		return -1;
684d2b81c07Sroy 	}
685d2b81c07Sroy 
686ecc36642Schristos 	if (eloop_sock_table_requeue(&eloop.readers) < 0)
687d2b81c07Sroy 		r = -1;
688ecc36642Schristos 	if (eloop_sock_table_requeue(&eloop.writers) < 0)
689d2b81c07Sroy 		r = -1;
690ecc36642Schristos 	if (eloop_sock_table_requeue(&eloop.exceptions) < 0)
691d2b81c07Sroy 		r = -1;
692ecc36642Schristos #endif /* CONFIG_ELOOP_KQUEUE */
693d2b81c07Sroy 
694d2b81c07Sroy 	return r;
695d2b81c07Sroy }
696d2b81c07Sroy 
6976da92e7fSroy 
6988dbcf02cSchristos static void eloop_sock_table_destroy(struct eloop_sock_table *table)
6998dbcf02cSchristos {
7008dbcf02cSchristos 	if (table) {
701*45d3cc13Schristos 		size_t i;
702*45d3cc13Schristos 
7038dbcf02cSchristos 		for (i = 0; i < table->count && table->table; i++) {
7048dbcf02cSchristos 			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
7058dbcf02cSchristos 				   "sock=%d eloop_data=%p user_data=%p "
7068dbcf02cSchristos 				   "handler=%p",
7078dbcf02cSchristos 				   table->table[i].sock,
7088dbcf02cSchristos 				   table->table[i].eloop_data,
7098dbcf02cSchristos 				   table->table[i].user_data,
7108dbcf02cSchristos 				   table->table[i].handler);
7118dbcf02cSchristos 			wpa_trace_dump_funcname("eloop unregistered socket "
7128dbcf02cSchristos 						"handler",
7138dbcf02cSchristos 						table->table[i].handler);
7148dbcf02cSchristos 			wpa_trace_dump("eloop sock", &table->table[i]);
7158dbcf02cSchristos 		}
7168dbcf02cSchristos 		os_free(table->table);
7178dbcf02cSchristos 	}
7188dbcf02cSchristos }
7198dbcf02cSchristos 
7208dbcf02cSchristos 
7218dbcf02cSchristos int eloop_register_read_sock(int sock, eloop_sock_handler handler,
7228dbcf02cSchristos 			     void *eloop_data, void *user_data)
7238dbcf02cSchristos {
7248dbcf02cSchristos 	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
7258dbcf02cSchristos 				   eloop_data, user_data);
7268dbcf02cSchristos }
7278dbcf02cSchristos 
7288dbcf02cSchristos 
7298dbcf02cSchristos void eloop_unregister_read_sock(int sock)
7308dbcf02cSchristos {
7318dbcf02cSchristos 	eloop_unregister_sock(sock, EVENT_TYPE_READ);
7328dbcf02cSchristos }
7338dbcf02cSchristos 
7348dbcf02cSchristos 
7358dbcf02cSchristos static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
7368dbcf02cSchristos {
7378dbcf02cSchristos 	switch (type) {
7388dbcf02cSchristos 	case EVENT_TYPE_READ:
7398dbcf02cSchristos 		return &eloop.readers;
7408dbcf02cSchristos 	case EVENT_TYPE_WRITE:
7418dbcf02cSchristos 		return &eloop.writers;
7428dbcf02cSchristos 	case EVENT_TYPE_EXCEPTION:
7438dbcf02cSchristos 		return &eloop.exceptions;
7448dbcf02cSchristos 	}
7458dbcf02cSchristos 
7468dbcf02cSchristos 	return NULL;
7478dbcf02cSchristos }
7488dbcf02cSchristos 
7498dbcf02cSchristos 
7508dbcf02cSchristos int eloop_register_sock(int sock, eloop_event_type type,
7518dbcf02cSchristos 			eloop_sock_handler handler,
7528dbcf02cSchristos 			void *eloop_data, void *user_data)
7538dbcf02cSchristos {
7548dbcf02cSchristos 	struct eloop_sock_table *table;
7558dbcf02cSchristos 
7563c5783d3Schristos 	assert(sock >= 0);
7578dbcf02cSchristos 	table = eloop_get_sock_table(type);
7588dbcf02cSchristos 	return eloop_sock_table_add_sock(table, sock, handler,
7598dbcf02cSchristos 					 eloop_data, user_data);
7608dbcf02cSchristos }
7618dbcf02cSchristos 
7628dbcf02cSchristos 
7638dbcf02cSchristos void eloop_unregister_sock(int sock, eloop_event_type type)
7648dbcf02cSchristos {
7658dbcf02cSchristos 	struct eloop_sock_table *table;
7668dbcf02cSchristos 
7678dbcf02cSchristos 	table = eloop_get_sock_table(type);
7688dbcf02cSchristos 	eloop_sock_table_remove_sock(table, sock);
7698dbcf02cSchristos }
7708dbcf02cSchristos 
7718dbcf02cSchristos 
7728dbcf02cSchristos int eloop_register_timeout(unsigned int secs, unsigned int usecs,
7738dbcf02cSchristos 			   eloop_timeout_handler handler,
7748dbcf02cSchristos 			   void *eloop_data, void *user_data)
7758dbcf02cSchristos {
7768dbcf02cSchristos 	struct eloop_timeout *timeout, *tmp;
777b8fa3219Schristos 	os_time_t now_sec;
7788dbcf02cSchristos 
7798dbcf02cSchristos 	timeout = os_zalloc(sizeof(*timeout));
7808dbcf02cSchristos 	if (timeout == NULL)
7818dbcf02cSchristos 		return -1;
7823c5783d3Schristos 	if (os_get_reltime(&timeout->time) < 0) {
7838dbcf02cSchristos 		os_free(timeout);
7848dbcf02cSchristos 		return -1;
7858dbcf02cSchristos 	}
786b8fa3219Schristos 	now_sec = timeout->time.sec;
7878dbcf02cSchristos 	timeout->time.sec += secs;
788*45d3cc13Schristos 	if (timeout->time.sec < now_sec)
789*45d3cc13Schristos 		goto overflow;
7908dbcf02cSchristos 	timeout->time.usec += usecs;
7918dbcf02cSchristos 	while (timeout->time.usec >= 1000000) {
7928dbcf02cSchristos 		timeout->time.sec++;
7938dbcf02cSchristos 		timeout->time.usec -= 1000000;
7948dbcf02cSchristos 	}
795*45d3cc13Schristos 	if (timeout->time.sec < now_sec)
796*45d3cc13Schristos 		goto overflow;
7978dbcf02cSchristos 	timeout->eloop_data = eloop_data;
7988dbcf02cSchristos 	timeout->user_data = user_data;
7998dbcf02cSchristos 	timeout->handler = handler;
8008dbcf02cSchristos 	wpa_trace_add_ref(timeout, eloop, eloop_data);
8018dbcf02cSchristos 	wpa_trace_add_ref(timeout, user, user_data);
8028dbcf02cSchristos 	wpa_trace_record(timeout);
8038dbcf02cSchristos 
8048dbcf02cSchristos 	/* Maintain timeouts in order of increasing time */
8058dbcf02cSchristos 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
8063c5783d3Schristos 		if (os_reltime_before(&timeout->time, &tmp->time)) {
8078dbcf02cSchristos 			dl_list_add(tmp->list.prev, &timeout->list);
8088dbcf02cSchristos 			return 0;
8098dbcf02cSchristos 		}
8108dbcf02cSchristos 	}
8118dbcf02cSchristos 	dl_list_add_tail(&eloop.timeout, &timeout->list);
8128dbcf02cSchristos 
8138dbcf02cSchristos 	return 0;
814*45d3cc13Schristos 
815*45d3cc13Schristos overflow:
816*45d3cc13Schristos 	/*
817*45d3cc13Schristos 	 * Integer overflow - assume long enough timeout to be assumed
818*45d3cc13Schristos 	 * to be infinite, i.e., the timeout would never happen.
819*45d3cc13Schristos 	 */
820*45d3cc13Schristos 	wpa_printf(MSG_DEBUG,
821*45d3cc13Schristos 		   "ELOOP: Too long timeout (secs=%u usecs=%u) to ever happen - ignore it",
822*45d3cc13Schristos 		   secs,usecs);
823*45d3cc13Schristos 	os_free(timeout);
824*45d3cc13Schristos 	return 0;
8258dbcf02cSchristos }
8268dbcf02cSchristos 
8278dbcf02cSchristos 
8288dbcf02cSchristos static void eloop_remove_timeout(struct eloop_timeout *timeout)
8298dbcf02cSchristos {
8308dbcf02cSchristos 	dl_list_del(&timeout->list);
8318dbcf02cSchristos 	wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
8328dbcf02cSchristos 	wpa_trace_remove_ref(timeout, user, timeout->user_data);
8338dbcf02cSchristos 	os_free(timeout);
8348dbcf02cSchristos }
8358dbcf02cSchristos 
8368dbcf02cSchristos 
8378dbcf02cSchristos int eloop_cancel_timeout(eloop_timeout_handler handler,
8388dbcf02cSchristos 			 void *eloop_data, void *user_data)
8398dbcf02cSchristos {
8408dbcf02cSchristos 	struct eloop_timeout *timeout, *prev;
8418dbcf02cSchristos 	int removed = 0;
8428dbcf02cSchristos 
8438dbcf02cSchristos 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
8448dbcf02cSchristos 			      struct eloop_timeout, list) {
8458dbcf02cSchristos 		if (timeout->handler == handler &&
8468dbcf02cSchristos 		    (timeout->eloop_data == eloop_data ||
8478dbcf02cSchristos 		     eloop_data == ELOOP_ALL_CTX) &&
8488dbcf02cSchristos 		    (timeout->user_data == user_data ||
8498dbcf02cSchristos 		     user_data == ELOOP_ALL_CTX)) {
8508dbcf02cSchristos 			eloop_remove_timeout(timeout);
8518dbcf02cSchristos 			removed++;
8528dbcf02cSchristos 		}
8538dbcf02cSchristos 	}
8548dbcf02cSchristos 
8558dbcf02cSchristos 	return removed;
8568dbcf02cSchristos }
8578dbcf02cSchristos 
8588dbcf02cSchristos 
8593c5783d3Schristos int eloop_cancel_timeout_one(eloop_timeout_handler handler,
8603c5783d3Schristos 			     void *eloop_data, void *user_data,
8613c5783d3Schristos 			     struct os_reltime *remaining)
8623c5783d3Schristos {
8633c5783d3Schristos 	struct eloop_timeout *timeout, *prev;
8643c5783d3Schristos 	int removed = 0;
8653c5783d3Schristos 	struct os_reltime now;
8663c5783d3Schristos 
8673c5783d3Schristos 	os_get_reltime(&now);
8683c5783d3Schristos 	remaining->sec = remaining->usec = 0;
8693c5783d3Schristos 
8703c5783d3Schristos 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
8713c5783d3Schristos 			      struct eloop_timeout, list) {
8723c5783d3Schristos 		if (timeout->handler == handler &&
8733c5783d3Schristos 		    (timeout->eloop_data == eloop_data) &&
8743c5783d3Schristos 		    (timeout->user_data == user_data)) {
8753c5783d3Schristos 			removed = 1;
8763c5783d3Schristos 			if (os_reltime_before(&now, &timeout->time))
8773c5783d3Schristos 				os_reltime_sub(&timeout->time, &now, remaining);
8783c5783d3Schristos 			eloop_remove_timeout(timeout);
8793c5783d3Schristos 			break;
8803c5783d3Schristos 		}
8813c5783d3Schristos 	}
8823c5783d3Schristos 	return removed;
8833c5783d3Schristos }
8843c5783d3Schristos 
8853c5783d3Schristos 
8868dbcf02cSchristos int eloop_is_timeout_registered(eloop_timeout_handler handler,
8878dbcf02cSchristos 				void *eloop_data, void *user_data)
8888dbcf02cSchristos {
8898dbcf02cSchristos 	struct eloop_timeout *tmp;
8908dbcf02cSchristos 
8918dbcf02cSchristos 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
8928dbcf02cSchristos 		if (tmp->handler == handler &&
8938dbcf02cSchristos 		    tmp->eloop_data == eloop_data &&
8948dbcf02cSchristos 		    tmp->user_data == user_data)
8958dbcf02cSchristos 			return 1;
8968dbcf02cSchristos 	}
8978dbcf02cSchristos 
8988dbcf02cSchristos 	return 0;
8998dbcf02cSchristos }
9008dbcf02cSchristos 
9018dbcf02cSchristos 
9023c5783d3Schristos int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
9033c5783d3Schristos 			  eloop_timeout_handler handler, void *eloop_data,
9043c5783d3Schristos 			  void *user_data)
9053c5783d3Schristos {
9063c5783d3Schristos 	struct os_reltime now, requested, remaining;
9073c5783d3Schristos 	struct eloop_timeout *tmp;
9083c5783d3Schristos 
9093c5783d3Schristos 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
9103c5783d3Schristos 		if (tmp->handler == handler &&
9113c5783d3Schristos 		    tmp->eloop_data == eloop_data &&
9123c5783d3Schristos 		    tmp->user_data == user_data) {
9133c5783d3Schristos 			requested.sec = req_secs;
9143c5783d3Schristos 			requested.usec = req_usecs;
9153c5783d3Schristos 			os_get_reltime(&now);
9163c5783d3Schristos 			os_reltime_sub(&tmp->time, &now, &remaining);
9173c5783d3Schristos 			if (os_reltime_before(&requested, &remaining)) {
9183c5783d3Schristos 				eloop_cancel_timeout(handler, eloop_data,
9193c5783d3Schristos 						     user_data);
9203c5783d3Schristos 				eloop_register_timeout(requested.sec,
9213c5783d3Schristos 						       requested.usec,
9223c5783d3Schristos 						       handler, eloop_data,
9233c5783d3Schristos 						       user_data);
9243c5783d3Schristos 				return 1;
9253c5783d3Schristos 			}
9263c5783d3Schristos 			return 0;
9273c5783d3Schristos 		}
9283c5783d3Schristos 	}
9293c5783d3Schristos 
9303c5783d3Schristos 	return -1;
9313c5783d3Schristos }
9323c5783d3Schristos 
9333c5783d3Schristos 
9343c5783d3Schristos int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
9353c5783d3Schristos 			    eloop_timeout_handler handler, void *eloop_data,
9363c5783d3Schristos 			    void *user_data)
9373c5783d3Schristos {
9383c5783d3Schristos 	struct os_reltime now, requested, remaining;
9393c5783d3Schristos 	struct eloop_timeout *tmp;
9403c5783d3Schristos 
9413c5783d3Schristos 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
9423c5783d3Schristos 		if (tmp->handler == handler &&
9433c5783d3Schristos 		    tmp->eloop_data == eloop_data &&
9443c5783d3Schristos 		    tmp->user_data == user_data) {
9453c5783d3Schristos 			requested.sec = req_secs;
9463c5783d3Schristos 			requested.usec = req_usecs;
9473c5783d3Schristos 			os_get_reltime(&now);
9483c5783d3Schristos 			os_reltime_sub(&tmp->time, &now, &remaining);
9493c5783d3Schristos 			if (os_reltime_before(&remaining, &requested)) {
9503c5783d3Schristos 				eloop_cancel_timeout(handler, eloop_data,
9513c5783d3Schristos 						     user_data);
9523c5783d3Schristos 				eloop_register_timeout(requested.sec,
9533c5783d3Schristos 						       requested.usec,
9543c5783d3Schristos 						       handler, eloop_data,
9553c5783d3Schristos 						       user_data);
9563c5783d3Schristos 				return 1;
9573c5783d3Schristos 			}
9583c5783d3Schristos 			return 0;
9593c5783d3Schristos 		}
9603c5783d3Schristos 	}
9613c5783d3Schristos 
9623c5783d3Schristos 	return -1;
9633c5783d3Schristos }
9643c5783d3Schristos 
9653c5783d3Schristos 
9668dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS
9678dbcf02cSchristos static void eloop_handle_alarm(int sig)
9688dbcf02cSchristos {
9698dbcf02cSchristos 	wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
9708dbcf02cSchristos 		   "two seconds. Looks like there\n"
9718dbcf02cSchristos 		   "is a bug that ends up in a busy loop that "
9728dbcf02cSchristos 		   "prevents clean shutdown.\n"
9738dbcf02cSchristos 		   "Killing program forcefully.\n");
9748dbcf02cSchristos 	exit(1);
9758dbcf02cSchristos }
9768dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */
9778dbcf02cSchristos 
9788dbcf02cSchristos 
9798dbcf02cSchristos static void eloop_handle_signal(int sig)
9808dbcf02cSchristos {
981*45d3cc13Schristos 	size_t i;
9828dbcf02cSchristos 
9838dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS
9848dbcf02cSchristos 	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
9858dbcf02cSchristos 		/* Use SIGALRM to break out from potential busy loops that
9868dbcf02cSchristos 		 * would not allow the program to be killed. */
9878dbcf02cSchristos 		eloop.pending_terminate = 1;
9888dbcf02cSchristos 		signal(SIGALRM, eloop_handle_alarm);
9898dbcf02cSchristos 		alarm(2);
9908dbcf02cSchristos 	}
9918dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */
9928dbcf02cSchristos 
9938dbcf02cSchristos 	eloop.signaled++;
9948dbcf02cSchristos 	for (i = 0; i < eloop.signal_count; i++) {
9958dbcf02cSchristos 		if (eloop.signals[i].sig == sig) {
9968dbcf02cSchristos 			eloop.signals[i].signaled++;
9978dbcf02cSchristos 			break;
9988dbcf02cSchristos 		}
9998dbcf02cSchristos 	}
10008dbcf02cSchristos }
10018dbcf02cSchristos 
10028dbcf02cSchristos 
10038dbcf02cSchristos static void eloop_process_pending_signals(void)
10048dbcf02cSchristos {
1005*45d3cc13Schristos 	size_t i;
10068dbcf02cSchristos 
10078dbcf02cSchristos 	if (eloop.signaled == 0)
10088dbcf02cSchristos 		return;
10098dbcf02cSchristos 	eloop.signaled = 0;
10108dbcf02cSchristos 
10118dbcf02cSchristos 	if (eloop.pending_terminate) {
10128dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS
10138dbcf02cSchristos 		alarm(0);
10148dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */
10158dbcf02cSchristos 		eloop.pending_terminate = 0;
10168dbcf02cSchristos 	}
10178dbcf02cSchristos 
10188dbcf02cSchristos 	for (i = 0; i < eloop.signal_count; i++) {
10198dbcf02cSchristos 		if (eloop.signals[i].signaled) {
10208dbcf02cSchristos 			eloop.signals[i].signaled = 0;
10218dbcf02cSchristos 			eloop.signals[i].handler(eloop.signals[i].sig,
10228dbcf02cSchristos 						 eloop.signals[i].user_data);
10238dbcf02cSchristos 		}
10248dbcf02cSchristos 	}
10258dbcf02cSchristos }
10268dbcf02cSchristos 
10278dbcf02cSchristos 
10288dbcf02cSchristos int eloop_register_signal(int sig, eloop_signal_handler handler,
10298dbcf02cSchristos 			  void *user_data)
10308dbcf02cSchristos {
10318dbcf02cSchristos 	struct eloop_signal *tmp;
10328dbcf02cSchristos 
1033316ee512Schristos 	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
10348dbcf02cSchristos 			       sizeof(struct eloop_signal));
10358dbcf02cSchristos 	if (tmp == NULL)
10368dbcf02cSchristos 		return -1;
10378dbcf02cSchristos 
10388dbcf02cSchristos 	tmp[eloop.signal_count].sig = sig;
10398dbcf02cSchristos 	tmp[eloop.signal_count].user_data = user_data;
10408dbcf02cSchristos 	tmp[eloop.signal_count].handler = handler;
10418dbcf02cSchristos 	tmp[eloop.signal_count].signaled = 0;
10428dbcf02cSchristos 	eloop.signal_count++;
10438dbcf02cSchristos 	eloop.signals = tmp;
10448dbcf02cSchristos 	signal(sig, eloop_handle_signal);
10458dbcf02cSchristos 
10468dbcf02cSchristos 	return 0;
10478dbcf02cSchristos }
10488dbcf02cSchristos 
10498dbcf02cSchristos 
10508dbcf02cSchristos int eloop_register_signal_terminate(eloop_signal_handler handler,
10518dbcf02cSchristos 				    void *user_data)
10528dbcf02cSchristos {
10538dbcf02cSchristos 	int ret = eloop_register_signal(SIGINT, handler, user_data);
10548dbcf02cSchristos 	if (ret == 0)
10558dbcf02cSchristos 		ret = eloop_register_signal(SIGTERM, handler, user_data);
10568dbcf02cSchristos 	return ret;
10578dbcf02cSchristos }
10588dbcf02cSchristos 
10598dbcf02cSchristos 
10608dbcf02cSchristos int eloop_register_signal_reconfig(eloop_signal_handler handler,
10618dbcf02cSchristos 				   void *user_data)
10628dbcf02cSchristos {
10638dbcf02cSchristos #ifdef CONFIG_NATIVE_WINDOWS
10648dbcf02cSchristos 	return 0;
10658dbcf02cSchristos #else /* CONFIG_NATIVE_WINDOWS */
10668dbcf02cSchristos 	return eloop_register_signal(SIGHUP, handler, user_data);
10678dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */
10688dbcf02cSchristos }
10698dbcf02cSchristos 
10708dbcf02cSchristos 
10718dbcf02cSchristos void eloop_run(void)
10728dbcf02cSchristos {
1073316ee512Schristos #ifdef CONFIG_ELOOP_POLL
1074316ee512Schristos 	int num_poll_fds;
1075316ee512Schristos 	int timeout_ms = 0;
10763c5783d3Schristos #endif /* CONFIG_ELOOP_POLL */
10773c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT
10788dbcf02cSchristos 	fd_set *rfds, *wfds, *efds;
10798dbcf02cSchristos 	struct timeval _tv;
10803c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */
10813c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL
10823c5783d3Schristos 	int timeout_ms = -1;
10833c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */
10846da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
10856da92e7fSroy 	struct timespec ts;
10866da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */
1087316ee512Schristos 	int res;
10883c5783d3Schristos 	struct os_reltime tv, now;
10898dbcf02cSchristos 
10903c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT
10918dbcf02cSchristos 	rfds = os_malloc(sizeof(*rfds));
10928dbcf02cSchristos 	wfds = os_malloc(sizeof(*wfds));
10938dbcf02cSchristos 	efds = os_malloc(sizeof(*efds));
10948dbcf02cSchristos 	if (rfds == NULL || wfds == NULL || efds == NULL)
10958dbcf02cSchristos 		goto out;
10963c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */
10978dbcf02cSchristos 
10988dbcf02cSchristos 	while (!eloop.terminate &&
10998dbcf02cSchristos 	       (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
11008dbcf02cSchristos 		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
11018dbcf02cSchristos 		struct eloop_timeout *timeout;
1102042b6b47Sroy 
1103042b6b47Sroy 		if (eloop.pending_terminate) {
1104042b6b47Sroy 			/*
1105042b6b47Sroy 			 * This may happen in some corner cases where a signal
1106042b6b47Sroy 			 * is received during a blocking operation. We need to
1107042b6b47Sroy 			 * process the pending signals and exit if requested to
1108042b6b47Sroy 			 * avoid hitting the SIGALRM limit if the blocking
1109042b6b47Sroy 			 * operation took more than two seconds.
1110042b6b47Sroy 			 */
1111042b6b47Sroy 			eloop_process_pending_signals();
1112042b6b47Sroy 			if (eloop.terminate)
1113042b6b47Sroy 				break;
1114042b6b47Sroy 		}
1115042b6b47Sroy 
11168dbcf02cSchristos 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
11178dbcf02cSchristos 					list);
11188dbcf02cSchristos 		if (timeout) {
11193c5783d3Schristos 			os_get_reltime(&now);
11203c5783d3Schristos 			if (os_reltime_before(&now, &timeout->time))
11213c5783d3Schristos 				os_reltime_sub(&timeout->time, &now, &tv);
11228dbcf02cSchristos 			else
11238dbcf02cSchristos 				tv.sec = tv.usec = 0;
11243c5783d3Schristos #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
1125316ee512Schristos 			timeout_ms = tv.sec * 1000 + tv.usec / 1000;
11263c5783d3Schristos #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
11273c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT
11288dbcf02cSchristos 			_tv.tv_sec = tv.sec;
11298dbcf02cSchristos 			_tv.tv_usec = tv.usec;
11303c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */
11316da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
11326da92e7fSroy 			ts.tv_sec = tv.sec;
11336da92e7fSroy 			ts.tv_nsec = tv.usec * 1000L;
11346da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */
11358dbcf02cSchristos 		}
11368dbcf02cSchristos 
1137316ee512Schristos #ifdef CONFIG_ELOOP_POLL
1138316ee512Schristos 		num_poll_fds = eloop_sock_table_set_fds(
1139316ee512Schristos 			&eloop.readers, &eloop.writers, &eloop.exceptions,
1140316ee512Schristos 			eloop.pollfds, eloop.pollfds_map,
1141316ee512Schristos 			eloop.max_pollfd_map);
1142316ee512Schristos 		res = poll(eloop.pollfds, num_poll_fds,
1143316ee512Schristos 			   timeout ? timeout_ms : -1);
11443c5783d3Schristos #endif /* CONFIG_ELOOP_POLL */
11453c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT
11468dbcf02cSchristos 		eloop_sock_table_set_fds(&eloop.readers, rfds);
11478dbcf02cSchristos 		eloop_sock_table_set_fds(&eloop.writers, wfds);
11488dbcf02cSchristos 		eloop_sock_table_set_fds(&eloop.exceptions, efds);
11498dbcf02cSchristos 		res = select(eloop.max_sock + 1, rfds, wfds, efds,
11508dbcf02cSchristos 			     timeout ? &_tv : NULL);
11513c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */
11523c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL
11533c5783d3Schristos 		if (eloop.count == 0) {
11543c5783d3Schristos 			res = 0;
11553c5783d3Schristos 		} else {
11563c5783d3Schristos 			res = epoll_wait(eloop.epollfd, eloop.epoll_events,
11573c5783d3Schristos 					 eloop.count, timeout_ms);
11583c5783d3Schristos 		}
11593c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */
11606da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
11616da92e7fSroy 		if (eloop.count == 0) {
11626da92e7fSroy 			res = 0;
11636da92e7fSroy 		} else {
11646da92e7fSroy 			res = kevent(eloop.kqueuefd, NULL, 0,
11656da92e7fSroy 				     eloop.kqueue_events, eloop.kqueue_nevents,
11666da92e7fSroy 				     timeout ? &ts : NULL);
11676da92e7fSroy 		}
11686da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */
11698dbcf02cSchristos 		if (res < 0 && errno != EINTR && errno != 0) {
11703c5783d3Schristos 			wpa_printf(MSG_ERROR, "eloop: %s: %s",
11713c5783d3Schristos #ifdef CONFIG_ELOOP_POLL
11723c5783d3Schristos 				   "poll"
11733c5783d3Schristos #endif /* CONFIG_ELOOP_POLL */
11743c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT
11753c5783d3Schristos 				   "select"
11763c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */
11773c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL
11783c5783d3Schristos 				   "epoll"
11793c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */
11806da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
11816da92e7fSroy 				   "kqueue"
11826da92e7fSroy #endif /* CONFIG_ELOOP_EKQUEUE */
11836da92e7fSroy 
11843c5783d3Schristos 				   , strerror(errno));
11858dbcf02cSchristos 			goto out;
11868dbcf02cSchristos 		}
1187042b6b47Sroy 
1188042b6b47Sroy 		eloop.readers.changed = 0;
1189042b6b47Sroy 		eloop.writers.changed = 0;
1190042b6b47Sroy 		eloop.exceptions.changed = 0;
1191042b6b47Sroy 
11928dbcf02cSchristos 		eloop_process_pending_signals();
11938dbcf02cSchristos 
1194042b6b47Sroy 
11958dbcf02cSchristos 		/* check if some registered timeouts have occurred */
1196e6e4448bSchristos 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
1197e6e4448bSchristos 					list);
11988dbcf02cSchristos 		if (timeout) {
11993c5783d3Schristos 			os_get_reltime(&now);
12003c5783d3Schristos 			if (!os_reltime_before(&now, &timeout->time)) {
12018dbcf02cSchristos 				void *eloop_data = timeout->eloop_data;
12028dbcf02cSchristos 				void *user_data = timeout->user_data;
12038dbcf02cSchristos 				eloop_timeout_handler handler =
12048dbcf02cSchristos 					timeout->handler;
12058dbcf02cSchristos 				eloop_remove_timeout(timeout);
12068dbcf02cSchristos 				handler(eloop_data, user_data);
12078dbcf02cSchristos 			}
12088dbcf02cSchristos 
12098dbcf02cSchristos 		}
12108dbcf02cSchristos 
12118dbcf02cSchristos 		if (res <= 0)
12128dbcf02cSchristos 			continue;
12138dbcf02cSchristos 
1214042b6b47Sroy 		if (eloop.readers.changed ||
1215042b6b47Sroy 		    eloop.writers.changed ||
1216042b6b47Sroy 		    eloop.exceptions.changed) {
1217042b6b47Sroy 			 /*
1218042b6b47Sroy 			  * Sockets may have been closed and reopened with the
1219042b6b47Sroy 			  * same FD in the signal or timeout handlers, so we
1220042b6b47Sroy 			  * must skip the previous results and check again
1221042b6b47Sroy 			  * whether any of the currently registered sockets have
1222042b6b47Sroy 			  * events.
1223042b6b47Sroy 			  */
1224042b6b47Sroy 			continue;
1225042b6b47Sroy 		}
1226042b6b47Sroy 
1227316ee512Schristos #ifdef CONFIG_ELOOP_POLL
1228316ee512Schristos 		eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
1229316ee512Schristos 					  &eloop.exceptions, eloop.pollfds_map,
1230316ee512Schristos 					  eloop.max_pollfd_map);
12313c5783d3Schristos #endif /* CONFIG_ELOOP_POLL */
12323c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT
12338dbcf02cSchristos 		eloop_sock_table_dispatch(&eloop.readers, rfds);
12348dbcf02cSchristos 		eloop_sock_table_dispatch(&eloop.writers, wfds);
12358dbcf02cSchristos 		eloop_sock_table_dispatch(&eloop.exceptions, efds);
12363c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */
12373c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL
12383c5783d3Schristos 		eloop_sock_table_dispatch(eloop.epoll_events, res);
12393c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */
12406da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
12416da92e7fSroy 		eloop_sock_table_dispatch(eloop.kqueue_events, res);
12426da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */
12438dbcf02cSchristos 	}
12448dbcf02cSchristos 
12453c5783d3Schristos 	eloop.terminate = 0;
12468dbcf02cSchristos out:
12473c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT
12488dbcf02cSchristos 	os_free(rfds);
12498dbcf02cSchristos 	os_free(wfds);
12508dbcf02cSchristos 	os_free(efds);
12513c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */
1252316ee512Schristos 	return;
12538dbcf02cSchristos }
12548dbcf02cSchristos 
12558dbcf02cSchristos 
12568dbcf02cSchristos void eloop_terminate(void)
12578dbcf02cSchristos {
12588dbcf02cSchristos 	eloop.terminate = 1;
12598dbcf02cSchristos }
12608dbcf02cSchristos 
12618dbcf02cSchristos 
12628dbcf02cSchristos void eloop_destroy(void)
12638dbcf02cSchristos {
12648dbcf02cSchristos 	struct eloop_timeout *timeout, *prev;
12653c5783d3Schristos 	struct os_reltime now;
12668dbcf02cSchristos 
12673c5783d3Schristos 	os_get_reltime(&now);
12688dbcf02cSchristos 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
12698dbcf02cSchristos 			      struct eloop_timeout, list) {
12708dbcf02cSchristos 		int sec, usec;
12718dbcf02cSchristos 		sec = timeout->time.sec - now.sec;
12728dbcf02cSchristos 		usec = timeout->time.usec - now.usec;
12738dbcf02cSchristos 		if (timeout->time.usec < now.usec) {
12748dbcf02cSchristos 			sec--;
12758dbcf02cSchristos 			usec += 1000000;
12768dbcf02cSchristos 		}
12778dbcf02cSchristos 		wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
12788dbcf02cSchristos 			   "eloop_data=%p user_data=%p handler=%p",
12798dbcf02cSchristos 			   sec, usec, timeout->eloop_data, timeout->user_data,
12808dbcf02cSchristos 			   timeout->handler);
12818dbcf02cSchristos 		wpa_trace_dump_funcname("eloop unregistered timeout handler",
12828dbcf02cSchristos 					timeout->handler);
12838dbcf02cSchristos 		wpa_trace_dump("eloop timeout", timeout);
12848dbcf02cSchristos 		eloop_remove_timeout(timeout);
12858dbcf02cSchristos 	}
12868dbcf02cSchristos 	eloop_sock_table_destroy(&eloop.readers);
12878dbcf02cSchristos 	eloop_sock_table_destroy(&eloop.writers);
12888dbcf02cSchristos 	eloop_sock_table_destroy(&eloop.exceptions);
12898dbcf02cSchristos 	os_free(eloop.signals);
1290316ee512Schristos 
1291316ee512Schristos #ifdef CONFIG_ELOOP_POLL
1292316ee512Schristos 	os_free(eloop.pollfds);
1293316ee512Schristos 	os_free(eloop.pollfds_map);
1294316ee512Schristos #endif /* CONFIG_ELOOP_POLL */
12956da92e7fSroy #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
12966da92e7fSroy 	os_free(eloop.fd_table);
1297ecc36642Schristos #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
12983c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL
12993c5783d3Schristos 	os_free(eloop.epoll_events);
13003c5783d3Schristos 	close(eloop.epollfd);
13013c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */
13026da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
13036da92e7fSroy 	os_free(eloop.kqueue_events);
13046da92e7fSroy 	close(eloop.kqueuefd);
13056da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */
13068dbcf02cSchristos }
13078dbcf02cSchristos 
13088dbcf02cSchristos 
13098dbcf02cSchristos int eloop_terminated(void)
13108dbcf02cSchristos {
1311042b6b47Sroy 	return eloop.terminate || eloop.pending_terminate;
13128dbcf02cSchristos }
13138dbcf02cSchristos 
13148dbcf02cSchristos 
13158dbcf02cSchristos void eloop_wait_for_read_sock(int sock)
13168dbcf02cSchristos {
1317316ee512Schristos #ifdef CONFIG_ELOOP_POLL
1318316ee512Schristos 	struct pollfd pfd;
1319316ee512Schristos 
1320316ee512Schristos 	if (sock < 0)
1321316ee512Schristos 		return;
1322316ee512Schristos 
1323316ee512Schristos 	os_memset(&pfd, 0, sizeof(pfd));
1324316ee512Schristos 	pfd.fd = sock;
1325316ee512Schristos 	pfd.events = POLLIN;
1326316ee512Schristos 
1327316ee512Schristos 	poll(&pfd, 1, -1);
13283c5783d3Schristos #endif /* CONFIG_ELOOP_POLL */
13293c5783d3Schristos #if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL)
13303c5783d3Schristos 	/*
13313c5783d3Schristos 	 * We can use epoll() here. But epoll() requres 4 system calls.
13323c5783d3Schristos 	 * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for
13333c5783d3Schristos 	 * epoll fd. So select() is better for performance here.
13343c5783d3Schristos 	 */
13358dbcf02cSchristos 	fd_set rfds;
13368dbcf02cSchristos 
13378dbcf02cSchristos 	if (sock < 0)
13388dbcf02cSchristos 		return;
13398dbcf02cSchristos 
13408dbcf02cSchristos 	FD_ZERO(&rfds);
13418dbcf02cSchristos 	FD_SET(sock, &rfds);
13428dbcf02cSchristos 	select(sock + 1, &rfds, NULL, NULL, NULL);
13433c5783d3Schristos #endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */
13446da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE
13456da92e7fSroy 	int kfd;
13466da92e7fSroy 	struct kevent ke1, ke2;
13476da92e7fSroy 
13486da92e7fSroy 	kfd = kqueue();
13496da92e7fSroy 	if (kfd == -1)
13506da92e7fSroy 		return;
1351b06fa2e7Schristos 	EV_SET(&ke1, sock, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
13526da92e7fSroy 	kevent(kfd, &ke1, 1, &ke2, 1, NULL);
13536da92e7fSroy 	close(kfd);
13546da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */
13558dbcf02cSchristos }
13563c5783d3Schristos 
13573c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT
13583c5783d3Schristos #undef CONFIG_ELOOP_SELECT
13593c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */
1360