Wed Jan 20 15:07:52 2016 UTC ()
Add kqueue(2) support.


(roy)
diff -r1.6 -r1.7 src/external/bsd/wpa/dist/src/utils/eloop.c

cvs diff -r1.6 -r1.7 src/external/bsd/wpa/dist/src/utils/eloop.c (expand / switch to context diff)
--- src/external/bsd/wpa/dist/src/utils/eloop.c 2015/04/01 19:45:15 1.6
+++ src/external/bsd/wpa/dist/src/utils/eloop.c 2016/01/20 15:07:52 1.7
@@ -18,7 +18,12 @@
 #error Do not define both of poll and epoll
 #endif
 
-#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL)
+#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)
 #define CONFIG_ELOOP_SELECT
 #endif
 
@@ -30,6 +35,10 @@
 #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;
@@ -61,7 +70,7 @@
 struct eloop_sock_table {
 	int count;
 	struct eloop_sock *table;
-#ifdef CONFIG_ELOOP_EPOLL
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
 	eloop_event_type type;
 #else /* CONFIG_ELOOP_EPOLL */
 	int changed;
@@ -78,13 +87,20 @@
 	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
 #ifdef CONFIG_ELOOP_EPOLL
 	int epollfd;
 	int epoll_max_event_num;
-	int epoll_max_fd;
-	struct eloop_sock *epoll_table;
 	struct epoll_event *epoll_events;
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+	int kqueuefd;
+	int 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;
@@ -160,6 +176,14 @@
 	eloop.writers.type = EVENT_TYPE_WRITE;
 	eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+	eloop.kqueuefd = kqueue();
+	if (eloop.kqueuefd < 0) {
+		wpa_printf(MSG_ERROR, "%s: kqueue failed. %s\n",
+			   __func__, strerror(errno));
+		return -1;
+	}
+#endif /* CONFIG_ELOOP_KQUEUE */
 #ifdef WPA_TRACE
 	signal(SIGSEGV, eloop_sigsegv_handler);
 #endif /* WPA_TRACE */
@@ -176,6 +200,11 @@
 	struct epoll_event ev, *temp_events;
 	int next;
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+	struct eloop_sock *temp_table;
+	int next, filter;
+	struct kevent ke;
+#endif
 	struct eloop_sock *tmp;
 	int new_max_sock;
 
@@ -211,18 +240,20 @@
 		eloop.pollfds = n;
 	}
 #endif /* CONFIG_ELOOP_POLL */
-#ifdef CONFIG_ELOOP_EPOLL
-	if (new_max_sock >= eloop.epoll_max_fd) {
-		next = eloop.epoll_max_fd == 0 ? 16 : eloop.epoll_max_fd * 2;
-		temp_table = os_realloc_array(eloop.epoll_table, next,
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
+	if (new_max_sock >= eloop.max_fd) {
+		next = eloop.max_fd == 0 ? 16 : eloop.max_fd * 2;
+		temp_table = os_realloc_array(eloop.fd_table, next,
 					      sizeof(struct eloop_sock));
 		if (temp_table == NULL)
 			return -1;
 
-		eloop.epoll_max_fd = next;
-		eloop.epoll_table = temp_table;
+		eloop.max_fd = next;
+		eloop.fd_table = temp_table;
 	}
+#endif
 
+#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;
@@ -238,7 +269,22 @@
 		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;
+		os_free(eloop.kqueue_events);
+		eloop.kqueue_events = os_malloc(next *
+					        sizeof(eloop.kqueue_events));
+		if (eloop.kqueue_events == NULL) {
+			wpa_printf(MSG_ERROR, "%s: malloc for kqueue failed. "
+				   "%s\n", __func__, strerror(errno));
+			return -1;
+		}
 
+		eloop.kqueue_nevents = next;
+	}
+#endif /* CONFIG_ELOOP_KQUEUE */
+
 	eloop_trace_sock_remove_ref(table);
 	tmp = os_realloc_array(table->table, table->count + 1,
 			       sizeof(struct eloop_sock));
@@ -256,7 +302,7 @@
 	table->table = tmp;
 	eloop.max_sock = new_max_sock;
 	eloop.count++;
-#ifndef CONFIG_ELOOP_EPOLL
+#if !defined(CONFIG_ELOOP_EPOLL) && !defined(CONFIG_ELOOP_KQUEUE)
 	table->changed = 1;
 #endif /* CONFIG_ELOOP_EPOLL */
 	eloop_trace_sock_add_ref(table);
@@ -285,9 +331,29 @@
 			   "failed. %s\n", __func__, sock, strerror(errno));
 		return -1;
 	}
