diff mbox series

eloop: Remove epoll and kqueue implementations

Message ID 20240926153459.676799-1-benjamin@sipsolutions.net
State New
Headers show
Series eloop: Remove epoll and kqueue implementations | expand

Commit Message

Benjamin Berg Sept. 26, 2024, 3:34 p.m. UTC
From: Benjamin Berg <benjamin.berg@intel.com>

Both of these implementations are broken by design currently and will
not work correctly with any socket that needs to be registered for
multiple event types (reading, writing, exception).

The reason for this is that the eloop_register_sock API can only take
one event at a time resulting in multiple entries for the FD. However,
epoll_ctl() will refuse to register the FD a second time and kqueue()
will happily overwrite the earlier information. As such, neither
implementation is working correctly.

Simply remove both, I doubt anyone ever tried to use them as at least
DBus is broken. Also, I don't expect that hostapd/wpa_supplicant has a
lot of FDs/sockets making this a micro-optimization which is likely
pointless in the first place.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
---
 hostapd/Android.mk            |   4 -
 hostapd/Makefile              |   8 -
 hostapd/android.config        |   3 -
 hostapd/defconfig             |   6 -
 src/utils/eloop.c             | 354 +---------------------------------
 src/utils/eloop.h             |   3 +-
 wpa_supplicant/Android.mk     |   4 -
 wpa_supplicant/Makefile       |   8 -
 wpa_supplicant/android.config |   6 -
 wpa_supplicant/defconfig      |   6 -
 10 files changed, 7 insertions(+), 395 deletions(-)

Comments

Nicolas Escande Oct. 3, 2024, 1:59 p.m. UTC | #1
Hello Benjamin,

On Thu Sep 26, 2024 at 5:34 PM CEST, Benjamin Berg wrote:
> From: Benjamin Berg <benjamin.berg@intel.com>
>
> Both of these implementations are broken by design currently and will
> not work correctly with any socket that needs to be registered for
> multiple event types (reading, writing, exception).
>
> The reason for this is that the eloop_register_sock API can only take
> one event at a time resulting in multiple entries for the FD. However,
> epoll_ctl() will refuse to register the FD a second time and kqueue()
> will happily overwrite the earlier information. As such, neither
> implementation is working correctly.

I never even realized that sometimes hostapd registers a socket for writing.

> Simply remove both, I doubt anyone ever tried to use them as at least
> DBus is broken. Also, I don't expect that hostapd/wpa_supplicant has a
> lot of FDs/sockets making this a micro-optimization which is likely
> pointless in the first place.
>
Actually, in our product we heavily use the epoll implementation, but with a
very light config / feature set (no dbus or dpp...) so we never encountered a
problem of that nature.

Instead of removing the code, we could $(error ) or # error for incompatible
configs ? But it seems hard to maintain in the long run when we add new stuff.
Either way, I don't really care as long as the poll implementationworks, we'll
switch to it if need be.
Benjamin Berg Oct. 3, 2024, 2:47 p.m. UTC | #2
On Thu, 2024-10-03 at 15:59 +0200, Nicolas Escande wrote:
> Hello Benjamin,
> 
> On Thu Sep 26, 2024 at 5:34 PM CEST, Benjamin Berg wrote:
> > From: Benjamin Berg <benjamin.berg@intel.com>
> > 
> > Both of these implementations are broken by design currently and will
> > not work correctly with any socket that needs to be registered for
> > multiple event types (reading, writing, exception).
> > 
> > The reason for this is that the eloop_register_sock API can only take
> > one event at a time resulting in multiple entries for the FD. However,
> > epoll_ctl() will refuse to register the FD a second time and kqueue()
> > will happily overwrite the earlier information. As such, neither
> > implementation is working correctly.
> 
> I never even realized that sometimes hostapd registers a socket for writing.

I think in the DBus case it is exceptions and either reading or
writing. There are also the DPP/HTTP/Radius clients that register
writing, but that might work just fine as long as only one event type
is active at a time.

> > Simply remove both, I doubt anyone ever tried to use them as at least
> > DBus is broken. Also, I don't expect that hostapd/wpa_supplicant has a
> > lot of FDs/sockets making this a micro-optimization which is likely
> > pointless in the first place.
> > 
> Actually, in our product we heavily use the epoll implementation, but with a
> very light config / feature set (no dbus or dpp...) so we never encountered a
> problem of that nature.
> 
> Instead of removing the code, we could $(error ) or # error for incompatible
> configs ? But it seems hard to maintain in the long run when we add new stuff.
> Either way, I don't really care as long as the poll implementationworks, we'll
> switch to it if need be.

