$search
00001 /* 00002 * Event loop based on select() loop 00003 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "trace.h" 00019 #include "list.h" 00020 #include "eloop.h" 00021 00022 00023 struct eloop_sock { 00024 int sock; 00025 void *eloop_data; 00026 void *user_data; 00027 eloop_sock_handler handler; 00028 WPA_TRACE_REF(eloop); 00029 WPA_TRACE_REF(user); 00030 WPA_TRACE_INFO 00031 }; 00032 00033 struct eloop_timeout { 00034 struct dl_list list; 00035 struct os_time time; 00036 void *eloop_data; 00037 void *user_data; 00038 eloop_timeout_handler handler; 00039 WPA_TRACE_REF(eloop); 00040 WPA_TRACE_REF(user); 00041 WPA_TRACE_INFO 00042 }; 00043 00044 struct eloop_signal { 00045 int sig; 00046 void *user_data; 00047 eloop_signal_handler handler; 00048 int signaled; 00049 }; 00050 00051 struct eloop_sock_table { 00052 int count; 00053 struct eloop_sock *table; 00054 int changed; 00055 }; 00056 00057 struct eloop_data { 00058 int max_sock; 00059 00060 struct eloop_sock_table readers; 00061 struct eloop_sock_table writers; 00062 struct eloop_sock_table exceptions; 00063 00064 struct dl_list timeout; 00065 00066 int signal_count; 00067 struct eloop_signal *signals; 00068 int signaled; 00069 int pending_terminate; 00070 00071 int terminate; 00072 int reader_table_changed; 00073 }; 00074 00075 static struct eloop_data eloop; 00076 00077 00078 #ifdef WPA_TRACE 00079 00080 static void eloop_sigsegv_handler(int sig) 00081 { 00082 wpa_trace_show("eloop SIGSEGV"); 00083 abort(); 00084 } 00085 00086 static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) 00087 { 00088 int i; 00089 if (table == NULL || table->table == NULL) 00090 return; 00091 for (i = 0; i < table->count; i++) { 00092 wpa_trace_add_ref(&table->table[i], eloop, 00093 table->table[i].eloop_data); 00094 wpa_trace_add_ref(&table->table[i], user, 00095 table->table[i].user_data); 00096 } 00097 } 00098 00099 00100 static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) 00101 { 00102 int i; 00103 if (table == NULL || table->table == NULL) 00104 return; 00105 for (i = 0; i < table->count; i++) { 00106 wpa_trace_remove_ref(&table->table[i], eloop, 00107 table->table[i].eloop_data); 00108 wpa_trace_remove_ref(&table->table[i], user, 00109 table->table[i].user_data); 00110 } 00111 } 00112 00113 #else /* WPA_TRACE */ 00114 00115 #define eloop_trace_sock_add_ref(table) do { } while (0) 00116 #define eloop_trace_sock_remove_ref(table) do { } while (0) 00117 00118 #endif /* WPA_TRACE */ 00119 00120 00121 int eloop_init(void) 00122 { 00123 os_memset(&eloop, 0, sizeof(eloop)); 00124 dl_list_init(&eloop.timeout); 00125 #ifdef WPA_TRACE 00126 signal(SIGSEGV, eloop_sigsegv_handler); 00127 #endif /* WPA_TRACE */ 00128 return 0; 00129 } 00130 00131 00132 static int eloop_sock_table_add_sock(struct eloop_sock_table *table, 00133 int sock, eloop_sock_handler handler, 00134 void *eloop_data, void *user_data) 00135 { 00136 struct eloop_sock *tmp; 00137 00138 if (table == NULL) 00139 return -1; 00140 00141 eloop_trace_sock_remove_ref(table); 00142 tmp = (struct eloop_sock *) 00143 os_realloc(table->table, 00144 (table->count + 1) * sizeof(struct eloop_sock)); 00145 if (tmp == NULL) 00146 return -1; 00147 00148 tmp[table->count].sock = sock; 00149 tmp[table->count].eloop_data = eloop_data; 00150 tmp[table->count].user_data = user_data; 00151 tmp[table->count].handler = handler; 00152 wpa_trace_record(&tmp[table->count]); 00153 table->count++; 00154 table->table = tmp; 00155 if (sock > eloop.max_sock) 00156 eloop.max_sock = sock; 00157 table->changed = 1; 00158 eloop_trace_sock_add_ref(table); 00159 00160 return 0; 00161 } 00162 00163 00164 static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, 00165 int sock) 00166 { 00167 int i; 00168 00169 if (table == NULL || table->table == NULL || table->count == 0) 00170 return; 00171 00172 for (i = 0; i < table->count; i++) { 00173 if (table->table[i].sock == sock) 00174 break; 00175 } 00176 if (i == table->count) 00177 return; 00178 eloop_trace_sock_remove_ref(table); 00179 if (i != table->count - 1) { 00180 os_memmove(&table->table[i], &table->table[i + 1], 00181 (table->count - i - 1) * 00182 sizeof(struct eloop_sock)); 00183 } 00184 table->count--; 00185 table->changed = 1; 00186 eloop_trace_sock_add_ref(table); 00187 } 00188 00189 00190 static void eloop_sock_table_set_fds(struct eloop_sock_table *table, 00191 fd_set *fds) 00192 { 00193 int i; 00194 00195 FD_ZERO(fds); 00196 00197 if (table->table == NULL) 00198 return; 00199 00200 for (i = 0; i < table->count; i++) 00201 FD_SET(table->table[i].sock, fds); 00202 } 00203 00204 00205 static void eloop_sock_table_dispatch(struct eloop_sock_table *table, 00206 fd_set *fds) 00207 { 00208 int i; 00209 00210 if (table == NULL || table->table == NULL) 00211 return; 00212 00213 table->changed = 0; 00214 for (i = 0; i < table->count; i++) { 00215 if (FD_ISSET(table->table[i].sock, fds)) { 00216 table->table[i].handler(table->table[i].sock, 00217 table->table[i].eloop_data, 00218 table->table[i].user_data); 00219 if (table->changed) 00220 break; 00221 } 00222 } 00223 } 00224 00225 00226 static void eloop_sock_table_destroy(struct eloop_sock_table *table) 00227 { 00228 if (table) { 00229 int i; 00230 for (i = 0; i < table->count && table->table; i++) { 00231 wpa_printf(MSG_INFO, "ELOOP: remaining socket: " 00232 "sock=%d eloop_data=%p user_data=%p " 00233 "handler=%p", 00234 table->table[i].sock, 00235 table->table[i].eloop_data, 00236 table->table[i].user_data, 00237 table->table[i].handler); 00238 wpa_trace_dump_funcname("eloop unregistered socket " 00239 "handler", 00240 table->table[i].handler); 00241 wpa_trace_dump("eloop sock", &table->table[i]); 00242 } 00243 os_free(table->table); 00244 } 00245 } 00246 00247 00248 int eloop_register_read_sock(int sock, eloop_sock_handler handler, 00249 void *eloop_data, void *user_data) 00250 { 00251 return eloop_register_sock(sock, EVENT_TYPE_READ, handler, 00252 eloop_data, user_data); 00253 } 00254 00255 00256 void eloop_unregister_read_sock(int sock) 00257 { 00258 eloop_unregister_sock(sock, EVENT_TYPE_READ); 00259 } 00260 00261 00262 static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type) 00263 { 00264 switch (type) { 00265 case EVENT_TYPE_READ: 00266 return &eloop.readers; 00267 case EVENT_TYPE_WRITE: 00268 return &eloop.writers; 00269 case EVENT_TYPE_EXCEPTION: 00270 return &eloop.exceptions; 00271 } 00272 00273 return NULL; 00274 } 00275 00276 00277 int eloop_register_sock(int sock, eloop_event_type type, 00278 eloop_sock_handler handler, 00279 void *eloop_data, void *user_data) 00280 { 00281 struct eloop_sock_table *table; 00282 00283 table = eloop_get_sock_table(type); 00284 return eloop_sock_table_add_sock(table, sock, handler, 00285 eloop_data, user_data); 00286 } 00287 00288 00289 void eloop_unregister_sock(int sock, eloop_event_type type) 00290 { 00291 struct eloop_sock_table *table; 00292 00293 table = eloop_get_sock_table(type); 00294 eloop_sock_table_remove_sock(table, sock); 00295 } 00296 00297 00298 int eloop_register_timeout(unsigned int secs, unsigned int usecs, 00299 eloop_timeout_handler handler, 00300 void *eloop_data, void *user_data) 00301 { 00302 struct eloop_timeout *timeout, *tmp; 00303 00304 timeout = os_zalloc(sizeof(*timeout)); 00305 if (timeout == NULL) 00306 return -1; 00307 if (os_get_time(&timeout->time) < 0) { 00308 os_free(timeout); 00309 return -1; 00310 } 00311 timeout->time.sec += secs; 00312 timeout->time.usec += usecs; 00313 while (timeout->time.usec >= 1000000) { 00314 timeout->time.sec++; 00315 timeout->time.usec -= 1000000; 00316 } 00317 timeout->eloop_data = eloop_data; 00318 timeout->user_data = user_data; 00319 timeout->handler = handler; 00320 wpa_trace_add_ref(timeout, eloop, eloop_data); 00321 wpa_trace_add_ref(timeout, user, user_data); 00322 wpa_trace_record(timeout); 00323 00324 /* Maintain timeouts in order of increasing time */ 00325 dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 00326 if (os_time_before(&timeout->time, &tmp->time)) { 00327 dl_list_add(tmp->list.prev, &timeout->list); 00328 return 0; 00329 } 00330 } 00331 dl_list_add_tail(&eloop.timeout, &timeout->list); 00332 00333 return 0; 00334 } 00335 00336 00337 static void eloop_remove_timeout(struct eloop_timeout *timeout) 00338 { 00339 dl_list_del(&timeout->list); 00340 wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data); 00341 wpa_trace_remove_ref(timeout, user, timeout->user_data); 00342 os_free(timeout); 00343 } 00344 00345 00346 int eloop_cancel_timeout(eloop_timeout_handler handler, 00347 void *eloop_data, void *user_data) 00348 { 00349 struct eloop_timeout *timeout, *prev; 00350 int removed = 0; 00351 00352 dl_list_for_each_safe(timeout, prev, &eloop.timeout, 00353 struct eloop_timeout, list) { 00354 if (timeout->handler == handler && 00355 (timeout->eloop_data == eloop_data || 00356 eloop_data == ELOOP_ALL_CTX) && 00357 (timeout->user_data == user_data || 00358 user_data == ELOOP_ALL_CTX)) { 00359 eloop_remove_timeout(timeout); 00360 removed++; 00361 } 00362 } 00363 00364 return removed; 00365 } 00366 00367 00368 int eloop_is_timeout_registered(eloop_timeout_handler handler, 00369 void *eloop_data, void *user_data) 00370 { 00371 struct eloop_timeout *tmp; 00372 00373 dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 00374 if (tmp->handler == handler && 00375 tmp->eloop_data == eloop_data && 00376 tmp->user_data == user_data) 00377 return 1; 00378 } 00379 00380 return 0; 00381 } 00382 00383 00384 #ifndef CONFIG_NATIVE_WINDOWS 00385 static void eloop_handle_alarm(int sig) 00386 { 00387 wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in " 00388 "two seconds. Looks like there\n" 00389 "is a bug that ends up in a busy loop that " 00390 "prevents clean shutdown.\n" 00391 "Killing program forcefully.\n"); 00392 exit(1); 00393 } 00394 #endif /* CONFIG_NATIVE_WINDOWS */ 00395 00396 00397 static void eloop_handle_signal(int sig) 00398 { 00399 int i; 00400 00401 #ifndef CONFIG_NATIVE_WINDOWS 00402 if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { 00403 /* Use SIGALRM to break out from potential busy loops that 00404 * would not allow the program to be killed. */ 00405 eloop.pending_terminate = 1; 00406 signal(SIGALRM, eloop_handle_alarm); 00407 alarm(2); 00408 } 00409 #endif /* CONFIG_NATIVE_WINDOWS */ 00410 00411 eloop.signaled++; 00412 for (i = 0; i < eloop.signal_count; i++) { 00413 if (eloop.signals[i].sig == sig) { 00414 eloop.signals[i].signaled++; 00415 break; 00416 } 00417 } 00418 } 00419 00420 00421 static void eloop_process_pending_signals(void) 00422 { 00423 int i; 00424 00425 if (eloop.signaled == 0) 00426 return; 00427 eloop.signaled = 0; 00428 00429 if (eloop.pending_terminate) { 00430 #ifndef CONFIG_NATIVE_WINDOWS 00431 alarm(0); 00432 #endif /* CONFIG_NATIVE_WINDOWS */ 00433 eloop.pending_terminate = 0; 00434 } 00435 00436 for (i = 0; i < eloop.signal_count; i++) { 00437 if (eloop.signals[i].signaled) { 00438 eloop.signals[i].signaled = 0; 00439 eloop.signals[i].handler(eloop.signals[i].sig, 00440 eloop.signals[i].user_data); 00441 } 00442 } 00443 } 00444 00445 00446 int eloop_register_signal(int sig, eloop_signal_handler handler, 00447 void *user_data) 00448 { 00449 struct eloop_signal *tmp; 00450 00451 tmp = (struct eloop_signal *) 00452 os_realloc(eloop.signals, 00453 (eloop.signal_count + 1) * 00454 sizeof(struct eloop_signal)); 00455 if (tmp == NULL) 00456 return -1; 00457 00458 tmp[eloop.signal_count].sig = sig; 00459 tmp[eloop.signal_count].user_data = user_data; 00460 tmp[eloop.signal_count].handler = handler; 00461 tmp[eloop.signal_count].signaled = 0; 00462 eloop.signal_count++; 00463 eloop.signals = tmp; 00464 signal(sig, eloop_handle_signal); 00465 00466 return 0; 00467 } 00468 00469 00470 int eloop_register_signal_terminate(eloop_signal_handler handler, 00471 void *user_data) 00472 { 00473 int ret = eloop_register_signal(SIGINT, handler, user_data); 00474 if (ret == 0) 00475 ret = eloop_register_signal(SIGTERM, handler, user_data); 00476 return ret; 00477 } 00478 00479 00480 int eloop_register_signal_reconfig(eloop_signal_handler handler, 00481 void *user_data) 00482 { 00483 #ifdef CONFIG_NATIVE_WINDOWS 00484 return 0; 00485 #else /* CONFIG_NATIVE_WINDOWS */ 00486 return eloop_register_signal(SIGHUP, handler, user_data); 00487 #endif /* CONFIG_NATIVE_WINDOWS */ 00488 } 00489 00490 00491 void eloop_run(void) 00492 { 00493 fd_set *rfds, *wfds, *efds; 00494 int res; 00495 struct timeval _tv; 00496 struct os_time tv, now; 00497 00498 rfds = os_malloc(sizeof(*rfds)); 00499 wfds = os_malloc(sizeof(*wfds)); 00500 efds = os_malloc(sizeof(*efds)); 00501 if (rfds == NULL || wfds == NULL || efds == NULL) 00502 goto out; 00503 00504 while (!eloop.terminate && 00505 (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || 00506 eloop.writers.count > 0 || eloop.exceptions.count > 0)) { 00507 struct eloop_timeout *timeout; 00508 timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 00509 list); 00510 if (timeout) { 00511 os_get_time(&now); 00512 if (os_time_before(&now, &timeout->time)) 00513 os_time_sub(&timeout->time, &now, &tv); 00514 else 00515 tv.sec = tv.usec = 0; 00516 _tv.tv_sec = tv.sec; 00517 _tv.tv_usec = tv.usec; 00518 } 00519 00520 eloop_sock_table_set_fds(&eloop.readers, rfds); 00521 eloop_sock_table_set_fds(&eloop.writers, wfds); 00522 eloop_sock_table_set_fds(&eloop.exceptions, efds); 00523 res = select(eloop.max_sock + 1, rfds, wfds, efds, 00524 timeout ? &_tv : NULL); 00525 if (res < 0 && errno != EINTR && errno != 0) { 00526 perror("select"); 00527 goto out; 00528 } 00529 eloop_process_pending_signals(); 00530 00531 /* check if some registered timeouts have occurred */ 00532 if (timeout) { 00533 os_get_time(&now); 00534 if (!os_time_before(&now, &timeout->time)) { 00535 void *eloop_data = timeout->eloop_data; 00536 void *user_data = timeout->user_data; 00537 eloop_timeout_handler handler = 00538 timeout->handler; 00539 eloop_remove_timeout(timeout); 00540 handler(eloop_data, user_data); 00541 } 00542 00543 } 00544 00545 if (res <= 0) 00546 continue; 00547 00548 eloop_sock_table_dispatch(&eloop.readers, rfds); 00549 eloop_sock_table_dispatch(&eloop.writers, wfds); 00550 eloop_sock_table_dispatch(&eloop.exceptions, efds); 00551 } 00552 00553 out: 00554 os_free(rfds); 00555 os_free(wfds); 00556 os_free(efds); 00557 } 00558 00559 00560 void eloop_terminate(void) 00561 { 00562 eloop.terminate = 1; 00563 } 00564 00565 00566 void eloop_destroy(void) 00567 { 00568 struct eloop_timeout *timeout, *prev; 00569 struct os_time now; 00570 00571 os_get_time(&now); 00572 dl_list_for_each_safe(timeout, prev, &eloop.timeout, 00573 struct eloop_timeout, list) { 00574 int sec, usec; 00575 sec = timeout->time.sec - now.sec; 00576 usec = timeout->time.usec - now.usec; 00577 if (timeout->time.usec < now.usec) { 00578 sec--; 00579 usec += 1000000; 00580 } 00581 wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d " 00582 "eloop_data=%p user_data=%p handler=%p", 00583 sec, usec, timeout->eloop_data, timeout->user_data, 00584 timeout->handler); 00585 wpa_trace_dump_funcname("eloop unregistered timeout handler", 00586 timeout->handler); 00587 wpa_trace_dump("eloop timeout", timeout); 00588 eloop_remove_timeout(timeout); 00589 } 00590 eloop_sock_table_destroy(&eloop.readers); 00591 eloop_sock_table_destroy(&eloop.writers); 00592 eloop_sock_table_destroy(&eloop.exceptions); 00593 os_free(eloop.signals); 00594 } 00595 00596 00597 int eloop_terminated(void) 00598 { 00599 return eloop.terminate; 00600 } 00601 00602 00603 void eloop_wait_for_read_sock(int sock) 00604 { 00605 fd_set rfds; 00606 00607 if (sock < 0) 00608 return; 00609 00610 FD_ZERO(&rfds); 00611 FD_SET(sock, &rfds); 00612 select(sock + 1, &rfds, NULL, NULL, NULL); 00613 }