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 23 struct 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 33 struct 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 44 struct eloop_signal { 45 int sig; 46 void *user_data; 47 eloop_signal_handler handler; 48 int signaled; 49 }; 50 51 struct eloop_sock_table { 52 int count; 53 struct eloop_sock *table; 54 int changed; 55 }; 56 57 struct 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 75 static struct eloop_data eloop; 76 77 78 #ifdef WPA_TRACE 79 80 static void eloop_sigsegv_handler(int sig) 81 { 82 wpa_trace_show("eloop SIGSEGV"); 83 abort(); 84 } 85 86 static 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 100 static 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 121 int 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 132 static 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 164 static 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 190 static 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 205 static 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 226 static 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 248 int 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 256 void eloop_unregister_read_sock(int sock) 257 { 258 eloop_unregister_sock(sock, EVENT_TYPE_READ); 259 } 260 261 262 static 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 277 int 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 289 void 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 298 int 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 304 timeout = os_zalloc(sizeof(*timeout)); 305 if (timeout == NULL) 306 return -1; 307 if (os_get_time(&timeout->time) < 0) { 308 os_free(timeout); 309 return -1; 310 } 311 timeout->time.sec += secs; 312 timeout->time.usec += usecs; 313 while (timeout->time.usec >= 1000000) { 314 timeout->time.sec++; 315 timeout->time.usec -= 1000000; 316 } 317 timeout->eloop_data = eloop_data; 318 timeout->user_data = user_data; 319 timeout->handler = handler; 320 wpa_trace_add_ref(timeout, eloop, eloop_data); 321 wpa_trace_add_ref(timeout, user, user_data); 322 wpa_trace_record(timeout); 323 324 /* Maintain timeouts in order of increasing time */ 325 dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 326 if (os_time_before(&timeout->time, &tmp->time)) { 327 dl_list_add(tmp->list.prev, &timeout->list); 328 return 0; 329 } 330 } 331 dl_list_add_tail(&eloop.timeout, &timeout->list); 332 333 return 0; 334 } 335 336 337 static void eloop_remove_timeout(struct eloop_timeout *timeout) 338 { 339 dl_list_del(&timeout->list); 340 wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data); 341 wpa_trace_remove_ref(timeout, user, timeout->user_data); 342 os_free(timeout); 343 } 344 345 346 int eloop_cancel_timeout(eloop_timeout_handler handler, 347 void *eloop_data, void *user_data) 348 { 349 struct eloop_timeout *timeout, *prev; 350 int removed = 0; 351 352 dl_list_for_each_safe(timeout, prev, &eloop.timeout, 353 struct eloop_timeout, list) { 354 if (timeout->handler == handler && 355 (timeout->eloop_data == eloop_data || 356 eloop_data == ELOOP_ALL_CTX) && 357 (timeout->user_data == user_data || 358 user_data == ELOOP_ALL_CTX)) { 359 eloop_remove_timeout(timeout); 360 removed++; 361 } 362 } 363 364 return removed; 365 } 366 367 368 int eloop_is_timeout_registered(eloop_timeout_handler handler, 369 void *eloop_data, void *user_data) 370 { 371 struct eloop_timeout *tmp; 372 373 dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 374 if (tmp->handler == handler && 375 tmp->eloop_data == eloop_data && 376 tmp->user_data == user_data) 377 return 1; 378 } 379 380 return 0; 381 } 382 383 384 #ifndef CONFIG_NATIVE_WINDOWS 385 static void eloop_handle_alarm(int sig) 386 { 387 wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in " 388 "two seconds. Looks like there\n" 389 "is a bug that ends up in a busy loop that " 390 "prevents clean shutdown.\n" 391 "Killing program forcefully.\n"); 392 exit(1); 393 } 394 #endif /* CONFIG_NATIVE_WINDOWS */ 395 396 397 static void eloop_handle_signal(int sig) 398 { 399 int i; 400 401 #ifndef CONFIG_NATIVE_WINDOWS 402 if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { 403 /* Use SIGALRM to break out from potential busy loops that 404 * would not allow the program to be killed. */ 405 eloop.pending_terminate = 1; 406 signal(SIGALRM, eloop_handle_alarm); 407 alarm(2); 408 } 409 #endif /* CONFIG_NATIVE_WINDOWS */ 410 411 eloop.signaled++; 412 for (i = 0; i < eloop.signal_count; i++) { 413 if (eloop.signals[i].sig == sig) { 414 eloop.signals[i].signaled++; 415 break; 416 } 417 } 418 } 419 420 421 static void eloop_process_pending_signals(void) 422 { 423 int i; 424 425 if (eloop.signaled == 0) 426 return; 427 eloop.signaled = 0; 428 429 if (eloop.pending_terminate) { 430 #ifndef CONFIG_NATIVE_WINDOWS 431 alarm(0); 432 #endif /* CONFIG_NATIVE_WINDOWS */ 433 eloop.pending_terminate = 0; 434 } 435 436 for (i = 0; i < eloop.signal_count; i++) { 437 if (eloop.signals[i].signaled) { 438 eloop.signals[i].signaled = 0; 439 eloop.signals[i].handler(eloop.signals[i].sig, 440 eloop.signals[i].user_data); 441 } 442 } 443 } 444 445 446 int eloop_register_signal(int sig, eloop_signal_handler handler, 447 void *user_data) 448 { 449 struct eloop_signal *tmp; 450 451 tmp = (struct eloop_signal *) 452 os_realloc(eloop.signals, 453 (eloop.signal_count + 1) * 454 sizeof(struct eloop_signal)); 455 if (tmp == NULL) 456 return -1; 457 458 tmp[eloop.signal_count].sig = sig; 459 tmp[eloop.signal_count].user_data = user_data; 460 tmp[eloop.signal_count].handler = handler; 461 tmp[eloop.signal_count].signaled = 0; 462 eloop.signal_count++; 463 eloop.signals = tmp; 464 signal(sig, eloop_handle_signal); 465 466 return 0; 467 } 468 469 470 int eloop_register_signal_terminate(eloop_signal_handler handler, 471 void *user_data) 472 { 473 int ret = eloop_register_signal(SIGINT, handler, user_data); 474 if (ret == 0) 475 ret = eloop_register_signal(SIGTERM, handler, user_data); 476 return ret; 477 } 478 479 480 int eloop_register_signal_reconfig(eloop_signal_handler handler, 481 void *user_data) 482 { 483 #ifdef CONFIG_NATIVE_WINDOWS 484 return 0; 485 #else /* CONFIG_NATIVE_WINDOWS */ 486 return eloop_register_signal(SIGHUP, handler, user_data); 487 #endif /* CONFIG_NATIVE_WINDOWS */ 488 } 489 490 491 void eloop_run(void) 492 { 493 fd_set *rfds, *wfds, *efds; 494 int res; 495 struct timeval _tv; 496 struct os_time tv, now; 497 498 rfds = os_malloc(sizeof(*rfds)); 499 wfds = os_malloc(sizeof(*wfds)); 500 efds = os_malloc(sizeof(*efds)); 501 if (rfds == NULL || wfds == NULL || efds == NULL) 502 goto out; 503 504 while (!eloop.terminate && 505 (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || 506 eloop.writers.count > 0 || eloop.exceptions.count > 0)) { 507 struct eloop_timeout *timeout; 508 timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 509 list); 510 if (timeout) { 511 os_get_time(&now); 512 if (os_time_before(&now, &timeout->time)) 513 os_time_sub(&timeout->time, &now, &tv); 514 else 515 tv.sec = tv.usec = 0; 516 _tv.tv_sec = tv.sec; 517 _tv.tv_usec = tv.usec; 518 } 519 520 eloop_sock_table_set_fds(&eloop.readers, rfds); 521 eloop_sock_table_set_fds(&eloop.writers, wfds); 522 eloop_sock_table_set_fds(&eloop.exceptions, efds); 523 res = select(eloop.max_sock + 1, rfds, wfds, efds, 524 timeout ? &_tv : NULL); 525 if (res < 0 && errno != EINTR && errno != 0) { 526 perror("select"); 527 goto out; 528 } 529 eloop_process_pending_signals(); 530 531 /* check if some registered timeouts have occurred */ 532 timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 533 list); 534 if (timeout) { 535 os_get_time(&now); 536 if (!os_time_before(&now, &timeout->time)) { 537 void *eloop_data = timeout->eloop_data; 538 void *user_data = timeout->user_data; 539 eloop_timeout_handler handler = 540 timeout->handler; 541 eloop_remove_timeout(timeout); 542 handler(eloop_data, user_data); 543 } 544 545 } 546 547 if (res <= 0) 548 continue; 549 550 eloop_sock_table_dispatch(&eloop.readers, rfds); 551 eloop_sock_table_dispatch(&eloop.writers, wfds); 552 eloop_sock_table_dispatch(&eloop.exceptions, efds); 553 } 554 555 out: 556 os_free(rfds); 557 os_free(wfds); 558 os_free(efds); 559 } 560 561 562 void eloop_terminate(void) 563 { 564 eloop.terminate = 1; 565 } 566 567 568 void eloop_destroy(void) 569 { 570 struct eloop_timeout *timeout, *prev; 571 struct os_time now; 572 573 os_get_time(&now); 574 dl_list_for_each_safe(timeout, prev, &eloop.timeout, 575 struct eloop_timeout, list) { 576 int sec, usec; 577 sec = timeout->time.sec - now.sec; 578 usec = timeout->time.usec - now.usec; 579 if (timeout->time.usec < now.usec) { 580 sec--; 581 usec += 1000000; 582 } 583 wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d " 584 "eloop_data=%p user_data=%p handler=%p", 585 sec, usec, timeout->eloop_data, timeout->user_data, 586 timeout->handler); 587 wpa_trace_dump_funcname("eloop unregistered timeout handler", 588 timeout->handler); 589 wpa_trace_dump("eloop timeout", timeout); 590 eloop_remove_timeout(timeout); 591 } 592 eloop_sock_table_destroy(&eloop.readers); 593 eloop_sock_table_destroy(&eloop.writers); 594 eloop_sock_table_destroy(&eloop.exceptions); 595 os_free(eloop.signals); 596 } 597 598 599 int eloop_terminated(void) 600 { 601 return eloop.terminate; 602 } 603 604 605 void eloop_wait_for_read_sock(int sock) 606 { 607 fd_set rfds; 608 609 if (sock < 0) 610 return; 611 612 FD_ZERO(&rfds); 613 FD_SET(sock, &rfds); 614 select(sock + 1, &rfds, NULL, NULL, NULL); 615 } 616