To be honest, one motivation for me to remove it entirely was because
it seemed unnecessarily hard to work with the code (I would have a hard
time testing kqueue at least). And I was wondering whether it might be
worthwhile to add a prioritization feature to eloop as that could make
some event handling code more predictable. For example, one could
ensure all nl80211 events are processed before the next timeout is
fired.

All that said, do you maybe have an idea if it is actually making a
relevant performance difference?

Benjamin
Nicolas Escande Oct. 3, 2024, 5:15 p.m. UTC | #3
On Thu Oct 3, 2024 at 4:47 PM CEST, Benjamin Berg wrote:
> On Thu, 2024-10-03 at 15:59 +0200, Nicolas Escande wrote:
> > Hello Benjamin,
> > 
> > On Thu Sep 26, 2024 at 5:34 PM CEST, Benjamin Berg wrote:
> > > From: Benjamin Berg <benjamin.berg@intel.com>
> > > 
> > > Both of these implementations are broken by design currently and will
> > > not work correctly with any socket that needs to be registered for
> > > multiple event types (reading, writing, exception).
> > > 
> > > The reason for this is that the eloop_register_sock API can only take
> > > one event at a time resulting in multiple entries for the FD. However,
> > > epoll_ctl() will refuse to register the FD a second time and kqueue()
> > > will happily overwrite the earlier information. As such, neither
> > > implementation is working correctly.
> > 
> > I never even realized that sometimes hostapd registers a socket for writing.
>
> I think in the DBus case it is exceptions and either reading or
> writing. There are also the DPP/HTTP/Radius clients that register
> writing, but that might work just fine as long as only one event type
> is active at a time.
>
> > > Simply remove both, I doubt anyone ever tried to use them as at least
> > > DBus is broken. Also, I don't expect that hostapd/wpa_supplicant has a
> > > lot of FDs/sockets making this a micro-optimization which is likely
> > > pointless in the first place.
> > > 
> > Actually, in our product we heavily use the epoll implementation, but with a
> > very light config / feature set (no dbus or dpp...) so we never encountered a
> > problem of that nature.
> > 
> > Instead of removing the code, we could $(error ) or # error for incompatible
> > configs ? But it seems hard to maintain in the long run when we add new stuff.
> > Either way, I don't really care as long as the poll implementationworks, we'll
> > switch to it if need be.
>
> To be honest, one motivation for me to remove it entirely was because
> it seemed unnecessarily hard to work with the code (I would have a hard
> time testing kqueue at least). And I was wondering whether it might be
> worthwhile to add a prioritization feature to eloop as that could make
> some event handling code more predictable. For example, one could
> ensure all nl80211 events are processed before the next timeout is
> fired.

I just wanted to point out that in specific configs epoll was not broken. So
maybe, if the only motivation was "it's broken, lets not anybody be deceived
by a silently broken build, lets remove it", we could have gone the error way
instead. But it's more work, and I don't mind removing epoll as long as poll
works instead. kqueue is alien for me, I don't care for it at all.
>
> All that said, do you maybe have an idea if it is actually making a
> relevant performance difference?

No, not at all. I don't really care about performance, we want reliability first
and foremost.

>
> Benjamin

Nicolas
diff mbox series

Patch

diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 573564d5b0..c8495f2120 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -140,10 +140,6 @@  ifdef CONFIG_ELOOP_POLL
 L_CFLAGS += -DCONFIG_ELOOP_POLL
 endif
 
-ifdef CONFIG_ELOOP_EPOLL
-L_CFLAGS += -DCONFIG_ELOOP_EPOLL
-endif
-
 OBJS += src/utils/common.c
 OBJS += src/utils/wpa_debug.c
 OBJS += src/utils/wpabuf.c
diff --git a/hostapd/Makefile b/hostapd/Makefile
index ca4439234a..a2448eb407 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -143,14 +143,6 @@  ifdef CONFIG_ELOOP_POLL
 CFLAGS += -DCONFIG_ELOOP_POLL
 endif
 
