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                 int i;
00174                 for (i = 0; i < table->count && table->table; i++) {
00175                         printf("ELOOP: remaining socket: sock=%d "
00176                                "eloop_data=%p user_data=%p handler=%p\n",
00177                                table->table[i].sock,
00178                                table->table[i].eloop_data,
00179                                table->table[i].user_data,
00180                                table->table[i].handler);
00181                 }
00182                 os_free(table->table);
00183         }
00184 }
00185 
00186 
00187 int eloop_register_read_sock(int sock, eloop_sock_handler handler,
00188                              void *eloop_data, void *user_data)
00189 {
00190         return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
00191                                    eloop_data, user_data);
00192 }
00193 
00194 
00195 void eloop_unregister_read_sock(int sock)
00196 {
00197         eloop_unregister_sock(sock, EVENT_TYPE_READ);
00198 }
00199 
00200 
00201 static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
00202 {
00203         switch (type) {
00204         case EVENT_TYPE_READ:
00205                 return &eloop.readers;
00206         case EVENT_TYPE_WRITE:
00207                 return &eloop.writers;
00208         case EVENT_TYPE_EXCEPTION:
00209                 return &eloop.exceptions;
00210         }
00211 
00212         return NULL;
00213 }
00214 
00215 
00216 int eloop_register_sock(int sock, eloop_event_type type,
00217                         eloop_sock_handler handler,
00218                         void *eloop_data, void *user_data)
00219 {
00220         struct eloop_sock_table *table;
00221 
00222         table = eloop_get_sock_table(type);
00223         return eloop_sock_table_add_sock(table, sock, handler,
00224                                          eloop_data, user_data);
00225 }
00226 
00227 
00228 void eloop_unregister_sock(int sock, eloop_event_type type)
00229 {
00230         struct eloop_sock_table *table;
00231 
00232         table = eloop_get_sock_table(type);
00233         eloop_sock_table_remove_sock(table, sock);
00234 }
00235 
00236 
00237 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
00238                            eloop_timeout_handler handler,
00239                            void *eloop_data, void *user_data)
00240 {
00241         struct eloop_timeout *timeout, *tmp, *prev;
00242 
00243         timeout = os_malloc(sizeof(*timeout));
00244         if (timeout == NULL)
00245                 return -1;
00246         if (os_get_time(&timeout->time) < 0) {
00247                 os_free(timeout);
00248                 return -1;
00249         }
00250         timeout->time.sec += secs;
00251         timeout->time.usec += usecs;
00252         while (timeout->time.usec >= 1000000) {
00253                 timeout->time.sec++;
00254                 timeout->time.usec -= 1000000;
00255         }
00256         timeout->eloop_data = eloop_data;
00257         timeout->user_data = user_data;
00258         timeout->handler = handler;
00259         timeout->next = NULL;
00260 
00261         if (eloop.timeout == NULL) {
00262                 eloop.timeout = timeout;
00263                 return 0;
00264         }
00265 
00266         prev = NULL;
00267         tmp = eloop.timeout;
00268         while (tmp != NULL) {
00269                 if (os_time_before(&timeout->time, &tmp->time))
00270                         break;
00271                 prev = tmp;
00272                 tmp = tmp->next;
00273         }
00274 
00275         if (prev == NULL) {
00276                 timeout->next = eloop.timeout;
00277                 eloop.timeout = timeout;
00278         } else {
00279                 timeout->next = prev->next;
00280                 prev->next = timeout;
00281         }
00282 
00283         return 0;
00284 }
00285 
00286 
00287 int eloop_cancel_timeout(eloop_timeout_handler handler,
00288                          void *eloop_data, void *user_data)
00289 {
00290         struct eloop_timeout *timeout, *prev, *next;
00291         int removed = 0;
00292 
00293         prev = NULL;
00294         timeout = eloop.timeout;
00295         while (timeout != NULL) {
00296                 next = timeout->next;
00297 
00298                 if (timeout->handler == handler &&
00299                     (timeout->eloop_data == eloop_data ||
00300                      eloop_data == ELOOP_ALL_CTX) &&
00301                     (timeout->user_data == user_data ||
00302                      user_data == ELOOP_ALL_CTX)) {
00303                         if (prev == NULL)
00304                                 eloop.timeout = next;
00305                         else
00306                                 prev->next = next;
00307                         os_free(timeout);
00308                         removed++;
00309                 } else
00310                         prev = timeout;
00311 
00312                 timeout = next;
00313         }
00314 
00315         return removed;
00316 }
00317 
00318 
00319 int eloop_is_timeout_registered(eloop_timeout_handler handler,
00320                                 void *eloop_data, void *user_data)
00321 {
00322         struct eloop_timeout *tmp;
00323 
00324         tmp = eloop.timeout;
00325         while (tmp != NULL) {
00326                 if (tmp->handler == handler &&
00327                     tmp->eloop_data == eloop_data &&
00328                     tmp->user_data == user_data)
00329                         return 1;
00330 
00331                 tmp = tmp->next;
00332         }
00333 
00334         return 0;
00335 }
00336 
00337 
00338 #ifndef CONFIG_NATIVE_WINDOWS
00339 static void eloop_handle_alarm(int sig)
00340 {
00341         fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
00342                 "seconds. Looks like there\n"
00343                 "is a bug that ends up in a busy loop that "
00344                 "prevents clean shutdown.\n"
00345                 "Killing program forcefully.\n");
00346         exit(1);
00347 }
00348 #endif /* CONFIG_NATIVE_WINDOWS */
00349 
00350 
00351 static void eloop_handle_signal(int sig)
00352 {
00353         int i;
00354 
00355 #ifndef CONFIG_NATIVE_WINDOWS
00356         if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
00357                 /* Use SIGALRM to break out from potential busy loops that
00358                  * would not allow the program to be killed. */
00359                 eloop.pending_terminate = 1;
00360                 signal(SIGALRM, eloop_handle_alarm);
00361                 alarm(2);
00362         }
00363 #endif /* CONFIG_NATIVE_WINDOWS */
00364 
00365         eloop.signaled++;
00366         for (i = 0; i < eloop.signal_count; i++) {
00367                 if (eloop.signals[i].sig == sig) {
00368                         eloop.signals[i].signaled++;
00369                         break;
00370                 }
00371         }
00372 }
00373 
00374 
00375 static void eloop_process_pending_signals(void)
00376 {
00377         int i;
00378 
00379         if (eloop.signaled == 0)
00380                 return;
00381         eloop.signaled = 0;
00382 
00383         if (eloop.pending_terminate) {
00384 #ifndef CONFIG_NATIVE_WINDOWS
00385                 alarm(0);
00386 #endif /* CONFIG_NATIVE_WINDOWS */
00387                 eloop.pending_terminate = 0;
00388         }
00389 
00390         for (i = 0; i < eloop.signal_count; i++) {
00391                 if (eloop.signals[i].signaled) {
00392                         eloop.signals[i].signaled = 0;
00393                         eloop.signals[i].handler(eloop.signals[i].sig,
00394                                                  eloop.user_data,
00395                                                  eloop.signals[i].user_data);
00396                 }
00397         }
00398 }
00399 
00400 
00401 int eloop_register_signal(int sig, eloop_signal_handler handler,
00402                           void *user_data)
00403 {
00404         struct eloop_signal *tmp;
00405 
00406         tmp = (struct eloop_signal *)
00407                 os_realloc(eloop.signals,
00408                            (eloop.signal_count + 1) *
00409                            sizeof(struct eloop_signal));
00410         if (tmp == NULL)
00411                 return -1;
00412 
00413         tmp[eloop.signal_count].sig = sig;
00414         tmp[eloop.signal_count].user_data = user_data;
00415         tmp[eloop.signal_count].handler = handler;
00416         tmp[eloop.signal_count].signaled = 0;
00417         eloop.signal_count++;
00418         eloop.signals = tmp;
00419         signal(sig, eloop_handle_signal);
00420 
00421         return 0;
00422 }
00423 
00424 
00425 int eloop_register_signal_terminate(eloop_signal_handler handler,
00426                                     void *user_data)
00427 {
00428         int ret = eloop_register_signal(SIGINT, handler, user_data);
00429         if (ret == 0)
00430                 ret = eloop_register_signal(SIGTERM, handler, user_data);
00431         return ret;
00432 }
00433 
00434 
00435 int eloop_register_signal_reconfig(eloop_signal_handler handler,
00436                                    void *user_data)
00437 {
00438 #ifdef CONFIG_NATIVE_WINDOWS
00439         return 0;
00440 #else /* CONFIG_NATIVE_WINDOWS */
00441         return eloop_register_signal(SIGHUP, handler, user_data);
00442 #endif /* CONFIG_NATIVE_WINDOWS */
00443 }
00444 
00445 
00446 void eloop_run(void)
00447 {
00448         fd_set *rfds, *wfds, *efds;
00449         int res;
00450         struct timeval _tv;
00451         struct os_time tv, now;
00452 
00453         rfds = os_malloc(sizeof(*rfds));
00454         wfds = os_malloc(sizeof(*wfds));
00455         efds = os_malloc(sizeof(*efds));
00456         if (rfds == NULL || wfds == NULL || efds == NULL) {
00457                 printf("eloop_run - malloc failed\n");
00458                 goto out;
00459         }
00460 
00461         while (!eloop.terminate &&
00462                (eloop.timeout || eloop.readers.count > 0 ||
00463                 eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
00464                 if (eloop.timeout) {
00465                         os_get_time(&now);
00466                         if (os_time_before(&now, &eloop.timeout->time))
00467                                 os_time_sub(&eloop.timeout->time, &now, &tv);
00468                         else
00469                                 tv.sec = tv.usec = 0;
00470 #if 0
00471                         printf("next timeout in %lu.%06lu sec\n",
00472                                tv.sec, tv.usec);
00473 #endif
00474                         _tv.tv_sec = tv.sec;
00475                         _tv.tv_usec = tv.usec;
00476                 }
00477 
00478                 eloop_sock_table_set_fds(&eloop.readers, rfds);
00479                 eloop_sock_table_set_fds(&eloop.writers, wfds);
00480                 eloop_sock_table_set_fds(&eloop.exceptions, efds);
00481                 res = select(eloop.max_sock + 1, rfds, wfds, efds,
00482                              eloop.timeout ? &_tv : NULL);
00483                 if (res < 0 && errno != EINTR && errno != 0) {
00484                         perror("select");
00485                         goto out;
00486                 }
00487                 eloop_process_pending_signals();
00488 
00489                 /* check if some registered timeouts have occurred */
00490                 if (eloop.timeout) {
00491                         struct eloop_timeout *tmp;
00492 
00493                         os_get_time(&now);
00494                         if (!os_time_before(&now, &eloop.timeout->time)) {
00495                                 tmp = eloop.timeout;
00496                                 eloop.timeout = eloop.timeout->next;
00497                                 tmp->handler(tmp->eloop_data,
00498                                              tmp->user_data);
00499                                 os_free(tmp);
00500                         }
00501 
00502                 }
00503 
00504                 if (res <= 0)
00505                         continue;
00506 
00507                 eloop_sock_table_dispatch(&eloop.readers, rfds);
00508                 eloop_sock_table_dispatch(&eloop.writers, wfds);
00509                 eloop_sock_table_dispatch(&eloop.exceptions, efds);
00510         }
00511 
00512 out:
00513         os_free(rfds);
00514         os_free(wfds);
00515         os_free(efds);
00516 }
00517 
00518 
00519 void eloop_terminate(void)
00520 {
00521         eloop.terminate = 1;
00522 }
00523 
00524 
00525 void eloop_destroy(void)
00526 {
00527         struct eloop_timeout *timeout, *prev;
00528         struct os_time now;
00529 
00530         timeout = eloop.timeout;
00531         if (timeout)
00532                 os_get_time(&now);
00533         while (timeout != NULL) {
00534                 int sec, usec;
00535                 prev = timeout;
00536                 timeout = timeout->next;
00537                 sec = prev->time.sec - now.sec;
00538                 usec = prev->time.usec - now.usec;
00539                 if (prev->time.usec < now.usec) {
00540                         sec--;
00541                         usec += 1000000;
00542                 }
00543                 printf("ELOOP: remaining timeout: %d.%06d eloop_data=%p "
00544                        "user_data=%p handler=%p\n",
00545                        sec, usec, prev->eloop_data, prev->user_data,
00546                        prev->handler);
00547                 os_free(prev);
00548         }
00549         eloop_sock_table_destroy(&eloop.readers);
00550         eloop_sock_table_destroy(&eloop.writers);
00551         eloop_sock_table_destroy(&eloop.exceptions);
00552         os_free(eloop.signals);
00553 }
00554 
00555 
00556 int eloop_terminated(void)
00557 {
00558         return eloop.terminate;
00559 }
00560 
00561 
00562 void eloop_wait_for_read_sock(int sock)
00563 {
00564         fd_set rfds;
00565 
00566         if (sock < 0)
00567                 return;
00568 
00569         FD_ZERO(&rfds);
00570         FD_SET(sock, &rfds);
00571         select(sock + 1, &rfds, NULL, NULL, NULL);
00572 }
00573 
00574 
00575 void * eloop_get_user_data(void)
00576 {
00577         return eloop.user_data;
00578 }
00579 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:53 2009 for hostapd by  doxygen 1.6.1