[RFC] supplicant: Support poll() in eloop.
greearb at candelatech.com
greearb
Thu Jan 5 16:34:08 PST 2012
From: Ben Greear <greearb at candelatech.com>
When using more than around 200 virtual stations, we start
hitting the max number of file-descriptors supported by
select. This patch adds support for poll(), which has no
hard upper limit.
Signed-hostap: Ben Greear <greearb at candelatech.com>
---
:100644 100644 b550c63... c260d09... M src/utils/eloop.c
:100644 100644 151d879... 9f09193... M wpa_supplicant/Makefile
:100644 100644 89bb458... fd8522d... M wpa_supplicant/defconfig
src/utils/eloop.c | 226 +++++++++++++++++++++++++++++++++++++++++++++-
wpa_supplicant/Makefile | 4 +
wpa_supplicant/defconfig | 4 +
3 files changed, 232 insertions(+), 2 deletions(-)
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index b550c63..c260d09 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -19,6 +19,11 @@
#include "list.h"
#include "eloop.h"
+#ifdef CONFIG_ELOOP_POLL
+#include <assert.h>
+#include <poll.h>
+#endif
+
struct eloop_sock {
int sock;
@@ -56,7 +61,13 @@ struct eloop_sock_table {
struct eloop_data {
int max_sock;
-
+ int count; /* sum of all table counts */
+#ifdef CONFIG_ELOOP_POLL
+ int max_pollfd_map; /* number of pollfds_map currently allocated */
+ int max_poll_fds; /* number of pollfds currently allocated */
+ struct pollfd *pollfds;
+ struct pollfd **pollfds_map;
+#endif
struct eloop_sock_table readers;
struct eloop_sock_table writers;
struct eloop_sock_table exceptions;
@@ -154,6 +165,24 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
table->table = tmp;
if (sock > eloop.max_sock)
eloop.max_sock = sock;
+ eloop.count++;
+#ifdef CONFIG_ELOOP_POLL
+ if (eloop.max_sock > eloop.max_pollfd_map) {
+ os_free(eloop.pollfds_map);
+ eloop.max_pollfd_map = eloop.max_sock + 50;
+ eloop.pollfds_map = os_zalloc(sizeof(struct pollfd *) * eloop.max_pollfd_map);
+ if (!eloop.pollfds_map)
+ eloop.max_pollfd_map = 0;
+ }
+
+ if (eloop.count > eloop.max_poll_fds) {
+ os_free(eloop.pollfds);
+ eloop.max_poll_fds = eloop.count + 50;
+ eloop.pollfds = os_zalloc(sizeof(struct pollfd) * eloop.max_poll_fds);
+ if (!eloop.pollfds)
+ eloop.max_poll_fds = 0;
+ }
+#endif
table->changed = 1;
eloop_trace_sock_add_ref(table);
@@ -182,11 +211,151 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
sizeof(struct eloop_sock));
}
table->count--;
+ eloop.count--;
table->changed = 1;
eloop_trace_sock_add_ref(table);
}
+#ifdef CONFIG_ELOOP_POLL
+
+static struct pollfd* find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
+{
+ if (fd < mx && fd >= 0)
+ return pollfds_map[fd];
+ return NULL;
+}
+
+static void eloop_sock_table_set_fds(struct eloop_sock_table *readers,
+ struct eloop_sock_table *writers,
+ struct eloop_sock_table *exceptions,
+ struct pollfd *pollfds,
+ struct pollfd **pollfds_map,
+ int max_pollfd_map,
+ int *num_poll_fds)
+{
+ int i;
+ int nxt = 0;
+ int fd;
+ struct pollfd *pfd;
+
+ /* Clear pollfd lookup map. It will be re-populated below. */
+ memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
+
+ if (readers && readers->table) {
+ for (i = 0; i < readers->count; i++) {
+ fd = readers->table[i].sock;
+ assert(fd >= 0 && fd < max_pollfd_map);
+ pollfds[nxt].fd = fd;
+ pollfds[nxt].events = POLLIN;
+ pollfds[nxt].revents = 0;
+ pollfds_map[fd] = &(pollfds[nxt]);
+ nxt++;
+ }
+ }
+
+ if (writers && writers->table) {
+ for (i = 0; i < writers->count; i++) {
+ /* See if we already added this descriptor, update it if so */
+ fd = writers->table[i].sock;
+ assert(fd >= 0 && fd < max_pollfd_map);
+ pfd = pollfds_map[fd];
+ if (!pfd) {
+ pfd = &(pollfds[nxt]);
+ pfd->events = 0;
+ pfd->fd = fd;
+ pollfds[i].revents = 0;
+ pollfds_map[fd] = pfd;
+ nxt++;
+ }
+ pfd->events |= POLLIN;
+ }
+ }
+
+ /*
+ * Exceptions are always checked when using poll, but I suppose it's possible
+ * that someone registered a socket *only* for exception handling. Set
+ * the POLLIN bit in this case.
+ */
+ if (exceptions && exceptions->table) {
+ for (i = 0; i < exceptions->count; i++) {
+ /* See if we already added this descriptor, just use it if so */
+ fd = exceptions->table[i].sock;
+ assert(fd >= 0 && fd < max_pollfd_map);
+ pfd = pollfds_map[fd];
+ if (!pfd) {
+ pfd = &(pollfds[nxt]);
+ pfd->events = POLLIN;
+ pfd->fd = fd;
+ pollfds[i].revents = 0;
+ pollfds_map[fd] = pfd;
+ nxt++;
+ }
+ }
+ }
+
+ *num_poll_fds = nxt;
+}
+
+static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
+ struct eloop_sock_table *writers,
+ struct eloop_sock_table *exceptions,
+ struct pollfd *pollfds,
+ struct pollfd **pollfds_map,
+ int max_pollfd_map)
+{
+ int i;
+ struct pollfd *pfd;
+ if (readers && readers->table) {
+ readers->changed = 0;
+ for (i = 0; i < readers->count; i++) {
+ pfd = find_pollfd(pollfds_map, readers->table[i].sock, max_pollfd_map);
+ if (pfd) {
+ if (pfd->revents & POLLIN) {
+ readers->table[i].handler(readers->table[i].sock,
+ readers->table[i].eloop_data,
+ readers->table[i].user_data);
+ if (readers->changed)
+ return; /* pollfds may be invalid at this point */
+ }
+ }
+ }
+ }
+
+ if (writers && writers->table) {
+ writers->changed = 0;
+ for (i = 0; i < writers->count; i++) {
+ pfd = find_pollfd(pollfds_map, writers->table[i].sock, max_pollfd_map);
+ if (pfd) {
+ if (pfd->revents & POLLOUT) {
+ writers->table[i].handler(writers->table[i].sock,
+ writers->table[i].eloop_data,
+ writers->table[i].user_data);
+ if (writers->changed)
+ return; /* pollfds may be invalid at this point */
+ }
+ }
+ }
+ }
+
+ if (exceptions && exceptions->table) {
+ exceptions->changed = 0;
+ for (i = 0; i < exceptions->count; i++) {
+ pfd = find_pollfd(pollfds_map, exceptions->table[i].sock, max_pollfd_map);
+ if (pfd) {
+ if (pfd->revents & (POLLERR|POLLHUP)) {
+ exceptions->table[i].handler(exceptions->table[i].sock,
+ exceptions->table[i].eloop_data,
+ exceptions->table[i].user_data);
+ if (exceptions->changed)
+ return; /* pollfds may be invalid at this point */
+ }
+ }
+ }
+ }
+}
+
+#else
static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
fd_set *fds)
{
@@ -221,6 +390,7 @@ static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
}
}
}
+#endif
static void eloop_sock_table_destroy(struct eloop_sock_table *table)
@@ -502,16 +672,24 @@ int eloop_register_signal_reconfig(eloop_signal_handler handler,
void eloop_run(void)
{
+#ifdef CONFIG_ELOOP_POLL
+ int num_poll_fds;
+ int timeout_ms = 0;
+#else
fd_set *rfds, *wfds, *efds;
- int res;
struct timeval _tv;
+#endif
+ int res;
struct os_time tv, now;
+#ifdef CONFIG_ELOOP_POLL
+#else
rfds = os_malloc(sizeof(*rfds));
wfds = os_malloc(sizeof(*wfds));
efds = os_malloc(sizeof(*efds));
if (rfds == NULL || wfds == NULL || efds == NULL)
goto out;
+#endif
while (!eloop.terminate &&
(!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
@@ -525,10 +703,28 @@ void eloop_run(void)
os_time_sub(&timeout->time, &now, &tv);
else
tv.sec = tv.usec = 0;
+#ifdef CONFIG_ELOOP_POLL
+ timeout_ms = tv.usec / 1000;
+ timeout_ms += (tv.sec * 1000);
+#else
_tv.tv_sec = tv.sec;
_tv.tv_usec = tv.usec;
+#endif
}
+#ifdef CONFIG_ELOOP_POLL
+ num_poll_fds = 0;
+ eloop_sock_table_set_fds(&eloop.readers, &eloop.writers,
+ &eloop.exceptions, eloop.pollfds,
+ eloop.pollfds_map, eloop.max_pollfd_map,
+ &num_poll_fds);
+ res = poll(eloop.pollfds, num_poll_fds, timeout ? timeout_ms : -1);
+
+ if (res < 0 && errno != EINTR && errno != 0) {
+ perror("poll");
+ goto out;
+ }
+#else
eloop_sock_table_set_fds(&eloop.readers, rfds);
eloop_sock_table_set_fds(&eloop.writers, wfds);
eloop_sock_table_set_fds(&eloop.exceptions, efds);
@@ -538,6 +734,7 @@ void eloop_run(void)
perror("select");
goto out;
}
+#endif
eloop_process_pending_signals();
/* check if some registered timeouts have occurred */
@@ -559,15 +756,23 @@ void eloop_run(void)
if (res <= 0)
continue;
+#ifdef CONFIG_ELOOP_POLL
+ eloop_sock_table_dispatch(&eloop.readers, &eloop.writers, &eloop.exceptions,
+ eloop.pollfds, eloop.pollfds_map, eloop.max_pollfd_map);
+#else
eloop_sock_table_dispatch(&eloop.readers, rfds);
eloop_sock_table_dispatch(&eloop.writers, wfds);
eloop_sock_table_dispatch(&eloop.exceptions, efds);
+#endif
}
out:
+#ifndef CONFIG_ELOOP_POLL
os_free(rfds);
os_free(wfds);
os_free(efds);
+#endif
+ return;
}
@@ -605,6 +810,11 @@ void eloop_destroy(void)
eloop_sock_table_destroy(&eloop.writers);
eloop_sock_table_destroy(&eloop.exceptions);
os_free(eloop.signals);
+
+#ifdef CONFIG_ELOOP_POLL
+ os_free(eloop.pollfds);
+ os_free(eloop.pollfds_map);
+#endif
}
@@ -616,6 +826,17 @@ int eloop_terminated(void)
void eloop_wait_for_read_sock(int sock)
{
+#ifdef CONFIG_ELOOP_POLL
+ struct pollfd pfd;
+ if (sock < 0)
+ return;
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = sock;
+ pfd.events = POLLIN;
+
+ poll(&pfd, 1, -1);
+#else
fd_set rfds;
if (sock < 0)
@@ -624,4 +845,5 @@ void eloop_wait_for_read_sock(int sock)
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
select(sock + 1, &rfds, NULL, NULL, NULL);
+#endif
}
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 151d879..9f09193 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -115,6 +115,10 @@ ifdef CONFIG_HT_OVERRIDES
CFLAGS += -DCONFIG_HT_OVERRIDES
endif
+ifdef CONFIG_ELOOP_POLL
+CFLAGS += -DCONFIG_ELOOP_POLL
+endif
+
ifndef CONFIG_BACKEND
CONFIG_BACKEND=file
endif
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 89bb458..fd8522d 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -220,6 +220,10 @@ CONFIG_SMARTCARD=y
# Support HT overrides (disable-ht40, mcs rates, etc)
# CONFIG_HT_OVERRIDES=y
+# Should we use poll instead of select? Select is
+# used by default.
+# CONFIG_ELOOP_POLL=y
+
# Development testing
#CONFIG_EAPOL_TEST=y
--
1.7.3.4
More information about the Hostap
mailing list