-ifdef CONFIG_ELOOP_EPOLL
-CFLAGS += -DCONFIG_ELOOP_EPOLL
-endif
-
-ifdef CONFIG_ELOOP_KQUEUE
-CFLAGS += -DCONFIG_ELOOP_KQUEUE
-endif
-
 OBJS += ../src/utils/common.o
 OBJS_c += ../src/utils/common.o
 OBJS += ../src/utils/wpa_debug.o
diff --git a/hostapd/android.config b/hostapd/android.config
index 522de87266..ac74de84dc 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -180,9 +180,6 @@  CONFIG_OS=unix
 # Should we use poll instead of select? Select is used by default.
 #CONFIG_ELOOP_POLL=y
 
-# Should we use epoll instead of select? Select is used by default.
-#CONFIG_ELOOP_EPOLL=y
-
 # Enable AP
 CONFIG_AP=y
 
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 550db697bc..e6c457b1c8 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -271,12 +271,6 @@  CONFIG_IPV6=y
 # Should we use poll instead of select? Select is used by default.
 #CONFIG_ELOOP_POLL=y
 
-# Should we use epoll instead of select? Select is used by default.
-#CONFIG_ELOOP_EPOLL=y
-
-# Should we use kqueue instead of select? Select is used by default.
-#CONFIG_ELOOP_KQUEUE=y
-
 # Select TLS implementation
 # openssl = OpenSSL (default)
 # gnutls = GnuTLS
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index 00b0beff0b..cbb6dc8ade 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -14,16 +14,7 @@ 
 #include "list.h"
 #include "eloop.h"
 
-#if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL)
-#error Do not define both of poll and epoll
-#endif
-
-#if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_KQUEUE)
-#error Do not define both of poll and kqueue
-#endif
-
-#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) && \
-    !defined(CONFIG_ELOOP_KQUEUE)
+#if !defined(CONFIG_ELOOP_POLL)
 #define CONFIG_ELOOP_SELECT
 #endif
 
@@ -31,14 +22,6 @@ 
 #include <poll.h>
 #endif /* CONFIG_ELOOP_POLL */
 
-#ifdef CONFIG_ELOOP_EPOLL
-#include <sys/epoll.h>
-#endif /* CONFIG_ELOOP_EPOLL */
-
-#ifdef CONFIG_ELOOP_KQUEUE
-#include <sys/event.h>
-#endif /* CONFIG_ELOOP_KQUEUE */
-
 struct eloop_sock {
 	int sock;
 	void *eloop_data;
@@ -84,20 +67,6 @@  struct eloop_data {
 	struct pollfd *pollfds;
 	struct pollfd **pollfds_map;
 #endif /* CONFIG_ELOOP_POLL */
-#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
-	int max_fd;
-	struct eloop_sock *fd_table;
-#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
-#ifdef CONFIG_ELOOP_EPOLL
-	int epollfd;
-	size_t epoll_max_event_num;
-	struct epoll_event *epoll_events;
-#endif /* CONFIG_ELOOP_EPOLL */
-#ifdef CONFIG_ELOOP_KQUEUE
-	int kqueuefd;
-	size_t kqueue_nevents;
-	struct kevent *kqueue_events;
-#endif /* CONFIG_ELOOP_KQUEUE */
 	struct eloop_sock_table readers;
 	struct eloop_sock_table writers;
 	struct eloop_sock_table exceptions;
@@ -164,27 +133,6 @@  int eloop_init(void)
 {
 	os_memset(&eloop, 0, sizeof(eloop));
 	dl_list_init(&eloop.timeout);
-#ifdef CONFIG_ELOOP_EPOLL
-	eloop.epollfd = epoll_create1(0);
-	if (eloop.epollfd < 0) {
-		wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s",
-			   __func__, strerror(errno));
-		return -1;
-	}
-#endif /* CONFIG_ELOOP_EPOLL */
-#ifdef CONFIG_ELOOP_KQUEUE
-	eloop.kqueuefd = kqueue();
-	if (eloop.kqueuefd < 0) {
-		wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
-			   __func__, strerror(errno));
-		return -1;
-	}
-#endif /* CONFIG_ELOOP_KQUEUE */
-#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
-	eloop.readers.type = EVENT_TYPE_READ;
-	eloop.writers.type = EVENT_TYPE_WRITE;
-	eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
-#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
 #ifdef WPA_TRACE
 	signal(SIGSEGV, eloop_sigsegv_handler);
 #endif /* WPA_TRACE */
@@ -192,84 +140,10 @@  int eloop_init(void)
 }
 
 
