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