eloop.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #include "common.h"
00019 #include "eloop.h"
00020 
00021 
00022 struct eloop_sock {
00023         int sock;
00024         void *eloop_data;
00025         void *user_data;
00026         eloop_sock_handler handler;
00027 };
00028 
00029 struct eloop_timeout {
00030         struct os_time time;
00031         void *eloop_data;
00032         void *user_data;
00033         eloop_timeout_handler handler;
00034         struct eloop_timeout *next;
00035 };
00036 
00037 struct eloop_signal {
00038         int sig;
00039         void *user_data;
00040         eloop_signal_handler handler;
00041         int signaled;
00042 };
00043 
00044 struct eloop_sock_table {
00045         int count;
00046         struct eloop_sock *table;
00047         int changed;
00048 };
00049 
00050 struct eloop_data {
00051         void *user_data;
00052 
00053         int max_sock;
00054 
00055         struct eloop_sock_table readers;
00056         struct eloop_sock_table writers;
00057         struct eloop_sock_table exceptions;
00058 
00059         struct eloop_timeout *timeout;
00060 
00061         int signal_count;
00062         struct eloop_signal *signals;
00063         int signaled;
00064         int pending_terminate;
00065 
00066         int terminate;
00067         int reader_table_changed;
00068 };
00069 
00070 static struct eloop_data eloop;
00071 
00072 
00073 int eloop_init(void *user_data)
00074 {
00075         os_memset(&eloop, 0, sizeof(eloop));
00076         eloop.user_data = user_data;
00077         return 0;
00078 }
00079 
00080 
00081 static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
00082                                      int sock, eloop_sock_handler handler,
00083                                      void *eloop_data, void *user_data)
00084 {
00085         struct eloop_sock *tmp;
00086 
00087         if (table == NULL)
00088                 return -1;
00089 
00090         tmp = (struct eloop_sock *)
00091                 os_realloc(table->table,
00092                            (table->count + 1) * sizeof(struct eloop_sock));
00093         if (tmp == NULL)
00094                 return -1;
00095 
00096         tmp[table->count].sock = sock;
00097         tmp[table->count].eloop_data = eloop_data;
00098         tmp[table->count].user_data = user_data;
00099         tmp[table->count].handler = handler;
00100         table->count++;
00101         table->table = tmp;
00102         if (sock > eloop.max_sock)
00103                 eloop.max_sock = sock;
00104         table->changed = 1;
00105 
00106         return 0;
00107 }
00108 
00109 
00110 static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
00111                                          int sock)
00112 {
00113         int i;
00114 
00115         if (table == NULL || table->table == NULL || table->count == 0)
00116                 return;
00117 
00118         for (i = 0; i < table->count; i++) {
00119                 if (table->table[i].sock == sock)
00120                         break;
00121         }
00122         if (i == table->count)
00123                 return;
00124         if (i != table->count - 1) {
00125                 os_memmove(&table->table[i], &table->table[i + 1],
00126                            (table->count - i - 1) *
00127                            sizeof(struct eloop_sock));
00128         }
00129         table->count--;
00130         table->changed = 1;
00131 }
00132 
00133 
00134 static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
00135                                      fd_set *fds)
00136 {
00137         int i;
00138 
00139         FD_ZERO(fds);
00140 
00141         if (table->table == NULL)
00142                 return;
00143 
00144         for (i = 0; i < table->count; i++)
00145                 FD_SET(table->table[i].sock, fds);
00146 }
00147 
00148 
00149 static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
00150                                       fd_set *fds)
00151 {
00152         int i;
00153 
00154         if (table == NULL || table->table == NULL)
00155                 return;
00156 
00157         table->changed = 0;
00158         for (i = 0; i < table->count; i++) {
00159                 if (FD_ISSET(table->table[i].sock, fds)) {
00160                         table->table[i].handler(table->table[i].sock,
00161                                                 table->table[i].eloop_data,
00162                                                 table->table[i].user_data);
00163                         if (table->changed)
00164                                 break;
00165                 }
00166         }
00167 }
00168 
00169 
00170 static void eloop_sock_table_destroy(struct eloop_sock_table *table)
00171 {
00172         if (table)
00173                 os_free(table->table);
00174 }
00175 
00176 
00177 int eloop_register_read_sock(int sock, eloop_sock_handler handler,
00178                              void *eloop_data, void *user_data)
00179 {
00180         return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
00181                                    eloop_data, user_data);
00182 }
00183 
00184 
00185 void eloop_unregister_read_sock(int sock)
00186 {
00187         eloop_unregister_sock(sock, EVENT_TYPE_READ);
00188 }
00189 
00190 
00191 static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
00192 {
00193         switch (type) {
00194         case EVENT_TYPE_READ:
00195                 return &eloop.readers;
00196         case EVENT_TYPE_WRITE:
00197                 return &eloop.writers;
00198         case EVENT_TYPE_EXCEPTION:
00199                 return &eloop.exceptions;
00200         }
00201 
00202         return NULL;
00203 }
00204 
00205 
00206 int eloop_register_sock(int sock, eloop_event_type type,
00207                         eloop_sock_handler handler,
00208                         void *eloop_data, void *user_data)
00209 {
00210         struct eloop_sock_table *table;
00211 
00212         table = eloop_get_sock_table(type);
00213         return eloop_sock_table_add_sock(table, sock, handler,
00214                                          eloop_data, user_data);
00215 }
00216 
00217 
00218 void eloop_unregister_sock(int sock, eloop_event_type type)
00219 {
00220         struct eloop_sock_table *table;
00221 
00222         table = eloop_get_sock_table(type);
00223         eloop_sock_table_remove_sock(table, sock);
00224 }
00225 
00226 
00227 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
00228                            eloop_timeout_handler handler,
00229                            void *eloop_data, void *user_data)
00230 {
00231         struct eloop_timeout *timeout, *tmp, *prev;
00232 
00233         timeout = os_malloc(sizeof(*timeout));
00234         if (timeout == NULL)
00235                 return -1;
00236         os_get_time(&timeout->time);
00237         timeout->time.sec += secs;
00238         timeout->time.usec += usecs;
00239         while (timeout->time.usec >= 1000000) {
00240                 timeout->time.sec++;
00241                 timeout->time.usec -= 1000000;
00242         }
00243         timeout->eloop_data = eloop_data;
00244         timeout->user_data = user_data;
00245         timeout->handler = handler;
00246         timeout->next = NULL;
00247 
00248         if (eloop.timeout == NULL) {
00249                 eloop.timeout = timeout;
00250                 return 0;
00251         }
00252 
00253         prev = NULL;
00254         tmp = eloop.timeout;
00255         while (tmp != NULL) {
00256                 if (os_time_before(&timeout->time, &tmp->time))
00257                         break;
00258                 prev = tmp;
00259                 tmp = tmp->next;
00260         }
00261 
00262         if (prev == NULL) {
00263                 timeout->next = eloop.timeout;
00264                 eloop.timeout = timeout;
00265         } else {
00266                 timeout->next = prev->next;
00267                 prev->next = timeout;
00268         }
00269 
00270         return 0;
00271 }
00272 
00273 
00274 int eloop_cancel_timeout(eloop_timeout_handler handler,
00275                          void *eloop_data, void *user_data)
00276 {
00277         struct eloop_timeout *timeout, *prev, *next;
00278         int removed = 0;
00279 
00280         prev = NULL;
00281         timeout = eloop.timeout;
00282         while (timeout != NULL) {
00283                 next = timeout->next;
00284 
00285                 if (timeout->handler == handler &&
00286                     (timeout->eloop_data == eloop_data ||
00287                      eloop_data == ELOOP_ALL_CTX) &&
00288                     (timeout->user_data == user_data ||
00289                      user_data == ELOOP_ALL_CTX)) {
00290                         if (prev == NULL)
00291                                 eloop.timeout = next;
00292                         else
00293                                 prev->next = next;
00294                         os_free(timeout);
00295                         removed++;
00296                 } else
00297                         prev = timeout;
00298 
00299                 timeout = next;
00300         }
00301 
00302         return removed;
00303 }
00304 
00305 
00306 #ifndef CONFIG_NATIVE_WINDOWS
00307 static void eloop_handle_alarm(int sig)
00308 {
00309         fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
00310                 "seconds. Looks like there\n"
00311                 "is a bug that ends up in a busy loop that "
00312                 "prevents clean shutdown.\n"
00313                 "Killing program forcefully.\n");
00314         exit(1);
00315 }
00316 #endif /* CONFIG_NATIVE_WINDOWS */
00317 
00318 
00319 static void eloop_handle_signal(int sig)
00320 {
00321         int i;
00322 
00323 #ifndef CONFIG_NATIVE_WINDOWS
00324         if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
00325                 /* Use SIGALRM to break out from potential busy loops that
00326                  * would not allow the program to be killed. */
00327                 eloop.pending_terminate = 1;
00328                 signal(SIGALRM, eloop_handle_alarm);
00329                 alarm(2);
00330         }
00331 #endif /* CONFIG_NATIVE_WINDOWS */
00332 
00333         eloop.signaled++;
00334         for (i = 0; i < eloop.signal_count; i++) {
00335                 if (eloop.signals[i].sig == sig) {
00336                         eloop.signals[i].signaled++;
00337                         break;
00338                 }
00339         }
00340 }
00341 
00342 
00343 static void eloop_process_pending_signals(void)
00344 {
00345         int i;
00346 
00347         if (eloop.signaled == 0)
00348                 return;
00349         eloop.signaled = 0;
00350 
00351         if (eloop.pending_terminate) {
00352 #ifndef CONFIG_NATIVE_WINDOWS
00353                 alarm(0);
00354 #endif /* CONFIG_NATIVE_WINDOWS */
00355                 eloop.pending_terminate = 0;
00356         }
00357 
00358         for (i = 0; i < eloop.signal_count; i++) {
00359                 if (eloop.signals[i].signaled) {
00360                         eloop.signals[i].signaled = 0;
00361                         eloop.signals[i].handler(eloop.signals[i].sig,
00362                                                  eloop.user_data,
00363                                                  eloop.signals[i].user_data);
00364                 }
00365         }
00366 }
00367 
00368 
00369 int eloop_register_signal(int sig, eloop_signal_handler handler,
00370                           void *user_data)
00371 {
00372         struct eloop_signal *tmp;
00373 
00374         tmp = (struct eloop_signal *)
00375                 os_realloc(eloop.signals,
00376                            (eloop.signal_count + 1) *
00377                            sizeof(struct eloop_signal));
00378         if (tmp == NULL)
00379                 return -1;
00380 
00381         tmp[eloop.signal_count].sig = sig;
00382         tmp[eloop.signal_count].user_data = user_data;
00383         tmp[eloop.signal_count].handler = handler;
00384         tmp[eloop.signal_count].signaled = 0;
00385         eloop.signal_count++;
00386         eloop.signals = tmp;
00387         signal(sig, eloop_handle_signal);
00388 
00389         return 0;
00390 }
00391 
00392 
00393 int eloop_register_signal_terminate(eloop_signal_handler handler,
00394                                     void *user_data)
00395 {
00396         int ret = eloop_register_signal(SIGINT, handler, user_data);
00397         if (ret == 0)
00398                 ret = eloop_register_signal(SIGTERM, handler, user_data);
00399         return ret;
00400 }
00401 
00402 
00403 int eloop_register_signal_reconfig(eloop_signal_handler handler,
00404                                    void *user_data)
00405 {
00406 #ifdef CONFIG_NATIVE_WINDOWS
00407         return 0;
00408 #else /* CONFIG_NATIVE_WINDOWS */
00409         return eloop_register_signal(SIGHUP, handler, user_data);
00410 #endif /* CONFIG_NATIVE_WINDOWS */
00411 }
00412 
00413 
00414 void eloop_run(void)
00415 {
00416         fd_set *rfds, *wfds, *efds;
00417         int res;
00418         struct timeval _tv;
00419         struct os_time tv, now;
00420 
00421         rfds = os_malloc(sizeof(*rfds));
00422         wfds = os_malloc(sizeof(*wfds));
00423         efds = os_malloc(sizeof(*efds));
00424         if (rfds == NULL || wfds == NULL || efds == NULL) {
00425                 printf("eloop_run - malloc failed\n");
00426                 goto out;
00427         }
00428 
00429         while (!eloop.terminate &&
00430                (eloop.timeout || eloop.readers.count > 0 ||
00431                 eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
00432                 if (eloop.timeout) {
00433                         os_get_time(&now);
00434                         if (os_time_before(&now, &eloop.timeout->time))
00435                                 os_time_sub(&eloop.timeout->time, &now, &tv);
00436                         else
00437                                 tv.sec = tv.usec = 0;
00438 #if 0
00439                         printf("next timeout in %lu.%06lu sec\n",
00440                                tv.sec, tv.usec);
00441 #endif
00442                         _tv.tv_sec = tv.sec;
00443                         _tv.tv_usec = tv.usec;
00444                 }
00445 
00446                 eloop_sock_table_set_fds(&eloop.readers, rfds);
00447                 eloop_sock_table_set_fds(&eloop.writers, wfds);
00448                 eloop_sock_table_set_fds(&eloop.exceptions, efds);
00449                 res = select(eloop.max_sock + 1, rfds, wfds, efds,
00450                              eloop.timeout ? &_tv : NULL);
00451                 if (res < 0 && errno != EINTR && errno != 0) {
00452                         perror("select");
00453                         goto out;
00454                 }
00455                 eloop_process_pending_signals();
00456 
00457                 /* check if some registered timeouts have occurred */
00458                 if (eloop.timeout) {
00459                         struct eloop_timeout *tmp;
00460 
00461                         os_get_time(&now);
00462                         if (!os_time_before(&now, &eloop.timeout->time)) {
00463                                 tmp = eloop.timeout;
00464                                 eloop.timeout = eloop.timeout->next;
00465                                 tmp->handler(tmp->eloop_data,
00466                                              tmp->user_data);
00467                                 os_free(tmp);
00468                         }
00469 
00470                 }
00471 
00472                 if (res <= 0)
00473                         continue;
00474 
00475                 eloop_sock_table_dispatch(&eloop.readers, rfds);
00476                 eloop_sock_table_dispatch(&eloop.writers, wfds);
00477                 eloop_sock_table_dispatch(&eloop.exceptions, efds);
00478         }
00479 
00480 out:
00481         os_free(rfds);
00482         os_free(wfds);
00483         os_free(efds);
00484 }
00485 
00486 
00487 void eloop_terminate(void)
00488 {
00489         eloop.terminate = 1;
00490 }
00491 
00492 
00493 void eloop_destroy(void)
00494 {
00495         struct eloop_timeout *timeout, *prev;
00496 
00497         timeout = eloop.timeout;
00498         while (timeout != NULL) {
00499                 prev = timeout;
00500                 timeout = timeout->next;
00501                 os_free(prev);
00502         }
00503         eloop_sock_table_destroy(&eloop.readers);
00504         eloop_sock_table_destroy(&eloop.writers);
00505         eloop_sock_table_destroy(&eloop.exceptions);
00506         os_free(eloop.signals);
00507 }
00508 
00509 
00510 int eloop_terminated(void)
00511 {
00512         return eloop.terminate;
00513 }
00514 
00515 
00516 void eloop_wait_for_read_sock(int sock)
00517 {
00518         fd_set rfds;
00519 
00520         if (sock < 0)
00521                 return;
00522 
00523         FD_ZERO(&rfds);
00524         FD_SET(sock, &rfds);
00525         select(sock + 1, &rfds, NULL, NULL, NULL);
00526 }
00527 
00528 
00529 void * eloop_get_user_data(void)
00530 {
00531         return eloop.user_data;
00532 }
00533 

Generated on Sun Dec 31 13:48:54 2006 for wpa_supplicant by  doxygen 1.4.2