xref: /freebsd/contrib/wpa/src/utils/eloop.c (revision e28a4053b110e06768631ac8401ed4a3c05e68a5)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * Event loop based on select() loop
3*e28a4053SRui Paulo  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
539beb93cSSam Leffler  * This program is free software; you can redistribute it and/or modify
639beb93cSSam Leffler  * it under the terms of the GNU General Public License version 2 as
739beb93cSSam Leffler  * published by the Free Software Foundation.
839beb93cSSam Leffler  *
939beb93cSSam Leffler  * Alternatively, this software may be distributed under the terms of BSD
1039beb93cSSam Leffler  * license.
1139beb93cSSam Leffler  *
1239beb93cSSam Leffler  * See README and COPYING for more details.
1339beb93cSSam Leffler  */
1439beb93cSSam Leffler 
1539beb93cSSam Leffler #include "includes.h"
1639beb93cSSam Leffler 
1739beb93cSSam Leffler #include "common.h"
18*e28a4053SRui Paulo #include "trace.h"
19*e28a4053SRui Paulo #include "list.h"
2039beb93cSSam Leffler #include "eloop.h"
2139beb93cSSam Leffler 
2239beb93cSSam Leffler 
2339beb93cSSam Leffler struct eloop_sock {
2439beb93cSSam Leffler 	int sock;
2539beb93cSSam Leffler 	void *eloop_data;
2639beb93cSSam Leffler 	void *user_data;
2739beb93cSSam Leffler 	eloop_sock_handler handler;
28*e28a4053SRui Paulo 	WPA_TRACE_REF(eloop);
29*e28a4053SRui Paulo 	WPA_TRACE_REF(user);
30*e28a4053SRui Paulo 	WPA_TRACE_INFO
3139beb93cSSam Leffler };
3239beb93cSSam Leffler 
3339beb93cSSam Leffler struct eloop_timeout {
34*e28a4053SRui Paulo 	struct dl_list list;
3539beb93cSSam Leffler 	struct os_time time;
3639beb93cSSam Leffler 	void *eloop_data;
3739beb93cSSam Leffler 	void *user_data;
3839beb93cSSam Leffler 	eloop_timeout_handler handler;
39*e28a4053SRui Paulo 	WPA_TRACE_REF(eloop);
40*e28a4053SRui Paulo 	WPA_TRACE_REF(user);
41*e28a4053SRui Paulo 	WPA_TRACE_INFO
4239beb93cSSam Leffler };
4339beb93cSSam Leffler 
4439beb93cSSam Leffler struct eloop_signal {
4539beb93cSSam Leffler 	int sig;
4639beb93cSSam Leffler 	void *user_data;
4739beb93cSSam Leffler 	eloop_signal_handler handler;
4839beb93cSSam Leffler 	int signaled;
4939beb93cSSam Leffler };
5039beb93cSSam Leffler 
5139beb93cSSam Leffler struct eloop_sock_table {
5239beb93cSSam Leffler 	int count;
5339beb93cSSam Leffler 	struct eloop_sock *table;
5439beb93cSSam Leffler 	int changed;
5539beb93cSSam Leffler };
5639beb93cSSam Leffler 
5739beb93cSSam Leffler struct eloop_data {
5839beb93cSSam Leffler 	int max_sock;
5939beb93cSSam Leffler 
6039beb93cSSam Leffler 	struct eloop_sock_table readers;
6139beb93cSSam Leffler 	struct eloop_sock_table writers;
6239beb93cSSam Leffler 	struct eloop_sock_table exceptions;
6339beb93cSSam Leffler 
64*e28a4053SRui Paulo 	struct dl_list timeout;
6539beb93cSSam Leffler 
6639beb93cSSam Leffler 	int signal_count;
6739beb93cSSam Leffler 	struct eloop_signal *signals;
6839beb93cSSam Leffler 	int signaled;
6939beb93cSSam Leffler 	int pending_terminate;
7039beb93cSSam Leffler 
7139beb93cSSam Leffler 	int terminate;
7239beb93cSSam Leffler 	int reader_table_changed;
7339beb93cSSam Leffler };
7439beb93cSSam Leffler 
7539beb93cSSam Leffler static struct eloop_data eloop;
7639beb93cSSam Leffler 
7739beb93cSSam Leffler 
78*e28a4053SRui Paulo #ifdef WPA_TRACE
79*e28a4053SRui Paulo 
80*e28a4053SRui Paulo static void eloop_sigsegv_handler(int sig)
81*e28a4053SRui Paulo {
82*e28a4053SRui Paulo 	wpa_trace_show("eloop SIGSEGV");
83*e28a4053SRui Paulo 	abort();
84*e28a4053SRui Paulo }
85*e28a4053SRui Paulo 
86*e28a4053SRui Paulo static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
87*e28a4053SRui Paulo {
88*e28a4053SRui Paulo 	int i;
89*e28a4053SRui Paulo 	if (table == NULL || table->table == NULL)
90*e28a4053SRui Paulo 		return;
91*e28a4053SRui Paulo 	for (i = 0; i < table->count; i++) {
92*e28a4053SRui Paulo 		wpa_trace_add_ref(&table->table[i], eloop,
93*e28a4053SRui Paulo 				  table->table[i].eloop_data);
94*e28a4053SRui Paulo 		wpa_trace_add_ref(&table->table[i], user,
95*e28a4053SRui Paulo 				  table->table[i].user_data);
96*e28a4053SRui Paulo 	}
97*e28a4053SRui Paulo }
98*e28a4053SRui Paulo 
99*e28a4053SRui Paulo 
100*e28a4053SRui Paulo static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
101*e28a4053SRui Paulo {
102*e28a4053SRui Paulo 	int i;
103*e28a4053SRui Paulo 	if (table == NULL || table->table == NULL)
104*e28a4053SRui Paulo 		return;
105*e28a4053SRui Paulo 	for (i = 0; i < table->count; i++) {
106*e28a4053SRui Paulo 		wpa_trace_remove_ref(&table->table[i], eloop,
107*e28a4053SRui Paulo 				     table->table[i].eloop_data);
108*e28a4053SRui Paulo 		wpa_trace_remove_ref(&table->table[i], user,
109*e28a4053SRui Paulo 				     table->table[i].user_data);
110*e28a4053SRui Paulo 	}
111*e28a4053SRui Paulo }
112*e28a4053SRui Paulo 
113*e28a4053SRui Paulo #else /* WPA_TRACE */
114*e28a4053SRui Paulo 
115*e28a4053SRui Paulo #define eloop_trace_sock_add_ref(table) do { } while (0)
116*e28a4053SRui Paulo #define eloop_trace_sock_remove_ref(table) do { } while (0)
117*e28a4053SRui Paulo 
118*e28a4053SRui Paulo #endif /* WPA_TRACE */
119*e28a4053SRui Paulo 
120*e28a4053SRui Paulo 
121*e28a4053SRui Paulo int eloop_init(void)
12239beb93cSSam Leffler {
12339beb93cSSam Leffler 	os_memset(&eloop, 0, sizeof(eloop));
124*e28a4053SRui Paulo 	dl_list_init(&eloop.timeout);
125*e28a4053SRui Paulo #ifdef WPA_TRACE
126*e28a4053SRui Paulo 	signal(SIGSEGV, eloop_sigsegv_handler);
127*e28a4053SRui Paulo #endif /* WPA_TRACE */
12839beb93cSSam Leffler 	return 0;
12939beb93cSSam Leffler }
13039beb93cSSam Leffler 
13139beb93cSSam Leffler 
13239beb93cSSam Leffler static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
13339beb93cSSam Leffler                                      int sock, eloop_sock_handler handler,
13439beb93cSSam Leffler                                      void *eloop_data, void *user_data)
13539beb93cSSam Leffler {
13639beb93cSSam Leffler 	struct eloop_sock *tmp;
13739beb93cSSam Leffler 
13839beb93cSSam Leffler 	if (table == NULL)
13939beb93cSSam Leffler 		return -1;
14039beb93cSSam Leffler 
141*e28a4053SRui Paulo 	eloop_trace_sock_remove_ref(table);
14239beb93cSSam Leffler 	tmp = (struct eloop_sock *)
14339beb93cSSam Leffler 		os_realloc(table->table,
14439beb93cSSam Leffler 			   (table->count + 1) * sizeof(struct eloop_sock));
14539beb93cSSam Leffler 	if (tmp == NULL)
14639beb93cSSam Leffler 		return -1;
14739beb93cSSam Leffler 
14839beb93cSSam Leffler 	tmp[table->count].sock = sock;
14939beb93cSSam Leffler 	tmp[table->count].eloop_data = eloop_data;
15039beb93cSSam Leffler 	tmp[table->count].user_data = user_data;
15139beb93cSSam Leffler 	tmp[table->count].handler = handler;
152*e28a4053SRui Paulo 	wpa_trace_record(&tmp[table->count]);
15339beb93cSSam Leffler 	table->count++;
15439beb93cSSam Leffler 	table->table = tmp;
15539beb93cSSam Leffler 	if (sock > eloop.max_sock)
15639beb93cSSam Leffler 		eloop.max_sock = sock;
15739beb93cSSam Leffler 	table->changed = 1;
158*e28a4053SRui Paulo 	eloop_trace_sock_add_ref(table);
15939beb93cSSam Leffler 
16039beb93cSSam Leffler 	return 0;
16139beb93cSSam Leffler }
16239beb93cSSam Leffler 
16339beb93cSSam Leffler 
16439beb93cSSam Leffler static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
16539beb93cSSam Leffler                                          int sock)
16639beb93cSSam Leffler {
16739beb93cSSam Leffler 	int i;
16839beb93cSSam Leffler 
16939beb93cSSam Leffler 	if (table == NULL || table->table == NULL || table->count == 0)
17039beb93cSSam Leffler 		return;
17139beb93cSSam Leffler 
17239beb93cSSam Leffler 	for (i = 0; i < table->count; i++) {
17339beb93cSSam Leffler 		if (table->table[i].sock == sock)
17439beb93cSSam Leffler 			break;
17539beb93cSSam Leffler 	}
17639beb93cSSam Leffler 	if (i == table->count)
17739beb93cSSam Leffler 		return;
178*e28a4053SRui Paulo 	eloop_trace_sock_remove_ref(table);
17939beb93cSSam Leffler 	if (i != table->count - 1) {
18039beb93cSSam Leffler 		os_memmove(&table->table[i], &table->table[i + 1],
18139beb93cSSam Leffler 			   (table->count - i - 1) *
18239beb93cSSam Leffler 			   sizeof(struct eloop_sock));
18339beb93cSSam Leffler 	}
18439beb93cSSam Leffler 	table->count--;
18539beb93cSSam Leffler 	table->changed = 1;
186*e28a4053SRui Paulo 	eloop_trace_sock_add_ref(table);
18739beb93cSSam Leffler }
18839beb93cSSam Leffler 
18939beb93cSSam Leffler 
19039beb93cSSam Leffler static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
19139beb93cSSam Leffler 				     fd_set *fds)
19239beb93cSSam Leffler {
19339beb93cSSam Leffler 	int i;
19439beb93cSSam Leffler 
19539beb93cSSam Leffler 	FD_ZERO(fds);
19639beb93cSSam Leffler 
19739beb93cSSam Leffler 	if (table->table == NULL)
19839beb93cSSam Leffler 		return;
19939beb93cSSam Leffler 
20039beb93cSSam Leffler 	for (i = 0; i < table->count; i++)
20139beb93cSSam Leffler 		FD_SET(table->table[i].sock, fds);
20239beb93cSSam Leffler }
20339beb93cSSam Leffler 
20439beb93cSSam Leffler 
20539beb93cSSam Leffler static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
20639beb93cSSam Leffler 				      fd_set *fds)
20739beb93cSSam Leffler {
20839beb93cSSam Leffler 	int i;
20939beb93cSSam Leffler 
21039beb93cSSam Leffler 	if (table == NULL || table->table == NULL)
21139beb93cSSam Leffler 		return;
21239beb93cSSam Leffler 
21339beb93cSSam Leffler 	table->changed = 0;
21439beb93cSSam Leffler 	for (i = 0; i < table->count; i++) {
21539beb93cSSam Leffler 		if (FD_ISSET(table->table[i].sock, fds)) {
21639beb93cSSam Leffler 			table->table[i].handler(table->table[i].sock,
21739beb93cSSam Leffler 						table->table[i].eloop_data,
21839beb93cSSam Leffler 						table->table[i].user_data);
21939beb93cSSam Leffler 			if (table->changed)
22039beb93cSSam Leffler 				break;
22139beb93cSSam Leffler 		}
22239beb93cSSam Leffler 	}
22339beb93cSSam Leffler }
22439beb93cSSam Leffler 
22539beb93cSSam Leffler 
22639beb93cSSam Leffler static void eloop_sock_table_destroy(struct eloop_sock_table *table)
22739beb93cSSam Leffler {
22839beb93cSSam Leffler 	if (table) {
22939beb93cSSam Leffler 		int i;
23039beb93cSSam Leffler 		for (i = 0; i < table->count && table->table; i++) {
231*e28a4053SRui Paulo 			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
232*e28a4053SRui Paulo 				   "sock=%d eloop_data=%p user_data=%p "
233*e28a4053SRui Paulo 				   "handler=%p",
23439beb93cSSam Leffler 				   table->table[i].sock,
23539beb93cSSam Leffler 				   table->table[i].eloop_data,
23639beb93cSSam Leffler 				   table->table[i].user_data,
23739beb93cSSam Leffler 				   table->table[i].handler);
238*e28a4053SRui Paulo 			wpa_trace_dump_funcname("eloop unregistered socket "
239*e28a4053SRui Paulo 						"handler",
240*e28a4053SRui Paulo 						table->table[i].handler);
241*e28a4053SRui Paulo 			wpa_trace_dump("eloop sock", &table->table[i]);
24239beb93cSSam Leffler 		}
24339beb93cSSam Leffler 		os_free(table->table);
24439beb93cSSam Leffler 	}
24539beb93cSSam Leffler }
24639beb93cSSam Leffler 
24739beb93cSSam Leffler 
24839beb93cSSam Leffler int eloop_register_read_sock(int sock, eloop_sock_handler handler,
24939beb93cSSam Leffler 			     void *eloop_data, void *user_data)
25039beb93cSSam Leffler {
25139beb93cSSam Leffler 	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
25239beb93cSSam Leffler 				   eloop_data, user_data);
25339beb93cSSam Leffler }
25439beb93cSSam Leffler 
25539beb93cSSam Leffler 
25639beb93cSSam Leffler void eloop_unregister_read_sock(int sock)
25739beb93cSSam Leffler {
25839beb93cSSam Leffler 	eloop_unregister_sock(sock, EVENT_TYPE_READ);
25939beb93cSSam Leffler }
26039beb93cSSam Leffler 
26139beb93cSSam Leffler 
26239beb93cSSam Leffler static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
26339beb93cSSam Leffler {
26439beb93cSSam Leffler 	switch (type) {
26539beb93cSSam Leffler 	case EVENT_TYPE_READ:
26639beb93cSSam Leffler 		return &eloop.readers;
26739beb93cSSam Leffler 	case EVENT_TYPE_WRITE:
26839beb93cSSam Leffler 		return &eloop.writers;
26939beb93cSSam Leffler 	case EVENT_TYPE_EXCEPTION:
27039beb93cSSam Leffler 		return &eloop.exceptions;
27139beb93cSSam Leffler 	}
27239beb93cSSam Leffler 
27339beb93cSSam Leffler 	return NULL;
27439beb93cSSam Leffler }
27539beb93cSSam Leffler 
27639beb93cSSam Leffler 
27739beb93cSSam Leffler int eloop_register_sock(int sock, eloop_event_type type,
27839beb93cSSam Leffler 			eloop_sock_handler handler,
27939beb93cSSam Leffler 			void *eloop_data, void *user_data)
28039beb93cSSam Leffler {
28139beb93cSSam Leffler 	struct eloop_sock_table *table;
28239beb93cSSam Leffler 
28339beb93cSSam Leffler 	table = eloop_get_sock_table(type);
28439beb93cSSam Leffler 	return eloop_sock_table_add_sock(table, sock, handler,
28539beb93cSSam Leffler 					 eloop_data, user_data);
28639beb93cSSam Leffler }
28739beb93cSSam Leffler 
28839beb93cSSam Leffler 
28939beb93cSSam Leffler void eloop_unregister_sock(int sock, eloop_event_type type)
29039beb93cSSam Leffler {
29139beb93cSSam Leffler 	struct eloop_sock_table *table;
29239beb93cSSam Leffler 
29339beb93cSSam Leffler 	table = eloop_get_sock_table(type);
29439beb93cSSam Leffler 	eloop_sock_table_remove_sock(table, sock);
29539beb93cSSam Leffler }
29639beb93cSSam Leffler 
29739beb93cSSam Leffler 
29839beb93cSSam Leffler int eloop_register_timeout(unsigned int secs, unsigned int usecs,
29939beb93cSSam Leffler 			   eloop_timeout_handler handler,
30039beb93cSSam Leffler 			   void *eloop_data, void *user_data)
30139beb93cSSam Leffler {
302*e28a4053SRui Paulo 	struct eloop_timeout *timeout, *tmp;
30339beb93cSSam Leffler 
304*e28a4053SRui Paulo 	timeout = os_zalloc(sizeof(*timeout));
30539beb93cSSam Leffler 	if (timeout == NULL)
30639beb93cSSam Leffler 		return -1;
30739beb93cSSam Leffler 	if (os_get_time(&timeout->time) < 0) {
30839beb93cSSam Leffler 		os_free(timeout);
30939beb93cSSam Leffler 		return -1;
31039beb93cSSam Leffler 	}
31139beb93cSSam Leffler 	timeout->time.sec += secs;
31239beb93cSSam Leffler 	timeout->time.usec += usecs;
31339beb93cSSam Leffler 	while (timeout->time.usec >= 1000000) {
31439beb93cSSam Leffler 		timeout->time.sec++;
31539beb93cSSam Leffler 		timeout->time.usec -= 1000000;
31639beb93cSSam Leffler 	}
31739beb93cSSam Leffler 	timeout->eloop_data = eloop_data;
31839beb93cSSam Leffler 	timeout->user_data = user_data;
31939beb93cSSam Leffler 	timeout->handler = handler;
320*e28a4053SRui Paulo 	wpa_trace_add_ref(timeout, eloop, eloop_data);
321*e28a4053SRui Paulo 	wpa_trace_add_ref(timeout, user, user_data);
322*e28a4053SRui Paulo 	wpa_trace_record(timeout);
32339beb93cSSam Leffler 
324*e28a4053SRui Paulo 	/* Maintain timeouts in order of increasing time */
325*e28a4053SRui Paulo 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
326*e28a4053SRui Paulo 		if (os_time_before(&timeout->time, &tmp->time)) {
327*e28a4053SRui Paulo 			dl_list_add(tmp->list.prev, &timeout->list);
328*e28a4053SRui Paulo 			return 0;
329*e28a4053SRui Paulo 		}
330*e28a4053SRui Paulo 	}
331*e28a4053SRui Paulo 	dl_list_add_tail(&eloop.timeout, &timeout->list);
332*e28a4053SRui Paulo 
33339beb93cSSam Leffler 	return 0;
33439beb93cSSam Leffler }
33539beb93cSSam Leffler 
33639beb93cSSam Leffler 
337*e28a4053SRui Paulo static void eloop_remove_timeout(struct eloop_timeout *timeout)
338*e28a4053SRui Paulo {
339*e28a4053SRui Paulo 	dl_list_del(&timeout->list);
340*e28a4053SRui Paulo 	wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
341*e28a4053SRui Paulo 	wpa_trace_remove_ref(timeout, user, timeout->user_data);
342*e28a4053SRui Paulo 	os_free(timeout);
34339beb93cSSam Leffler }
34439beb93cSSam Leffler 
34539beb93cSSam Leffler 
34639beb93cSSam Leffler int eloop_cancel_timeout(eloop_timeout_handler handler,
34739beb93cSSam Leffler 			 void *eloop_data, void *user_data)
34839beb93cSSam Leffler {
349*e28a4053SRui Paulo 	struct eloop_timeout *timeout, *prev;
35039beb93cSSam Leffler 	int removed = 0;
35139beb93cSSam Leffler 
352*e28a4053SRui Paulo 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
353*e28a4053SRui Paulo 			      struct eloop_timeout, list) {
35439beb93cSSam Leffler 		if (timeout->handler == handler &&
35539beb93cSSam Leffler 		    (timeout->eloop_data == eloop_data ||
35639beb93cSSam Leffler 		     eloop_data == ELOOP_ALL_CTX) &&
35739beb93cSSam Leffler 		    (timeout->user_data == user_data ||
35839beb93cSSam Leffler 		     user_data == ELOOP_ALL_CTX)) {
359*e28a4053SRui Paulo 			eloop_remove_timeout(timeout);
36039beb93cSSam Leffler 			removed++;
361*e28a4053SRui Paulo 		}
36239beb93cSSam Leffler 	}
36339beb93cSSam Leffler 
36439beb93cSSam Leffler 	return removed;
36539beb93cSSam Leffler }
36639beb93cSSam Leffler 
36739beb93cSSam Leffler 
36839beb93cSSam Leffler int eloop_is_timeout_registered(eloop_timeout_handler handler,
36939beb93cSSam Leffler 				void *eloop_data, void *user_data)
37039beb93cSSam Leffler {
37139beb93cSSam Leffler 	struct eloop_timeout *tmp;
37239beb93cSSam Leffler 
373*e28a4053SRui Paulo 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
37439beb93cSSam Leffler 		if (tmp->handler == handler &&
37539beb93cSSam Leffler 		    tmp->eloop_data == eloop_data &&
37639beb93cSSam Leffler 		    tmp->user_data == user_data)
37739beb93cSSam Leffler 			return 1;
37839beb93cSSam Leffler 	}
37939beb93cSSam Leffler 
38039beb93cSSam Leffler 	return 0;
38139beb93cSSam Leffler }
38239beb93cSSam Leffler 
38339beb93cSSam Leffler 
38439beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
38539beb93cSSam Leffler static void eloop_handle_alarm(int sig)
38639beb93cSSam Leffler {
387*e28a4053SRui Paulo 	wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
388*e28a4053SRui Paulo 		   "two seconds. Looks like there\n"
38939beb93cSSam Leffler 		   "is a bug that ends up in a busy loop that "
39039beb93cSSam Leffler 		   "prevents clean shutdown.\n"
39139beb93cSSam Leffler 		   "Killing program forcefully.\n");
39239beb93cSSam Leffler 	exit(1);
39339beb93cSSam Leffler }
39439beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
39539beb93cSSam Leffler 
39639beb93cSSam Leffler 
39739beb93cSSam Leffler static void eloop_handle_signal(int sig)
39839beb93cSSam Leffler {
39939beb93cSSam Leffler 	int i;
40039beb93cSSam Leffler 
40139beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
40239beb93cSSam Leffler 	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
40339beb93cSSam Leffler 		/* Use SIGALRM to break out from potential busy loops that
40439beb93cSSam Leffler 		 * would not allow the program to be killed. */
40539beb93cSSam Leffler 		eloop.pending_terminate = 1;
40639beb93cSSam Leffler 		signal(SIGALRM, eloop_handle_alarm);
40739beb93cSSam Leffler 		alarm(2);
40839beb93cSSam Leffler 	}
40939beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
41039beb93cSSam Leffler 
41139beb93cSSam Leffler 	eloop.signaled++;
41239beb93cSSam Leffler 	for (i = 0; i < eloop.signal_count; i++) {
41339beb93cSSam Leffler 		if (eloop.signals[i].sig == sig) {
41439beb93cSSam Leffler 			eloop.signals[i].signaled++;
41539beb93cSSam Leffler 			break;
41639beb93cSSam Leffler 		}
41739beb93cSSam Leffler 	}
41839beb93cSSam Leffler }
41939beb93cSSam Leffler 
42039beb93cSSam Leffler 
42139beb93cSSam Leffler static void eloop_process_pending_signals(void)
42239beb93cSSam Leffler {
42339beb93cSSam Leffler 	int i;
42439beb93cSSam Leffler 
42539beb93cSSam Leffler 	if (eloop.signaled == 0)
42639beb93cSSam Leffler 		return;
42739beb93cSSam Leffler 	eloop.signaled = 0;
42839beb93cSSam Leffler 
42939beb93cSSam Leffler 	if (eloop.pending_terminate) {
43039beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
43139beb93cSSam Leffler 		alarm(0);
43239beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
43339beb93cSSam Leffler 		eloop.pending_terminate = 0;
43439beb93cSSam Leffler 	}
43539beb93cSSam Leffler 
43639beb93cSSam Leffler 	for (i = 0; i < eloop.signal_count; i++) {
43739beb93cSSam Leffler 		if (eloop.signals[i].signaled) {
43839beb93cSSam Leffler 			eloop.signals[i].signaled = 0;
43939beb93cSSam Leffler 			eloop.signals[i].handler(eloop.signals[i].sig,
44039beb93cSSam Leffler 						 eloop.signals[i].user_data);
44139beb93cSSam Leffler 		}
44239beb93cSSam Leffler 	}
44339beb93cSSam Leffler }
44439beb93cSSam Leffler 
44539beb93cSSam Leffler 
44639beb93cSSam Leffler int eloop_register_signal(int sig, eloop_signal_handler handler,
44739beb93cSSam Leffler 			  void *user_data)
44839beb93cSSam Leffler {
44939beb93cSSam Leffler 	struct eloop_signal *tmp;
45039beb93cSSam Leffler 
45139beb93cSSam Leffler 	tmp = (struct eloop_signal *)
45239beb93cSSam Leffler 		os_realloc(eloop.signals,
45339beb93cSSam Leffler 			   (eloop.signal_count + 1) *
45439beb93cSSam Leffler 			   sizeof(struct eloop_signal));
45539beb93cSSam Leffler 	if (tmp == NULL)
45639beb93cSSam Leffler 		return -1;
45739beb93cSSam Leffler 
45839beb93cSSam Leffler 	tmp[eloop.signal_count].sig = sig;
45939beb93cSSam Leffler 	tmp[eloop.signal_count].user_data = user_data;
46039beb93cSSam Leffler 	tmp[eloop.signal_count].handler = handler;
46139beb93cSSam Leffler 	tmp[eloop.signal_count].signaled = 0;
46239beb93cSSam Leffler 	eloop.signal_count++;
46339beb93cSSam Leffler 	eloop.signals = tmp;
46439beb93cSSam Leffler 	signal(sig, eloop_handle_signal);
46539beb93cSSam Leffler 
46639beb93cSSam Leffler 	return 0;
46739beb93cSSam Leffler }
46839beb93cSSam Leffler 
46939beb93cSSam Leffler 
47039beb93cSSam Leffler int eloop_register_signal_terminate(eloop_signal_handler handler,
47139beb93cSSam Leffler 				    void *user_data)
47239beb93cSSam Leffler {
47339beb93cSSam Leffler 	int ret = eloop_register_signal(SIGINT, handler, user_data);
47439beb93cSSam Leffler 	if (ret == 0)
47539beb93cSSam Leffler 		ret = eloop_register_signal(SIGTERM, handler, user_data);
47639beb93cSSam Leffler 	return ret;
47739beb93cSSam Leffler }
47839beb93cSSam Leffler 
47939beb93cSSam Leffler 
48039beb93cSSam Leffler int eloop_register_signal_reconfig(eloop_signal_handler handler,
48139beb93cSSam Leffler 				   void *user_data)
48239beb93cSSam Leffler {
48339beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
48439beb93cSSam Leffler 	return 0;
48539beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */
48639beb93cSSam Leffler 	return eloop_register_signal(SIGHUP, handler, user_data);
48739beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
48839beb93cSSam Leffler }
48939beb93cSSam Leffler 
49039beb93cSSam Leffler 
49139beb93cSSam Leffler void eloop_run(void)
49239beb93cSSam Leffler {
49339beb93cSSam Leffler 	fd_set *rfds, *wfds, *efds;
49439beb93cSSam Leffler 	int res;
49539beb93cSSam Leffler 	struct timeval _tv;
49639beb93cSSam Leffler 	struct os_time tv, now;
49739beb93cSSam Leffler 
49839beb93cSSam Leffler 	rfds = os_malloc(sizeof(*rfds));
49939beb93cSSam Leffler 	wfds = os_malloc(sizeof(*wfds));
50039beb93cSSam Leffler 	efds = os_malloc(sizeof(*efds));
501*e28a4053SRui Paulo 	if (rfds == NULL || wfds == NULL || efds == NULL)
50239beb93cSSam Leffler 		goto out;
50339beb93cSSam Leffler 
50439beb93cSSam Leffler 	while (!eloop.terminate &&
505*e28a4053SRui Paulo 	       (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
50639beb93cSSam Leffler 		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
507*e28a4053SRui Paulo 		struct eloop_timeout *timeout;
508*e28a4053SRui Paulo 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
509*e28a4053SRui Paulo 					list);
510*e28a4053SRui Paulo 		if (timeout) {
51139beb93cSSam Leffler 			os_get_time(&now);
512*e28a4053SRui Paulo 			if (os_time_before(&now, &timeout->time))
513*e28a4053SRui Paulo 				os_time_sub(&timeout->time, &now, &tv);
51439beb93cSSam Leffler 			else
51539beb93cSSam Leffler 				tv.sec = tv.usec = 0;
51639beb93cSSam Leffler 			_tv.tv_sec = tv.sec;
51739beb93cSSam Leffler 			_tv.tv_usec = tv.usec;
51839beb93cSSam Leffler 		}
51939beb93cSSam Leffler 
52039beb93cSSam Leffler 		eloop_sock_table_set_fds(&eloop.readers, rfds);
52139beb93cSSam Leffler 		eloop_sock_table_set_fds(&eloop.writers, wfds);
52239beb93cSSam Leffler 		eloop_sock_table_set_fds(&eloop.exceptions, efds);
52339beb93cSSam Leffler 		res = select(eloop.max_sock + 1, rfds, wfds, efds,
524*e28a4053SRui Paulo 			     timeout ? &_tv : NULL);
52539beb93cSSam Leffler 		if (res < 0 && errno != EINTR && errno != 0) {
52639beb93cSSam Leffler 			perror("select");
52739beb93cSSam Leffler 			goto out;
52839beb93cSSam Leffler 		}
52939beb93cSSam Leffler 		eloop_process_pending_signals();
53039beb93cSSam Leffler 
53139beb93cSSam Leffler 		/* check if some registered timeouts have occurred */
532*e28a4053SRui Paulo 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
533*e28a4053SRui Paulo 					list);
534*e28a4053SRui Paulo 		if (timeout) {
53539beb93cSSam Leffler 			os_get_time(&now);
536*e28a4053SRui Paulo 			if (!os_time_before(&now, &timeout->time)) {
537*e28a4053SRui Paulo 				void *eloop_data = timeout->eloop_data;
538*e28a4053SRui Paulo 				void *user_data = timeout->user_data;
539*e28a4053SRui Paulo 				eloop_timeout_handler handler =
540*e28a4053SRui Paulo 					timeout->handler;
541*e28a4053SRui Paulo 				eloop_remove_timeout(timeout);
542*e28a4053SRui Paulo 				handler(eloop_data, user_data);
54339beb93cSSam Leffler 			}
54439beb93cSSam Leffler 
54539beb93cSSam Leffler 		}
54639beb93cSSam Leffler 
54739beb93cSSam Leffler 		if (res <= 0)
54839beb93cSSam Leffler 			continue;
54939beb93cSSam Leffler 
55039beb93cSSam Leffler 		eloop_sock_table_dispatch(&eloop.readers, rfds);
55139beb93cSSam Leffler 		eloop_sock_table_dispatch(&eloop.writers, wfds);
55239beb93cSSam Leffler 		eloop_sock_table_dispatch(&eloop.exceptions, efds);
55339beb93cSSam Leffler 	}
55439beb93cSSam Leffler 
55539beb93cSSam Leffler out:
55639beb93cSSam Leffler 	os_free(rfds);
55739beb93cSSam Leffler 	os_free(wfds);
55839beb93cSSam Leffler 	os_free(efds);
55939beb93cSSam Leffler }
56039beb93cSSam Leffler 
56139beb93cSSam Leffler 
56239beb93cSSam Leffler void eloop_terminate(void)
56339beb93cSSam Leffler {
56439beb93cSSam Leffler 	eloop.terminate = 1;
56539beb93cSSam Leffler }
56639beb93cSSam Leffler 
56739beb93cSSam Leffler 
56839beb93cSSam Leffler void eloop_destroy(void)
56939beb93cSSam Leffler {
57039beb93cSSam Leffler 	struct eloop_timeout *timeout, *prev;
57139beb93cSSam Leffler 	struct os_time now;
57239beb93cSSam Leffler 
57339beb93cSSam Leffler 	os_get_time(&now);
574*e28a4053SRui Paulo 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
575*e28a4053SRui Paulo 			      struct eloop_timeout, list) {
57639beb93cSSam Leffler 		int sec, usec;
577*e28a4053SRui Paulo 		sec = timeout->time.sec - now.sec;
578*e28a4053SRui Paulo 		usec = timeout->time.usec - now.usec;
579*e28a4053SRui Paulo 		if (timeout->time.usec < now.usec) {
58039beb93cSSam Leffler 			sec--;
58139beb93cSSam Leffler 			usec += 1000000;
58239beb93cSSam Leffler 		}
583*e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
584*e28a4053SRui Paulo 			   "eloop_data=%p user_data=%p handler=%p",
585*e28a4053SRui Paulo 			   sec, usec, timeout->eloop_data, timeout->user_data,
586*e28a4053SRui Paulo 			   timeout->handler);
587*e28a4053SRui Paulo 		wpa_trace_dump_funcname("eloop unregistered timeout handler",
588*e28a4053SRui Paulo 					timeout->handler);
589*e28a4053SRui Paulo 		wpa_trace_dump("eloop timeout", timeout);
590*e28a4053SRui Paulo 		eloop_remove_timeout(timeout);
59139beb93cSSam Leffler 	}
59239beb93cSSam Leffler 	eloop_sock_table_destroy(&eloop.readers);
59339beb93cSSam Leffler 	eloop_sock_table_destroy(&eloop.writers);
59439beb93cSSam Leffler 	eloop_sock_table_destroy(&eloop.exceptions);
59539beb93cSSam Leffler 	os_free(eloop.signals);
59639beb93cSSam Leffler }
59739beb93cSSam Leffler 
59839beb93cSSam Leffler 
59939beb93cSSam Leffler int eloop_terminated(void)
60039beb93cSSam Leffler {
60139beb93cSSam Leffler 	return eloop.terminate;
60239beb93cSSam Leffler }
60339beb93cSSam Leffler 
60439beb93cSSam Leffler 
60539beb93cSSam Leffler void eloop_wait_for_read_sock(int sock)
60639beb93cSSam Leffler {
60739beb93cSSam Leffler 	fd_set rfds;
60839beb93cSSam Leffler 
60939beb93cSSam Leffler 	if (sock < 0)
61039beb93cSSam Leffler 		return;
61139beb93cSSam Leffler 
61239beb93cSSam Leffler 	FD_ZERO(&rfds);
61339beb93cSSam Leffler 	FD_SET(sock, &rfds);
61439beb93cSSam Leffler 	select(sock + 1, &rfds, NULL, NULL, NULL);
61539beb93cSSam Leffler }
616