eloop.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
1/* 2 * Event loop based on select() loop 3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15#include "includes.h" 16 17#include "common.h" 18#include "trace.h" 19#include "list.h" 20#include "eloop.h" 21 22 23struct eloop_sock { 24 int sock; 25 void *eloop_data; 26 void *user_data; 27 eloop_sock_handler handler; 28 WPA_TRACE_REF(eloop); 29 WPA_TRACE_REF(user); 30 WPA_TRACE_INFO 31}; 32 33struct eloop_timeout { 34 struct dl_list list; 35 struct os_time time; 36 void *eloop_data; 37 void *user_data; 38 eloop_timeout_handler handler; 39 WPA_TRACE_REF(eloop); 40 WPA_TRACE_REF(user); 41 WPA_TRACE_INFO 42}; 43 44struct eloop_signal { 45 int sig; 46 void *user_data; 47 eloop_signal_handler handler; 48 int signaled; 49}; 50 51struct eloop_sock_table { 52 int count; 53 struct eloop_sock *table; 54 int changed; 55}; 56 57struct eloop_data { 58 int max_sock; 59 60 struct eloop_sock_table readers; 61 struct eloop_sock_table writers; 62 struct eloop_sock_table exceptions; 63 64 struct dl_list timeout; 65 66 int signal_count; 67 struct eloop_signal *signals; 68 int signaled; 69 int pending_terminate; 70 71 int terminate; 72 int reader_table_changed; 73}; 74 75static struct eloop_data eloop; 76 77 78#ifdef WPA_TRACE 79 80static void eloop_sigsegv_handler(int sig) 81{ 82 wpa_trace_show("eloop SIGSEGV"); 83 abort(); 84} 85 86static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) 87{ 88 int i; 89 if (table == NULL || table->table == NULL) 90 return; 91 for (i = 0; i < table->count; i++) { 92 wpa_trace_add_ref(&table->table[i], eloop, 93 table->table[i].eloop_data); 94 wpa_trace_add_ref(&table->table[i], user, 95 table->table[i].user_data); 96 } 97} 98 99 100static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) 101{ 102 int i; 103 if (table == NULL || table->table == NULL) 104 return; 105 for (i = 0; i < table->count; i++) { 106 wpa_trace_remove_ref(&table->table[i], eloop, 107 table->table[i].eloop_data); 108 wpa_trace_remove_ref(&table->table[i], user, 109 table->table[i].user_data); 110 } 111} 112 113#else /* WPA_TRACE */ 114 115#define eloop_trace_sock_add_ref(table) do { } while (0) 116#define eloop_trace_sock_remove_ref(table) do { } while (0) 117 118#endif /* WPA_TRACE */ 119 120 121int eloop_init(void) 122{ 123 os_memset(&eloop, 0, sizeof(eloop)); 124 dl_list_init(&eloop.timeout); 125#ifdef WPA_TRACE 126 signal(SIGSEGV, eloop_sigsegv_handler); 127#endif /* WPA_TRACE */ 128 return 0; 129} 130 131 132static int eloop_sock_table_add_sock(struct eloop_sock_table *table, 133 int sock, eloop_sock_handler handler, 134 void *eloop_data, void *user_data) 135{ 136 struct eloop_sock *tmp; 137 138 if (table == NULL) 139 return -1; 140 141 eloop_trace_sock_remove_ref(table); 142 tmp = (struct eloop_sock *) 143 os_realloc(table->table, 144 (table->count + 1) * sizeof(struct eloop_sock)); 145 if (tmp == NULL) 146 return -1; 147 148 tmp[table->count].sock = sock; 149 tmp[table->count].eloop_data = eloop_data; 150 tmp[table->count].user_data = user_data; 151 tmp[table->count].handler = handler; 152 wpa_trace_record(&tmp[table->count]); 153 table->count++; 154 table->table = tmp; 155 if (sock > eloop.max_sock) 156 eloop.max_sock = sock; 157 table->changed = 1; 158 eloop_trace_sock_add_ref(table); 159 160 return 0; 161} 162 163 164static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, 165 int sock) 166{ 167 int i; 168 169 if (table == NULL || table->table == NULL || table->count == 0) 170 return; 171 172 for (i = 0; i < table->count; i++) { 173 if (table->table[i].sock == sock) 174 break; 175 } 176 if (i == table->count) 177 return; 178 eloop_trace_sock_remove_ref(table); 179 if (i != table->count - 1) { 180 os_memmove(&table->table[i], &table->table[i + 1], 181 (table->count - i - 1) * 182 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