139beb93cSSam Leffler /*
239beb93cSSam Leffler * Event loop based on select() loop
3e28a4053SRui Paulo * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
739beb93cSSam Leffler */
839beb93cSSam Leffler
939beb93cSSam Leffler #include "includes.h"
105b9c547cSRui Paulo #include <assert.h>
1139beb93cSSam Leffler
1239beb93cSSam Leffler #include "common.h"
13e28a4053SRui Paulo #include "trace.h"
14e28a4053SRui Paulo #include "list.h"
1539beb93cSSam Leffler #include "eloop.h"
1639beb93cSSam Leffler
175b9c547cSRui Paulo #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL)
185b9c547cSRui Paulo #error Do not define both of poll and epoll
195b9c547cSRui Paulo #endif
205b9c547cSRui Paulo
21780fb4a2SCy Schubert #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_KQUEUE)
22780fb4a2SCy Schubert #error Do not define both of poll and kqueue
23780fb4a2SCy Schubert #endif
24780fb4a2SCy Schubert
25780fb4a2SCy Schubert #if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) && \
26780fb4a2SCy Schubert !defined(CONFIG_ELOOP_KQUEUE)
275b9c547cSRui Paulo #define CONFIG_ELOOP_SELECT
285b9c547cSRui Paulo #endif
295b9c547cSRui Paulo
30f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
31f05cddf9SRui Paulo #include <poll.h>
32f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
33f05cddf9SRui Paulo
345b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
355b9c547cSRui Paulo #include <sys/epoll.h>
365b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
3739beb93cSSam Leffler
38780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
39780fb4a2SCy Schubert #include <sys/event.h>
40780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
41780fb4a2SCy Schubert
4239beb93cSSam Leffler struct eloop_sock {
4339beb93cSSam Leffler int sock;
4439beb93cSSam Leffler void *eloop_data;
4539beb93cSSam Leffler void *user_data;
4639beb93cSSam Leffler eloop_sock_handler handler;
47e28a4053SRui Paulo WPA_TRACE_REF(eloop);
48e28a4053SRui Paulo WPA_TRACE_REF(user);
49e28a4053SRui Paulo WPA_TRACE_INFO
5039beb93cSSam Leffler };
5139beb93cSSam Leffler
5239beb93cSSam Leffler struct eloop_timeout {
53e28a4053SRui Paulo struct dl_list list;
545b9c547cSRui Paulo struct os_reltime time;
5539beb93cSSam Leffler void *eloop_data;
5639beb93cSSam Leffler void *user_data;
5739beb93cSSam Leffler eloop_timeout_handler handler;
58e28a4053SRui Paulo WPA_TRACE_REF(eloop);
59e28a4053SRui Paulo WPA_TRACE_REF(user);
60e28a4053SRui Paulo WPA_TRACE_INFO
6139beb93cSSam Leffler };
6239beb93cSSam Leffler
6339beb93cSSam Leffler struct eloop_signal {
6439beb93cSSam Leffler int sig;
6539beb93cSSam Leffler void *user_data;
6639beb93cSSam Leffler eloop_signal_handler handler;
6739beb93cSSam Leffler int signaled;
6839beb93cSSam Leffler };
6939beb93cSSam Leffler
7039beb93cSSam Leffler struct eloop_sock_table {
71c1d255d3SCy Schubert size_t count;
7239beb93cSSam Leffler struct eloop_sock *table;
735b9c547cSRui Paulo eloop_event_type type;
7439beb93cSSam Leffler int changed;
7539beb93cSSam Leffler };
7639beb93cSSam Leffler
7739beb93cSSam Leffler struct eloop_data {
7839beb93cSSam Leffler int max_sock;
7939beb93cSSam Leffler
80c1d255d3SCy Schubert size_t count; /* sum of all table counts */
81f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
82c1d255d3SCy Schubert size_t max_pollfd_map; /* number of pollfds_map currently allocated */
83c1d255d3SCy Schubert size_t max_poll_fds; /* number of pollfds currently allocated */
84f05cddf9SRui Paulo struct pollfd *pollfds;
85f05cddf9SRui Paulo struct pollfd **pollfds_map;
86f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
87780fb4a2SCy Schubert #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
88780fb4a2SCy Schubert int max_fd;
89780fb4a2SCy Schubert struct eloop_sock *fd_table;
90780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
915b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
925b9c547cSRui Paulo int epollfd;
93c1d255d3SCy Schubert size_t epoll_max_event_num;
945b9c547cSRui Paulo struct epoll_event *epoll_events;
955b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
96780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
97780fb4a2SCy Schubert int kqueuefd;
98c1d255d3SCy Schubert size_t kqueue_nevents;
99780fb4a2SCy Schubert struct kevent *kqueue_events;
100780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
10139beb93cSSam Leffler struct eloop_sock_table readers;
10239beb93cSSam Leffler struct eloop_sock_table writers;
10339beb93cSSam Leffler struct eloop_sock_table exceptions;
10439beb93cSSam Leffler
105e28a4053SRui Paulo struct dl_list timeout;
10639beb93cSSam Leffler
107c1d255d3SCy Schubert size_t signal_count;
10839beb93cSSam Leffler struct eloop_signal *signals;
10939beb93cSSam Leffler int signaled;
11039beb93cSSam Leffler int pending_terminate;
11139beb93cSSam Leffler
11239beb93cSSam Leffler int terminate;
11339beb93cSSam Leffler };
11439beb93cSSam Leffler
11539beb93cSSam Leffler static struct eloop_data eloop;
11639beb93cSSam Leffler
11739beb93cSSam Leffler
118e28a4053SRui Paulo #ifdef WPA_TRACE
119e28a4053SRui Paulo
eloop_sigsegv_handler(int sig)120e28a4053SRui Paulo static void eloop_sigsegv_handler(int sig)
121e28a4053SRui Paulo {
122e28a4053SRui Paulo wpa_trace_show("eloop SIGSEGV");
123e28a4053SRui Paulo abort();
124e28a4053SRui Paulo }
125e28a4053SRui Paulo
eloop_trace_sock_add_ref(struct eloop_sock_table * table)126e28a4053SRui Paulo static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
127e28a4053SRui Paulo {
128c1d255d3SCy Schubert size_t i;
129c1d255d3SCy Schubert
130e28a4053SRui Paulo if (table == NULL || table->table == NULL)
131e28a4053SRui Paulo return;
132e28a4053SRui Paulo for (i = 0; i < table->count; i++) {
133e28a4053SRui Paulo wpa_trace_add_ref(&table->table[i], eloop,
134e28a4053SRui Paulo table->table[i].eloop_data);
135e28a4053SRui Paulo wpa_trace_add_ref(&table->table[i], user,
136e28a4053SRui Paulo table->table[i].user_data);
137e28a4053SRui Paulo }
138e28a4053SRui Paulo }
139e28a4053SRui Paulo
140e28a4053SRui Paulo
eloop_trace_sock_remove_ref(struct eloop_sock_table * table)141e28a4053SRui Paulo static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
142e28a4053SRui Paulo {
143c1d255d3SCy Schubert size_t i;
144c1d255d3SCy Schubert
145e28a4053SRui Paulo if (table == NULL || table->table == NULL)
146e28a4053SRui Paulo return;
147e28a4053SRui Paulo for (i = 0; i < table->count; i++) {
148e28a4053SRui Paulo wpa_trace_remove_ref(&table->table[i], eloop,
149e28a4053SRui Paulo table->table[i].eloop_data);
150e28a4053SRui Paulo wpa_trace_remove_ref(&table->table[i], user,
151e28a4053SRui Paulo table->table[i].user_data);
152e28a4053SRui Paulo }
153e28a4053SRui Paulo }
154e28a4053SRui Paulo
155e28a4053SRui Paulo #else /* WPA_TRACE */
156e28a4053SRui Paulo
157e28a4053SRui Paulo #define eloop_trace_sock_add_ref(table) do { } while (0)
158e28a4053SRui Paulo #define eloop_trace_sock_remove_ref(table) do { } while (0)
159e28a4053SRui Paulo
160e28a4053SRui Paulo #endif /* WPA_TRACE */
161e28a4053SRui Paulo
162e28a4053SRui Paulo
eloop_init(void)163e28a4053SRui Paulo int eloop_init(void)
16439beb93cSSam Leffler {
16539beb93cSSam Leffler os_memset(&eloop, 0, sizeof(eloop));
166e28a4053SRui Paulo dl_list_init(&eloop.timeout);
1675b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
1685b9c547cSRui Paulo eloop.epollfd = epoll_create1(0);
1695b9c547cSRui Paulo if (eloop.epollfd < 0) {
170780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s",
1715b9c547cSRui Paulo __func__, strerror(errno));
1725b9c547cSRui Paulo return -1;
1735b9c547cSRui Paulo }
174780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_EPOLL */
175780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
176780fb4a2SCy Schubert eloop.kqueuefd = kqueue();
177780fb4a2SCy Schubert if (eloop.kqueuefd < 0) {
178780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
179780fb4a2SCy Schubert __func__, strerror(errno));
180780fb4a2SCy Schubert return -1;
181780fb4a2SCy Schubert }
182780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
183780fb4a2SCy Schubert #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
1845b9c547cSRui Paulo eloop.readers.type = EVENT_TYPE_READ;
1855b9c547cSRui Paulo eloop.writers.type = EVENT_TYPE_WRITE;
1865b9c547cSRui Paulo eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
187780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
188e28a4053SRui Paulo #ifdef WPA_TRACE
189e28a4053SRui Paulo signal(SIGSEGV, eloop_sigsegv_handler);
190e28a4053SRui Paulo #endif /* WPA_TRACE */
19139beb93cSSam Leffler return 0;
19239beb93cSSam Leffler }
19339beb93cSSam Leffler
19439beb93cSSam Leffler
195780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_EPOLL
eloop_sock_queue(int sock,eloop_event_type type)196780fb4a2SCy Schubert static int eloop_sock_queue(int sock, eloop_event_type type)
197780fb4a2SCy Schubert {
198780fb4a2SCy Schubert struct epoll_event ev;
199780fb4a2SCy Schubert
200780fb4a2SCy Schubert os_memset(&ev, 0, sizeof(ev));
201780fb4a2SCy Schubert switch (type) {
202780fb4a2SCy Schubert case EVENT_TYPE_READ:
203780fb4a2SCy Schubert ev.events = EPOLLIN;
204780fb4a2SCy Schubert break;
205780fb4a2SCy Schubert case EVENT_TYPE_WRITE:
206780fb4a2SCy Schubert ev.events = EPOLLOUT;
207780fb4a2SCy Schubert break;
208780fb4a2SCy Schubert /*
209780fb4a2SCy Schubert * Exceptions are always checked when using epoll, but I suppose it's
210780fb4a2SCy Schubert * possible that someone registered a socket *only* for exception
211780fb4a2SCy Schubert * handling.
212780fb4a2SCy Schubert */
213780fb4a2SCy Schubert case EVENT_TYPE_EXCEPTION:
214780fb4a2SCy Schubert ev.events = EPOLLERR | EPOLLHUP;
215780fb4a2SCy Schubert break;
216780fb4a2SCy Schubert }
217780fb4a2SCy Schubert ev.data.fd = sock;
218780fb4a2SCy Schubert if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
219780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d failed: %s",
220780fb4a2SCy Schubert __func__, sock, strerror(errno));
221780fb4a2SCy Schubert return -1;
222780fb4a2SCy Schubert }
223780fb4a2SCy Schubert return 0;
224780fb4a2SCy Schubert }
225780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_EPOLL */
226780fb4a2SCy Schubert
227780fb4a2SCy Schubert
228780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
229780fb4a2SCy Schubert
event_type_kevent_filter(eloop_event_type type)2304bc52338SCy Schubert static short event_type_kevent_filter(eloop_event_type type)
2314bc52338SCy Schubert {
232780fb4a2SCy Schubert switch (type) {
233780fb4a2SCy Schubert case EVENT_TYPE_READ:
2344bc52338SCy Schubert return EVFILT_READ;
235780fb4a2SCy Schubert case EVENT_TYPE_WRITE:
2364bc52338SCy Schubert return EVFILT_WRITE;
237780fb4a2SCy Schubert default:
2384bc52338SCy Schubert return 0;
239780fb4a2SCy Schubert }
2404bc52338SCy Schubert }
2414bc52338SCy Schubert
2424bc52338SCy Schubert
eloop_sock_queue(int sock,eloop_event_type type)2434bc52338SCy Schubert static int eloop_sock_queue(int sock, eloop_event_type type)
2444bc52338SCy Schubert {
2454bc52338SCy Schubert struct kevent ke;
2464bc52338SCy Schubert
2474bc52338SCy Schubert EV_SET(&ke, sock, event_type_kevent_filter(type), EV_ADD, 0, 0, 0);
248780fb4a2SCy Schubert if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) {
249780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s",
250780fb4a2SCy Schubert __func__, sock, strerror(errno));
251780fb4a2SCy Schubert return -1;
252780fb4a2SCy Schubert }
253780fb4a2SCy Schubert return 0;
254780fb4a2SCy Schubert }
2554bc52338SCy Schubert
256780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
257780fb4a2SCy Schubert
258780fb4a2SCy Schubert
eloop_sock_table_add_sock(struct eloop_sock_table * table,int sock,eloop_sock_handler handler,void * eloop_data,void * user_data)25939beb93cSSam Leffler static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
26039beb93cSSam Leffler int sock, eloop_sock_handler handler,
26139beb93cSSam Leffler void *eloop_data, void *user_data)
26239beb93cSSam Leffler {
2635b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
264780fb4a2SCy Schubert struct epoll_event *temp_events;
2655b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
266780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
267780fb4a2SCy Schubert struct kevent *temp_events;
268780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_EPOLL */
269780fb4a2SCy Schubert #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
270780fb4a2SCy Schubert struct eloop_sock *temp_table;
271c1d255d3SCy Schubert size_t next;
272780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
27339beb93cSSam Leffler struct eloop_sock *tmp;
274f05cddf9SRui Paulo int new_max_sock;
275f05cddf9SRui Paulo
276f05cddf9SRui Paulo if (sock > eloop.max_sock)
277f05cddf9SRui Paulo new_max_sock = sock;
278f05cddf9SRui Paulo else
279f05cddf9SRui Paulo new_max_sock = eloop.max_sock;
28039beb93cSSam Leffler
28139beb93cSSam Leffler if (table == NULL)
28239beb93cSSam Leffler return -1;
28339beb93cSSam Leffler
284f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
285c1d255d3SCy Schubert if ((size_t) new_max_sock >= eloop.max_pollfd_map) {
286f05cddf9SRui Paulo struct pollfd **nmap;
287f05cddf9SRui Paulo nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
288f05cddf9SRui Paulo sizeof(struct pollfd *));
289f05cddf9SRui Paulo if (nmap == NULL)
290f05cddf9SRui Paulo return -1;
291f05cddf9SRui Paulo
292f05cddf9SRui Paulo eloop.max_pollfd_map = new_max_sock + 50;
293f05cddf9SRui Paulo eloop.pollfds_map = nmap;
294f05cddf9SRui Paulo }
295f05cddf9SRui Paulo
296f05cddf9SRui Paulo if (eloop.count + 1 > eloop.max_poll_fds) {
297f05cddf9SRui Paulo struct pollfd *n;
298c1d255d3SCy Schubert size_t nmax = eloop.count + 1 + 50;
299c1d255d3SCy Schubert
300f05cddf9SRui Paulo n = os_realloc_array(eloop.pollfds, nmax,
301f05cddf9SRui Paulo sizeof(struct pollfd));
302f05cddf9SRui Paulo if (n == NULL)
303f05cddf9SRui Paulo return -1;
304f05cddf9SRui Paulo
305f05cddf9SRui Paulo eloop.max_poll_fds = nmax;
306f05cddf9SRui Paulo eloop.pollfds = n;
307f05cddf9SRui Paulo }
308f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
309780fb4a2SCy Schubert #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
310780fb4a2SCy Schubert if (new_max_sock >= eloop.max_fd) {
3114bc52338SCy Schubert next = new_max_sock + 16;
312780fb4a2SCy Schubert temp_table = os_realloc_array(eloop.fd_table, next,
3135b9c547cSRui Paulo sizeof(struct eloop_sock));
3145b9c547cSRui Paulo if (temp_table == NULL)
3155b9c547cSRui Paulo return -1;
3165b9c547cSRui Paulo
317780fb4a2SCy Schubert eloop.max_fd = next;
318780fb4a2SCy Schubert eloop.fd_table = temp_table;
3195b9c547cSRui Paulo }
320780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
3215b9c547cSRui Paulo
322780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_EPOLL
3235b9c547cSRui Paulo if (eloop.count + 1 > eloop.epoll_max_event_num) {
3245b9c547cSRui Paulo next = eloop.epoll_max_event_num == 0 ? 8 :
3255b9c547cSRui Paulo eloop.epoll_max_event_num * 2;
3265b9c547cSRui Paulo temp_events = os_realloc_array(eloop.epoll_events, next,
3275b9c547cSRui Paulo sizeof(struct epoll_event));
3285b9c547cSRui Paulo if (temp_events == NULL) {
329780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "%s: malloc for epoll failed: %s",
330780fb4a2SCy Schubert __func__, strerror(errno));
3315b9c547cSRui Paulo return -1;
3325b9c547cSRui Paulo }
3335b9c547cSRui Paulo
3345b9c547cSRui Paulo eloop.epoll_max_event_num = next;
3355b9c547cSRui Paulo eloop.epoll_events = temp_events;
3365b9c547cSRui Paulo }
3375b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
338780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
339780fb4a2SCy Schubert if (eloop.count + 1 > eloop.kqueue_nevents) {
340780fb4a2SCy Schubert next = eloop.kqueue_nevents == 0 ? 8 : eloop.kqueue_nevents * 2;
341780fb4a2SCy Schubert temp_events = os_malloc(next * sizeof(*temp_events));
342780fb4a2SCy Schubert if (!temp_events) {
343780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
344780fb4a2SCy Schubert "%s: malloc for kqueue failed: %s",
345780fb4a2SCy Schubert __func__, strerror(errno));
346780fb4a2SCy Schubert return -1;
347780fb4a2SCy Schubert }
348780fb4a2SCy Schubert
349780fb4a2SCy Schubert os_free(eloop.kqueue_events);
350780fb4a2SCy Schubert eloop.kqueue_events = temp_events;
351780fb4a2SCy Schubert eloop.kqueue_nevents = next;
352780fb4a2SCy Schubert }
353780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
354f05cddf9SRui Paulo
355e28a4053SRui Paulo eloop_trace_sock_remove_ref(table);
356f05cddf9SRui Paulo tmp = os_realloc_array(table->table, table->count + 1,
357f05cddf9SRui Paulo sizeof(struct eloop_sock));
3585b9c547cSRui Paulo if (tmp == NULL) {
3595b9c547cSRui Paulo eloop_trace_sock_add_ref(table);
36039beb93cSSam Leffler return -1;
3615b9c547cSRui Paulo }
36239beb93cSSam Leffler
36339beb93cSSam Leffler tmp[table->count].sock = sock;
36439beb93cSSam Leffler tmp[table->count].eloop_data = eloop_data;
36539beb93cSSam Leffler tmp[table->count].user_data = user_data;
36639beb93cSSam Leffler tmp[table->count].handler = handler;
367e28a4053SRui Paulo wpa_trace_record(&tmp[table->count]);
36839beb93cSSam Leffler table->count++;
36939beb93cSSam Leffler table->table = tmp;
370f05cddf9SRui Paulo eloop.max_sock = new_max_sock;
371f05cddf9SRui Paulo eloop.count++;
37239beb93cSSam Leffler table->changed = 1;
373e28a4053SRui Paulo eloop_trace_sock_add_ref(table);
37439beb93cSSam Leffler
375780fb4a2SCy Schubert #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
376780fb4a2SCy Schubert if (eloop_sock_queue(sock, table->type) < 0)
3775b9c547cSRui Paulo return -1;
378780fb4a2SCy Schubert os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1],
3795b9c547cSRui Paulo sizeof(struct eloop_sock));
380780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
38139beb93cSSam Leffler return 0;
38239beb93cSSam Leffler }
38339beb93cSSam Leffler
38439beb93cSSam Leffler
eloop_sock_table_remove_sock(struct eloop_sock_table * table,int sock)38539beb93cSSam Leffler static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
38639beb93cSSam Leffler int sock)
38739beb93cSSam Leffler {
388780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
389780fb4a2SCy Schubert struct kevent ke;
390780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
391c1d255d3SCy Schubert size_t i;
39239beb93cSSam Leffler
39339beb93cSSam Leffler if (table == NULL || table->table == NULL || table->count == 0)
39439beb93cSSam Leffler return;
39539beb93cSSam Leffler
39639beb93cSSam Leffler for (i = 0; i < table->count; i++) {
39739beb93cSSam Leffler if (table->table[i].sock == sock)
39839beb93cSSam Leffler break;
39939beb93cSSam Leffler }
40039beb93cSSam Leffler if (i == table->count)
40139beb93cSSam Leffler return;
402e28a4053SRui Paulo eloop_trace_sock_remove_ref(table);
40339beb93cSSam Leffler if (i != table->count - 1) {
40439beb93cSSam Leffler os_memmove(&table->table[i], &table->table[i + 1],
40539beb93cSSam Leffler (table->count - i - 1) *
40639beb93cSSam Leffler sizeof(struct eloop_sock));
40739beb93cSSam Leffler }
40839beb93cSSam Leffler table->count--;
409f05cddf9SRui Paulo eloop.count--;
41039beb93cSSam Leffler table->changed = 1;
411e28a4053SRui Paulo eloop_trace_sock_add_ref(table);
4125b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
4135b9c547cSRui Paulo if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
414780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d failed: %s",
415780fb4a2SCy Schubert __func__, sock, strerror(errno));
4165b9c547cSRui Paulo return;
4175b9c547cSRui Paulo }
418780fb4a2SCy Schubert os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
4195b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
420780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
4214bc52338SCy Schubert EV_SET(&ke, sock, event_type_kevent_filter(table->type), EV_DELETE, 0,
4224bc52338SCy Schubert 0, 0);
423780fb4a2SCy Schubert if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) {
424780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s",
425780fb4a2SCy Schubert __func__, sock, strerror(errno));
426780fb4a2SCy Schubert return;
427780fb4a2SCy Schubert }
428780fb4a2SCy Schubert os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
429780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
43039beb93cSSam Leffler }
43139beb93cSSam Leffler
43239beb93cSSam Leffler
433f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
434f05cddf9SRui Paulo
find_pollfd(struct pollfd ** pollfds_map,int fd,int mx)435f05cddf9SRui Paulo static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
436f05cddf9SRui Paulo {
437f05cddf9SRui Paulo if (fd < mx && fd >= 0)
438f05cddf9SRui Paulo return pollfds_map[fd];
439f05cddf9SRui Paulo return NULL;
440f05cddf9SRui Paulo }
441f05cddf9SRui Paulo
442f05cddf9SRui Paulo
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)443f05cddf9SRui Paulo static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
444f05cddf9SRui Paulo struct eloop_sock_table *writers,
445f05cddf9SRui Paulo struct eloop_sock_table *exceptions,
446f05cddf9SRui Paulo struct pollfd *pollfds,
447f05cddf9SRui Paulo struct pollfd **pollfds_map,
448f05cddf9SRui Paulo int max_pollfd_map)
449f05cddf9SRui Paulo {
450c1d255d3SCy Schubert size_t i;
451f05cddf9SRui Paulo int nxt = 0;
452f05cddf9SRui Paulo int fd;
453f05cddf9SRui Paulo struct pollfd *pfd;
454f05cddf9SRui Paulo
455f05cddf9SRui Paulo /* Clear pollfd lookup map. It will be re-populated below. */
456f05cddf9SRui Paulo os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
457f05cddf9SRui Paulo
458f05cddf9SRui Paulo if (readers && readers->table) {
459f05cddf9SRui Paulo for (i = 0; i < readers->count; i++) {
460f05cddf9SRui Paulo fd = readers->table[i].sock;
461f05cddf9SRui Paulo assert(fd >= 0 && fd < max_pollfd_map);
462f05cddf9SRui Paulo pollfds[nxt].fd = fd;
463f05cddf9SRui Paulo pollfds[nxt].events = POLLIN;
464f05cddf9SRui Paulo pollfds[nxt].revents = 0;
465f05cddf9SRui Paulo pollfds_map[fd] = &(pollfds[nxt]);
466f05cddf9SRui Paulo nxt++;
467f05cddf9SRui Paulo }
468f05cddf9SRui Paulo }
469f05cddf9SRui Paulo
470f05cddf9SRui Paulo if (writers && writers->table) {
471f05cddf9SRui Paulo for (i = 0; i < writers->count; i++) {
472f05cddf9SRui Paulo /*
473f05cddf9SRui Paulo * See if we already added this descriptor, update it
474f05cddf9SRui Paulo * if so.
475f05cddf9SRui Paulo */
476f05cddf9SRui Paulo fd = writers->table[i].sock;
477f05cddf9SRui Paulo assert(fd >= 0 && fd < max_pollfd_map);
478f05cddf9SRui Paulo pfd = pollfds_map[fd];
479f05cddf9SRui Paulo if (!pfd) {
480f05cddf9SRui Paulo pfd = &(pollfds[nxt]);
481f05cddf9SRui Paulo pfd->events = 0;
482f05cddf9SRui Paulo pfd->fd = fd;
483f05cddf9SRui Paulo pollfds[i].revents = 0;
484f05cddf9SRui Paulo pollfds_map[fd] = pfd;
485f05cddf9SRui Paulo nxt++;
486f05cddf9SRui Paulo }
487f05cddf9SRui Paulo pfd->events |= POLLOUT;
488f05cddf9SRui Paulo }
489f05cddf9SRui Paulo }
490f05cddf9SRui Paulo
491f05cddf9SRui Paulo /*
492f05cddf9SRui Paulo * Exceptions are always checked when using poll, but I suppose it's
493f05cddf9SRui Paulo * possible that someone registered a socket *only* for exception
494f05cddf9SRui Paulo * handling. Set the POLLIN bit in this case.
495f05cddf9SRui Paulo */
496f05cddf9SRui Paulo if (exceptions && exceptions->table) {
497f05cddf9SRui Paulo for (i = 0; i < exceptions->count; i++) {
498f05cddf9SRui Paulo /*
499f05cddf9SRui Paulo * See if we already added this descriptor, just use it
500f05cddf9SRui Paulo * if so.
501f05cddf9SRui Paulo */
502f05cddf9SRui Paulo fd = exceptions->table[i].sock;
503f05cddf9SRui Paulo assert(fd >= 0 && fd < max_pollfd_map);
504f05cddf9SRui Paulo pfd = pollfds_map[fd];
505f05cddf9SRui Paulo if (!pfd) {
506f05cddf9SRui Paulo pfd = &(pollfds[nxt]);
507f05cddf9SRui Paulo pfd->events = POLLIN;
508f05cddf9SRui Paulo pfd->fd = fd;
509f05cddf9SRui Paulo pollfds[i].revents = 0;
510f05cddf9SRui Paulo pollfds_map[fd] = pfd;
511f05cddf9SRui Paulo nxt++;
512f05cddf9SRui Paulo }
513f05cddf9SRui Paulo }
514f05cddf9SRui Paulo }
515f05cddf9SRui Paulo
516f05cddf9SRui Paulo return nxt;
517f05cddf9SRui Paulo }
518f05cddf9SRui Paulo
519f05cddf9SRui Paulo
eloop_sock_table_dispatch_table(struct eloop_sock_table * table,struct pollfd ** pollfds_map,int max_pollfd_map,short int revents)520f05cddf9SRui Paulo static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
521f05cddf9SRui Paulo struct pollfd **pollfds_map,
522f05cddf9SRui Paulo int max_pollfd_map,
523f05cddf9SRui Paulo short int revents)
524f05cddf9SRui Paulo {
525c1d255d3SCy Schubert size_t i;
526f05cddf9SRui Paulo struct pollfd *pfd;
527f05cddf9SRui Paulo
528f05cddf9SRui Paulo if (!table || !table->table)
529f05cddf9SRui Paulo return 0;
530f05cddf9SRui Paulo
531f05cddf9SRui Paulo table->changed = 0;
532f05cddf9SRui Paulo for (i = 0; i < table->count; i++) {
533f05cddf9SRui Paulo pfd = find_pollfd(pollfds_map, table->table[i].sock,
534f05cddf9SRui Paulo max_pollfd_map);
535f05cddf9SRui Paulo if (!pfd)
536f05cddf9SRui Paulo continue;
537f05cddf9SRui Paulo
538f05cddf9SRui Paulo if (!(pfd->revents & revents))
539f05cddf9SRui Paulo continue;
540f05cddf9SRui Paulo
541f05cddf9SRui Paulo table->table[i].handler(table->table[i].sock,
542f05cddf9SRui Paulo table->table[i].eloop_data,
543f05cddf9SRui Paulo table->table[i].user_data);
544f05cddf9SRui Paulo if (table->changed)
545f05cddf9SRui Paulo return 1;
546f05cddf9SRui Paulo }
547f05cddf9SRui Paulo
548f05cddf9SRui Paulo return 0;
549f05cddf9SRui Paulo }
550f05cddf9SRui Paulo
551f05cddf9SRui Paulo
eloop_sock_table_dispatch(struct eloop_sock_table * readers,struct eloop_sock_table * writers,struct eloop_sock_table * exceptions,struct pollfd ** pollfds_map,int max_pollfd_map)552f05cddf9SRui Paulo static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
553f05cddf9SRui Paulo struct eloop_sock_table *writers,
554f05cddf9SRui Paulo struct eloop_sock_table *exceptions,
555f05cddf9SRui Paulo struct pollfd **pollfds_map,
556f05cddf9SRui Paulo int max_pollfd_map)
557f05cddf9SRui Paulo {
558f05cddf9SRui Paulo if (eloop_sock_table_dispatch_table(readers, pollfds_map,
559f05cddf9SRui Paulo max_pollfd_map, POLLIN | POLLERR |
560f05cddf9SRui Paulo POLLHUP))
561f05cddf9SRui Paulo return; /* pollfds may be invalid at this point */
562f05cddf9SRui Paulo
563f05cddf9SRui Paulo if (eloop_sock_table_dispatch_table(writers, pollfds_map,
564f05cddf9SRui Paulo max_pollfd_map, POLLOUT))
565f05cddf9SRui Paulo return; /* pollfds may be invalid at this point */
566f05cddf9SRui Paulo
567f05cddf9SRui Paulo eloop_sock_table_dispatch_table(exceptions, pollfds_map,
568f05cddf9SRui Paulo max_pollfd_map, POLLERR | POLLHUP);
569f05cddf9SRui Paulo }
570f05cddf9SRui Paulo
5715b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */
5725b9c547cSRui Paulo
5735b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
574f05cddf9SRui Paulo
eloop_sock_table_set_fds(struct eloop_sock_table * table,fd_set * fds)57539beb93cSSam Leffler static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
57639beb93cSSam Leffler fd_set *fds)
57739beb93cSSam Leffler {
578c1d255d3SCy Schubert size_t i;
57939beb93cSSam Leffler
58039beb93cSSam Leffler FD_ZERO(fds);
58139beb93cSSam Leffler
58239beb93cSSam Leffler if (table->table == NULL)
58339beb93cSSam Leffler return;
58439beb93cSSam Leffler
5855b9c547cSRui Paulo for (i = 0; i < table->count; i++) {
5865b9c547cSRui Paulo assert(table->table[i].sock >= 0);
58739beb93cSSam Leffler FD_SET(table->table[i].sock, fds);
58839beb93cSSam Leffler }
5895b9c547cSRui Paulo }
59039beb93cSSam Leffler
59139beb93cSSam Leffler
eloop_sock_table_dispatch(struct eloop_sock_table * table,fd_set * fds)59239beb93cSSam Leffler static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
59339beb93cSSam Leffler fd_set *fds)
59439beb93cSSam Leffler {
595c1d255d3SCy Schubert size_t i;
59639beb93cSSam Leffler
59739beb93cSSam Leffler if (table == NULL || table->table == NULL)
59839beb93cSSam Leffler return;
59939beb93cSSam Leffler
60039beb93cSSam Leffler table->changed = 0;
60139beb93cSSam Leffler for (i = 0; i < table->count; i++) {
60239beb93cSSam Leffler if (FD_ISSET(table->table[i].sock, fds)) {
60339beb93cSSam Leffler table->table[i].handler(table->table[i].sock,
60439beb93cSSam Leffler table->table[i].eloop_data,
60539beb93cSSam Leffler table->table[i].user_data);
60639beb93cSSam Leffler if (table->changed)
60739beb93cSSam Leffler break;
60839beb93cSSam Leffler }
60939beb93cSSam Leffler }
61039beb93cSSam Leffler }
61139beb93cSSam Leffler
6125b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
6135b9c547cSRui Paulo
6145b9c547cSRui Paulo
6155b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
eloop_sock_table_dispatch(struct epoll_event * events,int nfds)6165b9c547cSRui Paulo static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
6175b9c547cSRui Paulo {
6185b9c547cSRui Paulo struct eloop_sock *table;
6195b9c547cSRui Paulo int i;
6205b9c547cSRui Paulo
6215b9c547cSRui Paulo for (i = 0; i < nfds; i++) {
622780fb4a2SCy Schubert table = &eloop.fd_table[events[i].data.fd];
6235b9c547cSRui Paulo if (table->handler == NULL)
6245b9c547cSRui Paulo continue;
6255b9c547cSRui Paulo table->handler(table->sock, table->eloop_data,
6265b9c547cSRui Paulo table->user_data);
627325151a3SRui Paulo if (eloop.readers.changed ||
628325151a3SRui Paulo eloop.writers.changed ||
629325151a3SRui Paulo eloop.exceptions.changed)
630325151a3SRui Paulo break;
6315b9c547cSRui Paulo }
6325b9c547cSRui Paulo }
6335b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
634f05cddf9SRui Paulo
63539beb93cSSam Leffler
636780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
637780fb4a2SCy Schubert
eloop_sock_table_dispatch(struct kevent * events,int nfds)638780fb4a2SCy Schubert static void eloop_sock_table_dispatch(struct kevent *events, int nfds)
639780fb4a2SCy Schubert {
640780fb4a2SCy Schubert struct eloop_sock *table;
641780fb4a2SCy Schubert int i;
642780fb4a2SCy Schubert
643780fb4a2SCy Schubert for (i = 0; i < nfds; i++) {
644780fb4a2SCy Schubert table = &eloop.fd_table[events[i].ident];
645780fb4a2SCy Schubert if (table->handler == NULL)
646780fb4a2SCy Schubert continue;
647780fb4a2SCy Schubert table->handler(table->sock, table->eloop_data,
648780fb4a2SCy Schubert table->user_data);
649780fb4a2SCy Schubert if (eloop.readers.changed ||
650780fb4a2SCy Schubert eloop.writers.changed ||
651780fb4a2SCy Schubert eloop.exceptions.changed)
652780fb4a2SCy Schubert break;
653780fb4a2SCy Schubert }
654780fb4a2SCy Schubert }
655780fb4a2SCy Schubert
656780fb4a2SCy Schubert
eloop_sock_table_requeue(struct eloop_sock_table * table)657780fb4a2SCy Schubert static int eloop_sock_table_requeue(struct eloop_sock_table *table)
658780fb4a2SCy Schubert {
659c1d255d3SCy Schubert size_t i;
660c1d255d3SCy Schubert int r;
661780fb4a2SCy Schubert
662780fb4a2SCy Schubert r = 0;
663780fb4a2SCy Schubert for (i = 0; i < table->count && table->table; i++) {
664780fb4a2SCy Schubert if (eloop_sock_queue(table->table[i].sock, table->type) == -1)
665780fb4a2SCy Schubert r = -1;
666780fb4a2SCy Schubert }
667780fb4a2SCy Schubert return r;
668780fb4a2SCy Schubert }
669780fb4a2SCy Schubert
670780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
671780fb4a2SCy Schubert
672780fb4a2SCy Schubert
eloop_sock_requeue(void)673780fb4a2SCy Schubert int eloop_sock_requeue(void)
674780fb4a2SCy Schubert {
675780fb4a2SCy Schubert int r = 0;
676780fb4a2SCy Schubert
677780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
678780fb4a2SCy Schubert close(eloop.kqueuefd);
679780fb4a2SCy Schubert eloop.kqueuefd = kqueue();
680780fb4a2SCy Schubert if (eloop.kqueuefd < 0) {
681780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
682780fb4a2SCy Schubert __func__, strerror(errno));
683780fb4a2SCy Schubert return -1;
684780fb4a2SCy Schubert }
685780fb4a2SCy Schubert
686780fb4a2SCy Schubert if (eloop_sock_table_requeue(&eloop.readers) < 0)
687780fb4a2SCy Schubert r = -1;
688780fb4a2SCy Schubert if (eloop_sock_table_requeue(&eloop.writers) < 0)
689780fb4a2SCy Schubert r = -1;
690780fb4a2SCy Schubert if (eloop_sock_table_requeue(&eloop.exceptions) < 0)
691780fb4a2SCy Schubert r = -1;
692780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
693780fb4a2SCy Schubert
694780fb4a2SCy Schubert return r;
695780fb4a2SCy Schubert }
696780fb4a2SCy Schubert
697780fb4a2SCy Schubert
eloop_sock_table_destroy(struct eloop_sock_table * table)69839beb93cSSam Leffler static void eloop_sock_table_destroy(struct eloop_sock_table *table)
69939beb93cSSam Leffler {
70039beb93cSSam Leffler if (table) {
701c1d255d3SCy Schubert size_t i;
702c1d255d3SCy Schubert
70339beb93cSSam Leffler for (i = 0; i < table->count && table->table; i++) {
704e28a4053SRui Paulo wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
705e28a4053SRui Paulo "sock=%d eloop_data=%p user_data=%p "
706e28a4053SRui Paulo "handler=%p",
70739beb93cSSam Leffler table->table[i].sock,
70839beb93cSSam Leffler table->table[i].eloop_data,
70939beb93cSSam Leffler table->table[i].user_data,
71039beb93cSSam Leffler table->table[i].handler);
711e28a4053SRui Paulo wpa_trace_dump_funcname("eloop unregistered socket "
712e28a4053SRui Paulo "handler",
713e28a4053SRui Paulo table->table[i].handler);
714e28a4053SRui Paulo wpa_trace_dump("eloop sock", &table->table[i]);
71539beb93cSSam Leffler }
71639beb93cSSam Leffler os_free(table->table);
71739beb93cSSam Leffler }
71839beb93cSSam Leffler }
71939beb93cSSam Leffler
72039beb93cSSam Leffler
eloop_register_read_sock(int sock,eloop_sock_handler handler,void * eloop_data,void * user_data)72139beb93cSSam Leffler int eloop_register_read_sock(int sock, eloop_sock_handler handler,
72239beb93cSSam Leffler void *eloop_data, void *user_data)
72339beb93cSSam Leffler {
72439beb93cSSam Leffler return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
72539beb93cSSam Leffler eloop_data, user_data);
72639beb93cSSam Leffler }
72739beb93cSSam Leffler
72839beb93cSSam Leffler
eloop_unregister_read_sock(int sock)72939beb93cSSam Leffler void eloop_unregister_read_sock(int sock)
73039beb93cSSam Leffler {
73139beb93cSSam Leffler eloop_unregister_sock(sock, EVENT_TYPE_READ);
73239beb93cSSam Leffler }
73339beb93cSSam Leffler
73439beb93cSSam Leffler
eloop_get_sock_table(eloop_event_type type)73539beb93cSSam Leffler static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
73639beb93cSSam Leffler {
73739beb93cSSam Leffler switch (type) {
73839beb93cSSam Leffler case EVENT_TYPE_READ:
73939beb93cSSam Leffler return &eloop.readers;
74039beb93cSSam Leffler case EVENT_TYPE_WRITE:
74139beb93cSSam Leffler return &eloop.writers;
74239beb93cSSam Leffler case EVENT_TYPE_EXCEPTION:
74339beb93cSSam Leffler return &eloop.exceptions;
74439beb93cSSam Leffler }
74539beb93cSSam Leffler
74639beb93cSSam Leffler return NULL;
74739beb93cSSam Leffler }
74839beb93cSSam Leffler
74939beb93cSSam Leffler
eloop_register_sock(int sock,eloop_event_type type,eloop_sock_handler handler,void * eloop_data,void * user_data)75039beb93cSSam Leffler int eloop_register_sock(int sock, eloop_event_type type,
75139beb93cSSam Leffler eloop_sock_handler handler,
75239beb93cSSam Leffler void *eloop_data, void *user_data)
75339beb93cSSam Leffler {
75439beb93cSSam Leffler struct eloop_sock_table *table;
75539beb93cSSam Leffler
7565b9c547cSRui Paulo assert(sock >= 0);
75739beb93cSSam Leffler table = eloop_get_sock_table(type);
75839beb93cSSam Leffler return eloop_sock_table_add_sock(table, sock, handler,
75939beb93cSSam Leffler eloop_data, user_data);
76039beb93cSSam Leffler }
76139beb93cSSam Leffler
76239beb93cSSam Leffler
eloop_unregister_sock(int sock,eloop_event_type type)76339beb93cSSam Leffler void eloop_unregister_sock(int sock, eloop_event_type type)
76439beb93cSSam Leffler {
76539beb93cSSam Leffler struct eloop_sock_table *table;
76639beb93cSSam Leffler
76739beb93cSSam Leffler table = eloop_get_sock_table(type);
76839beb93cSSam Leffler eloop_sock_table_remove_sock(table, sock);
76939beb93cSSam Leffler }
77039beb93cSSam Leffler
77139beb93cSSam Leffler
eloop_register_timeout(unsigned int secs,unsigned int usecs,eloop_timeout_handler handler,void * eloop_data,void * user_data)77239beb93cSSam Leffler int eloop_register_timeout(unsigned int secs, unsigned int usecs,
77339beb93cSSam Leffler eloop_timeout_handler handler,
77439beb93cSSam Leffler void *eloop_data, void *user_data)
77539beb93cSSam Leffler {
776e28a4053SRui Paulo struct eloop_timeout *timeout, *tmp;
777f05cddf9SRui Paulo os_time_t now_sec;
77839beb93cSSam Leffler
779e28a4053SRui Paulo timeout = os_zalloc(sizeof(*timeout));
78039beb93cSSam Leffler if (timeout == NULL)
78139beb93cSSam Leffler return -1;
7825b9c547cSRui Paulo if (os_get_reltime(&timeout->time) < 0) {
78339beb93cSSam Leffler os_free(timeout);
78439beb93cSSam Leffler return -1;
78539beb93cSSam Leffler }
786f05cddf9SRui Paulo now_sec = timeout->time.sec;
78739beb93cSSam Leffler timeout->time.sec += secs;
788*4b72b91aSCy Schubert if (timeout->time.sec < now_sec)
789*4b72b91aSCy Schubert goto overflow;
79039beb93cSSam Leffler timeout->time.usec += usecs;
79139beb93cSSam Leffler while (timeout->time.usec >= 1000000) {
79239beb93cSSam Leffler timeout->time.sec++;
79339beb93cSSam Leffler timeout->time.usec -= 1000000;
79439beb93cSSam Leffler }
795*4b72b91aSCy Schubert if (timeout->time.sec < now_sec)
796*4b72b91aSCy Schubert goto overflow;
79739beb93cSSam Leffler timeout->eloop_data = eloop_data;
79839beb93cSSam Leffler timeout->user_data = user_data;
79939beb93cSSam Leffler timeout->handler = handler;
800e28a4053SRui Paulo wpa_trace_add_ref(timeout, eloop, eloop_data);
801e28a4053SRui Paulo wpa_trace_add_ref(timeout, user, user_data);
802e28a4053SRui Paulo wpa_trace_record(timeout);
80339beb93cSSam Leffler
804e28a4053SRui Paulo /* Maintain timeouts in order of increasing time */
805e28a4053SRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
8065b9c547cSRui Paulo if (os_reltime_before(&timeout->time, &tmp->time)) {
807e28a4053SRui Paulo dl_list_add(tmp->list.prev, &timeout->list);
808e28a4053SRui Paulo return 0;
809e28a4053SRui Paulo }
810e28a4053SRui Paulo }
811e28a4053SRui Paulo dl_list_add_tail(&eloop.timeout, &timeout->list);
812e28a4053SRui Paulo
81339beb93cSSam Leffler return 0;
814*4b72b91aSCy Schubert
815*4b72b91aSCy Schubert overflow:
816*4b72b91aSCy Schubert /*
817*4b72b91aSCy Schubert * Integer overflow - assume long enough timeout to be assumed
818*4b72b91aSCy Schubert * to be infinite, i.e., the timeout would never happen.
819*4b72b91aSCy Schubert */
820*4b72b91aSCy Schubert wpa_printf(MSG_DEBUG,
821*4b72b91aSCy Schubert "ELOOP: Too long timeout (secs=%u usecs=%u) to ever happen - ignore it",
822*4b72b91aSCy Schubert secs,usecs);
823*4b72b91aSCy Schubert os_free(timeout);
824*4b72b91aSCy Schubert return 0;
82539beb93cSSam Leffler }
82639beb93cSSam Leffler
82739beb93cSSam Leffler
eloop_remove_timeout(struct eloop_timeout * timeout)828e28a4053SRui Paulo static void eloop_remove_timeout(struct eloop_timeout *timeout)
829e28a4053SRui Paulo {
830e28a4053SRui Paulo dl_list_del(&timeout->list);
831e28a4053SRui Paulo wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
832e28a4053SRui Paulo wpa_trace_remove_ref(timeout, user, timeout->user_data);
833e28a4053SRui Paulo os_free(timeout);
83439beb93cSSam Leffler }
83539beb93cSSam Leffler
83639beb93cSSam Leffler
eloop_cancel_timeout(eloop_timeout_handler handler,void * eloop_data,void * user_data)83739beb93cSSam Leffler int eloop_cancel_timeout(eloop_timeout_handler handler,
83839beb93cSSam Leffler void *eloop_data, void *user_data)
83939beb93cSSam Leffler {
840e28a4053SRui Paulo struct eloop_timeout *timeout, *prev;
84139beb93cSSam Leffler int removed = 0;
84239beb93cSSam Leffler
843e28a4053SRui Paulo dl_list_for_each_safe(timeout, prev, &eloop.timeout,
844e28a4053SRui Paulo struct eloop_timeout, list) {
84539beb93cSSam Leffler if (timeout->handler == handler &&
84639beb93cSSam Leffler (timeout->eloop_data == eloop_data ||
84739beb93cSSam Leffler eloop_data == ELOOP_ALL_CTX) &&
84839beb93cSSam Leffler (timeout->user_data == user_data ||
84939beb93cSSam Leffler user_data == ELOOP_ALL_CTX)) {
850e28a4053SRui Paulo eloop_remove_timeout(timeout);
85139beb93cSSam Leffler removed++;
852e28a4053SRui Paulo }
85339beb93cSSam Leffler }
85439beb93cSSam Leffler
85539beb93cSSam Leffler return removed;
85639beb93cSSam Leffler }
85739beb93cSSam Leffler
85839beb93cSSam Leffler
eloop_cancel_timeout_one(eloop_timeout_handler handler,void * eloop_data,void * user_data,struct os_reltime * remaining)8595b9c547cSRui Paulo int eloop_cancel_timeout_one(eloop_timeout_handler handler,
8605b9c547cSRui Paulo void *eloop_data, void *user_data,
8615b9c547cSRui Paulo struct os_reltime *remaining)
8625b9c547cSRui Paulo {
8635b9c547cSRui Paulo struct eloop_timeout *timeout, *prev;
8645b9c547cSRui Paulo int removed = 0;
8655b9c547cSRui Paulo struct os_reltime now;
8665b9c547cSRui Paulo
8675b9c547cSRui Paulo os_get_reltime(&now);
8685b9c547cSRui Paulo remaining->sec = remaining->usec = 0;
8695b9c547cSRui Paulo
8705b9c547cSRui Paulo dl_list_for_each_safe(timeout, prev, &eloop.timeout,
8715b9c547cSRui Paulo struct eloop_timeout, list) {
8725b9c547cSRui Paulo if (timeout->handler == handler &&
8735b9c547cSRui Paulo (timeout->eloop_data == eloop_data) &&
8745b9c547cSRui Paulo (timeout->user_data == user_data)) {
8755b9c547cSRui Paulo removed = 1;
8765b9c547cSRui Paulo if (os_reltime_before(&now, &timeout->time))
8775b9c547cSRui Paulo os_reltime_sub(&timeout->time, &now, remaining);
8785b9c547cSRui Paulo eloop_remove_timeout(timeout);
8795b9c547cSRui Paulo break;
8805b9c547cSRui Paulo }
8815b9c547cSRui Paulo }
8825b9c547cSRui Paulo return removed;
8835b9c547cSRui Paulo }
8845b9c547cSRui Paulo
8855b9c547cSRui Paulo
eloop_is_timeout_registered(eloop_timeout_handler handler,void * eloop_data,void * user_data)88639beb93cSSam Leffler int eloop_is_timeout_registered(eloop_timeout_handler handler,
88739beb93cSSam Leffler void *eloop_data, void *user_data)
88839beb93cSSam Leffler {
88939beb93cSSam Leffler struct eloop_timeout *tmp;
89039beb93cSSam Leffler
891e28a4053SRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
89239beb93cSSam Leffler if (tmp->handler == handler &&
89339beb93cSSam Leffler tmp->eloop_data == eloop_data &&
89439beb93cSSam Leffler tmp->user_data == user_data)
89539beb93cSSam Leffler return 1;
89639beb93cSSam Leffler }
89739beb93cSSam Leffler
89839beb93cSSam Leffler return 0;
89939beb93cSSam Leffler }
90039beb93cSSam Leffler
90139beb93cSSam Leffler
eloop_deplete_timeout(unsigned int req_secs,unsigned int req_usecs,eloop_timeout_handler handler,void * eloop_data,void * user_data)9025b9c547cSRui Paulo int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
9035b9c547cSRui Paulo eloop_timeout_handler handler, void *eloop_data,
9045b9c547cSRui Paulo void *user_data)
9055b9c547cSRui Paulo {
9065b9c547cSRui Paulo struct os_reltime now, requested, remaining;
9075b9c547cSRui Paulo struct eloop_timeout *tmp;
9085b9c547cSRui Paulo
9095b9c547cSRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
9105b9c547cSRui Paulo if (tmp->handler == handler &&
9115b9c547cSRui Paulo tmp->eloop_data == eloop_data &&
9125b9c547cSRui Paulo tmp->user_data == user_data) {
9135b9c547cSRui Paulo requested.sec = req_secs;
9145b9c547cSRui Paulo requested.usec = req_usecs;
9155b9c547cSRui Paulo os_get_reltime(&now);
9165b9c547cSRui Paulo os_reltime_sub(&tmp->time, &now, &remaining);
9175b9c547cSRui Paulo if (os_reltime_before(&requested, &remaining)) {
9185b9c547cSRui Paulo eloop_cancel_timeout(handler, eloop_data,
9195b9c547cSRui Paulo user_data);
9205b9c547cSRui Paulo eloop_register_timeout(requested.sec,
9215b9c547cSRui Paulo requested.usec,
9225b9c547cSRui Paulo handler, eloop_data,
9235b9c547cSRui Paulo user_data);
9245b9c547cSRui Paulo return 1;
9255b9c547cSRui Paulo }
9265b9c547cSRui Paulo return 0;
9275b9c547cSRui Paulo }
9285b9c547cSRui Paulo }
9295b9c547cSRui Paulo
9305b9c547cSRui Paulo return -1;
9315b9c547cSRui Paulo }
9325b9c547cSRui Paulo
9335b9c547cSRui Paulo
eloop_replenish_timeout(unsigned int req_secs,unsigned int req_usecs,eloop_timeout_handler handler,void * eloop_data,void * user_data)9345b9c547cSRui Paulo int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
9355b9c547cSRui Paulo eloop_timeout_handler handler, void *eloop_data,
9365b9c547cSRui Paulo void *user_data)
9375b9c547cSRui Paulo {
9385b9c547cSRui Paulo struct os_reltime now, requested, remaining;
9395b9c547cSRui Paulo struct eloop_timeout *tmp;
9405b9c547cSRui Paulo
9415b9c547cSRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
9425b9c547cSRui Paulo if (tmp->handler == handler &&
9435b9c547cSRui Paulo tmp->eloop_data == eloop_data &&
9445b9c547cSRui Paulo tmp->user_data == user_data) {
9455b9c547cSRui Paulo requested.sec = req_secs;
9465b9c547cSRui Paulo requested.usec = req_usecs;
9475b9c547cSRui Paulo os_get_reltime(&now);
9485b9c547cSRui Paulo os_reltime_sub(&tmp->time, &now, &remaining);
9495b9c547cSRui Paulo if (os_reltime_before(&remaining, &requested)) {
9505b9c547cSRui Paulo eloop_cancel_timeout(handler, eloop_data,
9515b9c547cSRui Paulo user_data);
9525b9c547cSRui Paulo eloop_register_timeout(requested.sec,
9535b9c547cSRui Paulo requested.usec,
9545b9c547cSRui Paulo handler, eloop_data,
9555b9c547cSRui Paulo user_data);
9565b9c547cSRui Paulo return 1;
9575b9c547cSRui Paulo }
9585b9c547cSRui Paulo return 0;
9595b9c547cSRui Paulo }
9605b9c547cSRui Paulo }
9615b9c547cSRui Paulo
9625b9c547cSRui Paulo return -1;
9635b9c547cSRui Paulo }
9645b9c547cSRui Paulo
9655b9c547cSRui Paulo
96639beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
eloop_handle_alarm(int sig)96739beb93cSSam Leffler static void eloop_handle_alarm(int sig)
96839beb93cSSam Leffler {
969e28a4053SRui Paulo wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
970e28a4053SRui Paulo "two seconds. Looks like there\n"
97139beb93cSSam Leffler "is a bug that ends up in a busy loop that "
97239beb93cSSam Leffler "prevents clean shutdown.\n"
97339beb93cSSam Leffler "Killing program forcefully.\n");
97439beb93cSSam Leffler exit(1);
97539beb93cSSam Leffler }
97639beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
97739beb93cSSam Leffler
97839beb93cSSam Leffler
eloop_handle_signal(int sig)97939beb93cSSam Leffler static void eloop_handle_signal(int sig)
98039beb93cSSam Leffler {
981c1d255d3SCy Schubert size_t i;
98239beb93cSSam Leffler
98339beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
98439beb93cSSam Leffler if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
98539beb93cSSam Leffler /* Use SIGALRM to break out from potential busy loops that
98639beb93cSSam Leffler * would not allow the program to be killed. */
98739beb93cSSam Leffler eloop.pending_terminate = 1;
98839beb93cSSam Leffler signal(SIGALRM, eloop_handle_alarm);
98939beb93cSSam Leffler alarm(2);
99039beb93cSSam Leffler }
99139beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
99239beb93cSSam Leffler
99339beb93cSSam Leffler eloop.signaled++;
99439beb93cSSam Leffler for (i = 0; i < eloop.signal_count; i++) {
99539beb93cSSam Leffler if (eloop.signals[i].sig == sig) {
99639beb93cSSam Leffler eloop.signals[i].signaled++;
99739beb93cSSam Leffler break;
99839beb93cSSam Leffler }
99939beb93cSSam Leffler }
100039beb93cSSam Leffler }
100139beb93cSSam Leffler
100239beb93cSSam Leffler
eloop_process_pending_signals(void)100339beb93cSSam Leffler static void eloop_process_pending_signals(void)
100439beb93cSSam Leffler {
1005c1d255d3SCy Schubert size_t i;
100639beb93cSSam Leffler
100739beb93cSSam Leffler if (eloop.signaled == 0)
100839beb93cSSam Leffler return;
100939beb93cSSam Leffler eloop.signaled = 0;
101039beb93cSSam Leffler
101139beb93cSSam Leffler if (eloop.pending_terminate) {
101239beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
101339beb93cSSam Leffler alarm(0);
101439beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
101539beb93cSSam Leffler eloop.pending_terminate = 0;
101639beb93cSSam Leffler }
101739beb93cSSam Leffler
101839beb93cSSam Leffler for (i = 0; i < eloop.signal_count; i++) {
101939beb93cSSam Leffler if (eloop.signals[i].signaled) {
102039beb93cSSam Leffler eloop.signals[i].signaled = 0;
102139beb93cSSam Leffler eloop.signals[i].handler(eloop.signals[i].sig,
102239beb93cSSam Leffler eloop.signals[i].user_data);
102339beb93cSSam Leffler }
102439beb93cSSam Leffler }
102539beb93cSSam Leffler }
102639beb93cSSam Leffler
102739beb93cSSam Leffler
eloop_register_signal(int sig,eloop_signal_handler handler,void * user_data)102839beb93cSSam Leffler int eloop_register_signal(int sig, eloop_signal_handler handler,
102939beb93cSSam Leffler void *user_data)
103039beb93cSSam Leffler {
103139beb93cSSam Leffler struct eloop_signal *tmp;
103239beb93cSSam Leffler
1033f05cddf9SRui Paulo tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
103439beb93cSSam Leffler sizeof(struct eloop_signal));
103539beb93cSSam Leffler if (tmp == NULL)
103639beb93cSSam Leffler return -1;
103739beb93cSSam Leffler
103839beb93cSSam Leffler tmp[eloop.signal_count].sig = sig;
103939beb93cSSam Leffler tmp[eloop.signal_count].user_data = user_data;
104039beb93cSSam Leffler tmp[eloop.signal_count].handler = handler;
104139beb93cSSam Leffler tmp[eloop.signal_count].signaled = 0;
104239beb93cSSam Leffler eloop.signal_count++;
104339beb93cSSam Leffler eloop.signals = tmp;
104439beb93cSSam Leffler signal(sig, eloop_handle_signal);
104539beb93cSSam Leffler
104639beb93cSSam Leffler return 0;
104739beb93cSSam Leffler }
104839beb93cSSam Leffler
104939beb93cSSam Leffler
eloop_register_signal_terminate(eloop_signal_handler handler,void * user_data)105039beb93cSSam Leffler int eloop_register_signal_terminate(eloop_signal_handler handler,
105139beb93cSSam Leffler void *user_data)
105239beb93cSSam Leffler {
105339beb93cSSam Leffler int ret = eloop_register_signal(SIGINT, handler, user_data);
105439beb93cSSam Leffler if (ret == 0)
105539beb93cSSam Leffler ret = eloop_register_signal(SIGTERM, handler, user_data);
105639beb93cSSam Leffler return ret;
105739beb93cSSam Leffler }
105839beb93cSSam Leffler
105939beb93cSSam Leffler
eloop_register_signal_reconfig(eloop_signal_handler handler,void * user_data)106039beb93cSSam Leffler int eloop_register_signal_reconfig(eloop_signal_handler handler,
106139beb93cSSam Leffler void *user_data)
106239beb93cSSam Leffler {
106339beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
106439beb93cSSam Leffler return 0;
106539beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */
106639beb93cSSam Leffler return eloop_register_signal(SIGHUP, handler, user_data);
106739beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
106839beb93cSSam Leffler }
106939beb93cSSam Leffler
107039beb93cSSam Leffler
eloop_run(void)107139beb93cSSam Leffler void eloop_run(void)
107239beb93cSSam Leffler {
1073f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
1074f05cddf9SRui Paulo int num_poll_fds;
1075f05cddf9SRui Paulo int timeout_ms = 0;
10765b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */
10775b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
107839beb93cSSam Leffler fd_set *rfds, *wfds, *efds;
107939beb93cSSam Leffler struct timeval _tv;
10805b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
10815b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
10825b9c547cSRui Paulo int timeout_ms = -1;
10835b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
1084780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
1085780fb4a2SCy Schubert struct timespec ts;
1086780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
1087f05cddf9SRui Paulo int res;
10885b9c547cSRui Paulo struct os_reltime tv, now;
108939beb93cSSam Leffler
10905b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
109139beb93cSSam Leffler rfds = os_malloc(sizeof(*rfds));
109239beb93cSSam Leffler wfds = os_malloc(sizeof(*wfds));
109339beb93cSSam Leffler efds = os_malloc(sizeof(*efds));
1094e28a4053SRui Paulo if (rfds == NULL || wfds == NULL || efds == NULL)
109539beb93cSSam Leffler goto out;
10965b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
109739beb93cSSam Leffler
109839beb93cSSam Leffler while (!eloop.terminate &&
1099e28a4053SRui Paulo (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
110039beb93cSSam Leffler eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
1101e28a4053SRui Paulo struct eloop_timeout *timeout;
1102325151a3SRui Paulo
1103325151a3SRui Paulo if (eloop.pending_terminate) {
1104325151a3SRui Paulo /*
1105325151a3SRui Paulo * This may happen in some corner cases where a signal
1106325151a3SRui Paulo * is received during a blocking operation. We need to
1107325151a3SRui Paulo * process the pending signals and exit if requested to
1108325151a3SRui Paulo * avoid hitting the SIGALRM limit if the blocking
1109325151a3SRui Paulo * operation took more than two seconds.
1110325151a3SRui Paulo */
1111325151a3SRui Paulo eloop_process_pending_signals();
1112325151a3SRui Paulo if (eloop.terminate)
1113325151a3SRui Paulo break;
1114325151a3SRui Paulo }
1115325151a3SRui Paulo
1116e28a4053SRui Paulo timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
1117e28a4053SRui Paulo list);
1118e28a4053SRui Paulo if (timeout) {
11195b9c547cSRui Paulo os_get_reltime(&now);
11205b9c547cSRui Paulo if (os_reltime_before(&now, &timeout->time))
11215b9c547cSRui Paulo os_reltime_sub(&timeout->time, &now, &tv);
112239beb93cSSam Leffler else
112339beb93cSSam Leffler tv.sec = tv.usec = 0;
11245b9c547cSRui Paulo #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
1125f05cddf9SRui Paulo timeout_ms = tv.sec * 1000 + tv.usec / 1000;
11265b9c547cSRui Paulo #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
11275b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
112839beb93cSSam Leffler _tv.tv_sec = tv.sec;
112939beb93cSSam Leffler _tv.tv_usec = tv.usec;
11305b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
1131780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
1132780fb4a2SCy Schubert ts.tv_sec = tv.sec;
1133780fb4a2SCy Schubert ts.tv_nsec = tv.usec * 1000L;
1134780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
113539beb93cSSam Leffler }
113639beb93cSSam Leffler
1137f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
1138f05cddf9SRui Paulo num_poll_fds = eloop_sock_table_set_fds(
1139f05cddf9SRui Paulo &eloop.readers, &eloop.writers, &eloop.exceptions,
1140f05cddf9SRui Paulo eloop.pollfds, eloop.pollfds_map,
1141f05cddf9SRui Paulo eloop.max_pollfd_map);
1142f05cddf9SRui Paulo res = poll(eloop.pollfds, num_poll_fds,
1143f05cddf9SRui Paulo timeout ? timeout_ms : -1);
11445b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */
11455b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
114639beb93cSSam Leffler eloop_sock_table_set_fds(&eloop.readers, rfds);
114739beb93cSSam Leffler eloop_sock_table_set_fds(&eloop.writers, wfds);
114839beb93cSSam Leffler eloop_sock_table_set_fds(&eloop.exceptions, efds);
114939beb93cSSam Leffler res = select(eloop.max_sock + 1, rfds, wfds, efds,
1150e28a4053SRui Paulo timeout ? &_tv : NULL);
11515b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
11525b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
11535b9c547cSRui Paulo if (eloop.count == 0) {
11545b9c547cSRui Paulo res = 0;
11555b9c547cSRui Paulo } else {
11565b9c547cSRui Paulo res = epoll_wait(eloop.epollfd, eloop.epoll_events,
11575b9c547cSRui Paulo eloop.count, timeout_ms);
11585b9c547cSRui Paulo }
11595b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
1160780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
1161780fb4a2SCy Schubert if (eloop.count == 0) {
1162780fb4a2SCy Schubert res = 0;
1163780fb4a2SCy Schubert } else {
1164780fb4a2SCy Schubert res = kevent(eloop.kqueuefd, NULL, 0,
1165780fb4a2SCy Schubert eloop.kqueue_events, eloop.kqueue_nevents,
1166780fb4a2SCy Schubert timeout ? &ts : NULL);
1167780fb4a2SCy Schubert }
1168780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
116939beb93cSSam Leffler if (res < 0 && errno != EINTR && errno != 0) {
11705b9c547cSRui Paulo wpa_printf(MSG_ERROR, "eloop: %s: %s",
11715b9c547cSRui Paulo #ifdef CONFIG_ELOOP_POLL
11725b9c547cSRui Paulo "poll"
11735b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */
11745b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
11755b9c547cSRui Paulo "select"
11765b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
11775b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
11785b9c547cSRui Paulo "epoll"
11795b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
1180780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
1181780fb4a2SCy Schubert "kqueue"
1182780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_EKQUEUE */
1183780fb4a2SCy Schubert
11845b9c547cSRui Paulo , strerror(errno));
118539beb93cSSam Leffler goto out;
118639beb93cSSam Leffler }
1187325151a3SRui Paulo
1188325151a3SRui Paulo eloop.readers.changed = 0;
1189325151a3SRui Paulo eloop.writers.changed = 0;
1190325151a3SRui Paulo eloop.exceptions.changed = 0;
1191325151a3SRui Paulo
119239beb93cSSam Leffler eloop_process_pending_signals();
119339beb93cSSam Leffler
1194780fb4a2SCy Schubert
119539beb93cSSam Leffler /* check if some registered timeouts have occurred */
1196e28a4053SRui Paulo timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
1197e28a4053SRui Paulo list);
1198e28a4053SRui Paulo if (timeout) {
11995b9c547cSRui Paulo os_get_reltime(&now);
12005b9c547cSRui Paulo if (!os_reltime_before(&now, &timeout->time)) {
1201e28a4053SRui Paulo void *eloop_data = timeout->eloop_data;
1202e28a4053SRui Paulo void *user_data = timeout->user_data;
1203e28a4053SRui Paulo eloop_timeout_handler handler =
1204e28a4053SRui Paulo timeout->handler;
1205e28a4053SRui Paulo eloop_remove_timeout(timeout);
1206e28a4053SRui Paulo handler(eloop_data, user_data);
120739beb93cSSam Leffler }
120839beb93cSSam Leffler
120939beb93cSSam Leffler }
121039beb93cSSam Leffler
121139beb93cSSam Leffler if (res <= 0)
121239beb93cSSam Leffler continue;
121339beb93cSSam Leffler
1214325151a3SRui Paulo if (eloop.readers.changed ||
1215325151a3SRui Paulo eloop.writers.changed ||
1216325151a3SRui Paulo eloop.exceptions.changed) {
1217325151a3SRui Paulo /*
1218325151a3SRui Paulo * Sockets may have been closed and reopened with the
1219325151a3SRui Paulo * same FD in the signal or timeout handlers, so we
1220325151a3SRui Paulo * must skip the previous results and check again
1221325151a3SRui Paulo * whether any of the currently registered sockets have
1222325151a3SRui Paulo * events.
1223325151a3SRui Paulo */
1224325151a3SRui Paulo continue;
1225325151a3SRui Paulo }
1226325151a3SRui Paulo
1227f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
1228f05cddf9SRui Paulo eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
1229f05cddf9SRui Paulo &eloop.exceptions, eloop.pollfds_map,
1230f05cddf9SRui Paulo eloop.max_pollfd_map);
12315b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */
12325b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
123339beb93cSSam Leffler eloop_sock_table_dispatch(&eloop.readers, rfds);
123439beb93cSSam Leffler eloop_sock_table_dispatch(&eloop.writers, wfds);
123539beb93cSSam Leffler eloop_sock_table_dispatch(&eloop.exceptions, efds);
12365b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
12375b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
12385b9c547cSRui Paulo eloop_sock_table_dispatch(eloop.epoll_events, res);
12395b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
1240780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
1241780fb4a2SCy Schubert eloop_sock_table_dispatch(eloop.kqueue_events, res);
1242780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
124339beb93cSSam Leffler }
124439beb93cSSam Leffler
12455b9c547cSRui Paulo eloop.terminate = 0;
124639beb93cSSam Leffler out:
12475b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
124839beb93cSSam Leffler os_free(rfds);
124939beb93cSSam Leffler os_free(wfds);
125039beb93cSSam Leffler os_free(efds);
12515b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
1252f05cddf9SRui Paulo return;
125339beb93cSSam Leffler }
125439beb93cSSam Leffler
125539beb93cSSam Leffler
eloop_terminate(void)125639beb93cSSam Leffler void eloop_terminate(void)
125739beb93cSSam Leffler {
125839beb93cSSam Leffler eloop.terminate = 1;
125939beb93cSSam Leffler }
126039beb93cSSam Leffler
126139beb93cSSam Leffler
eloop_destroy(void)126239beb93cSSam Leffler void eloop_destroy(void)
126339beb93cSSam Leffler {
126439beb93cSSam Leffler struct eloop_timeout *timeout, *prev;
12655b9c547cSRui Paulo struct os_reltime now;
126639beb93cSSam Leffler
12675b9c547cSRui Paulo os_get_reltime(&now);
1268e28a4053SRui Paulo dl_list_for_each_safe(timeout, prev, &eloop.timeout,
1269e28a4053SRui Paulo struct eloop_timeout, list) {
127039beb93cSSam Leffler int sec, usec;
1271e28a4053SRui Paulo sec = timeout->time.sec - now.sec;
1272e28a4053SRui Paulo usec = timeout->time.usec - now.usec;
1273e28a4053SRui Paulo if (timeout->time.usec < now.usec) {
127439beb93cSSam Leffler sec--;
127539beb93cSSam Leffler usec += 1000000;
127639beb93cSSam Leffler }
1277e28a4053SRui Paulo wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
1278e28a4053SRui Paulo "eloop_data=%p user_data=%p handler=%p",
1279e28a4053SRui Paulo sec, usec, timeout->eloop_data, timeout->user_data,
1280e28a4053SRui Paulo timeout->handler);
1281e28a4053SRui Paulo wpa_trace_dump_funcname("eloop unregistered timeout handler",
1282e28a4053SRui Paulo timeout->handler);
1283e28a4053SRui Paulo wpa_trace_dump("eloop timeout", timeout);
1284e28a4053SRui Paulo eloop_remove_timeout(timeout);
128539beb93cSSam Leffler }
128639beb93cSSam Leffler eloop_sock_table_destroy(&eloop.readers);
128739beb93cSSam Leffler eloop_sock_table_destroy(&eloop.writers);
128839beb93cSSam Leffler eloop_sock_table_destroy(&eloop.exceptions);
128939beb93cSSam Leffler os_free(eloop.signals);
1290f05cddf9SRui Paulo
1291f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
1292f05cddf9SRui Paulo os_free(eloop.pollfds);
1293f05cddf9SRui Paulo os_free(eloop.pollfds_map);
1294f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */
1295780fb4a2SCy Schubert #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
1296780fb4a2SCy Schubert os_free(eloop.fd_table);
1297780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
12985b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL
12995b9c547cSRui Paulo os_free(eloop.epoll_events);
13005b9c547cSRui Paulo close(eloop.epollfd);
13015b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */
1302780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
1303780fb4a2SCy Schubert os_free(eloop.kqueue_events);
1304780fb4a2SCy Schubert close(eloop.kqueuefd);
1305780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
130639beb93cSSam Leffler }
130739beb93cSSam Leffler
130839beb93cSSam Leffler
eloop_terminated(void)130939beb93cSSam Leffler int eloop_terminated(void)
131039beb93cSSam Leffler {
1311325151a3SRui Paulo return eloop.terminate || eloop.pending_terminate;
131239beb93cSSam Leffler }
131339beb93cSSam Leffler
131439beb93cSSam Leffler
eloop_wait_for_read_sock(int sock)131539beb93cSSam Leffler void eloop_wait_for_read_sock(int sock)
131639beb93cSSam Leffler {
1317f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL
1318f05cddf9SRui Paulo struct pollfd pfd;
1319f05cddf9SRui Paulo
1320f05cddf9SRui Paulo if (sock < 0)
1321f05cddf9SRui Paulo return;
1322f05cddf9SRui Paulo
1323f05cddf9SRui Paulo os_memset(&pfd, 0, sizeof(pfd));
1324f05cddf9SRui Paulo pfd.fd = sock;
1325f05cddf9SRui Paulo pfd.events = POLLIN;
1326f05cddf9SRui Paulo
1327f05cddf9SRui Paulo poll(&pfd, 1, -1);
13285b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */
13295b9c547cSRui Paulo #if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL)
13305b9c547cSRui Paulo /*
13315b9c547cSRui Paulo * We can use epoll() here. But epoll() requres 4 system calls.
13325b9c547cSRui Paulo * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for
13335b9c547cSRui Paulo * epoll fd. So select() is better for performance here.
13345b9c547cSRui Paulo */
133539beb93cSSam Leffler fd_set rfds;
133639beb93cSSam Leffler
133739beb93cSSam Leffler if (sock < 0)
133839beb93cSSam Leffler return;
133939beb93cSSam Leffler
134039beb93cSSam Leffler FD_ZERO(&rfds);
134139beb93cSSam Leffler FD_SET(sock, &rfds);
134239beb93cSSam Leffler select(sock + 1, &rfds, NULL, NULL, NULL);
13435b9c547cSRui Paulo #endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */
1344780fb4a2SCy Schubert #ifdef CONFIG_ELOOP_KQUEUE
1345780fb4a2SCy Schubert int kfd;
1346780fb4a2SCy Schubert struct kevent ke1, ke2;
1347780fb4a2SCy Schubert
1348780fb4a2SCy Schubert kfd = kqueue();
1349780fb4a2SCy Schubert if (kfd == -1)
1350780fb4a2SCy Schubert return;
1351780fb4a2SCy Schubert EV_SET(&ke1, sock, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
1352780fb4a2SCy Schubert kevent(kfd, &ke1, 1, &ke2, 1, NULL);
1353780fb4a2SCy Schubert close(kfd);
1354780fb4a2SCy Schubert #endif /* CONFIG_ELOOP_KQUEUE */
135539beb93cSSam Leffler }
13565b9c547cSRui Paulo
13575b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT
13585b9c547cSRui Paulo #undef CONFIG_ELOOP_SELECT
13595b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */
1360