1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * Event loop based on select() loop
3e5b75505Sopenharmony_ci * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "includes.h"
10e5b75505Sopenharmony_ci#include <assert.h>
11e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
12e5b75505Sopenharmony_ci#include <pthread.h>
13e5b75505Sopenharmony_ci#endif
14e5b75505Sopenharmony_ci
15e5b75505Sopenharmony_ci#include "common.h"
16e5b75505Sopenharmony_ci#include "trace.h"
17e5b75505Sopenharmony_ci#include "list.h"
18e5b75505Sopenharmony_ci#include "eloop.h"
19e5b75505Sopenharmony_ci
20e5b75505Sopenharmony_ci#if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL)
21e5b75505Sopenharmony_ci#error Do not define both of poll and epoll
22e5b75505Sopenharmony_ci#endif
23e5b75505Sopenharmony_ci
24e5b75505Sopenharmony_ci#if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_KQUEUE)
25e5b75505Sopenharmony_ci#error Do not define both of poll and kqueue
26e5b75505Sopenharmony_ci#endif
27e5b75505Sopenharmony_ci
28e5b75505Sopenharmony_ci#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) && \
29e5b75505Sopenharmony_ci    !defined(CONFIG_ELOOP_KQUEUE)
30e5b75505Sopenharmony_ci#define CONFIG_ELOOP_SELECT
31e5b75505Sopenharmony_ci#endif
32e5b75505Sopenharmony_ci
33e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_POLL
34e5b75505Sopenharmony_ci#include <poll.h>
35e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_POLL */
36e5b75505Sopenharmony_ci
37e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
38e5b75505Sopenharmony_ci#include <sys/epoll.h>
39e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
40e5b75505Sopenharmony_ci
41e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
42e5b75505Sopenharmony_ci#include <sys/event.h>
43e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
44e5b75505Sopenharmony_ci
45e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
46e5b75505Sopenharmony_cienum eloop_ctrl_fd_index {
47e5b75505Sopenharmony_ci	ELOOP_CTRL_FD_READ = 0,
48e5b75505Sopenharmony_ci	ELOOP_CTRL_FD_WRITE,
49e5b75505Sopenharmony_ci
50e5b75505Sopenharmony_ci	ELOOP_CTRL_FD_BUTT
51e5b75505Sopenharmony_ci};
52e5b75505Sopenharmony_ci#endif
53e5b75505Sopenharmony_ci
54e5b75505Sopenharmony_cistruct eloop_sock {
55e5b75505Sopenharmony_ci	int sock;
56e5b75505Sopenharmony_ci	void *eloop_data;
57e5b75505Sopenharmony_ci	void *user_data;
58e5b75505Sopenharmony_ci	eloop_sock_handler handler;
59e5b75505Sopenharmony_ci	WPA_TRACE_REF(eloop);
60e5b75505Sopenharmony_ci	WPA_TRACE_REF(user);
61e5b75505Sopenharmony_ci	WPA_TRACE_INFO
62e5b75505Sopenharmony_ci};
63e5b75505Sopenharmony_ci
64e5b75505Sopenharmony_cistruct eloop_timeout {
65e5b75505Sopenharmony_ci	struct dl_list list;
66e5b75505Sopenharmony_ci	struct os_reltime time;
67e5b75505Sopenharmony_ci	void *eloop_data;
68e5b75505Sopenharmony_ci	void *user_data;
69e5b75505Sopenharmony_ci	eloop_timeout_handler handler;
70e5b75505Sopenharmony_ci	WPA_TRACE_REF(eloop);
71e5b75505Sopenharmony_ci	WPA_TRACE_REF(user);
72e5b75505Sopenharmony_ci	WPA_TRACE_INFO
73e5b75505Sopenharmony_ci};
74e5b75505Sopenharmony_ci
75e5b75505Sopenharmony_cistruct eloop_signal {
76e5b75505Sopenharmony_ci	int sig;
77e5b75505Sopenharmony_ci	void *user_data;
78e5b75505Sopenharmony_ci	eloop_signal_handler handler;
79e5b75505Sopenharmony_ci	int signaled;
80e5b75505Sopenharmony_ci};
81e5b75505Sopenharmony_ci
82e5b75505Sopenharmony_cistruct eloop_sock_table {
83e5b75505Sopenharmony_ci	int count;
84e5b75505Sopenharmony_ci	struct eloop_sock *table;
85e5b75505Sopenharmony_ci	eloop_event_type type;
86e5b75505Sopenharmony_ci	int changed;
87e5b75505Sopenharmony_ci};
88e5b75505Sopenharmony_ci
89e5b75505Sopenharmony_cistruct eloop_data {
90e5b75505Sopenharmony_ci	int max_sock;
91e5b75505Sopenharmony_ci
92e5b75505Sopenharmony_ci	int count; /* sum of all table counts */
93e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_POLL
94e5b75505Sopenharmony_ci	int max_pollfd_map; /* number of pollfds_map currently allocated */
95e5b75505Sopenharmony_ci	int max_poll_fds; /* number of pollfds currently allocated */
96e5b75505Sopenharmony_ci	struct pollfd *pollfds;
97e5b75505Sopenharmony_ci	struct pollfd **pollfds_map;
98e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_POLL */
99e5b75505Sopenharmony_ci#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
100e5b75505Sopenharmony_ci	int max_fd;
101e5b75505Sopenharmony_ci	struct eloop_sock *fd_table;
102e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
103e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
104e5b75505Sopenharmony_ci	int epollfd;
105e5b75505Sopenharmony_ci	int epoll_max_event_num;
106e5b75505Sopenharmony_ci	struct epoll_event *epoll_events;
107e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
108e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
109e5b75505Sopenharmony_ci	int kqueuefd;
110e5b75505Sopenharmony_ci	int kqueue_nevents;
111e5b75505Sopenharmony_ci	struct kevent *kqueue_events;
112e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
113e5b75505Sopenharmony_ci	struct eloop_sock_table readers;
114e5b75505Sopenharmony_ci	struct eloop_sock_table writers;
115e5b75505Sopenharmony_ci	struct eloop_sock_table exceptions;
116e5b75505Sopenharmony_ci
117e5b75505Sopenharmony_ci	struct dl_list timeout;
118e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
119e5b75505Sopenharmony_ci	int ctrl_fd[ELOOP_CTRL_FD_BUTT];
120e5b75505Sopenharmony_ci#endif
121e5b75505Sopenharmony_ci	int signal_count;
122e5b75505Sopenharmony_ci	struct eloop_signal *signals;
123e5b75505Sopenharmony_ci	int signaled;
124e5b75505Sopenharmony_ci	int pending_terminate;
125e5b75505Sopenharmony_ci
126e5b75505Sopenharmony_ci	int terminate;
127e5b75505Sopenharmony_ci};
128e5b75505Sopenharmony_ci
129e5b75505Sopenharmony_cistatic struct eloop_data eloop;
130e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
131e5b75505Sopenharmony_cistatic pthread_mutex_t lock;
132e5b75505Sopenharmony_ci#endif
133e5b75505Sopenharmony_ci#ifdef WPA_TRACE
134e5b75505Sopenharmony_ci
135e5b75505Sopenharmony_cistatic void eloop_sigsegv_handler(int sig)
136e5b75505Sopenharmony_ci{
137e5b75505Sopenharmony_ci	wpa_trace_show("eloop SIGSEGV");
138e5b75505Sopenharmony_ci	abort();
139e5b75505Sopenharmony_ci}
140e5b75505Sopenharmony_ci
141e5b75505Sopenharmony_cistatic void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
142e5b75505Sopenharmony_ci{
143e5b75505Sopenharmony_ci	int i;
144e5b75505Sopenharmony_ci	if (table == NULL || table->table == NULL)
145e5b75505Sopenharmony_ci		return;
146e5b75505Sopenharmony_ci	for (i = 0; i < table->count; i++) {
147e5b75505Sopenharmony_ci		wpa_trace_add_ref(&table->table[i], eloop,
148e5b75505Sopenharmony_ci				  table->table[i].eloop_data);
149e5b75505Sopenharmony_ci		wpa_trace_add_ref(&table->table[i], user,
150e5b75505Sopenharmony_ci				  table->table[i].user_data);
151e5b75505Sopenharmony_ci	}
152e5b75505Sopenharmony_ci}
153e5b75505Sopenharmony_ci
154e5b75505Sopenharmony_ci
155e5b75505Sopenharmony_cistatic void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
156e5b75505Sopenharmony_ci{
157e5b75505Sopenharmony_ci	int i;
158e5b75505Sopenharmony_ci	if (table == NULL || table->table == NULL)
159e5b75505Sopenharmony_ci		return;
160e5b75505Sopenharmony_ci	for (i = 0; i < table->count; i++) {
161e5b75505Sopenharmony_ci		wpa_trace_remove_ref(&table->table[i], eloop,
162e5b75505Sopenharmony_ci				     table->table[i].eloop_data);
163e5b75505Sopenharmony_ci		wpa_trace_remove_ref(&table->table[i], user,
164e5b75505Sopenharmony_ci				     table->table[i].user_data);
165e5b75505Sopenharmony_ci	}
166e5b75505Sopenharmony_ci}
167e5b75505Sopenharmony_ci
168e5b75505Sopenharmony_ci#else /* WPA_TRACE */
169e5b75505Sopenharmony_ci
170e5b75505Sopenharmony_ci#define eloop_trace_sock_add_ref(table) do { } while (0)
171e5b75505Sopenharmony_ci#define eloop_trace_sock_remove_ref(table) do { } while (0)
172e5b75505Sopenharmony_ci
173e5b75505Sopenharmony_ci#endif /* WPA_TRACE */
174e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
175e5b75505Sopenharmony_cistatic void eloop_ctrl_read_handler(int sock, void *eloop_ctx, void *sock_ctx)
176e5b75505Sopenharmony_ci{
177e5b75505Sopenharmony_ci	int8_t buf;
178e5b75505Sopenharmony_ci
179e5b75505Sopenharmony_ci	(void)eloop_ctx;
180e5b75505Sopenharmony_ci	(void)sock_ctx;
181e5b75505Sopenharmony_ci	if (sock != eloop.ctrl_fd[ELOOP_CTRL_FD_READ]) {
182e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: socket is mismatched.", __func__);
183e5b75505Sopenharmony_ci		return;
184e5b75505Sopenharmony_ci	}
185e5b75505Sopenharmony_ci
186e5b75505Sopenharmony_ci	if (eloop.ctrl_fd[ELOOP_CTRL_FD_READ] != -1) {
187e5b75505Sopenharmony_ci		read(eloop.ctrl_fd[ELOOP_CTRL_FD_READ], &buf, 1);
188e5b75505Sopenharmony_ci	} else {
189e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: pipe read end was closed", __func__);
190e5b75505Sopenharmony_ci	}
191e5b75505Sopenharmony_ci}
192e5b75505Sopenharmony_ci
193e5b75505Sopenharmony_cistatic void eloop_ctrl_init()
194e5b75505Sopenharmony_ci{
195e5b75505Sopenharmony_ci	int ret;
196e5b75505Sopenharmony_ci
197e5b75505Sopenharmony_ci	ret = pipe(eloop.ctrl_fd);
198e5b75505Sopenharmony_ci	if (ret != 0) {
199e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: pipe failed: %s", __func__, strerror(errno));
200e5b75505Sopenharmony_ci		return;
201e5b75505Sopenharmony_ci	}
202e5b75505Sopenharmony_ci	eloop_register_read_sock(eloop.ctrl_fd[ELOOP_CTRL_FD_READ],
203e5b75505Sopenharmony_ci				 eloop_ctrl_read_handler, NULL, NULL);
204e5b75505Sopenharmony_ci
205e5b75505Sopenharmony_ci	wpa_printf(MSG_INFO, "eloop_ctrl_init: %d", ret);
206e5b75505Sopenharmony_ci}
207e5b75505Sopenharmony_ci
208e5b75505Sopenharmony_cistatic void eloop_ctrl_deinit()
209e5b75505Sopenharmony_ci{
210e5b75505Sopenharmony_ci	if (eloop.ctrl_fd[ELOOP_CTRL_FD_READ] != -1) {
211e5b75505Sopenharmony_ci		eloop_unregister_read_sock(eloop.ctrl_fd[ELOOP_CTRL_FD_READ]);
212e5b75505Sopenharmony_ci	}
213e5b75505Sopenharmony_ci	close(eloop.ctrl_fd[ELOOP_CTRL_FD_READ]);
214e5b75505Sopenharmony_ci	close(eloop.ctrl_fd[ELOOP_CTRL_FD_WRITE]);
215e5b75505Sopenharmony_ci	eloop.ctrl_fd[ELOOP_CTRL_FD_READ] = -1;
216e5b75505Sopenharmony_ci	eloop.ctrl_fd[ELOOP_CTRL_FD_WRITE] = -1;
217e5b75505Sopenharmony_ci
218e5b75505Sopenharmony_ci	wpa_printf(MSG_INFO, "eloop_ctrl_deinit done");
219e5b75505Sopenharmony_ci}
220e5b75505Sopenharmony_ci
221e5b75505Sopenharmony_cistatic int eloop_wakeup()
222e5b75505Sopenharmony_ci{
223e5b75505Sopenharmony_ci	int ret = -1;
224e5b75505Sopenharmony_ci	uint8_t buf = '0'; // no meaning
225e5b75505Sopenharmony_ci
226e5b75505Sopenharmony_ci	if (eloop.ctrl_fd[ELOOP_CTRL_FD_WRITE] != -1) {
227e5b75505Sopenharmony_ci		ret = write(eloop.ctrl_fd[ELOOP_CTRL_FD_WRITE], &buf, 1);
228e5b75505Sopenharmony_ci	} else {
229e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: pipe write end was closed", __func__);
230e5b75505Sopenharmony_ci	}
231e5b75505Sopenharmony_ci	return ret;
232e5b75505Sopenharmony_ci}
233e5b75505Sopenharmony_ci#endif // CONFIG_DRIVER_HDF
234e5b75505Sopenharmony_ci
235e5b75505Sopenharmony_ciint eloop_init(void)
236e5b75505Sopenharmony_ci{
237e5b75505Sopenharmony_ci	os_memset(&eloop, 0, sizeof(eloop));
238e5b75505Sopenharmony_ci	dl_list_init(&eloop.timeout);
239e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
240e5b75505Sopenharmony_ci	eloop.epollfd = epoll_create1(0);
241e5b75505Sopenharmony_ci	if (eloop.epollfd < 0) {
242e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s",
243e5b75505Sopenharmony_ci			   __func__, strerror(errno));
244e5b75505Sopenharmony_ci		return -1;
245e5b75505Sopenharmony_ci	}
246e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
247e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
248e5b75505Sopenharmony_ci	eloop.kqueuefd = kqueue();
249e5b75505Sopenharmony_ci	if (eloop.kqueuefd < 0) {
250e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
251e5b75505Sopenharmony_ci			   __func__, strerror(errno));
252e5b75505Sopenharmony_ci		return -1;
253e5b75505Sopenharmony_ci	}
254e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
255e5b75505Sopenharmony_ci#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
256e5b75505Sopenharmony_ci	eloop.readers.type = EVENT_TYPE_READ;
257e5b75505Sopenharmony_ci	eloop.writers.type = EVENT_TYPE_WRITE;
258e5b75505Sopenharmony_ci	eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
259e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
260e5b75505Sopenharmony_ci#ifdef WPA_TRACE
261e5b75505Sopenharmony_ci	signal(SIGSEGV, eloop_sigsegv_handler);
262e5b75505Sopenharmony_ci#endif /* WPA_TRACE */
263e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
264e5b75505Sopenharmony_ci	eloop_ctrl_init();
265e5b75505Sopenharmony_ci#endif
266e5b75505Sopenharmony_ci	return 0;
267e5b75505Sopenharmony_ci}
268e5b75505Sopenharmony_ci
269e5b75505Sopenharmony_ci
270e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
271e5b75505Sopenharmony_cistatic int eloop_sock_queue(int sock, eloop_event_type type)
272e5b75505Sopenharmony_ci{
273e5b75505Sopenharmony_ci	struct epoll_event ev;
274e5b75505Sopenharmony_ci
275e5b75505Sopenharmony_ci	os_memset(&ev, 0, sizeof(ev));
276e5b75505Sopenharmony_ci	switch (type) {
277e5b75505Sopenharmony_ci	case EVENT_TYPE_READ:
278e5b75505Sopenharmony_ci		ev.events = EPOLLIN;
279e5b75505Sopenharmony_ci		break;
280e5b75505Sopenharmony_ci	case EVENT_TYPE_WRITE:
281e5b75505Sopenharmony_ci		ev.events = EPOLLOUT;
282e5b75505Sopenharmony_ci		break;
283e5b75505Sopenharmony_ci	/*
284e5b75505Sopenharmony_ci	 * Exceptions are always checked when using epoll, but I suppose it's
285e5b75505Sopenharmony_ci	 * possible that someone registered a socket *only* for exception
286e5b75505Sopenharmony_ci	 * handling.
287e5b75505Sopenharmony_ci	 */
288e5b75505Sopenharmony_ci	case EVENT_TYPE_EXCEPTION:
289e5b75505Sopenharmony_ci		ev.events = EPOLLERR | EPOLLHUP;
290e5b75505Sopenharmony_ci		break;
291e5b75505Sopenharmony_ci	}
292e5b75505Sopenharmony_ci	ev.data.fd = sock;
293e5b75505Sopenharmony_ci	if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
294e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d failed: %s",
295e5b75505Sopenharmony_ci			   __func__, sock, strerror(errno));
296e5b75505Sopenharmony_ci		return -1;
297e5b75505Sopenharmony_ci	}
298e5b75505Sopenharmony_ci	return 0;
299e5b75505Sopenharmony_ci}
300e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
301e5b75505Sopenharmony_ci
302e5b75505Sopenharmony_ci
303e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
304e5b75505Sopenharmony_ci
305e5b75505Sopenharmony_cistatic short event_type_kevent_filter(eloop_event_type type)
306e5b75505Sopenharmony_ci{
307e5b75505Sopenharmony_ci	switch (type) {
308e5b75505Sopenharmony_ci	case EVENT_TYPE_READ:
309e5b75505Sopenharmony_ci		return EVFILT_READ;
310e5b75505Sopenharmony_ci	case EVENT_TYPE_WRITE:
311e5b75505Sopenharmony_ci		return EVFILT_WRITE;
312e5b75505Sopenharmony_ci	default:
313e5b75505Sopenharmony_ci		return 0;
314e5b75505Sopenharmony_ci	}
315e5b75505Sopenharmony_ci}
316e5b75505Sopenharmony_ci
317e5b75505Sopenharmony_ci
318e5b75505Sopenharmony_cistatic int eloop_sock_queue(int sock, eloop_event_type type)
319e5b75505Sopenharmony_ci{
320e5b75505Sopenharmony_ci	struct kevent ke;
321e5b75505Sopenharmony_ci
322e5b75505Sopenharmony_ci	EV_SET(&ke, sock, event_type_kevent_filter(type), EV_ADD, 0, 0, 0);
323e5b75505Sopenharmony_ci	if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) {
324e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s",
325e5b75505Sopenharmony_ci			   __func__, sock, strerror(errno));
326e5b75505Sopenharmony_ci		return -1;
327e5b75505Sopenharmony_ci	}
328e5b75505Sopenharmony_ci	return 0;
329e5b75505Sopenharmony_ci}
330e5b75505Sopenharmony_ci
331e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
332e5b75505Sopenharmony_ci
333e5b75505Sopenharmony_ci
334e5b75505Sopenharmony_cistatic int eloop_sock_table_add_sock(struct eloop_sock_table *table,
335e5b75505Sopenharmony_ci                                     int sock, eloop_sock_handler handler,
336e5b75505Sopenharmony_ci                                     void *eloop_data, void *user_data)
337e5b75505Sopenharmony_ci{
338e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
339e5b75505Sopenharmony_ci	struct epoll_event *temp_events;
340e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
341e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
342e5b75505Sopenharmony_ci	struct kevent *temp_events;
343e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
344e5b75505Sopenharmony_ci#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
345e5b75505Sopenharmony_ci	struct eloop_sock *temp_table;
346e5b75505Sopenharmony_ci	int next;
347e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
348e5b75505Sopenharmony_ci	struct eloop_sock *tmp;
349e5b75505Sopenharmony_ci	int new_max_sock;
350e5b75505Sopenharmony_ci
351e5b75505Sopenharmony_ci	if (sock > eloop.max_sock)
352e5b75505Sopenharmony_ci		new_max_sock = sock;
353e5b75505Sopenharmony_ci	else
354e5b75505Sopenharmony_ci		new_max_sock = eloop.max_sock;
355e5b75505Sopenharmony_ci
356e5b75505Sopenharmony_ci	if (table == NULL)
357e5b75505Sopenharmony_ci		return -1;
358e5b75505Sopenharmony_ci
359e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_POLL
360e5b75505Sopenharmony_ci	if (new_max_sock >= eloop.max_pollfd_map) {
361e5b75505Sopenharmony_ci		struct pollfd **nmap;
362e5b75505Sopenharmony_ci		nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
363e5b75505Sopenharmony_ci					sizeof(struct pollfd *));
364e5b75505Sopenharmony_ci		if (nmap == NULL)
365e5b75505Sopenharmony_ci			return -1;
366e5b75505Sopenharmony_ci
367e5b75505Sopenharmony_ci		eloop.max_pollfd_map = new_max_sock + 50;
368e5b75505Sopenharmony_ci		eloop.pollfds_map = nmap;
369e5b75505Sopenharmony_ci	}
370e5b75505Sopenharmony_ci
371e5b75505Sopenharmony_ci	if (eloop.count + 1 > eloop.max_poll_fds) {
372e5b75505Sopenharmony_ci		struct pollfd *n;
373e5b75505Sopenharmony_ci		int nmax = eloop.count + 1 + 50;
374e5b75505Sopenharmony_ci		n = os_realloc_array(eloop.pollfds, nmax,
375e5b75505Sopenharmony_ci				     sizeof(struct pollfd));
376e5b75505Sopenharmony_ci		if (n == NULL)
377e5b75505Sopenharmony_ci			return -1;
378e5b75505Sopenharmony_ci
379e5b75505Sopenharmony_ci		eloop.max_poll_fds = nmax;
380e5b75505Sopenharmony_ci		eloop.pollfds = n;
381e5b75505Sopenharmony_ci	}
382e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_POLL */
383e5b75505Sopenharmony_ci#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
384e5b75505Sopenharmony_ci	if (new_max_sock >= eloop.max_fd) {
385e5b75505Sopenharmony_ci		next = new_max_sock + 16;
386e5b75505Sopenharmony_ci		temp_table = os_realloc_array(eloop.fd_table, next,
387e5b75505Sopenharmony_ci					      sizeof(struct eloop_sock));
388e5b75505Sopenharmony_ci		if (temp_table == NULL)
389e5b75505Sopenharmony_ci			return -1;
390e5b75505Sopenharmony_ci
391e5b75505Sopenharmony_ci		eloop.max_fd = next;
392e5b75505Sopenharmony_ci		eloop.fd_table = temp_table;
393e5b75505Sopenharmony_ci	}
394e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
395e5b75505Sopenharmony_ci
396e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
397e5b75505Sopenharmony_ci	if (eloop.count + 1 > eloop.epoll_max_event_num) {
398e5b75505Sopenharmony_ci		next = eloop.epoll_max_event_num == 0 ? 8 :
399e5b75505Sopenharmony_ci			eloop.epoll_max_event_num * 2;
400e5b75505Sopenharmony_ci		temp_events = os_realloc_array(eloop.epoll_events, next,
401e5b75505Sopenharmony_ci					       sizeof(struct epoll_event));
402e5b75505Sopenharmony_ci		if (temp_events == NULL) {
403e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR, "%s: malloc for epoll failed: %s",
404e5b75505Sopenharmony_ci				   __func__, strerror(errno));
405e5b75505Sopenharmony_ci			return -1;
406e5b75505Sopenharmony_ci		}
407e5b75505Sopenharmony_ci
408e5b75505Sopenharmony_ci		eloop.epoll_max_event_num = next;
409e5b75505Sopenharmony_ci		eloop.epoll_events = temp_events;
410e5b75505Sopenharmony_ci	}
411e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
412e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
413e5b75505Sopenharmony_ci	if (eloop.count + 1 > eloop.kqueue_nevents) {
414e5b75505Sopenharmony_ci		next = eloop.kqueue_nevents == 0 ? 8 : eloop.kqueue_nevents * 2;
415e5b75505Sopenharmony_ci		temp_events = os_malloc(next * sizeof(*temp_events));
416e5b75505Sopenharmony_ci		if (!temp_events) {
417e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR,
418e5b75505Sopenharmony_ci				   "%s: malloc for kqueue failed: %s",
419e5b75505Sopenharmony_ci				   __func__, strerror(errno));
420e5b75505Sopenharmony_ci			return -1;
421e5b75505Sopenharmony_ci		}
422e5b75505Sopenharmony_ci
423e5b75505Sopenharmony_ci		os_free(eloop.kqueue_events);
424e5b75505Sopenharmony_ci		eloop.kqueue_events = temp_events;
425e5b75505Sopenharmony_ci		eloop.kqueue_nevents = next;
426e5b75505Sopenharmony_ci	}
427e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
428e5b75505Sopenharmony_ci
429e5b75505Sopenharmony_ci	eloop_trace_sock_remove_ref(table);
430e5b75505Sopenharmony_ci	tmp = os_realloc_array(table->table, table->count + 1,
431e5b75505Sopenharmony_ci			       sizeof(struct eloop_sock));
432e5b75505Sopenharmony_ci	if (tmp == NULL) {
433e5b75505Sopenharmony_ci		eloop_trace_sock_add_ref(table);
434e5b75505Sopenharmony_ci		return -1;
435e5b75505Sopenharmony_ci	}
436e5b75505Sopenharmony_ci
437e5b75505Sopenharmony_ci	tmp[table->count].sock = sock;
438e5b75505Sopenharmony_ci	tmp[table->count].eloop_data = eloop_data;
439e5b75505Sopenharmony_ci	tmp[table->count].user_data = user_data;
440e5b75505Sopenharmony_ci	tmp[table->count].handler = handler;
441e5b75505Sopenharmony_ci	wpa_trace_record(&tmp[table->count]);
442e5b75505Sopenharmony_ci	table->count++;
443e5b75505Sopenharmony_ci	table->table = tmp;
444e5b75505Sopenharmony_ci	eloop.max_sock = new_max_sock;
445e5b75505Sopenharmony_ci	eloop.count++;
446e5b75505Sopenharmony_ci	table->changed = 1;
447e5b75505Sopenharmony_ci	eloop_trace_sock_add_ref(table);
448e5b75505Sopenharmony_ci
449e5b75505Sopenharmony_ci#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
450e5b75505Sopenharmony_ci	if (eloop_sock_queue(sock, table->type) < 0)
451e5b75505Sopenharmony_ci		return -1;
452e5b75505Sopenharmony_ci	os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1],
453e5b75505Sopenharmony_ci		  sizeof(struct eloop_sock));
454e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
455e5b75505Sopenharmony_ci	return 0;
456e5b75505Sopenharmony_ci}
457e5b75505Sopenharmony_ci
458e5b75505Sopenharmony_ci
459e5b75505Sopenharmony_cistatic void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
460e5b75505Sopenharmony_ci                                         int sock)
461e5b75505Sopenharmony_ci{
462e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
463e5b75505Sopenharmony_ci	struct kevent ke;
464e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
465e5b75505Sopenharmony_ci	int i;
466e5b75505Sopenharmony_ci
467e5b75505Sopenharmony_ci	if (table == NULL || table->table == NULL || table->count == 0)
468e5b75505Sopenharmony_ci		return;
469e5b75505Sopenharmony_ci
470e5b75505Sopenharmony_ci	for (i = 0; i < table->count; i++) {
471e5b75505Sopenharmony_ci		if (table->table[i].sock == sock)
472e5b75505Sopenharmony_ci			break;
473e5b75505Sopenharmony_ci	}
474e5b75505Sopenharmony_ci	if (i == table->count)
475e5b75505Sopenharmony_ci		return;
476e5b75505Sopenharmony_ci	eloop_trace_sock_remove_ref(table);
477e5b75505Sopenharmony_ci	if (i != table->count - 1) {
478e5b75505Sopenharmony_ci		os_memmove(&table->table[i], &table->table[i + 1],
479e5b75505Sopenharmony_ci			   (table->count - i - 1) *
480e5b75505Sopenharmony_ci			   sizeof(struct eloop_sock));
481e5b75505Sopenharmony_ci	}
482e5b75505Sopenharmony_ci	table->count--;
483e5b75505Sopenharmony_ci	eloop.count--;
484e5b75505Sopenharmony_ci	table->changed = 1;
485e5b75505Sopenharmony_ci	eloop_trace_sock_add_ref(table);
486e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
487e5b75505Sopenharmony_ci	if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
488e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d failed: %s",
489e5b75505Sopenharmony_ci			   __func__, sock, strerror(errno));
490e5b75505Sopenharmony_ci		return;
491e5b75505Sopenharmony_ci	}
492e5b75505Sopenharmony_ci	os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
493e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
494e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
495e5b75505Sopenharmony_ci	EV_SET(&ke, sock, event_type_kevent_filter(table->type), EV_DELETE, 0,
496e5b75505Sopenharmony_ci	       0, 0);
497e5b75505Sopenharmony_ci	if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) {
498e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s",
499e5b75505Sopenharmony_ci			   __func__, sock, strerror(errno));
500e5b75505Sopenharmony_ci		return;
501e5b75505Sopenharmony_ci	}
502e5b75505Sopenharmony_ci	os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
503e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
504e5b75505Sopenharmony_ci}
505e5b75505Sopenharmony_ci
506e5b75505Sopenharmony_ci
507e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_POLL
508e5b75505Sopenharmony_ci
509e5b75505Sopenharmony_cistatic struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
510e5b75505Sopenharmony_ci{
511e5b75505Sopenharmony_ci	if (fd < mx && fd >= 0)
512e5b75505Sopenharmony_ci		return pollfds_map[fd];
513e5b75505Sopenharmony_ci	return NULL;
514e5b75505Sopenharmony_ci}
515e5b75505Sopenharmony_ci
516e5b75505Sopenharmony_ci
517e5b75505Sopenharmony_cistatic int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
518e5b75505Sopenharmony_ci				    struct eloop_sock_table *writers,
519e5b75505Sopenharmony_ci				    struct eloop_sock_table *exceptions,
520e5b75505Sopenharmony_ci				    struct pollfd *pollfds,
521e5b75505Sopenharmony_ci				    struct pollfd **pollfds_map,
522e5b75505Sopenharmony_ci				    int max_pollfd_map)
523e5b75505Sopenharmony_ci{
524e5b75505Sopenharmony_ci	int i;
525e5b75505Sopenharmony_ci	int nxt = 0;
526e5b75505Sopenharmony_ci	int fd;
527e5b75505Sopenharmony_ci	struct pollfd *pfd;
528e5b75505Sopenharmony_ci
529e5b75505Sopenharmony_ci	/* Clear pollfd lookup map. It will be re-populated below. */
530e5b75505Sopenharmony_ci	os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
531e5b75505Sopenharmony_ci
532e5b75505Sopenharmony_ci	if (readers && readers->table) {
533e5b75505Sopenharmony_ci		for (i = 0; i < readers->count; i++) {
534e5b75505Sopenharmony_ci			fd = readers->table[i].sock;
535e5b75505Sopenharmony_ci			assert(fd >= 0 && fd < max_pollfd_map);
536e5b75505Sopenharmony_ci			pollfds[nxt].fd = fd;
537e5b75505Sopenharmony_ci			pollfds[nxt].events = POLLIN;
538e5b75505Sopenharmony_ci			pollfds[nxt].revents = 0;
539e5b75505Sopenharmony_ci			pollfds_map[fd] = &(pollfds[nxt]);
540e5b75505Sopenharmony_ci			nxt++;
541e5b75505Sopenharmony_ci		}
542e5b75505Sopenharmony_ci	}
543e5b75505Sopenharmony_ci
544e5b75505Sopenharmony_ci	if (writers && writers->table) {
545e5b75505Sopenharmony_ci		for (i = 0; i < writers->count; i++) {
546e5b75505Sopenharmony_ci			/*
547e5b75505Sopenharmony_ci			 * See if we already added this descriptor, update it
548e5b75505Sopenharmony_ci			 * if so.
549e5b75505Sopenharmony_ci			 */
550e5b75505Sopenharmony_ci			fd = writers->table[i].sock;
551e5b75505Sopenharmony_ci			assert(fd >= 0 && fd < max_pollfd_map);
552e5b75505Sopenharmony_ci			pfd = pollfds_map[fd];
553e5b75505Sopenharmony_ci			if (!pfd) {
554e5b75505Sopenharmony_ci				pfd = &(pollfds[nxt]);
555e5b75505Sopenharmony_ci				pfd->events = 0;
556e5b75505Sopenharmony_ci				pfd->fd = fd;
557e5b75505Sopenharmony_ci				pollfds[i].revents = 0;
558e5b75505Sopenharmony_ci				pollfds_map[fd] = pfd;
559e5b75505Sopenharmony_ci				nxt++;
560e5b75505Sopenharmony_ci			}
561e5b75505Sopenharmony_ci			pfd->events |= POLLOUT;
562e5b75505Sopenharmony_ci		}
563e5b75505Sopenharmony_ci	}
564e5b75505Sopenharmony_ci
565e5b75505Sopenharmony_ci	/*
566e5b75505Sopenharmony_ci	 * Exceptions are always checked when using poll, but I suppose it's
567e5b75505Sopenharmony_ci	 * possible that someone registered a socket *only* for exception
568e5b75505Sopenharmony_ci	 * handling. Set the POLLIN bit in this case.
569e5b75505Sopenharmony_ci	 */
570e5b75505Sopenharmony_ci	if (exceptions && exceptions->table) {
571e5b75505Sopenharmony_ci		for (i = 0; i < exceptions->count; i++) {
572e5b75505Sopenharmony_ci			/*
573e5b75505Sopenharmony_ci			 * See if we already added this descriptor, just use it
574e5b75505Sopenharmony_ci			 * if so.
575e5b75505Sopenharmony_ci			 */
576e5b75505Sopenharmony_ci			fd = exceptions->table[i].sock;
577e5b75505Sopenharmony_ci			assert(fd >= 0 && fd < max_pollfd_map);
578e5b75505Sopenharmony_ci			pfd = pollfds_map[fd];
579e5b75505Sopenharmony_ci			if (!pfd) {
580e5b75505Sopenharmony_ci				pfd = &(pollfds[nxt]);
581e5b75505Sopenharmony_ci				pfd->events = POLLIN;
582e5b75505Sopenharmony_ci				pfd->fd = fd;
583e5b75505Sopenharmony_ci				pollfds[i].revents = 0;
584e5b75505Sopenharmony_ci				pollfds_map[fd] = pfd;
585e5b75505Sopenharmony_ci				nxt++;
586e5b75505Sopenharmony_ci			}
587e5b75505Sopenharmony_ci		}
588e5b75505Sopenharmony_ci	}
589e5b75505Sopenharmony_ci
590e5b75505Sopenharmony_ci	return nxt;
591e5b75505Sopenharmony_ci}
592e5b75505Sopenharmony_ci
593e5b75505Sopenharmony_ci
594e5b75505Sopenharmony_cistatic int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
595e5b75505Sopenharmony_ci					   struct pollfd **pollfds_map,
596e5b75505Sopenharmony_ci					   int max_pollfd_map,
597e5b75505Sopenharmony_ci					   short int revents)
598e5b75505Sopenharmony_ci{
599e5b75505Sopenharmony_ci	int i;
600e5b75505Sopenharmony_ci	struct pollfd *pfd;
601e5b75505Sopenharmony_ci
602e5b75505Sopenharmony_ci	if (!table || !table->table)
603e5b75505Sopenharmony_ci		return 0;
604e5b75505Sopenharmony_ci
605e5b75505Sopenharmony_ci	table->changed = 0;
606e5b75505Sopenharmony_ci	for (i = 0; i < table->count; i++) {
607e5b75505Sopenharmony_ci		pfd = find_pollfd(pollfds_map, table->table[i].sock,
608e5b75505Sopenharmony_ci				  max_pollfd_map);
609e5b75505Sopenharmony_ci		if (!pfd)
610e5b75505Sopenharmony_ci			continue;
611e5b75505Sopenharmony_ci
612e5b75505Sopenharmony_ci		if (!(pfd->revents & revents))
613e5b75505Sopenharmony_ci			continue;
614e5b75505Sopenharmony_ci
615e5b75505Sopenharmony_ci		table->table[i].handler(table->table[i].sock,
616e5b75505Sopenharmony_ci					table->table[i].eloop_data,
617e5b75505Sopenharmony_ci					table->table[i].user_data);
618e5b75505Sopenharmony_ci		if (table->changed)
619e5b75505Sopenharmony_ci			return 1;
620e5b75505Sopenharmony_ci	}
621e5b75505Sopenharmony_ci
622e5b75505Sopenharmony_ci	return 0;
623e5b75505Sopenharmony_ci}
624e5b75505Sopenharmony_ci
625e5b75505Sopenharmony_ci
626e5b75505Sopenharmony_cistatic void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
627e5b75505Sopenharmony_ci				      struct eloop_sock_table *writers,
628e5b75505Sopenharmony_ci				      struct eloop_sock_table *exceptions,
629e5b75505Sopenharmony_ci				      struct pollfd **pollfds_map,
630e5b75505Sopenharmony_ci				      int max_pollfd_map)
631e5b75505Sopenharmony_ci{
632e5b75505Sopenharmony_ci	if (eloop_sock_table_dispatch_table(readers, pollfds_map,
633e5b75505Sopenharmony_ci					    max_pollfd_map, POLLIN | POLLERR |
634e5b75505Sopenharmony_ci					    POLLHUP))
635e5b75505Sopenharmony_ci		return; /* pollfds may be invalid at this point */
636e5b75505Sopenharmony_ci
637e5b75505Sopenharmony_ci	if (eloop_sock_table_dispatch_table(writers, pollfds_map,
638e5b75505Sopenharmony_ci					    max_pollfd_map, POLLOUT))
639e5b75505Sopenharmony_ci		return; /* pollfds may be invalid at this point */
640e5b75505Sopenharmony_ci
641e5b75505Sopenharmony_ci	eloop_sock_table_dispatch_table(exceptions, pollfds_map,
642e5b75505Sopenharmony_ci					max_pollfd_map, POLLERR | POLLHUP);
643e5b75505Sopenharmony_ci}
644e5b75505Sopenharmony_ci
645e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_POLL */
646e5b75505Sopenharmony_ci
647e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_SELECT
648e5b75505Sopenharmony_ci
649e5b75505Sopenharmony_cistatic void eloop_sock_table_set_fds(struct eloop_sock_table *table,
650e5b75505Sopenharmony_ci				     fd_set *fds)
651e5b75505Sopenharmony_ci{
652e5b75505Sopenharmony_ci	int i;
653e5b75505Sopenharmony_ci
654e5b75505Sopenharmony_ci	FD_ZERO(fds);
655e5b75505Sopenharmony_ci
656e5b75505Sopenharmony_ci	if (table->table == NULL)
657e5b75505Sopenharmony_ci		return;
658e5b75505Sopenharmony_ci
659e5b75505Sopenharmony_ci	for (i = 0; i < table->count; i++) {
660e5b75505Sopenharmony_ci		assert(table->table[i].sock >= 0);
661e5b75505Sopenharmony_ci		FD_SET(table->table[i].sock, fds);
662e5b75505Sopenharmony_ci	}
663e5b75505Sopenharmony_ci}
664e5b75505Sopenharmony_ci
665e5b75505Sopenharmony_ci
666e5b75505Sopenharmony_cistatic void eloop_sock_table_dispatch(struct eloop_sock_table *table,
667e5b75505Sopenharmony_ci				      fd_set *fds)
668e5b75505Sopenharmony_ci{
669e5b75505Sopenharmony_ci	int i;
670e5b75505Sopenharmony_ci
671e5b75505Sopenharmony_ci	if (table == NULL || table->table == NULL)
672e5b75505Sopenharmony_ci		return;
673e5b75505Sopenharmony_ci
674e5b75505Sopenharmony_ci	table->changed = 0;
675e5b75505Sopenharmony_ci	for (i = 0; i < table->count; i++) {
676e5b75505Sopenharmony_ci		if (FD_ISSET(table->table[i].sock, fds)) {
677e5b75505Sopenharmony_ci			table->table[i].handler(table->table[i].sock,
678e5b75505Sopenharmony_ci						table->table[i].eloop_data,
679e5b75505Sopenharmony_ci						table->table[i].user_data);
680e5b75505Sopenharmony_ci			if (table->changed)
681e5b75505Sopenharmony_ci				break;
682e5b75505Sopenharmony_ci		}
683e5b75505Sopenharmony_ci	}
684e5b75505Sopenharmony_ci}
685e5b75505Sopenharmony_ci
686e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_SELECT */
687e5b75505Sopenharmony_ci
688e5b75505Sopenharmony_ci
689e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
690e5b75505Sopenharmony_cistatic void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
691e5b75505Sopenharmony_ci{
692e5b75505Sopenharmony_ci	struct eloop_sock *table;
693e5b75505Sopenharmony_ci	int i;
694e5b75505Sopenharmony_ci
695e5b75505Sopenharmony_ci	for (i = 0; i < nfds; i++) {
696e5b75505Sopenharmony_ci		table = &eloop.fd_table[events[i].data.fd];
697e5b75505Sopenharmony_ci		if (table->handler == NULL)
698e5b75505Sopenharmony_ci			continue;
699e5b75505Sopenharmony_ci		table->handler(table->sock, table->eloop_data,
700e5b75505Sopenharmony_ci			       table->user_data);
701e5b75505Sopenharmony_ci		if (eloop.readers.changed ||
702e5b75505Sopenharmony_ci		    eloop.writers.changed ||
703e5b75505Sopenharmony_ci		    eloop.exceptions.changed)
704e5b75505Sopenharmony_ci			break;
705e5b75505Sopenharmony_ci	}
706e5b75505Sopenharmony_ci}
707e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
708e5b75505Sopenharmony_ci
709e5b75505Sopenharmony_ci
710e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
711e5b75505Sopenharmony_ci
712e5b75505Sopenharmony_cistatic void eloop_sock_table_dispatch(struct kevent *events, int nfds)
713e5b75505Sopenharmony_ci{
714e5b75505Sopenharmony_ci	struct eloop_sock *table;
715e5b75505Sopenharmony_ci	int i;
716e5b75505Sopenharmony_ci
717e5b75505Sopenharmony_ci	for (i = 0; i < nfds; i++) {
718e5b75505Sopenharmony_ci		table = &eloop.fd_table[events[i].ident];
719e5b75505Sopenharmony_ci		if (table->handler == NULL)
720e5b75505Sopenharmony_ci			continue;
721e5b75505Sopenharmony_ci		table->handler(table->sock, table->eloop_data,
722e5b75505Sopenharmony_ci			       table->user_data);
723e5b75505Sopenharmony_ci		if (eloop.readers.changed ||
724e5b75505Sopenharmony_ci		    eloop.writers.changed ||
725e5b75505Sopenharmony_ci		    eloop.exceptions.changed)
726e5b75505Sopenharmony_ci			break;
727e5b75505Sopenharmony_ci	}
728e5b75505Sopenharmony_ci}
729e5b75505Sopenharmony_ci
730e5b75505Sopenharmony_ci
731e5b75505Sopenharmony_cistatic int eloop_sock_table_requeue(struct eloop_sock_table *table)
732e5b75505Sopenharmony_ci{
733e5b75505Sopenharmony_ci	int i, r;
734e5b75505Sopenharmony_ci
735e5b75505Sopenharmony_ci	r = 0;
736e5b75505Sopenharmony_ci	for (i = 0; i < table->count && table->table; i++) {
737e5b75505Sopenharmony_ci		if (eloop_sock_queue(table->table[i].sock, table->type) == -1)
738e5b75505Sopenharmony_ci			r = -1;
739e5b75505Sopenharmony_ci	}
740e5b75505Sopenharmony_ci	return r;
741e5b75505Sopenharmony_ci}
742e5b75505Sopenharmony_ci
743e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
744e5b75505Sopenharmony_ci
745e5b75505Sopenharmony_ci
746e5b75505Sopenharmony_ciint eloop_sock_requeue(void)
747e5b75505Sopenharmony_ci{
748e5b75505Sopenharmony_ci	int r = 0;
749e5b75505Sopenharmony_ci
750e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
751e5b75505Sopenharmony_ci	close(eloop.kqueuefd);
752e5b75505Sopenharmony_ci	eloop.kqueuefd = kqueue();
753e5b75505Sopenharmony_ci	if (eloop.kqueuefd < 0) {
754e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
755e5b75505Sopenharmony_ci			   __func__, strerror(errno));
756e5b75505Sopenharmony_ci		return -1;
757e5b75505Sopenharmony_ci	}
758e5b75505Sopenharmony_ci
759e5b75505Sopenharmony_ci	if (eloop_sock_table_requeue(&eloop.readers) < 0)
760e5b75505Sopenharmony_ci		r = -1;
761e5b75505Sopenharmony_ci	if (eloop_sock_table_requeue(&eloop.writers) < 0)
762e5b75505Sopenharmony_ci		r = -1;
763e5b75505Sopenharmony_ci	if (eloop_sock_table_requeue(&eloop.exceptions) < 0)
764e5b75505Sopenharmony_ci		r = -1;
765e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
766e5b75505Sopenharmony_ci
767e5b75505Sopenharmony_ci	return r;
768e5b75505Sopenharmony_ci}
769e5b75505Sopenharmony_ci
770e5b75505Sopenharmony_ci
771e5b75505Sopenharmony_cistatic void eloop_sock_table_destroy(struct eloop_sock_table *table)
772e5b75505Sopenharmony_ci{
773e5b75505Sopenharmony_ci	if (table) {
774e5b75505Sopenharmony_ci		int i;
775e5b75505Sopenharmony_ci		for (i = 0; i < table->count && table->table; i++) {
776e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
777e5b75505Sopenharmony_ci				   "sock=%d eloop_data=%p user_data=%p "
778e5b75505Sopenharmony_ci				   "handler=%p",
779e5b75505Sopenharmony_ci				   table->table[i].sock,
780e5b75505Sopenharmony_ci				   table->table[i].eloop_data,
781e5b75505Sopenharmony_ci				   table->table[i].user_data,
782e5b75505Sopenharmony_ci				   table->table[i].handler);
783e5b75505Sopenharmony_ci			wpa_trace_dump_funcname("eloop unregistered socket "
784e5b75505Sopenharmony_ci						"handler",
785e5b75505Sopenharmony_ci						table->table[i].handler);
786e5b75505Sopenharmony_ci			wpa_trace_dump("eloop sock", &table->table[i]);
787e5b75505Sopenharmony_ci		}
788e5b75505Sopenharmony_ci		os_free(table->table);
789e5b75505Sopenharmony_ci	}
790e5b75505Sopenharmony_ci}
791e5b75505Sopenharmony_ci
792e5b75505Sopenharmony_ci
793e5b75505Sopenharmony_ciint eloop_register_read_sock(int sock, eloop_sock_handler handler,
794e5b75505Sopenharmony_ci			     void *eloop_data, void *user_data)
795e5b75505Sopenharmony_ci{
796e5b75505Sopenharmony_ci	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
797e5b75505Sopenharmony_ci				   eloop_data, user_data);
798e5b75505Sopenharmony_ci}
799e5b75505Sopenharmony_ci
800e5b75505Sopenharmony_ci
801e5b75505Sopenharmony_civoid eloop_unregister_read_sock(int sock)
802e5b75505Sopenharmony_ci{
803e5b75505Sopenharmony_ci	eloop_unregister_sock(sock, EVENT_TYPE_READ);
804e5b75505Sopenharmony_ci}
805e5b75505Sopenharmony_ci
806e5b75505Sopenharmony_ci
807e5b75505Sopenharmony_cistatic struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
808e5b75505Sopenharmony_ci{
809e5b75505Sopenharmony_ci	switch (type) {
810e5b75505Sopenharmony_ci	case EVENT_TYPE_READ:
811e5b75505Sopenharmony_ci		return &eloop.readers;
812e5b75505Sopenharmony_ci	case EVENT_TYPE_WRITE:
813e5b75505Sopenharmony_ci		return &eloop.writers;
814e5b75505Sopenharmony_ci	case EVENT_TYPE_EXCEPTION:
815e5b75505Sopenharmony_ci		return &eloop.exceptions;
816e5b75505Sopenharmony_ci	}
817e5b75505Sopenharmony_ci
818e5b75505Sopenharmony_ci	return NULL;
819e5b75505Sopenharmony_ci}
820e5b75505Sopenharmony_ci
821e5b75505Sopenharmony_ci
822e5b75505Sopenharmony_ciint eloop_register_sock(int sock, eloop_event_type type,
823e5b75505Sopenharmony_ci			eloop_sock_handler handler,
824e5b75505Sopenharmony_ci			void *eloop_data, void *user_data)
825e5b75505Sopenharmony_ci{
826e5b75505Sopenharmony_ci	struct eloop_sock_table *table;
827e5b75505Sopenharmony_ci
828e5b75505Sopenharmony_ci	assert(sock >= 0);
829e5b75505Sopenharmony_ci	table = eloop_get_sock_table(type);
830e5b75505Sopenharmony_ci	return eloop_sock_table_add_sock(table, sock, handler,
831e5b75505Sopenharmony_ci					 eloop_data, user_data);
832e5b75505Sopenharmony_ci}
833e5b75505Sopenharmony_ci
834e5b75505Sopenharmony_ci
835e5b75505Sopenharmony_civoid eloop_unregister_sock(int sock, eloop_event_type type)
836e5b75505Sopenharmony_ci{
837e5b75505Sopenharmony_ci	struct eloop_sock_table *table;
838e5b75505Sopenharmony_ci
839e5b75505Sopenharmony_ci	table = eloop_get_sock_table(type);
840e5b75505Sopenharmony_ci	eloop_sock_table_remove_sock(table, sock);
841e5b75505Sopenharmony_ci}
842e5b75505Sopenharmony_ci
843e5b75505Sopenharmony_ci
844e5b75505Sopenharmony_ciint eloop_register_timeout(unsigned int secs, unsigned int usecs,
845e5b75505Sopenharmony_ci			   eloop_timeout_handler handler,
846e5b75505Sopenharmony_ci			   void *eloop_data, void *user_data)
847e5b75505Sopenharmony_ci{
848e5b75505Sopenharmony_ci	struct eloop_timeout *timeout, *tmp;
849e5b75505Sopenharmony_ci	os_time_t now_sec;
850e5b75505Sopenharmony_ci
851e5b75505Sopenharmony_ci	timeout = os_zalloc(sizeof(*timeout));
852e5b75505Sopenharmony_ci	if (timeout == NULL)
853e5b75505Sopenharmony_ci		return -1;
854e5b75505Sopenharmony_ci	if (os_get_reltime(&timeout->time) < 0) {
855e5b75505Sopenharmony_ci		os_free(timeout);
856e5b75505Sopenharmony_ci		return -1;
857e5b75505Sopenharmony_ci	}
858e5b75505Sopenharmony_ci	now_sec = timeout->time.sec;
859e5b75505Sopenharmony_ci	timeout->time.sec += secs;
860e5b75505Sopenharmony_ci	if (timeout->time.sec < now_sec) {
861e5b75505Sopenharmony_ci		/*
862e5b75505Sopenharmony_ci		 * Integer overflow - assume long enough timeout to be assumed
863e5b75505Sopenharmony_ci		 * to be infinite, i.e., the timeout would never happen.
864e5b75505Sopenharmony_ci		 */
865e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
866e5b75505Sopenharmony_ci			   "ever happen - ignore it", secs);
867e5b75505Sopenharmony_ci		os_free(timeout);
868e5b75505Sopenharmony_ci		return 0;
869e5b75505Sopenharmony_ci	}
870e5b75505Sopenharmony_ci	timeout->time.usec += usecs;
871e5b75505Sopenharmony_ci	while (timeout->time.usec >= 1000000) {
872e5b75505Sopenharmony_ci		timeout->time.sec++;
873e5b75505Sopenharmony_ci		timeout->time.usec -= 1000000;
874e5b75505Sopenharmony_ci	}
875e5b75505Sopenharmony_ci	timeout->eloop_data = eloop_data;
876e5b75505Sopenharmony_ci	timeout->user_data = user_data;
877e5b75505Sopenharmony_ci	timeout->handler = handler;
878e5b75505Sopenharmony_ci	wpa_trace_add_ref(timeout, eloop, eloop_data);
879e5b75505Sopenharmony_ci	wpa_trace_add_ref(timeout, user, user_data);
880e5b75505Sopenharmony_ci	wpa_trace_record(timeout);
881e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
882e5b75505Sopenharmony_ci	pthread_mutex_lock(&lock);
883e5b75505Sopenharmony_ci#endif
884e5b75505Sopenharmony_ci	/* Maintain timeouts in order of increasing time */
885e5b75505Sopenharmony_ci	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
886e5b75505Sopenharmony_ci		if (os_reltime_before(&timeout->time, &tmp->time)) {
887e5b75505Sopenharmony_ci			dl_list_add(tmp->list.prev, &timeout->list);
888e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
889e5b75505Sopenharmony_ci			(void)eloop_wakeup();
890e5b75505Sopenharmony_ci			pthread_mutex_unlock(&lock);
891e5b75505Sopenharmony_ci#endif
892e5b75505Sopenharmony_ci			return 0;
893e5b75505Sopenharmony_ci		}
894e5b75505Sopenharmony_ci	}
895e5b75505Sopenharmony_ci	dl_list_add_tail(&eloop.timeout, &timeout->list);
896e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
897e5b75505Sopenharmony_ci	pthread_mutex_unlock(&lock);
898e5b75505Sopenharmony_ci	(void)eloop_wakeup();
899e5b75505Sopenharmony_ci#endif
900e5b75505Sopenharmony_ci
901e5b75505Sopenharmony_ci	return 0;
902e5b75505Sopenharmony_ci}
903e5b75505Sopenharmony_ci
904e5b75505Sopenharmony_ci
905e5b75505Sopenharmony_cistatic void eloop_remove_timeout(struct eloop_timeout *timeout)
906e5b75505Sopenharmony_ci{
907e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
908e5b75505Sopenharmony_ci	pthread_mutex_lock(&lock);
909e5b75505Sopenharmony_ci#endif
910e5b75505Sopenharmony_ci	dl_list_del(&timeout->list);
911e5b75505Sopenharmony_ci	wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
912e5b75505Sopenharmony_ci	wpa_trace_remove_ref(timeout, user, timeout->user_data);
913e5b75505Sopenharmony_ci	os_free(timeout);
914e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
915e5b75505Sopenharmony_ci	pthread_mutex_unlock(&lock);
916e5b75505Sopenharmony_ci#endif
917e5b75505Sopenharmony_ci}
918e5b75505Sopenharmony_ci
919e5b75505Sopenharmony_ci
920e5b75505Sopenharmony_ciint eloop_cancel_timeout(eloop_timeout_handler handler,
921e5b75505Sopenharmony_ci			 void *eloop_data, void *user_data)
922e5b75505Sopenharmony_ci{
923e5b75505Sopenharmony_ci	struct eloop_timeout *timeout, *prev;
924e5b75505Sopenharmony_ci	int removed = 0;
925e5b75505Sopenharmony_ci
926e5b75505Sopenharmony_ci	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
927e5b75505Sopenharmony_ci			      struct eloop_timeout, list) {
928e5b75505Sopenharmony_ci		if (timeout->handler == handler &&
929e5b75505Sopenharmony_ci		    (timeout->eloop_data == eloop_data ||
930e5b75505Sopenharmony_ci		     eloop_data == ELOOP_ALL_CTX) &&
931e5b75505Sopenharmony_ci		    (timeout->user_data == user_data ||
932e5b75505Sopenharmony_ci		     user_data == ELOOP_ALL_CTX)) {
933e5b75505Sopenharmony_ci			eloop_remove_timeout(timeout);
934e5b75505Sopenharmony_ci			removed++;
935e5b75505Sopenharmony_ci		}
936e5b75505Sopenharmony_ci	}
937e5b75505Sopenharmony_ci
938e5b75505Sopenharmony_ci	return removed;
939e5b75505Sopenharmony_ci}
940e5b75505Sopenharmony_ci
941e5b75505Sopenharmony_ci
942e5b75505Sopenharmony_ciint eloop_cancel_timeout_one(eloop_timeout_handler handler,
943e5b75505Sopenharmony_ci			     void *eloop_data, void *user_data,
944e5b75505Sopenharmony_ci			     struct os_reltime *remaining)
945e5b75505Sopenharmony_ci{
946e5b75505Sopenharmony_ci	struct eloop_timeout *timeout, *prev;
947e5b75505Sopenharmony_ci	int removed = 0;
948e5b75505Sopenharmony_ci	struct os_reltime now;
949e5b75505Sopenharmony_ci
950e5b75505Sopenharmony_ci	os_get_reltime(&now);
951e5b75505Sopenharmony_ci	remaining->sec = remaining->usec = 0;
952e5b75505Sopenharmony_ci
953e5b75505Sopenharmony_ci	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
954e5b75505Sopenharmony_ci			      struct eloop_timeout, list) {
955e5b75505Sopenharmony_ci		if (timeout->handler == handler &&
956e5b75505Sopenharmony_ci		    (timeout->eloop_data == eloop_data) &&
957e5b75505Sopenharmony_ci		    (timeout->user_data == user_data)) {
958e5b75505Sopenharmony_ci			removed = 1;
959e5b75505Sopenharmony_ci			if (os_reltime_before(&now, &timeout->time))
960e5b75505Sopenharmony_ci				os_reltime_sub(&timeout->time, &now, remaining);
961e5b75505Sopenharmony_ci			eloop_remove_timeout(timeout);
962e5b75505Sopenharmony_ci			break;
963e5b75505Sopenharmony_ci		}
964e5b75505Sopenharmony_ci	}
965e5b75505Sopenharmony_ci	return removed;
966e5b75505Sopenharmony_ci}
967e5b75505Sopenharmony_ci
968e5b75505Sopenharmony_ci
969e5b75505Sopenharmony_ciint eloop_is_timeout_registered(eloop_timeout_handler handler,
970e5b75505Sopenharmony_ci				void *eloop_data, void *user_data)
971e5b75505Sopenharmony_ci{
972e5b75505Sopenharmony_ci	struct eloop_timeout *tmp;
973e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
974e5b75505Sopenharmony_ci	pthread_mutex_lock(&lock);
975e5b75505Sopenharmony_ci#endif
976e5b75505Sopenharmony_ci	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
977e5b75505Sopenharmony_ci		if (tmp->handler == handler &&
978e5b75505Sopenharmony_ci		    tmp->eloop_data == eloop_data &&
979e5b75505Sopenharmony_ci		    tmp->user_data == user_data) {
980e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
981e5b75505Sopenharmony_ci				pthread_mutex_unlock(&lock);
982e5b75505Sopenharmony_ci#endif
983e5b75505Sopenharmony_ci				return 1;
984e5b75505Sopenharmony_ci			}
985e5b75505Sopenharmony_ci	}
986e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
987e5b75505Sopenharmony_ci	pthread_mutex_unlock(&lock);
988e5b75505Sopenharmony_ci#endif
989e5b75505Sopenharmony_ci	return 0;
990e5b75505Sopenharmony_ci}
991e5b75505Sopenharmony_ci
992e5b75505Sopenharmony_ci
993e5b75505Sopenharmony_ciint eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
994e5b75505Sopenharmony_ci			  eloop_timeout_handler handler, void *eloop_data,
995e5b75505Sopenharmony_ci			  void *user_data)
996e5b75505Sopenharmony_ci{
997e5b75505Sopenharmony_ci	struct os_reltime now, requested, remaining;
998e5b75505Sopenharmony_ci	struct eloop_timeout *tmp;
999e5b75505Sopenharmony_ci
1000e5b75505Sopenharmony_ci	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
1001e5b75505Sopenharmony_ci		if (tmp->handler == handler &&
1002e5b75505Sopenharmony_ci		    tmp->eloop_data == eloop_data &&
1003e5b75505Sopenharmony_ci		    tmp->user_data == user_data) {
1004e5b75505Sopenharmony_ci			requested.sec = req_secs;
1005e5b75505Sopenharmony_ci			requested.usec = req_usecs;
1006e5b75505Sopenharmony_ci			os_get_reltime(&now);
1007e5b75505Sopenharmony_ci			os_reltime_sub(&tmp->time, &now, &remaining);
1008e5b75505Sopenharmony_ci			if (os_reltime_before(&requested, &remaining)) {
1009e5b75505Sopenharmony_ci				eloop_cancel_timeout(handler, eloop_data,
1010e5b75505Sopenharmony_ci						     user_data);
1011e5b75505Sopenharmony_ci				eloop_register_timeout(requested.sec,
1012e5b75505Sopenharmony_ci						       requested.usec,
1013e5b75505Sopenharmony_ci						       handler, eloop_data,
1014e5b75505Sopenharmony_ci						       user_data);
1015e5b75505Sopenharmony_ci				return 1;
1016e5b75505Sopenharmony_ci			}
1017e5b75505Sopenharmony_ci			return 0;
1018e5b75505Sopenharmony_ci		}
1019e5b75505Sopenharmony_ci	}
1020e5b75505Sopenharmony_ci
1021e5b75505Sopenharmony_ci	return -1;
1022e5b75505Sopenharmony_ci}
1023e5b75505Sopenharmony_ci
1024e5b75505Sopenharmony_ci
1025e5b75505Sopenharmony_ciint eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
1026e5b75505Sopenharmony_ci			    eloop_timeout_handler handler, void *eloop_data,
1027e5b75505Sopenharmony_ci			    void *user_data)
1028e5b75505Sopenharmony_ci{
1029e5b75505Sopenharmony_ci	struct os_reltime now, requested, remaining;
1030e5b75505Sopenharmony_ci	struct eloop_timeout *tmp;
1031e5b75505Sopenharmony_ci
1032e5b75505Sopenharmony_ci	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
1033e5b75505Sopenharmony_ci		if (tmp->handler == handler &&
1034e5b75505Sopenharmony_ci		    tmp->eloop_data == eloop_data &&
1035e5b75505Sopenharmony_ci		    tmp->user_data == user_data) {
1036e5b75505Sopenharmony_ci			requested.sec = req_secs;
1037e5b75505Sopenharmony_ci			requested.usec = req_usecs;
1038e5b75505Sopenharmony_ci			os_get_reltime(&now);
1039e5b75505Sopenharmony_ci			os_reltime_sub(&tmp->time, &now, &remaining);
1040e5b75505Sopenharmony_ci			if (os_reltime_before(&remaining, &requested)) {
1041e5b75505Sopenharmony_ci				eloop_cancel_timeout(handler, eloop_data,
1042e5b75505Sopenharmony_ci						     user_data);
1043e5b75505Sopenharmony_ci				eloop_register_timeout(requested.sec,
1044e5b75505Sopenharmony_ci						       requested.usec,
1045e5b75505Sopenharmony_ci						       handler, eloop_data,
1046e5b75505Sopenharmony_ci						       user_data);
1047e5b75505Sopenharmony_ci				return 1;
1048e5b75505Sopenharmony_ci			}
1049e5b75505Sopenharmony_ci			return 0;
1050e5b75505Sopenharmony_ci		}
1051e5b75505Sopenharmony_ci	}
1052e5b75505Sopenharmony_ci
1053e5b75505Sopenharmony_ci	return -1;
1054e5b75505Sopenharmony_ci}
1055e5b75505Sopenharmony_ci
1056e5b75505Sopenharmony_ci
1057e5b75505Sopenharmony_ci#ifndef CONFIG_NATIVE_WINDOWS
1058e5b75505Sopenharmony_cistatic void eloop_handle_alarm(int sig)
1059e5b75505Sopenharmony_ci{
1060e5b75505Sopenharmony_ci	wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
1061e5b75505Sopenharmony_ci		   "two seconds. Looks like there\n"
1062e5b75505Sopenharmony_ci		   "is a bug that ends up in a busy loop that "
1063e5b75505Sopenharmony_ci		   "prevents clean shutdown.\n"
1064e5b75505Sopenharmony_ci		   "Killing program forcefully.\n");
1065e5b75505Sopenharmony_ci	exit(1);
1066e5b75505Sopenharmony_ci}
1067e5b75505Sopenharmony_ci#endif /* CONFIG_NATIVE_WINDOWS */
1068e5b75505Sopenharmony_ci
1069e5b75505Sopenharmony_ci
1070e5b75505Sopenharmony_cistatic void eloop_handle_signal(int sig)
1071e5b75505Sopenharmony_ci{
1072e5b75505Sopenharmony_ci	int i;
1073e5b75505Sopenharmony_ci
1074e5b75505Sopenharmony_ci#ifndef CONFIG_NATIVE_WINDOWS
1075e5b75505Sopenharmony_ci	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
1076e5b75505Sopenharmony_ci		/* Use SIGALRM to break out from potential busy loops that
1077e5b75505Sopenharmony_ci		 * would not allow the program to be killed. */
1078e5b75505Sopenharmony_ci		eloop.pending_terminate = 1;
1079e5b75505Sopenharmony_ci		signal(SIGALRM, eloop_handle_alarm);
1080e5b75505Sopenharmony_ci		alarm(2);
1081e5b75505Sopenharmony_ci	}
1082e5b75505Sopenharmony_ci#endif /* CONFIG_NATIVE_WINDOWS */
1083e5b75505Sopenharmony_ci
1084e5b75505Sopenharmony_ci	eloop.signaled++;
1085e5b75505Sopenharmony_ci	for (i = 0; i < eloop.signal_count; i++) {
1086e5b75505Sopenharmony_ci		if (eloop.signals[i].sig == sig) {
1087e5b75505Sopenharmony_ci			eloop.signals[i].signaled++;
1088e5b75505Sopenharmony_ci			break;
1089e5b75505Sopenharmony_ci		}
1090e5b75505Sopenharmony_ci	}
1091e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
1092e5b75505Sopenharmony_ci	(void)eloop_wakeup();
1093e5b75505Sopenharmony_ci#endif
1094e5b75505Sopenharmony_ci}
1095e5b75505Sopenharmony_ci
1096e5b75505Sopenharmony_ci
1097e5b75505Sopenharmony_cistatic void eloop_process_pending_signals(void)
1098e5b75505Sopenharmony_ci{
1099e5b75505Sopenharmony_ci	int i;
1100e5b75505Sopenharmony_ci
1101e5b75505Sopenharmony_ci	if (eloop.signaled == 0)
1102e5b75505Sopenharmony_ci		return;
1103e5b75505Sopenharmony_ci	eloop.signaled = 0;
1104e5b75505Sopenharmony_ci
1105e5b75505Sopenharmony_ci	if (eloop.pending_terminate) {
1106e5b75505Sopenharmony_ci#ifndef CONFIG_NATIVE_WINDOWS
1107e5b75505Sopenharmony_ci		alarm(0);
1108e5b75505Sopenharmony_ci#endif /* CONFIG_NATIVE_WINDOWS */
1109e5b75505Sopenharmony_ci		eloop.pending_terminate = 0;
1110e5b75505Sopenharmony_ci	}
1111e5b75505Sopenharmony_ci
1112e5b75505Sopenharmony_ci	for (i = 0; i < eloop.signal_count; i++) {
1113e5b75505Sopenharmony_ci		if (eloop.signals[i].signaled) {
1114e5b75505Sopenharmony_ci			eloop.signals[i].signaled = 0;
1115e5b75505Sopenharmony_ci			eloop.signals[i].handler(eloop.signals[i].sig,
1116e5b75505Sopenharmony_ci						 eloop.signals[i].user_data);
1117e5b75505Sopenharmony_ci		}
1118e5b75505Sopenharmony_ci	}
1119e5b75505Sopenharmony_ci}
1120e5b75505Sopenharmony_ci
1121e5b75505Sopenharmony_ci
1122e5b75505Sopenharmony_ciint eloop_register_signal(int sig, eloop_signal_handler handler,
1123e5b75505Sopenharmony_ci			  void *user_data)
1124e5b75505Sopenharmony_ci{
1125e5b75505Sopenharmony_ci	struct eloop_signal *tmp;
1126e5b75505Sopenharmony_ci
1127e5b75505Sopenharmony_ci	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
1128e5b75505Sopenharmony_ci			       sizeof(struct eloop_signal));
1129e5b75505Sopenharmony_ci	if (tmp == NULL)
1130e5b75505Sopenharmony_ci		return -1;
1131e5b75505Sopenharmony_ci
1132e5b75505Sopenharmony_ci	tmp[eloop.signal_count].sig = sig;
1133e5b75505Sopenharmony_ci	tmp[eloop.signal_count].user_data = user_data;
1134e5b75505Sopenharmony_ci	tmp[eloop.signal_count].handler = handler;
1135e5b75505Sopenharmony_ci	tmp[eloop.signal_count].signaled = 0;
1136e5b75505Sopenharmony_ci	eloop.signal_count++;
1137e5b75505Sopenharmony_ci	eloop.signals = tmp;
1138e5b75505Sopenharmony_ci	signal(sig, eloop_handle_signal);
1139e5b75505Sopenharmony_ci
1140e5b75505Sopenharmony_ci	return 0;
1141e5b75505Sopenharmony_ci}
1142e5b75505Sopenharmony_ci
1143e5b75505Sopenharmony_ci
1144e5b75505Sopenharmony_ciint eloop_register_signal_terminate(eloop_signal_handler handler,
1145e5b75505Sopenharmony_ci				    void *user_data)
1146e5b75505Sopenharmony_ci{
1147e5b75505Sopenharmony_ci	int ret = eloop_register_signal(SIGINT, handler, user_data);
1148e5b75505Sopenharmony_ci	if (ret == 0)
1149e5b75505Sopenharmony_ci		ret = eloop_register_signal(SIGTERM, handler, user_data);
1150e5b75505Sopenharmony_ci	return ret;
1151e5b75505Sopenharmony_ci}
1152e5b75505Sopenharmony_ci
1153e5b75505Sopenharmony_ci
1154e5b75505Sopenharmony_ciint eloop_register_signal_reconfig(eloop_signal_handler handler,
1155e5b75505Sopenharmony_ci				   void *user_data)
1156e5b75505Sopenharmony_ci{
1157e5b75505Sopenharmony_ci#ifdef CONFIG_NATIVE_WINDOWS
1158e5b75505Sopenharmony_ci	return 0;
1159e5b75505Sopenharmony_ci#else /* CONFIG_NATIVE_WINDOWS */
1160e5b75505Sopenharmony_ci	return eloop_register_signal(SIGHUP, handler, user_data);
1161e5b75505Sopenharmony_ci#endif /* CONFIG_NATIVE_WINDOWS */
1162e5b75505Sopenharmony_ci}
1163e5b75505Sopenharmony_ci
1164e5b75505Sopenharmony_ci
1165e5b75505Sopenharmony_civoid eloop_run(void)
1166e5b75505Sopenharmony_ci{
1167e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_POLL
1168e5b75505Sopenharmony_ci	int num_poll_fds;
1169e5b75505Sopenharmony_ci	int timeout_ms = 0;
1170e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_POLL */
1171e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_SELECT
1172e5b75505Sopenharmony_ci	fd_set *rfds, *wfds, *efds;
1173e5b75505Sopenharmony_ci	struct timeval _tv;
1174e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_SELECT */
1175e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
1176e5b75505Sopenharmony_ci	int timeout_ms = -1;
1177e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
1178e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
1179e5b75505Sopenharmony_ci	struct timespec ts;
1180e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
1181e5b75505Sopenharmony_ci	int res;
1182e5b75505Sopenharmony_ci	struct os_reltime tv, now;
1183e5b75505Sopenharmony_ci
1184e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_SELECT
1185e5b75505Sopenharmony_ci	rfds = os_malloc(sizeof(*rfds));
1186e5b75505Sopenharmony_ci	wfds = os_malloc(sizeof(*wfds));
1187e5b75505Sopenharmony_ci	efds = os_malloc(sizeof(*efds));
1188e5b75505Sopenharmony_ci	if (rfds == NULL || wfds == NULL || efds == NULL)
1189e5b75505Sopenharmony_ci		goto out;
1190e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_SELECT */
1191e5b75505Sopenharmony_ci
1192e5b75505Sopenharmony_ci	while (!eloop.terminate &&
1193e5b75505Sopenharmony_ci	       (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
1194e5b75505Sopenharmony_ci		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
1195e5b75505Sopenharmony_ci		struct eloop_timeout *timeout;
1196e5b75505Sopenharmony_ci
1197e5b75505Sopenharmony_ci		if (eloop.pending_terminate) {
1198e5b75505Sopenharmony_ci			/*
1199e5b75505Sopenharmony_ci			 * This may happen in some corner cases where a signal
1200e5b75505Sopenharmony_ci			 * is received during a blocking operation. We need to
1201e5b75505Sopenharmony_ci			 * process the pending signals and exit if requested to
1202e5b75505Sopenharmony_ci			 * avoid hitting the SIGALRM limit if the blocking
1203e5b75505Sopenharmony_ci			 * operation took more than two seconds.
1204e5b75505Sopenharmony_ci			 */
1205e5b75505Sopenharmony_ci			eloop_process_pending_signals();
1206e5b75505Sopenharmony_ci			if (eloop.terminate)
1207e5b75505Sopenharmony_ci				break;
1208e5b75505Sopenharmony_ci		}
1209e5b75505Sopenharmony_ci
1210e5b75505Sopenharmony_ci		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
1211e5b75505Sopenharmony_ci					list);
1212e5b75505Sopenharmony_ci		if (timeout) {
1213e5b75505Sopenharmony_ci			os_get_reltime(&now);
1214e5b75505Sopenharmony_ci			if (os_reltime_before(&now, &timeout->time))
1215e5b75505Sopenharmony_ci				os_reltime_sub(&timeout->time, &now, &tv);
1216e5b75505Sopenharmony_ci			else
1217e5b75505Sopenharmony_ci				tv.sec = tv.usec = 0;
1218e5b75505Sopenharmony_ci#if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
1219e5b75505Sopenharmony_ci			timeout_ms = tv.sec * 1000 + tv.usec / 1000;
1220e5b75505Sopenharmony_ci#endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
1221e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_SELECT
1222e5b75505Sopenharmony_ci			_tv.tv_sec = tv.sec;
1223e5b75505Sopenharmony_ci			_tv.tv_usec = tv.usec;
1224e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_SELECT */
1225e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
1226e5b75505Sopenharmony_ci			ts.tv_sec = tv.sec;
1227e5b75505Sopenharmony_ci			ts.tv_nsec = tv.usec * 1000L;
1228e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
1229e5b75505Sopenharmony_ci		}
1230e5b75505Sopenharmony_ci
1231e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_POLL
1232e5b75505Sopenharmony_ci		num_poll_fds = eloop_sock_table_set_fds(
1233e5b75505Sopenharmony_ci			&eloop.readers, &eloop.writers, &eloop.exceptions,
1234e5b75505Sopenharmony_ci			eloop.pollfds, eloop.pollfds_map,
1235e5b75505Sopenharmony_ci			eloop.max_pollfd_map);
1236e5b75505Sopenharmony_ci		res = poll(eloop.pollfds, num_poll_fds,
1237e5b75505Sopenharmony_ci			   timeout ? timeout_ms : -1);
1238e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_POLL */
1239e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_SELECT
1240e5b75505Sopenharmony_ci		eloop_sock_table_set_fds(&eloop.readers, rfds);
1241e5b75505Sopenharmony_ci		eloop_sock_table_set_fds(&eloop.writers, wfds);
1242e5b75505Sopenharmony_ci		eloop_sock_table_set_fds(&eloop.exceptions, efds);
1243e5b75505Sopenharmony_ci		res = select(eloop.max_sock + 1, rfds, wfds, efds,
1244e5b75505Sopenharmony_ci			     timeout ? &_tv : NULL);
1245e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_SELECT */
1246e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
1247e5b75505Sopenharmony_ci		if (eloop.count == 0) {
1248e5b75505Sopenharmony_ci			res = 0;
1249e5b75505Sopenharmony_ci		} else {
1250e5b75505Sopenharmony_ci			res = epoll_wait(eloop.epollfd, eloop.epoll_events,
1251e5b75505Sopenharmony_ci					 eloop.count, timeout_ms);
1252e5b75505Sopenharmony_ci		}
1253e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
1254e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
1255e5b75505Sopenharmony_ci		if (eloop.count == 0) {
1256e5b75505Sopenharmony_ci			res = 0;
1257e5b75505Sopenharmony_ci		} else {
1258e5b75505Sopenharmony_ci			res = kevent(eloop.kqueuefd, NULL, 0,
1259e5b75505Sopenharmony_ci				     eloop.kqueue_events, eloop.kqueue_nevents,
1260e5b75505Sopenharmony_ci				     timeout ? &ts : NULL);
1261e5b75505Sopenharmony_ci		}
1262e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
1263e5b75505Sopenharmony_ci		if (res < 0 && errno != EINTR && errno != 0) {
1264e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR, "eloop: %s: %s",
1265e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_POLL
1266e5b75505Sopenharmony_ci				   "poll"
1267e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_POLL */
1268e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_SELECT
1269e5b75505Sopenharmony_ci				   "select"
1270e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_SELECT */
1271e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
1272e5b75505Sopenharmony_ci				   "epoll"
1273e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
1274e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
1275e5b75505Sopenharmony_ci				   "kqueue"
1276e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EKQUEUE */
1277e5b75505Sopenharmony_ci
1278e5b75505Sopenharmony_ci				   , strerror(errno));
1279e5b75505Sopenharmony_ci			goto out;
1280e5b75505Sopenharmony_ci		}
1281e5b75505Sopenharmony_ci
1282e5b75505Sopenharmony_ci		eloop.readers.changed = 0;
1283e5b75505Sopenharmony_ci		eloop.writers.changed = 0;
1284e5b75505Sopenharmony_ci		eloop.exceptions.changed = 0;
1285e5b75505Sopenharmony_ci
1286e5b75505Sopenharmony_ci		eloop_process_pending_signals();
1287e5b75505Sopenharmony_ci
1288e5b75505Sopenharmony_ci
1289e5b75505Sopenharmony_ci		/* check if some registered timeouts have occurred */
1290e5b75505Sopenharmony_ci		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
1291e5b75505Sopenharmony_ci					list);
1292e5b75505Sopenharmony_ci		if (timeout) {
1293e5b75505Sopenharmony_ci			os_get_reltime(&now);
1294e5b75505Sopenharmony_ci			if (!os_reltime_before(&now, &timeout->time)) {
1295e5b75505Sopenharmony_ci				void *eloop_data = timeout->eloop_data;
1296e5b75505Sopenharmony_ci				void *user_data = timeout->user_data;
1297e5b75505Sopenharmony_ci				eloop_timeout_handler handler =
1298e5b75505Sopenharmony_ci					timeout->handler;
1299e5b75505Sopenharmony_ci				eloop_remove_timeout(timeout);
1300e5b75505Sopenharmony_ci				handler(eloop_data, user_data);
1301e5b75505Sopenharmony_ci			}
1302e5b75505Sopenharmony_ci
1303e5b75505Sopenharmony_ci		}
1304e5b75505Sopenharmony_ci
1305e5b75505Sopenharmony_ci		if (res <= 0)
1306e5b75505Sopenharmony_ci			continue;
1307e5b75505Sopenharmony_ci
1308e5b75505Sopenharmony_ci		if (eloop.readers.changed ||
1309e5b75505Sopenharmony_ci		    eloop.writers.changed ||
1310e5b75505Sopenharmony_ci		    eloop.exceptions.changed) {
1311e5b75505Sopenharmony_ci			 /*
1312e5b75505Sopenharmony_ci			  * Sockets may have been closed and reopened with the
1313e5b75505Sopenharmony_ci			  * same FD in the signal or timeout handlers, so we
1314e5b75505Sopenharmony_ci			  * must skip the previous results and check again
1315e5b75505Sopenharmony_ci			  * whether any of the currently registered sockets have
1316e5b75505Sopenharmony_ci			  * events.
1317e5b75505Sopenharmony_ci			  */
1318e5b75505Sopenharmony_ci			continue;
1319e5b75505Sopenharmony_ci		}
1320e5b75505Sopenharmony_ci
1321e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_POLL
1322e5b75505Sopenharmony_ci		eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
1323e5b75505Sopenharmony_ci					  &eloop.exceptions, eloop.pollfds_map,
1324e5b75505Sopenharmony_ci					  eloop.max_pollfd_map);
1325e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_POLL */
1326e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_SELECT
1327e5b75505Sopenharmony_ci		eloop_sock_table_dispatch(&eloop.readers, rfds);
1328e5b75505Sopenharmony_ci		eloop_sock_table_dispatch(&eloop.writers, wfds);
1329e5b75505Sopenharmony_ci		eloop_sock_table_dispatch(&eloop.exceptions, efds);
1330e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_SELECT */
1331e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
1332e5b75505Sopenharmony_ci		eloop_sock_table_dispatch(eloop.epoll_events, res);
1333e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
1334e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
1335e5b75505Sopenharmony_ci		eloop_sock_table_dispatch(eloop.kqueue_events, res);
1336e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
1337e5b75505Sopenharmony_ci	}
1338e5b75505Sopenharmony_ci
1339e5b75505Sopenharmony_ci	eloop.terminate = 0;
1340e5b75505Sopenharmony_ciout:
1341e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_SELECT
1342e5b75505Sopenharmony_ci	os_free(rfds);
1343e5b75505Sopenharmony_ci	os_free(wfds);
1344e5b75505Sopenharmony_ci	os_free(efds);
1345e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_SELECT */
1346e5b75505Sopenharmony_ci	return;
1347e5b75505Sopenharmony_ci}
1348e5b75505Sopenharmony_ci
1349e5b75505Sopenharmony_ci
1350e5b75505Sopenharmony_civoid eloop_terminate(void)
1351e5b75505Sopenharmony_ci{
1352e5b75505Sopenharmony_ci	eloop.terminate = 1;
1353e5b75505Sopenharmony_ci}
1354e5b75505Sopenharmony_ci
1355e5b75505Sopenharmony_ci
1356e5b75505Sopenharmony_civoid eloop_destroy(void)
1357e5b75505Sopenharmony_ci{
1358e5b75505Sopenharmony_ci	struct eloop_timeout *timeout, *prev;
1359e5b75505Sopenharmony_ci	struct os_reltime now;
1360e5b75505Sopenharmony_ci
1361e5b75505Sopenharmony_ci	os_get_reltime(&now);
1362e5b75505Sopenharmony_ci	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
1363e5b75505Sopenharmony_ci			      struct eloop_timeout, list) {
1364e5b75505Sopenharmony_ci		int sec, usec;
1365e5b75505Sopenharmony_ci		sec = timeout->time.sec - now.sec;
1366e5b75505Sopenharmony_ci		usec = timeout->time.usec - now.usec;
1367e5b75505Sopenharmony_ci		if (timeout->time.usec < now.usec) {
1368e5b75505Sopenharmony_ci			sec--;
1369e5b75505Sopenharmony_ci			usec += 1000000;
1370e5b75505Sopenharmony_ci		}
1371e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
1372e5b75505Sopenharmony_ci			   "eloop_data=%p user_data=%p handler=%p",
1373e5b75505Sopenharmony_ci			   sec, usec, timeout->eloop_data, timeout->user_data,
1374e5b75505Sopenharmony_ci			   timeout->handler);
1375e5b75505Sopenharmony_ci		wpa_trace_dump_funcname("eloop unregistered timeout handler",
1376e5b75505Sopenharmony_ci					timeout->handler);
1377e5b75505Sopenharmony_ci		wpa_trace_dump("eloop timeout", timeout);
1378e5b75505Sopenharmony_ci		eloop_remove_timeout(timeout);
1379e5b75505Sopenharmony_ci	}
1380e5b75505Sopenharmony_ci#ifdef CONFIG_DRIVER_HDF
1381e5b75505Sopenharmony_ci	eloop_ctrl_deinit();
1382e5b75505Sopenharmony_ci#endif
1383e5b75505Sopenharmony_ci	eloop_sock_table_destroy(&eloop.readers);
1384e5b75505Sopenharmony_ci	eloop_sock_table_destroy(&eloop.writers);
1385e5b75505Sopenharmony_ci	eloop_sock_table_destroy(&eloop.exceptions);
1386e5b75505Sopenharmony_ci	os_free(eloop.signals);
1387e5b75505Sopenharmony_ci
1388e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_POLL
1389e5b75505Sopenharmony_ci	os_free(eloop.pollfds);
1390e5b75505Sopenharmony_ci	os_free(eloop.pollfds_map);
1391e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_POLL */
1392e5b75505Sopenharmony_ci#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
1393e5b75505Sopenharmony_ci	os_free(eloop.fd_table);
1394e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
1395e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_EPOLL
1396e5b75505Sopenharmony_ci	os_free(eloop.epoll_events);
1397e5b75505Sopenharmony_ci	close(eloop.epollfd);
1398e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_EPOLL */
1399e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
1400e5b75505Sopenharmony_ci	os_free(eloop.kqueue_events);
1401e5b75505Sopenharmony_ci	close(eloop.kqueuefd);
1402e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
1403e5b75505Sopenharmony_ci}
1404e5b75505Sopenharmony_ci
1405e5b75505Sopenharmony_ci
1406e5b75505Sopenharmony_ciint eloop_terminated(void)
1407e5b75505Sopenharmony_ci{
1408e5b75505Sopenharmony_ci	return eloop.terminate || eloop.pending_terminate;
1409e5b75505Sopenharmony_ci}
1410e5b75505Sopenharmony_ci
1411e5b75505Sopenharmony_ci
1412e5b75505Sopenharmony_civoid eloop_wait_for_read_sock(int sock)
1413e5b75505Sopenharmony_ci{
1414e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_POLL
1415e5b75505Sopenharmony_ci	struct pollfd pfd;
1416e5b75505Sopenharmony_ci
1417e5b75505Sopenharmony_ci	if (sock < 0)
1418e5b75505Sopenharmony_ci		return;
1419e5b75505Sopenharmony_ci
1420e5b75505Sopenharmony_ci	os_memset(&pfd, 0, sizeof(pfd));
1421e5b75505Sopenharmony_ci	pfd.fd = sock;
1422e5b75505Sopenharmony_ci	pfd.events = POLLIN;
1423e5b75505Sopenharmony_ci
1424e5b75505Sopenharmony_ci	poll(&pfd, 1, -1);
1425e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_POLL */
1426e5b75505Sopenharmony_ci#if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL)
1427e5b75505Sopenharmony_ci	/*
1428e5b75505Sopenharmony_ci	 * We can use epoll() here. But epoll() requres 4 system calls.
1429e5b75505Sopenharmony_ci	 * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for
1430e5b75505Sopenharmony_ci	 * epoll fd. So select() is better for performance here.
1431e5b75505Sopenharmony_ci	 */
1432e5b75505Sopenharmony_ci	fd_set rfds;
1433e5b75505Sopenharmony_ci
1434e5b75505Sopenharmony_ci	if (sock < 0)
1435e5b75505Sopenharmony_ci		return;
1436e5b75505Sopenharmony_ci
1437e5b75505Sopenharmony_ci	FD_ZERO(&rfds);
1438e5b75505Sopenharmony_ci	FD_SET(sock, &rfds);
1439e5b75505Sopenharmony_ci	select(sock + 1, &rfds, NULL, NULL, NULL);
1440e5b75505Sopenharmony_ci#endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */
1441e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_KQUEUE
1442e5b75505Sopenharmony_ci	int kfd;
1443e5b75505Sopenharmony_ci	struct kevent ke1, ke2;
1444e5b75505Sopenharmony_ci
1445e5b75505Sopenharmony_ci	kfd = kqueue();
1446e5b75505Sopenharmony_ci	if (kfd == -1)
1447e5b75505Sopenharmony_ci		return;
1448e5b75505Sopenharmony_ci	EV_SET(&ke1, sock, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
1449e5b75505Sopenharmony_ci	kevent(kfd, &ke1, 1, &ke2, 1, NULL);
1450e5b75505Sopenharmony_ci	close(kfd);
1451e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_KQUEUE */
1452e5b75505Sopenharmony_ci}
1453e5b75505Sopenharmony_ci
1454e5b75505Sopenharmony_ci#ifdef CONFIG_ELOOP_SELECT
1455e5b75505Sopenharmony_ci#undef CONFIG_ELOOP_SELECT
1456e5b75505Sopenharmony_ci#endif /* CONFIG_ELOOP_SELECT */
1457