eloop.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Event loop based on select() loop
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * This program is free software; you can redistribute it and/or modify
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * it under the terms of the GNU General Public License version 2 as
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * published by the Free Software Foundation.
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Alternatively, this software may be distributed under the terms of BSD
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * license.
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See README and COPYING for more details.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "includes.h"
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "common.h"
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "trace.h"
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "list.h"
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "eloop.h"
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstruct eloop_sock {
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int sock;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	void *eloop_data;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	void *user_data;
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	eloop_sock_handler handler;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	WPA_TRACE_REF(eloop);
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	WPA_TRACE_REF(user);
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	WPA_TRACE_INFO
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson};
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstruct eloop_timeout {
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	struct dl_list list;
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	struct os_time time;
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	void *eloop_data;
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	void *user_data;
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	eloop_timeout_handler handler;
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	WPA_TRACE_REF(eloop);
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	WPA_TRACE_REF(user);
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	WPA_TRACE_INFO
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson};
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstruct eloop_signal {
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int sig;
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	void *user_data;
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	eloop_signal_handler handler;
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int signaled;
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson};
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstruct eloop_sock_table {
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int count;
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	struct eloop_sock *table;
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int changed;
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson};
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstruct eloop_data {
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int max_sock;
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	struct eloop_sock_table readers;
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	struct eloop_sock_table writers;
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	struct eloop_sock_table exceptions;
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	struct dl_list timeout;
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int signal_count;
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	struct eloop_signal *signals;
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int signaled;
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int pending_terminate;
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int terminate;
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int reader_table_changed;
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson};
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstatic struct eloop_data eloop;
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#ifdef WPA_TRACE
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstatic void eloop_sigsegv_handler(int sig)
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson{
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	wpa_trace_show("eloop SIGSEGV");
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	abort();
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstatic void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson{
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int i;
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	if (table == NULL || table->table == NULL)
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		return;
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	for (i = 0; i < table->count; i++) {
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		wpa_trace_add_ref(&table->table[i], eloop,
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson				  table->table[i].eloop_data);
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		wpa_trace_add_ref(&table->table[i], user,
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson				  table->table[i].user_data);
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	}
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstatic void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson{
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int i;
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	if (table == NULL || table->table == NULL)
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		return;
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	for (i = 0; i < table->count; i++) {
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		wpa_trace_remove_ref(&table->table[i], eloop,
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson				     table->table[i].eloop_data);
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		wpa_trace_remove_ref(&table->table[i], user,
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson				     table->table[i].user_data);
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	}
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#else /* WPA_TRACE */
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#define eloop_trace_sock_add_ref(table) do { } while (0)
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#define eloop_trace_sock_remove_ref(table) do { } while (0)
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#endif /* WPA_TRACE */
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonint eloop_init(void)
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson{
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	os_memset(&eloop, 0, sizeof(eloop));
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	dl_list_init(&eloop.timeout);
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#ifdef WPA_TRACE
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	signal(SIGSEGV, eloop_sigsegv_handler);
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#endif /* WPA_TRACE */
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	return 0;
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstatic int eloop_sock_table_add_sock(struct eloop_sock_table *table,
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                     int sock, eloop_sock_handler handler,
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                     void *eloop_data, void *user_data)
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson{
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	struct eloop_sock *tmp;
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	if (table == NULL)
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		return -1;
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	eloop_trace_sock_remove_ref(table);
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	tmp = (struct eloop_sock *)
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		os_realloc(table->table,
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson			   (table->count + 1) * sizeof(struct eloop_sock));
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	if (tmp == NULL)
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		return -1;
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	tmp[table->count].sock = sock;
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	tmp[table->count].eloop_data = eloop_data;
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	tmp[table->count].user_data = user_data;
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	tmp[table->count].handler = handler;
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	wpa_trace_record(&tmp[table->count]);
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	table->count++;
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	table->table = tmp;
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	if (sock > eloop.max_sock)
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		eloop.max_sock = sock;
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	table->changed = 1;
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	eloop_trace_sock_add_ref(table);
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	return 0;
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstatic void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                         int sock)
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson{
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	int i;
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	if (table == NULL || table->table == NULL || table->count == 0)
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		return;
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	for (i = 0; i < table->count; i++) {
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		if (table->table[i].sock == sock)
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson			break;
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	}
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	if (i == table->count)
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		return;
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	eloop_trace_sock_remove_ref(table);
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson	if (i != table->count - 1) {
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson		os_memmove(&table->table[i], &table->table[i + 1],
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson			   (table->count - i - 1) *
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson			   sizeof(struct eloop_sock));
183	}
184	table->count--;
185	table->changed = 1;
186	eloop_trace_sock_add_ref(table);
187}
188
189
190static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
191				     fd_set *fds)
192{
193	int i;
194
195	FD_ZERO(fds);
196
197	if (table->table == NULL)
198		return;
199
200	for (i = 0; i < table->count; i++)
201		FD_SET(table->table[i].sock, fds);
202}
203
204
205static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
206				      fd_set *fds)
207{
208	int i;
209
210	if (table == NULL || table->table == NULL)
211		return;
212
213	table->changed = 0;
214	for (i = 0; i < table->count; i++) {
215		if (FD_ISSET(table->table[i].sock, fds)) {
216			table->table[i].handler(table->table[i].sock,
217						table->table[i].eloop_data,
218						table->table[i].user_data);
219			if (table->changed)
220				break;
221		}
222	}
223}
224
225
226static void eloop_sock_table_destroy(struct eloop_sock_table *table)
227{
228	if (table) {
229		int i;
230		for (i = 0; i < table->count && table->table; i++) {
231			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
232				   "sock=%d eloop_data=%p user_data=%p "
233				   "handler=%p",
234				   table->table[i].sock,
235				   table->table[i].eloop_data,
236				   table->table[i].user_data,
237				   table->table[i].handler);
238			wpa_trace_dump_funcname("eloop unregistered socket "
239						"handler",
240						table->table[i].handler);
241			wpa_trace_dump("eloop sock", &table->table[i]);
242		}
243		os_free(table->table);
244	}
245}
246
247
248int eloop_register_read_sock(int sock, eloop_sock_handler handler,
249			     void *eloop_data, void *user_data)
250{
251	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
252				   eloop_data, user_data);
253}
254
255
256void eloop_unregister_read_sock(int sock)
257{
258	eloop_unregister_sock(sock, EVENT_TYPE_READ);
259}
260
261
262static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
263{
264	switch (type) {
265	case EVENT_TYPE_READ:
266		return &eloop.readers;
267	case EVENT_TYPE_WRITE:
268		return &eloop.writers;
269	case EVENT_TYPE_EXCEPTION:
270		return &eloop.exceptions;
271	}
272
273	return NULL;
274}
275
276
277int eloop_register_sock(int sock, eloop_event_type type,
278			eloop_sock_handler handler,
279			void *eloop_data, void *user_data)
280{
281	struct eloop_sock_table *table;
282
283	table = eloop_get_sock_table(type);
284	return eloop_sock_table_add_sock(table, sock, handler,
285					 eloop_data, user_data);
286}
287
288
289void eloop_unregister_sock(int sock, eloop_event_type type)
290{
291	struct eloop_sock_table *table;
292
293	table = eloop_get_sock_table(type);
294	eloop_sock_table_remove_sock(table, sock);
295}
296
297
298int eloop_register_timeout(unsigned int secs, unsigned int usecs,
299			   eloop_timeout_handler handler,
300			   void *eloop_data, void *user_data)
301{
302	struct eloop_timeout *timeout, *tmp;
303	os_time_t now_sec;
304
305	timeout = os_zalloc(sizeof(*timeout));
306	if (timeout == NULL)
307		return -1;
308	if (os_get_time(&timeout->time) < 0) {
309		os_free(timeout);
310		return -1;
311	}
312	now_sec = timeout->time.sec;
313	timeout->time.sec += secs;
314	if (timeout->time.sec < now_sec) {
315		/*
316		 * Integer overflow - assume long enough timeout to be assumed
317		 * to be infinite, i.e., the timeout would never happen.
318		 */
319		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
320			   "ever happen - ignore it", secs);
321		os_free(timeout);
322		return 0;
323	}
324	timeout->time.usec += usecs;
325	while (timeout->time.usec >= 1000000) {
326		timeout->time.sec++;
327		timeout->time.usec -= 1000000;
328	}
329	timeout->eloop_data = eloop_data;
330	timeout->user_data = user_data;
331	timeout->handler = handler;
332	wpa_trace_add_ref(timeout, eloop, eloop_data);
333	wpa_trace_add_ref(timeout, user, user_data);
334	wpa_trace_record(timeout);
335
336	/* Maintain timeouts in order of increasing time */
337	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
338		if (os_time_before(&timeout->time, &tmp->time)) {
339			dl_list_add(tmp->list.prev, &timeout->list);
340			return 0;
341		}
342	}
343	dl_list_add_tail(&eloop.timeout, &timeout->list);
344
345	return 0;
346}
347
348
349static void eloop_remove_timeout(struct eloop_timeout *timeout)
350{
351	dl_list_del(&timeout->list);
352	wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
353	wpa_trace_remove_ref(timeout, user, timeout->user_data);
354	os_free(timeout);
355}
356
357
358int eloop_cancel_timeout(eloop_timeout_handler handler,
359			 void *eloop_data, void *user_data)
360{
361	struct eloop_timeout *timeout, *prev;
362	int removed = 0;
363
364	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
365			      struct eloop_timeout, list) {
366		if (timeout->handler == handler &&
367		    (timeout->eloop_data == eloop_data ||
368		     eloop_data == ELOOP_ALL_CTX) &&
369		    (timeout->user_data == user_data ||
370		     user_data == ELOOP_ALL_CTX)) {
371			eloop_remove_timeout(timeout);
372			removed++;
373		}
374	}
375
376	return removed;
377}
378
379
380int eloop_is_timeout_registered(eloop_timeout_handler handler,
381				void *eloop_data, void *user_data)
382{
383	struct eloop_timeout *tmp;
384
385	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
386		if (tmp->handler == handler &&
387		    tmp->eloop_data == eloop_data &&
388		    tmp->user_data == user_data)
389			return 1;
390	}
391
392	return 0;
393}
394
395
396#ifndef CONFIG_NATIVE_WINDOWS
397static void eloop_handle_alarm(int sig)
398{
399	wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
400		   "two seconds. Looks like there\n"
401		   "is a bug that ends up in a busy loop that "
402		   "prevents clean shutdown.\n"
403		   "Killing program forcefully.\n");
404	exit(1);
405}
406#endif /* CONFIG_NATIVE_WINDOWS */
407
408
409static void eloop_handle_signal(int sig)
410{
411	int i;
412
413#ifndef CONFIG_NATIVE_WINDOWS
414	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
415		/* Use SIGALRM to break out from potential busy loops that
416		 * would not allow the program to be killed. */
417		eloop.pending_terminate = 1;
418		signal(SIGALRM, eloop_handle_alarm);
419		alarm(2);
420	}
421#endif /* CONFIG_NATIVE_WINDOWS */
422
423	eloop.signaled++;
424	for (i = 0; i < eloop.signal_count; i++) {
425		if (eloop.signals[i].sig == sig) {
426			eloop.signals[i].signaled++;
427			break;
428		}
429	}
430}
431
432
433static void eloop_process_pending_signals(void)
434{
435	int i;
436
437	if (eloop.signaled == 0)
438		return;
439	eloop.signaled = 0;
440
441	if (eloop.pending_terminate) {
442#ifndef CONFIG_NATIVE_WINDOWS
443		alarm(0);
444#endif /* CONFIG_NATIVE_WINDOWS */
445		eloop.pending_terminate = 0;
446	}
447
448	for (i = 0; i < eloop.signal_count; i++) {
449		if (eloop.signals[i].signaled) {
450			eloop.signals[i].signaled = 0;
451			eloop.signals[i].handler(eloop.signals[i].sig,
452						 eloop.signals[i].user_data);
453		}
454	}
455}
456
457
458int eloop_register_signal(int sig, eloop_signal_handler handler,
459			  void *user_data)
460{
461	struct eloop_signal *tmp;
462
463	tmp = (struct eloop_signal *)
464		os_realloc(eloop.signals,
465			   (eloop.signal_count + 1) *
466			   sizeof(struct eloop_signal));
467	if (tmp == NULL)
468		return -1;
469
470	tmp[eloop.signal_count].sig = sig;
471	tmp[eloop.signal_count].user_data = user_data;
472	tmp[eloop.signal_count].handler = handler;
473	tmp[eloop.signal_count].signaled = 0;
474	eloop.signal_count++;
475	eloop.signals = tmp;
476	signal(sig, eloop_handle_signal);
477
478	return 0;
479}
480
481
482int eloop_register_signal_terminate(eloop_signal_handler handler,
483				    void *user_data)
484{
485	int ret = eloop_register_signal(SIGINT, handler, user_data);
486	if (ret == 0)
487		ret = eloop_register_signal(SIGTERM, handler, user_data);
488	return ret;
489}
490
491
492int eloop_register_signal_reconfig(eloop_signal_handler handler,
493				   void *user_data)
494{
495#ifdef CONFIG_NATIVE_WINDOWS
496	return 0;
497#else /* CONFIG_NATIVE_WINDOWS */
498	return eloop_register_signal(SIGHUP, handler, user_data);
499#endif /* CONFIG_NATIVE_WINDOWS */
500}
501
502
503void eloop_run(void)
504{
505	fd_set *rfds, *wfds, *efds;
506	int res;
507	struct timeval _tv;
508	struct os_time tv, now;
509
510	rfds = os_malloc(sizeof(*rfds));
511	wfds = os_malloc(sizeof(*wfds));
512	efds = os_malloc(sizeof(*efds));
513	if (rfds == NULL || wfds == NULL || efds == NULL)
514		goto out;
515
516	while (!eloop.terminate &&
517	       (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
518		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
519		struct eloop_timeout *timeout;
520		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
521					list);
522		if (timeout) {
523			os_get_time(&now);
524			if (os_time_before(&now, &timeout->time))
525				os_time_sub(&timeout->time, &now, &tv);
526			else
527				tv.sec = tv.usec = 0;
528			_tv.tv_sec = tv.sec;
529			_tv.tv_usec = tv.usec;
530		}
531
532		eloop_sock_table_set_fds(&eloop.readers, rfds);
533		eloop_sock_table_set_fds(&eloop.writers, wfds);
534		eloop_sock_table_set_fds(&eloop.exceptions, efds);
535		res = select(eloop.max_sock + 1, rfds, wfds, efds,
536			     timeout ? &_tv : NULL);
537		if (res < 0 && errno != EINTR && errno != 0) {
538			perror("select");
539			goto out;
540		}
541		eloop_process_pending_signals();
542
543		/* check if some registered timeouts have occurred */
544		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
545					list);
546		if (timeout) {
547			os_get_time(&now);
548			if (!os_time_before(&now, &timeout->time)) {
549				void *eloop_data = timeout->eloop_data;
550				void *user_data = timeout->user_data;
551				eloop_timeout_handler handler =
552					timeout->handler;
553				eloop_remove_timeout(timeout);
554				handler(eloop_data, user_data);
555			}
556
557		}
558
559		if (res <= 0)
560			continue;
561
562		eloop_sock_table_dispatch(&eloop.readers, rfds);
563		eloop_sock_table_dispatch(&eloop.writers, wfds);
564		eloop_sock_table_dispatch(&eloop.exceptions, efds);
565	}
566
567out:
568	os_free(rfds);
569	os_free(wfds);
570	os_free(efds);
571}
572
573
574void eloop_terminate(void)
575{
576	eloop.terminate = 1;
577}
578
579
580void eloop_destroy(void)
581{
582	struct eloop_timeout *timeout, *prev;
583	struct os_time now;
584
585	os_get_time(&now);
586	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
587			      struct eloop_timeout, list) {
588		int sec, usec;
589		sec = timeout->time.sec - now.sec;
590		usec = timeout->time.usec - now.usec;
591		if (timeout->time.usec < now.usec) {
592			sec--;
593			usec += 1000000;
594		}
595		wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
596			   "eloop_data=%p user_data=%p handler=%p",
597			   sec, usec, timeout->eloop_data, timeout->user_data,
598			   timeout->handler);
599		wpa_trace_dump_funcname("eloop unregistered timeout handler",
600					timeout->handler);
601		wpa_trace_dump("eloop timeout", timeout);
602		eloop_remove_timeout(timeout);
603	}
604	eloop_sock_table_destroy(&eloop.readers);
605	eloop_sock_table_destroy(&eloop.writers);
606	eloop_sock_table_destroy(&eloop.exceptions);
607	os_free(eloop.signals);
608}
609
610
611int eloop_terminated(void)
612{
613	return eloop.terminate;
614}
615
616
617void eloop_wait_for_read_sock(int sock)
618{
619	fd_set rfds;
620
621	if (sock < 0)
622		return;
623
624	FD_ZERO(&rfds);
625	FD_SET(sock, &rfds);
626	select(sock + 1, &rfds, NULL, NULL, NULL);
627}
628