-	os_memcpy(&eloop.epoll_table[sock], &table->table[table->count - 1],
+	os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1],
 		  sizeof(struct eloop_sock));
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+	switch (table->type) {
+	case EVENT_TYPE_READ:
+		filter = EVFILT_READ;
+		break;
+	case EVENT_TYPE_WRITE:
+		filter = EVFILT_WRITE;
+		break;
+	default:
+		filter = 0;
+	}
+	EV_SET(&ke, sock, filter, EV_ADD, 0, 0, NULL);
+	if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) {
+		wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d "
+			   "failed. %s\n", __func__, sock, strerror(errno));
+		return -1;
+	}
+	os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1],
+		  sizeof(struct eloop_sock));
+#endif /* CONFIG_ELOOP_KQUEUE */
 	return 0;
 }
 
@@ -295,6 +361,9 @@
 static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
                                          int sock)
 {
+#ifdef CONFIG_ELOOP_KQUEUE
+	struct kevent ke;
+#endif
 	int i;
 
 	if (table == NULL || table->table == NULL || table->count == 0)
@@ -314,7 +383,7 @@
 	}
 	table->count--;
 	eloop.count--;
-#ifndef CONFIG_ELOOP_EPOLL
+#if !defined(CONFIG_ELOOP_EPOLL) && !defined(CONFIG_ELOOP_KQUEUE)
 	table->changed = 1;
 #endif /* CONFIG_ELOOP_EPOLL */
 	eloop_trace_sock_add_ref(table);
@@ -324,8 +393,17 @@
 			   "failed. %s\n", __func__, sock, strerror(errno));
 		return;
 	}
-	os_memset(&eloop.epoll_table[sock], 0, sizeof(struct eloop_sock));
+	os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+	EV_SET(&ke, sock, 0, EV_DELETE, 0, 0, NULL);
+	if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) {
+		wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d "
+			   "failed. %s\n", __func__, sock, strerror(errno));
+		return;
+	}
+	os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
+#endif /* CONFIG_ELOOP_KQUEUE */
 }
 
 
@@ -518,7 +596,7 @@
 	int i;
 
 	for (i = 0; i < nfds; i++) {
-		table = &eloop.epoll_table[events[i].data.fd];
+		table = &eloop.fd_table[events[i].data.fd];
 		if (table->handler == NULL)
 			continue;
 		table->handler(table->sock, table->eloop_data,
@@ -528,6 +606,22 @@
 #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);
+	}
+}
+#endif /* CONFIG_ELOOP_KQUEUE */
+
 static void eloop_sock_table_destroy(struct eloop_sock_table *table)
 {
 	if (table) {
@@ -908,6 +1002,9 @@
 #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;
 
@@ -938,6 +1035,10 @@
 			_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
@@ -963,6 +1064,15 @@
 					 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
@@ -974,6 +1084,10 @@
 #ifdef CONFIG_ELOOP_EPOLL
 				   "epoll"
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+				   "kqueue"
+#endif /* CONFIG_ELOOP_EKQUEUE */
+
 				   , strerror(errno));
 			goto out;
 		}
@@ -1011,6 +1125,9 @@
 #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;
@@ -1063,11 +1180,17 @@
 	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
 #ifdef CONFIG_ELOOP_EPOLL
-	os_free(eloop.epoll_table);
 	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 */
 }
 
 
@@ -1106,6 +1229,17 @@
 	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, NULL);
+	kevent(kfd, &ke1, 1, &ke2, 1, NULL);
+	close(kfd);
+#endif /* CONFIG_ELOOP_KQUEUE */
 }
 
 #ifdef CONFIG_ELOOP_SELECT