-#ifdef CONFIG_ELOOP_EPOLL
-static int eloop_sock_queue(int sock, eloop_event_type type)
-{
-	struct epoll_event ev;
-
-	os_memset(&ev, 0, sizeof(ev));
-	switch (type) {
-	case EVENT_TYPE_READ:
-		ev.events = EPOLLIN;
-		break;
-	case EVENT_TYPE_WRITE:
-		ev.events = EPOLLOUT;
-		break;
-	/*
-	 * Exceptions are always checked when using epoll, but I suppose it's
-	 * possible that someone registered a socket *only* for exception
-	 * handling.
-	 */
-	case EVENT_TYPE_EXCEPTION:
-		ev.events = EPOLLERR | EPOLLHUP;
-		break;
-	}
-	ev.data.fd = sock;
-	if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
-		wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d failed: %s",
-			   __func__, sock, strerror(errno));
-		return -1;
-	}
-	return 0;
-}
-#endif /* CONFIG_ELOOP_EPOLL */
-
-
-#ifdef CONFIG_ELOOP_KQUEUE
-
-static short event_type_kevent_filter(eloop_event_type type)
-{
-	switch (type) {
-	case EVENT_TYPE_READ:
-		return EVFILT_READ;
-	case EVENT_TYPE_WRITE:
-		return EVFILT_WRITE;
-	default:
-		return 0;
-	}
-}
-
-
-static int eloop_sock_queue(int sock, eloop_event_type type)
-{
-	struct kevent ke;
-
-	EV_SET(&ke, sock, event_type_kevent_filter(type), EV_ADD, 0, 0, 0);
-	if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) {
-		wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s",
-			   __func__, sock, strerror(errno));
-		return -1;
-	}
-	return 0;
-}
-
-#endif /* CONFIG_ELOOP_KQUEUE */
-
-
 static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
                                      int sock, eloop_sock_handler handler,
                                      void *eloop_data, void *user_data)
 {
-#ifdef CONFIG_ELOOP_EPOLL
-	struct epoll_event *temp_events;
-#endif /* CONFIG_ELOOP_EPOLL */
-#ifdef CONFIG_ELOOP_KQUEUE
-	struct kevent *temp_events;
-#endif /* CONFIG_ELOOP_EPOLL */
-#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
-	struct eloop_sock *temp_table;
-	size_t next;
-#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
 	struct eloop_sock *tmp;
 	int new_max_sock;
 
@@ -306,51 +180,6 @@  static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
 		eloop.pollfds = n;
 	}
 #endif /* CONFIG_ELOOP_POLL */
-#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
-	if (new_max_sock >= eloop.max_fd) {
-		next = new_max_sock + 16;
-		temp_table = os_realloc_array(eloop.fd_table, next,
-					      sizeof(struct eloop_sock));
-		if (temp_table == NULL)
-			return -1;
-
-		eloop.max_fd = next;
-		eloop.fd_table = temp_table;
-	}
-#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
-
-#ifdef CONFIG_ELOOP_EPOLL
-	if (eloop.count + 1 > eloop.epoll_max_event_num) {
-		next = eloop.epoll_max_event_num == 0 ? 8 :
-			eloop.epoll_max_event_num * 2;
-		temp_events = os_realloc_array(eloop.epoll_events, next,
-					       sizeof(struct epoll_event));
-		if (temp_events == NULL) {
-			wpa_printf(MSG_ERROR, "%s: malloc for epoll failed: %s",
-				   __func__, strerror(errno));
-			return -1;
-		}
-
-		eloop.epoll_max_event_num = next;
-		eloop.epoll_events = temp_events;
-	}
-#endif /* CONFIG_ELOOP_EPOLL */
-#ifdef CONFIG_ELOOP_KQUEUE
-	if (eloop.count + 1 > eloop.kqueue_nevents) {
-		next = eloop.kqueue_nevents == 0 ? 8 : eloop.kqueue_nevents * 2;
-		temp_events = os_malloc(next * sizeof(*temp_events));
-		if (!temp_events) {
-			wpa_printf(MSG_ERROR,
-				   "%s: malloc for kqueue failed: %s",
-				   __func__, strerror(errno));
-			return -1;
-		}
-
-		os_free(eloop.kqueue_events);
-		eloop.kqueue_events = temp_events;
-		eloop.kqueue_nevents = next;
-	}
-#endif /* CONFIG_ELOOP_KQUEUE */
 
 	eloop_trace_sock_remove_ref(table);
 	tmp = os_realloc_array(table->table, table->count + 1,
@@ -372,12 +201,6 @@  static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
 	table->changed = 1;
 	eloop_trace_sock_add_ref(table);
 
-#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
-	if (eloop_sock_queue(sock, table->type) < 0)
-		return -1;
-	os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1],
-		  sizeof(struct eloop_sock));
-#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
 	return 0;
 }
 
