eloop.c
Go to the documentation of this file.
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 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:37