18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Event loop based on select() loop
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
10df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt#include <assert.h>
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "trace.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "list.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL)
1850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#error Do not define both of poll and epoll
1950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif
2050b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt
21b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_KQUEUE)
22b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#error Do not define both of poll and kqueue
23b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif
24b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
25b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) && \
26b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt    !defined(CONFIG_ELOOP_KQUEUE)
2750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#define CONFIG_ELOOP_SELECT
2850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif
2950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt
30c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#ifdef CONFIG_ELOOP_POLL
31c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#include <poll.h>
32c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#endif /* CONFIG_ELOOP_POLL */
33c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
3450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
3550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#include <sys/epoll.h>
3650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
39b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#include <sys/event.h>
40b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
41b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eloop_sock {
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int sock;
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *eloop_data;
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *user_data;
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_sock_handler handler;
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_TRACE_REF(eloop);
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_TRACE_REF(user);
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_TRACE_INFO
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eloop_timeout {
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct dl_list list;
54fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt	struct os_reltime time;
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *eloop_data;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *user_data;
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_timeout_handler handler;
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_TRACE_REF(eloop);
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_TRACE_REF(user);
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_TRACE_INFO
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eloop_signal {
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int sig;
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *user_data;
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_signal_handler handler;
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int signaled;
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eloop_sock_table {
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int count;
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_sock *table;
7350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	eloop_event_type type;
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int changed;
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eloop_data {
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int max_sock;
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
80c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	int count; /* sum of all table counts */
81c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#ifdef CONFIG_ELOOP_POLL
82c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	int max_pollfd_map; /* number of pollfds_map currently allocated */
83c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	int max_poll_fds; /* number of pollfds currently allocated */
84c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	struct pollfd *pollfds;
85c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	struct pollfd **pollfds_map;
86c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#endif /* CONFIG_ELOOP_POLL */
87b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
88b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	int max_fd;
89b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	struct eloop_sock *fd_table;
90b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
9150b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
9250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	int epollfd;
9350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	int epoll_max_event_num;
9450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	struct epoll_event *epoll_events;
9550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
96b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
97b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	int kqueuefd;
98b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	int kqueue_nevents;
99b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	struct kevent *kqueue_events;
100b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_sock_table readers;
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_sock_table writers;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_sock_table exceptions;
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct dl_list timeout;
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int signal_count;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_signal *signals;
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int signaled;
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int pending_terminate;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int terminate;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct eloop_data eloop;
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef WPA_TRACE
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eloop_sigsegv_handler(int sig)
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_trace_show("eloop SIGSEGV");
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	abort();
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (table == NULL || table->table == NULL)
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < table->count; i++) {
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_trace_add_ref(&table->table[i], eloop,
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  table->table[i].eloop_data);
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_trace_add_ref(&table->table[i], user,
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  table->table[i].user_data);
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (table == NULL || table->table == NULL)
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < table->count; i++) {
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_trace_remove_ref(&table->table[i], eloop,
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     table->table[i].eloop_data);
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_trace_remove_ref(&table->table[i], user,
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     table->table[i].user_data);
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* WPA_TRACE */
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define eloop_trace_sock_add_ref(table) do { } while (0)
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define eloop_trace_sock_remove_ref(table) do { } while (0)
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* WPA_TRACE */
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eloop_init(void)
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&eloop, 0, sizeof(eloop));
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_init(&eloop.timeout);
16550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
16650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	eloop.epollfd = epoll_create1(0);
16750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	if (eloop.epollfd < 0) {
168b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s",
169b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			   __func__, strerror(errno));
170b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		return -1;
171b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	}
172b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
173b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
174b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	eloop.kqueuefd = kqueue();
175b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (eloop.kqueuefd < 0) {
176b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
17750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt			   __func__, strerror(errno));
17850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		return -1;
17950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	}
180b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
181b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
18250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	eloop.readers.type = EVENT_TYPE_READ;
18350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	eloop.writers.type = EVENT_TYPE_WRITE;
18450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
185b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef WPA_TRACE
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	signal(SIGSEGV, eloop_sigsegv_handler);
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* WPA_TRACE */
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
193b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
194b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidtstatic int eloop_sock_queue(int sock, eloop_event_type type)
195b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt{
196b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	struct epoll_event ev;
197b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
198b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	os_memset(&ev, 0, sizeof(ev));
199b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	switch (type) {
200b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	case EVENT_TYPE_READ:
201b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		ev.events = EPOLLIN;
202b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		break;
203b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	case EVENT_TYPE_WRITE:
204b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		ev.events = EPOLLOUT;
205b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		break;
206b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	/*
207b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	 * Exceptions are always checked when using epoll, but I suppose it's
208b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	 * possible that someone registered a socket *only* for exception
209b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	 * handling.
210b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	 */
211b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	case EVENT_TYPE_EXCEPTION:
212b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		ev.events = EPOLLERR | EPOLLHUP;
213b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		break;
214b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	}
215b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	ev.data.fd = sock;
216b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
217b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d failed: %s",
218b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			   __func__, sock, strerror(errno));
219b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		return -1;
220b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	}
221b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	return 0;
222b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt}
223b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
224b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
225b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
226b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
227b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidtstatic int eloop_sock_queue(int sock, eloop_event_type type)
228b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt{
229b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	int filter;
230b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	struct kevent ke;
231b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
232b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	switch (type) {
233b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	case EVENT_TYPE_READ:
234b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		filter = EVFILT_READ;
235b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		break;
236b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	case EVENT_TYPE_WRITE:
237b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		filter = EVFILT_WRITE;
238b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		break;
239b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	default:
240b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		filter = 0;
241b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	}
24257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	EV_SET(&ke, sock, filter, EV_ADD, 0, 0, 0);
243b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) {
244b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s",
245b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			   __func__, sock, strerror(errno));
246b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		return -1;
247b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	}
248b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	return 0;
249b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt}
250b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
251b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
252b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eloop_sock_table_add_sock(struct eloop_sock_table *table,
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                     int sock, eloop_sock_handler handler,
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                     void *eloop_data, void *user_data)
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
25750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
258b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	struct epoll_event *temp_events;
259b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
260b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
261b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	struct kevent *temp_events;
262b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
263b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
26450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	struct eloop_sock *temp_table;
26550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	int next;
266b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_sock *tmp;
268c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	int new_max_sock;
269c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
270c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (sock > eloop.max_sock)
271c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		new_max_sock = sock;
272c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	else
273c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		new_max_sock = eloop.max_sock;
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (table == NULL)
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
278c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#ifdef CONFIG_ELOOP_POLL
279c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (new_max_sock >= eloop.max_pollfd_map) {
280c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		struct pollfd **nmap;
28161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
28261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					sizeof(struct pollfd *));
283c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (nmap == NULL)
284c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			return -1;
285c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
286c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eloop.max_pollfd_map = new_max_sock + 50;
287c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eloop.pollfds_map = nmap;
288c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
289c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
290c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (eloop.count + 1 > eloop.max_poll_fds) {
291c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		struct pollfd *n;
292c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		int nmax = eloop.count + 1 + 50;
29361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		n = os_realloc_array(eloop.pollfds, nmax,
29461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				     sizeof(struct pollfd));
295c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (n == NULL)
296c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			return -1;
297c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
298c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eloop.max_poll_fds = nmax;
299c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eloop.pollfds = n;
300c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
301c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#endif /* CONFIG_ELOOP_POLL */
302b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
303b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (new_max_sock >= eloop.max_fd) {
304b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		next = eloop.max_fd == 0 ? 16 : eloop.max_fd * 2;
305b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		temp_table = os_realloc_array(eloop.fd_table, next,
30650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt					      sizeof(struct eloop_sock));
30750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		if (temp_table == NULL)
30850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt			return -1;
30950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt
310b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		eloop.max_fd = next;
311b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		eloop.fd_table = temp_table;
31250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	}
313b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
31450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt
315b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
31650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	if (eloop.count + 1 > eloop.epoll_max_event_num) {
31750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		next = eloop.epoll_max_event_num == 0 ? 8 :
31850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt			eloop.epoll_max_event_num * 2;
31950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		temp_events = os_realloc_array(eloop.epoll_events, next,
32050b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt					       sizeof(struct epoll_event));
32150b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		if (temp_events == NULL) {
322b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			wpa_printf(MSG_ERROR, "%s: malloc for epoll failed: %s",
323b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt				   __func__, strerror(errno));
32450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt			return -1;
32550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		}
32650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt
32750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		eloop.epoll_max_event_num = next;
32850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		eloop.epoll_events = temp_events;
32950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	}
33050b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
331b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
332b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (eloop.count + 1 > eloop.kqueue_nevents) {
333b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		next = eloop.kqueue_nevents == 0 ? 8 : eloop.kqueue_nevents * 2;
334b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		temp_events = os_malloc(next * sizeof(*temp_events));
335b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		if (!temp_events) {
336b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			wpa_printf(MSG_ERROR,
337b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt				   "%s: malloc for kqueue failed: %s",
338b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt				   __func__, strerror(errno));
339b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			return -1;
340b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		}
341b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
342b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		os_free(eloop.kqueue_events);
343b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		eloop.kqueue_events = temp_events;
344b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		eloop.kqueue_nevents = next;
345b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	}
346b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
347c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_trace_sock_remove_ref(table);
34961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	tmp = os_realloc_array(table->table, table->count + 1,
35061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			       sizeof(struct eloop_sock));
351746bde5f922dfd627d25111da4313395bc4ed6afDmitry Shmidt	if (tmp == NULL) {
352746bde5f922dfd627d25111da4313395bc4ed6afDmitry Shmidt		eloop_trace_sock_add_ref(table);
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
354746bde5f922dfd627d25111da4313395bc4ed6afDmitry Shmidt	}
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp[table->count].sock = sock;
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp[table->count].eloop_data = eloop_data;
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp[table->count].user_data = user_data;
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp[table->count].handler = handler;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_trace_record(&tmp[table->count]);
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	table->count++;
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	table->table = tmp;
363c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	eloop.max_sock = new_max_sock;
364c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	eloop.count++;
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	table->changed = 1;
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_trace_sock_add_ref(table);
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
368b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
369b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (eloop_sock_queue(sock, table->type) < 0)
37050b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		return -1;
371b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1],
37250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		  sizeof(struct eloop_sock));
373b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                         int sock)
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
381b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
382b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	struct kevent ke;
383b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (table == NULL || table->table == NULL || table->count == 0)
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < table->count; i++) {
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (table->table[i].sock == sock)
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (i == table->count)
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_trace_sock_remove_ref(table);
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (i != table->count - 1) {
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memmove(&table->table[i], &table->table[i + 1],
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (table->count - i - 1) *
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   sizeof(struct eloop_sock));
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	table->count--;
402c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	eloop.count--;
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	table->changed = 1;
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_trace_sock_add_ref(table);
40550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
40650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
407b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d failed: %s",
408b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			   __func__, sock, strerror(errno));
40950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		return;
41050b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	}
411b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
41250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
413b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
41457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	EV_SET(&ke, sock, 0, EV_DELETE, 0, 0, 0);
415b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) {
416b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s",
417b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			   __func__, sock, strerror(errno));
418b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		return;
419b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	}
420b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
421b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
425c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#ifdef CONFIG_ELOOP_POLL
426c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
427c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtstatic struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
428c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt{
429c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (fd < mx && fd >= 0)
430c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return pollfds_map[fd];
431c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	return NULL;
432c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt}
433c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
434c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
435c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtstatic int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
436c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				    struct eloop_sock_table *writers,
437c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				    struct eloop_sock_table *exceptions,
438c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				    struct pollfd *pollfds,
439c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				    struct pollfd **pollfds_map,
440c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				    int max_pollfd_map)
441c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt{
442c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	int i;
443c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	int nxt = 0;
444c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	int fd;
445c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	struct pollfd *pfd;
446c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
447c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/* Clear pollfd lookup map. It will be re-populated below. */
448c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
449c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
450c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (readers && readers->table) {
451c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		for (i = 0; i < readers->count; i++) {
452c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			fd = readers->table[i].sock;
453c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			assert(fd >= 0 && fd < max_pollfd_map);
454c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			pollfds[nxt].fd = fd;
455c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			pollfds[nxt].events = POLLIN;
456c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			pollfds[nxt].revents = 0;
457c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			pollfds_map[fd] = &(pollfds[nxt]);
458c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			nxt++;
459c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		}
460c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
461c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
462c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (writers && writers->table) {
463c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		for (i = 0; i < writers->count; i++) {
464c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			/*
465c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			 * See if we already added this descriptor, update it
466c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			 * if so.
467c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			 */
468c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			fd = writers->table[i].sock;
469c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			assert(fd >= 0 && fd < max_pollfd_map);
470c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			pfd = pollfds_map[fd];
471c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			if (!pfd) {
472c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				pfd = &(pollfds[nxt]);
473c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				pfd->events = 0;
474c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				pfd->fd = fd;
475c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				pollfds[i].revents = 0;
476c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				pollfds_map[fd] = pfd;
477c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				nxt++;
478c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			}
47904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			pfd->events |= POLLOUT;
480c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		}
481c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
482c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
483c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
484c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * Exceptions are always checked when using poll, but I suppose it's
485c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * possible that someone registered a socket *only* for exception
486c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * handling. Set the POLLIN bit in this case.
487c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
488c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (exceptions && exceptions->table) {
489c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		for (i = 0; i < exceptions->count; i++) {
490c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			/*
491c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			 * See if we already added this descriptor, just use it
492c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			 * if so.
493c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			 */
494c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			fd = exceptions->table[i].sock;
495c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			assert(fd >= 0 && fd < max_pollfd_map);
496c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			pfd = pollfds_map[fd];
497c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			if (!pfd) {
498c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				pfd = &(pollfds[nxt]);
499c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				pfd->events = POLLIN;
500c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				pfd->fd = fd;
501c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				pollfds[i].revents = 0;
502c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				pollfds_map[fd] = pfd;
503c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				nxt++;
504c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			}
505c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		}
506c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
507c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
508c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	return nxt;
509c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt}
510c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
511c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
512c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtstatic int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
513c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					   struct pollfd **pollfds_map,
514c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					   int max_pollfd_map,
515c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					   short int revents)
516c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt{
517c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	int i;
518c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	struct pollfd *pfd;
519c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
520c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (!table || !table->table)
521c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return 0;
522c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
523c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	table->changed = 0;
524c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	for (i = 0; i < table->count; i++) {
525c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		pfd = find_pollfd(pollfds_map, table->table[i].sock,
526c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				  max_pollfd_map);
527c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (!pfd)
528c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			continue;
529c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
530c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (!(pfd->revents & revents))
531c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			continue;
532c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
533c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		table->table[i].handler(table->table[i].sock,
534c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					table->table[i].eloop_data,
535c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					table->table[i].user_data);
536c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (table->changed)
537c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			return 1;
538c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
539c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
540c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	return 0;
541c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt}
542c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
543c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
544c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtstatic void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
545c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				      struct eloop_sock_table *writers,
546c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				      struct eloop_sock_table *exceptions,
547c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				      struct pollfd **pollfds_map,
548c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				      int max_pollfd_map)
549c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt{
550c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (eloop_sock_table_dispatch_table(readers, pollfds_map,
55104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					    max_pollfd_map, POLLIN | POLLERR |
55204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					    POLLHUP))
553c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return; /* pollfds may be invalid at this point */
554c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
555c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (eloop_sock_table_dispatch_table(writers, pollfds_map,
556c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					    max_pollfd_map, POLLOUT))
557c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return; /* pollfds may be invalid at this point */
558c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
559c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	eloop_sock_table_dispatch_table(exceptions, pollfds_map,
560c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					max_pollfd_map, POLLERR | POLLHUP);
561c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt}
562c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
56350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_POLL */
56450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt
56550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_SELECT
566c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eloop_sock_table_set_fds(struct eloop_sock_table *table,
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     fd_set *fds)
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	FD_ZERO(fds);
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (table->table == NULL)
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
577df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	for (i = 0; i < table->count; i++) {
578df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		assert(table->table[i].sock >= 0);
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		FD_SET(table->table[i].sock, fds);
580df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eloop_sock_table_dispatch(struct eloop_sock_table *table,
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      fd_set *fds)
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (table == NULL || table->table == NULL)
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	table->changed = 0;
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < table->count; i++) {
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (FD_ISSET(table->table[i].sock, fds)) {
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			table->table[i].handler(table->table[i].sock,
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						table->table[i].eloop_data,
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						table->table[i].user_data);
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (table->changed)
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_SELECT */
60550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt
60650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt
60750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
60850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidtstatic void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
60950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt{
61050b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	struct eloop_sock *table;
61150b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	int i;
61250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt
61350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	for (i = 0; i < nfds; i++) {
614b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		table = &eloop.fd_table[events[i].data.fd];
61550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		if (table->handler == NULL)
61650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt			continue;
61750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		table->handler(table->sock, table->eloop_data,
61850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt			       table->user_data);
619d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (eloop.readers.changed ||
620d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		    eloop.writers.changed ||
621d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		    eloop.exceptions.changed)
622d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			break;
62350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	}
62450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt}
62550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
626c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
628b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
629b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
630b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidtstatic void eloop_sock_table_dispatch(struct kevent *events, int nfds)
631b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt{
632b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	struct eloop_sock *table;
633b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	int i;
634b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
635b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	for (i = 0; i < nfds; i++) {
636b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		table = &eloop.fd_table[events[i].ident];
637b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		if (table->handler == NULL)
638b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			continue;
639b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		table->handler(table->sock, table->eloop_data,
640b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			       table->user_data);
641b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		if (eloop.readers.changed ||
642b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		    eloop.writers.changed ||
643b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		    eloop.exceptions.changed)
644b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			break;
645b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	}
646b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt}
647b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
648b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
649b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidtstatic int eloop_sock_table_requeue(struct eloop_sock_table *table)
650b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt{
651b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	int i, r;
652b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
653b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	r = 0;
654b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	for (i = 0; i < table->count && table->table; i++) {
655b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		if (eloop_sock_queue(table->table[i].sock, table->type) == -1)
656b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			r = -1;
657b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	}
658b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	return r;
659b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt}
660b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
661b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
662b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
663b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
664b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidtint eloop_sock_requeue(void)
665b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt{
666b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	int r = 0;
667b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
668b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
669b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	close(eloop.kqueuefd);
670b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	eloop.kqueuefd = kqueue();
671b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (eloop.kqueuefd < 0) {
672b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
673b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			   __func__, strerror(errno));
674b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		return -1;
675b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	}
676b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
677b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (eloop_sock_table_requeue(&eloop.readers) < 0)
678b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		r = -1;
679b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (eloop_sock_table_requeue(&eloop.writers) < 0)
680b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		r = -1;
681b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (eloop_sock_table_requeue(&eloop.exceptions) < 0)
682b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		r = -1;
683b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
684b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
685b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	return r;
686b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt}
687b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
688b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eloop_sock_table_destroy(struct eloop_sock_table *table)
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (table) {
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int i;
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < table->count && table->table; i++) {
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "sock=%d eloop_data=%p user_data=%p "
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "handler=%p",
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   table->table[i].sock,
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   table->table[i].eloop_data,
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   table->table[i].user_data,
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   table->table[i].handler);
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_trace_dump_funcname("eloop unregistered socket "
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						"handler",
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						table->table[i].handler);
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_trace_dump("eloop sock", &table->table[i]);
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(table->table);
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eloop_register_read_sock(int sock, eloop_sock_handler handler,
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     void *eloop_data, void *user_data)
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   eloop_data, user_data);
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eloop_unregister_read_sock(int sock)
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_unregister_sock(sock, EVENT_TYPE_READ);
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (type) {
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EVENT_TYPE_READ:
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return &eloop.readers;
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EVENT_TYPE_WRITE:
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return &eloop.writers;
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EVENT_TYPE_EXCEPTION:
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return &eloop.exceptions;
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eloop_register_sock(int sock, eloop_event_type type,
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eloop_sock_handler handler,
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			void *eloop_data, void *user_data)
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_sock_table *table;
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
746df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	assert(sock >= 0);
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	table = eloop_get_sock_table(type);
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return eloop_sock_table_add_sock(table, sock, handler,
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 eloop_data, user_data);
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eloop_unregister_sock(int sock, eloop_event_type type)
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_sock_table *table;
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	table = eloop_get_sock_table(type);
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_sock_table_remove_sock(table, sock);
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eloop_register_timeout(unsigned int secs, unsigned int usecs,
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   eloop_timeout_handler handler,
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   void *eloop_data, void *user_data)
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_timeout *timeout, *tmp;
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_time_t now_sec;
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	timeout = os_zalloc(sizeof(*timeout));
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (timeout == NULL)
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
772fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt	if (os_get_reltime(&timeout->time) < 0) {
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(timeout);
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	now_sec = timeout->time.sec;
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	timeout->time.sec += secs;
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (timeout->time.sec < now_sec) {
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Integer overflow - assume long enough timeout to be assumed
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * to be infinite, i.e., the timeout would never happen.
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "ever happen - ignore it", secs);
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(timeout);
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	timeout->time.usec += usecs;
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (timeout->time.usec >= 1000000) {
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		timeout->time.sec++;
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		timeout->time.usec -= 1000000;
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	timeout->eloop_data = eloop_data;
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	timeout->user_data = user_data;
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	timeout->handler = handler;
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_trace_add_ref(timeout, eloop, eloop_data);
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_trace_add_ref(timeout, user, user_data);
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_trace_record(timeout);
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Maintain timeouts in order of increasing time */
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
802fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt		if (os_reltime_before(&timeout->time, &tmp->time)) {
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			dl_list_add(tmp->list.prev, &timeout->list);
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_add_tail(&eloop.timeout, &timeout->list);
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eloop_remove_timeout(struct eloop_timeout *timeout)
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_del(&timeout->list);
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_trace_remove_ref(timeout, user, timeout->user_data);
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(timeout);
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eloop_cancel_timeout(eloop_timeout_handler handler,
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 void *eloop_data, void *user_data)
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_timeout *timeout, *prev;
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int removed = 0;
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      struct eloop_timeout, list) {
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (timeout->handler == handler &&
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (timeout->eloop_data == eloop_data ||
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     eloop_data == ELOOP_ALL_CTX) &&
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (timeout->user_data == user_data ||
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     user_data == ELOOP_ALL_CTX)) {
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eloop_remove_timeout(timeout);
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			removed++;
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return removed;
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8444b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtint eloop_cancel_timeout_one(eloop_timeout_handler handler,
8454b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt			     void *eloop_data, void *user_data,
846fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt			     struct os_reltime *remaining)
8474b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
8484b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct eloop_timeout *timeout, *prev;
8494b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	int removed = 0;
850fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt	struct os_reltime now;
8514b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
852fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt	os_get_reltime(&now);
8534b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	remaining->sec = remaining->usec = 0;
8544b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
8554b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
8564b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt			      struct eloop_timeout, list) {
8574b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		if (timeout->handler == handler &&
8584b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		    (timeout->eloop_data == eloop_data) &&
8594b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		    (timeout->user_data == user_data)) {
8604b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt			removed = 1;
861fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt			if (os_reltime_before(&now, &timeout->time))
862fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt				os_reltime_sub(&timeout->time, &now, remaining);
8634b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt			eloop_remove_timeout(timeout);
8644b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt			break;
8654b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		}
8664b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	}
8674b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return removed;
8684b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
8694b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
8704b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eloop_is_timeout_registered(eloop_timeout_handler handler,
8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				void *eloop_data, void *user_data)
8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_timeout *tmp;
8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tmp->handler == handler &&
8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    tmp->eloop_data == eloop_data &&
8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    tmp->user_data == user_data)
8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 1;
8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
887e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidtint eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
888e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt			  eloop_timeout_handler handler, void *eloop_data,
889e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt			  void *user_data)
890e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt{
891fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt	struct os_reltime now, requested, remaining;
892e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	struct eloop_timeout *tmp;
893e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
894e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
895e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt		if (tmp->handler == handler &&
896e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt		    tmp->eloop_data == eloop_data &&
897e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt		    tmp->user_data == user_data) {
898e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt			requested.sec = req_secs;
899e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt			requested.usec = req_usecs;
900fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt			os_get_reltime(&now);
901fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt			os_reltime_sub(&tmp->time, &now, &remaining);
902fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt			if (os_reltime_before(&requested, &remaining)) {
903e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt				eloop_cancel_timeout(handler, eloop_data,
904e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt						     user_data);
905e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt				eloop_register_timeout(requested.sec,
906e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt						       requested.usec,
907e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt						       handler, eloop_data,
908e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt						       user_data);
909e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt				return 1;
910e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt			}
911fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			return 0;
912e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt		}
913e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	}
914e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
915fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	return -1;
916e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt}
917e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
918e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
9195460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidtint eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
9205460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			    eloop_timeout_handler handler, void *eloop_data,
9215460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			    void *user_data)
9225460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt{
923fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt	struct os_reltime now, requested, remaining;
9245460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	struct eloop_timeout *tmp;
9255460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
9265460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
9275460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		if (tmp->handler == handler &&
9285460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		    tmp->eloop_data == eloop_data &&
9295460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		    tmp->user_data == user_data) {
9305460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			requested.sec = req_secs;
9315460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			requested.usec = req_usecs;
932fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt			os_get_reltime(&now);
933fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt			os_reltime_sub(&tmp->time, &now, &remaining);
934fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt			if (os_reltime_before(&remaining, &requested)) {
9355460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt				eloop_cancel_timeout(handler, eloop_data,
9365460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt						     user_data);
9375460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt				eloop_register_timeout(requested.sec,
9385460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt						       requested.usec,
9395460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt						       handler, eloop_data,
9405460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt						       user_data);
9415460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt				return 1;
9425460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			}
943fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			return 0;
9445460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		}
9455460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	}
9465460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
947fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	return -1;
9485460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt}
9495460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
9505460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NATIVE_WINDOWS
9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eloop_handle_alarm(int sig)
9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "two seconds. Looks like there\n"
9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "is a bug that ends up in a busy loop that "
9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "prevents clean shutdown.\n"
9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "Killing program forcefully.\n");
9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	exit(1);
9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NATIVE_WINDOWS */
9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eloop_handle_signal(int sig)
9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NATIVE_WINDOWS
9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Use SIGALRM to break out from potential busy loops that
9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * would not allow the program to be killed. */
9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop.pending_terminate = 1;
9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		signal(SIGALRM, eloop_handle_alarm);
9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		alarm(2);
9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NATIVE_WINDOWS */
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop.signaled++;
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < eloop.signal_count; i++) {
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (eloop.signals[i].sig == sig) {
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eloop.signals[i].signaled++;
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eloop_process_pending_signals(void)
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eloop.signaled == 0)
9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop.signaled = 0;
9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eloop.pending_terminate) {
9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NATIVE_WINDOWS
9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		alarm(0);
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NATIVE_WINDOWS */
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop.pending_terminate = 0;
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < eloop.signal_count; i++) {
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (eloop.signals[i].signaled) {
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eloop.signals[i].signaled = 0;
10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eloop.signals[i].handler(eloop.signals[i].sig,
10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 eloop.signals[i].user_data);
10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eloop_register_signal(int sig, eloop_signal_handler handler,
10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  void *user_data)
10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_signal *tmp;
10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
101861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
101961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			       sizeof(struct eloop_signal));
10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tmp == NULL)
10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp[eloop.signal_count].sig = sig;
10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp[eloop.signal_count].user_data = user_data;
10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp[eloop.signal_count].handler = handler;
10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp[eloop.signal_count].signaled = 0;
10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop.signal_count++;
10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop.signals = tmp;
10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	signal(sig, eloop_handle_signal);
10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eloop_register_signal_terminate(eloop_signal_handler handler,
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    void *user_data)
10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = eloop_register_signal(SIGINT, handler, user_data);
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0)
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = eloop_register_signal(SIGTERM, handler, user_data);
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eloop_register_signal_reconfig(eloop_signal_handler handler,
10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   void *user_data)
10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_NATIVE_WINDOWS
10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* CONFIG_NATIVE_WINDOWS */
10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return eloop_register_signal(SIGHUP, handler, user_data);
10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NATIVE_WINDOWS */
10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eloop_run(void)
10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1058c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#ifdef CONFIG_ELOOP_POLL
1059c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	int num_poll_fds;
1060c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	int timeout_ms = 0;
106150b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_POLL */
106250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_SELECT
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fd_set *rfds, *wfds, *efds;
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct timeval _tv;
106550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_SELECT */
106650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
106750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	int timeout_ms = -1;
106850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
1069b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
1070b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	struct timespec ts;
1071b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
1072c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	int res;
1073fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt	struct os_reltime tv, now;
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
107550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_SELECT
10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rfds = os_malloc(sizeof(*rfds));
10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wfds = os_malloc(sizeof(*wfds));
10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	efds = os_malloc(sizeof(*efds));
10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rfds == NULL || wfds == NULL || efds == NULL)
10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out;
108150b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_SELECT */
10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (!eloop.terminate &&
10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct eloop_timeout *timeout;
1087d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1088d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (eloop.pending_terminate) {
1089d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			/*
1090d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			 * This may happen in some corner cases where a signal
1091d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			 * is received during a blocking operation. We need to
1092d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			 * process the pending signals and exit if requested to
1093d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			 * avoid hitting the SIGALRM limit if the blocking
1094d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			 * operation took more than two seconds.
1095d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			 */
1096d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			eloop_process_pending_signals();
1097d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			if (eloop.terminate)
1098d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				break;
1099d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		}
1100d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					list);
11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (timeout) {
1104fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt			os_get_reltime(&now);
1105fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt			if (os_reltime_before(&now, &timeout->time))
1106fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt				os_reltime_sub(&timeout->time, &now, &tv);
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				tv.sec = tv.usec = 0;
110950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
1110c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			timeout_ms = tv.sec * 1000 + tv.usec / 1000;
111150b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
111250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_SELECT
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			_tv.tv_sec = tv.sec;
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			_tv.tv_usec = tv.usec;
111550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_SELECT */
1116b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
1117b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			ts.tv_sec = tv.sec;
1118b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			ts.tv_nsec = tv.usec * 1000L;
1119b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1122c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#ifdef CONFIG_ELOOP_POLL
1123c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		num_poll_fds = eloop_sock_table_set_fds(
1124c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			&eloop.readers, &eloop.writers, &eloop.exceptions,
1125c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			eloop.pollfds, eloop.pollfds_map,
1126c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			eloop.max_pollfd_map);
1127c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		res = poll(eloop.pollfds, num_poll_fds,
1128c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			   timeout ? timeout_ms : -1);
112950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_POLL */
113050b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_SELECT
11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_sock_table_set_fds(&eloop.readers, rfds);
11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_sock_table_set_fds(&eloop.writers, wfds);
11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_sock_table_set_fds(&eloop.exceptions, efds);
11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res = select(eloop.max_sock + 1, rfds, wfds, efds,
11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     timeout ? &_tv : NULL);
113650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_SELECT */
113750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
113850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		if (eloop.count == 0) {
113950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt			res = 0;
114050b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		} else {
114150b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt			res = epoll_wait(eloop.epollfd, eloop.epoll_events,
114250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt					 eloop.count, timeout_ms);
114350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		}
114450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
1145b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
1146b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		if (eloop.count == 0) {
1147b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			res = 0;
1148b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		} else {
1149b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			res = kevent(eloop.kqueuefd, NULL, 0,
1150b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt				     eloop.kqueue_events, eloop.kqueue_nevents,
1151b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt				     timeout ? &ts : NULL);
1152b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		}
1153b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (res < 0 && errno != EINTR && errno != 0) {
115550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt			wpa_printf(MSG_ERROR, "eloop: %s: %s",
115650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_POLL
115750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt				   "poll"
115850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_POLL */
115950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_SELECT
116050b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt				   "select"
116150b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_SELECT */
116250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
116350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt				   "epoll"
116450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
1165b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
1166b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt				   "kqueue"
1167b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_EKQUEUE */
1168b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
116950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt				   , strerror(errno));
11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto out;
11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1172d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1173d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		eloop.readers.changed = 0;
1174d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		eloop.writers.changed = 0;
1175d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		eloop.exceptions.changed = 0;
1176d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_process_pending_signals();
11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1179b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* check if some registered timeouts have occurred */
11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					list);
11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (timeout) {
1184fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt			os_get_reltime(&now);
1185fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt			if (!os_reltime_before(&now, &timeout->time)) {
11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				void *eloop_data = timeout->eloop_data;
11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				void *user_data = timeout->user_data;
11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				eloop_timeout_handler handler =
11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					timeout->handler;
11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				eloop_remove_timeout(timeout);
11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				handler(eloop_data, user_data);
11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (res <= 0)
11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1199d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (eloop.readers.changed ||
1200d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		    eloop.writers.changed ||
1201d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		    eloop.exceptions.changed) {
1202d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			 /*
1203d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			  * Sockets may have been closed and reopened with the
1204d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			  * same FD in the signal or timeout handlers, so we
1205d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			  * must skip the previous results and check again
1206d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			  * whether any of the currently registered sockets have
1207d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			  * events.
1208d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			  */
1209d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			continue;
1210d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		}
1211d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1212c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#ifdef CONFIG_ELOOP_POLL
1213c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
1214c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					  &eloop.exceptions, eloop.pollfds_map,
1215c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					  eloop.max_pollfd_map);
121650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_POLL */
121750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_SELECT
12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_sock_table_dispatch(&eloop.readers, rfds);
12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_sock_table_dispatch(&eloop.writers, wfds);
12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_sock_table_dispatch(&eloop.exceptions, efds);
122150b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_SELECT */
122250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
122350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		eloop_sock_table_dispatch(eloop.epoll_events, res);
122450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
1225b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
1226b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		eloop_sock_table_dispatch(eloop.kqueue_events, res);
1227b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1230ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	eloop.terminate = 0;
12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtout:
123250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_SELECT
12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(rfds);
12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(wfds);
12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(efds);
123650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_SELECT */
1237c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	return;
12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eloop_terminate(void)
12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop.terminate = 1;
12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eloop_destroy(void)
12488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eloop_timeout *timeout, *prev;
1250fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt	struct os_reltime now;
12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1252fa3fc4a1ac08ad14272301c7f6f01b362997c3e4Dmitry Shmidt	os_get_reltime(&now);
12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
12548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      struct eloop_timeout, list) {
12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int sec, usec;
12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sec = timeout->time.sec - now.sec;
12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		usec = timeout->time.usec - now.usec;
12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (timeout->time.usec < now.usec) {
12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sec--;
12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			usec += 1000000;
12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
12638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "eloop_data=%p user_data=%p handler=%p",
12648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   sec, usec, timeout->eloop_data, timeout->user_data,
12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   timeout->handler);
12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_trace_dump_funcname("eloop unregistered timeout handler",
12678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					timeout->handler);
12688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_trace_dump("eloop timeout", timeout);
12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_remove_timeout(timeout);
12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_sock_table_destroy(&eloop.readers);
12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_sock_table_destroy(&eloop.writers);
12738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_sock_table_destroy(&eloop.exceptions);
12748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(eloop.signals);
1275c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
1276c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#ifdef CONFIG_ELOOP_POLL
1277c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	os_free(eloop.pollfds);
1278c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	os_free(eloop.pollfds_map);
1279c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#endif /* CONFIG_ELOOP_POLL */
1280b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
1281b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	os_free(eloop.fd_table);
1282b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
128350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_EPOLL
128450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	os_free(eloop.epoll_events);
128550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	close(eloop.epollfd);
128650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_EPOLL */
1287b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
1288b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	os_free(eloop.kqueue_events);
1289b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	close(eloop.kqueuefd);
1290b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
12918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eloop_terminated(void)
12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1296d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	return eloop.terminate || eloop.pending_terminate;
12978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eloop_wait_for_read_sock(int sock)
13018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1302c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#ifdef CONFIG_ELOOP_POLL
1303c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	struct pollfd pfd;
1304c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
1305c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (sock < 0)
1306c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return;
1307c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
1308c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	os_memset(&pfd, 0, sizeof(pfd));
1309c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	pfd.fd = sock;
1310c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	pfd.events = POLLIN;
1311c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
1312c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	poll(&pfd, 1, -1);
131350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_POLL */
131450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL)
131550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	/*
131650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	 * We can use epoll() here. But epoll() requres 4 system calls.
131750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	 * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for
131850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	 * epoll fd. So select() is better for performance here.
131950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	 */
13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fd_set rfds;
13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sock < 0)
13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
13248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	FD_ZERO(&rfds);
13268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	FD_SET(sock, &rfds);
13278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	select(sock + 1, &rfds, NULL, NULL, NULL);
132850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */
1329b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#ifdef CONFIG_ELOOP_KQUEUE
1330b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	int kfd;
1331b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	struct kevent ke1, ke2;
1332b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
1333b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	kfd = kqueue();
1334b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (kfd == -1)
1335b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		return;
133657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	EV_SET(&ke1, sock, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
1337b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	kevent(kfd, &ke1, 1, &ke2, 1, NULL);
1338b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	close(kfd);
1339b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt#endif /* CONFIG_ELOOP_KQUEUE */
13408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
134150b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt
134250b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifdef CONFIG_ELOOP_SELECT
134350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#undef CONFIG_ELOOP_SELECT
134450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* CONFIG_ELOOP_SELECT */
1345