@@ -385,9 +208,6 @@  static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
 static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
                                          int sock)
 {
-#ifdef CONFIG_ELOOP_KQUEUE
-	struct kevent ke;
-#endif /* CONFIG_ELOOP_KQUEUE */
 	size_t i;
 
 	if (table == NULL || table->table == NULL || table->count == 0)
@@ -409,24 +229,6 @@  static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
 	eloop.count--;
 	table->changed = 1;
 	eloop_trace_sock_add_ref(table);
-#ifdef CONFIG_ELOOP_EPOLL
-	if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
-		wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d failed: %s",
-			   __func__, sock, strerror(errno));
-		return;
-	}
-	os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
-#endif /* CONFIG_ELOOP_EPOLL */
-#ifdef CONFIG_ELOOP_KQUEUE
-	EV_SET(&ke, sock, event_type_kevent_filter(table->type), EV_DELETE, 0,
-	       0, 0);
-	if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) {
-		wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s",
-			   __func__, sock, strerror(errno));
-		return;
-	}
-	os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
-#endif /* CONFIG_ELOOP_KQUEUE */
 }
 
 
@@ -611,87 +413,9 @@  static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
 
 #endif /* CONFIG_ELOOP_SELECT */
 
-
-#ifdef CONFIG_ELOOP_EPOLL
-static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
-{
-	struct eloop_sock *table;
-	int i;
-
-	for (i = 0; i < nfds; i++) {
-		table = &eloop.fd_table[events[i].data.fd];
-		if (table->handler == NULL)
-			continue;
-		table->handler(table->sock, table->eloop_data,
-			       table->user_data);
-		if (eloop.readers.changed ||
-		    eloop.writers.changed ||
-		    eloop.exceptions.changed)
-			break;
-	}
-}
-#endif /* CONFIG_ELOOP_EPOLL */
-
-
-#ifdef CONFIG_ELOOP_KQUEUE
-
-static void eloop_sock_table_dispatch(struct kevent *events, int nfds)
-{
-	struct eloop_sock *table;
-	int i;
-
-	for (i = 0; i < nfds; i++) {
-		table = &eloop.fd_table[events[i].ident];
-		if (table->handler == NULL)
-			continue;
-		table->handler(table->sock, table->eloop_data,
-			       table->user_data);
-		if (eloop.readers.changed ||
-		    eloop.writers.changed ||
-		    eloop.exceptions.changed)
-			break;
-	}
-}
-
-
-static int eloop_sock_table_requeue(struct eloop_sock_table *table)
-{
-	size_t i;
-	int r;
-
-	r = 0;
-	for (i = 0; i < table->count && table->table; i++) {
-		if (eloop_sock_queue(table->table[i].sock, table->type) == -1)
-			r = -1;
-	}
-	return r;
-}
-
-#endif /* CONFIG_ELOOP_KQUEUE */
-
-
 int eloop_sock_requeue(void)
 {
-	int r = 0;
-
-#ifdef CONFIG_ELOOP_KQUEUE
-	close(eloop.kqueuefd);
-	eloop.kqueuefd = kqueue();
-	if (eloop.kqueuefd < 0) {
-		wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
-			   __func__, strerror(errno));
-		return -1;
-	}
-
-	if (eloop_sock_table_requeue(&eloop.readers) < 0)
-		r = -1;
-	if (eloop_sock_table_requeue(&eloop.writers) < 0)
-		r = -1;
-	if (eloop_sock_table_requeue(&eloop.exceptions) < 0)
-		r = -1;
-#endif /* CONFIG_ELOOP_KQUEUE */
-
-	return r;
+	return 0;
 }
 
 
@@ -1078,12 +802,6 @@  void eloop_run(void)
 	fd_set *rfds, *wfds, *efds;
 	struct timeval _tv;
 #endif /* CONFIG_ELOOP_SELECT */
-#ifdef CONFIG_ELOOP_EPOLL
-	int timeout_ms = -1;
-#endif /* CONFIG_ELOOP_EPOLL */
-#ifdef CONFIG_ELOOP_KQUEUE
-	struct timespec ts;
-#endif /* CONFIG_ELOOP_KQUEUE */
 	int res;
 	struct os_reltime tv, now;
 
@@ -1121,17 +839,13 @@  void eloop_run(void)
 				os_reltime_sub(&timeout->time, &now, &tv);
 			else
 				tv.sec = tv.usec = 0;
-#if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
+#if defined(CONFIG_ELOOP_POLL)
 			timeout_ms = tv.sec * 1000 + tv.usec / 1000;
-#endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
+#endif /* defined(CONFIG_ELOOP_POLL) */
 #ifdef CONFIG_ELOOP_SELECT
 			_tv.tv_sec = tv.sec;
 			_tv.tv_usec = tv.usec;
 #endif /* CONFIG_ELOOP_SELECT */
-#ifdef CONFIG_ELOOP_KQUEUE
-			ts.tv_sec = tv.sec;
-			ts.tv_nsec = tv.usec * 1000L;
-#endif /* CONFIG_ELOOP_KQUEUE */
 		}
 
 #ifdef CONFIG_ELOOP_POLL
@@ -1149,23 +863,6 @@  void eloop_run(void)
 		res = select(eloop.max_sock + 1, rfds, wfds, efds,
 			     timeout ? &_tv : NULL);
 #endif /* CONFIG_ELOOP_SELECT */
-#ifdef CONFIG_ELOOP_EPOLL
-		if (eloop.count == 0) {
-			res = 0;
-		} else {
-			res = epoll_wait(eloop.epollfd, eloop.epoll_events,
-					 eloop.count, timeout_ms);
-		}
-#endif /* CONFIG_ELOOP_EPOLL */
-#ifdef CONFIG_ELOOP_KQUEUE
-		if (eloop.count == 0) {
-			res = 0;
-		} else {
-			res = kevent(eloop.kqueuefd, NULL, 0,
-				     eloop.kqueue_events, eloop.kqueue_nevents,
-				     timeout ? &ts : NULL);
-		}
-#endif /* CONFIG_ELOOP_KQUEUE */
 		if (res < 0 && errno != EINTR && errno != 0) {
 			wpa_printf(MSG_ERROR, "eloop: %s: %s",
 #ifdef CONFIG_ELOOP_POLL
@@ -1174,12 +871,6 @@  void eloop_run(void)
 #ifdef CONFIG_ELOOP_SELECT
 				   "select"
 #endif /* CONFIG_ELOOP_SELECT */
-#ifdef CONFIG_ELOOP_EPOLL
-				   "epoll"
-#endif /* CONFIG_ELOOP_EPOLL */
-#ifdef CONFIG_ELOOP_KQUEUE
-				   "kqueue"
-#endif /* CONFIG_ELOOP_EKQUEUE */
 
 				   , strerror(errno));
 			goto out;
@@ -1234,12 +925,6 @@  void eloop_run(void)
 		eloop_sock_table_dispatch(&eloop.writers, wfds);
 		eloop_sock_table_dispatch(&eloop.exceptions, efds);
 #endif /* CONFIG_ELOOP_SELECT */
-#ifdef CONFIG_ELOOP_EPOLL
-		eloop_sock_table_dispatch(eloop.epoll_events, res);
-#endif /* CONFIG_ELOOP_EPOLL */
-#ifdef CONFIG_ELOOP_KQUEUE
-		eloop_sock_table_dispatch(eloop.kqueue_events, res);
-#endif /* CONFIG_ELOOP_KQUEUE */
 	}
 
 	eloop.terminate = 0;
@@ -1292,17 +977,6 @@  void eloop_destroy(void)
 	os_free(eloop.pollfds);
 	os_free(eloop.pollfds_map);
 #endif /* CONFIG_ELOOP_POLL */
-#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
-	os_free(eloop.fd_table);
-#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
-#ifdef CONFIG_ELOOP_EPOLL
-	os_free(eloop.epoll_events);
-	close(eloop.epollfd);
-#endif /* CONFIG_ELOOP_EPOLL */
-#ifdef CONFIG_ELOOP_KQUEUE
-	os_free(eloop.kqueue_events);
-	close(eloop.kqueuefd);
-#endif /* CONFIG_ELOOP_KQUEUE */
 }
 
 
@@ -1326,12 +1000,7 @@  void eloop_wait_for_read_sock(int sock)
 
 	poll(&pfd, 1, -1);
 #endif /* CONFIG_ELOOP_POLL */
-#if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL)
-	/*
-	 * We can use epoll() here. But epoll() requres 4 system calls.
-	 * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for
-	 * epoll fd. So select() is better for performance here.
-	 */
+#if defined(CONFIG_ELOOP_SELECT)
 	fd_set rfds;
 
 	if (sock < 0)
@@ -1340,18 +1009,7 @@  void eloop_wait_for_read_sock(int sock)
 	FD_ZERO(&rfds);
 	FD_SET(sock, &rfds);
 	select(sock + 1, &rfds, NULL, NULL, NULL);
-#endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */
-#ifdef CONFIG_ELOOP_KQUEUE
-	int kfd;
-	struct kevent ke1, ke2;
-
-	kfd = kqueue();
-	if (kfd == -1)
-		return;
-	EV_SET(&ke1, sock, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
-	kevent(kfd, &ke1, 1, &ke2, 1, NULL);
-	close(kfd);
-#endif /* CONFIG_ELOOP_KQUEUE */
+#endif /* defined(CONFIG_ELOOP_SELECT) */
 }
 
 #ifdef CONFIG_ELOOP_SELECT
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
index 04ee6d1837..719792feb2 100644
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -315,8 +315,7 @@  int eloop_register_signal_reconfig(eloop_signal_handler handler,
 /**
  * eloop_sock_requeue - Requeue sockets
  *
- * Requeue sockets after forking because some implementations require this,
- * such as epoll and kqueue.
+ * Requeue sockets after forking because some implementations may require this.
  */
 int eloop_sock_requeue(void);
 
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 3aadcb2bb9..969e9325f5 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -155,10 +155,6 @@  ifdef CONFIG_ELOOP_POLL
 L_CFLAGS += -DCONFIG_ELOOP_POLL
 endif
 
-ifdef CONFIG_ELOOP_EPOLL
-L_CFLAGS += -DCONFIG_ELOOP_EPOLL
-endif
-
 ifdef CONFIG_EAPOL_TEST
 L_CFLAGS += -Werror -DEAPOL_TEST
 endif
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 743c8acd68..de12a214c4 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -178,14 +178,6 @@  ifdef CONFIG_ELOOP_POLL
 CFLAGS += -DCONFIG_ELOOP_POLL
 endif
 
-ifdef CONFIG_ELOOP_EPOLL
-CFLAGS += -DCONFIG_ELOOP_EPOLL
-endif
-
-ifdef CONFIG_ELOOP_KQUEUE
-CFLAGS += -DCONFIG_ELOOP_KQUEUE
-endif
-
 ifdef CONFIG_EAPOL_TEST
 CFLAGS += -Werror -DEAPOL_TEST
 endif
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 5ae3808fb6..6122e9678b 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -252,12 +252,6 @@  CONFIG_ELOOP=eloop
 # Should we use poll instead of select? Select is used by default.
 #CONFIG_ELOOP_POLL=y
 
-# Should we use epoll instead of select? Select is used by default.
-#CONFIG_ELOOP_EPOLL=y
-
-# Should we use kqueue instead of select? Select is used by default.
-#CONFIG_ELOOP_KQUEUE=y
-
 # Select layer 2 packet implementation
 # linux = Linux packet socket (default)
 # pcap = libpcap/libdnet/WinPcap
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 52befd8f15..4a43157d87 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -301,12 +301,6 @@  CONFIG_BACKEND=file
 # Should we use poll instead of select? Select is used by default.
 #CONFIG_ELOOP_POLL=y
 
-# Should we use epoll instead of select? Select is used by default.
-#CONFIG_ELOOP_EPOLL=y
-
-# Should we use kqueue instead of select? Select is used by default.
-#CONFIG_ELOOP_KQUEUE=y
-
 # Select layer 2 packet implementation
 # linux = Linux packet socket (default)
 # pcap = libpcap/libdnet/WinPcap