eloop.c

Go to the documentation of this file.
00001 
00016 #include <stdlib.h>
00017 #include <stdio.h>
00018 #include <string.h>
00019 #include <sys/time.h>
00020 #include <sys/types.h>
00021 #include <unistd.h>
00022 #include <errno.h>
00023 #include <signal.h>
00024 
00025 #ifdef CONFIG_NATIVE_WINDOWS
00026 #include "common.h"
00027 #endif /* CONFIG_NATIVE_WINDOWS */
00028 
00029 #include "eloop.h"
00030 
00031 
00032 struct eloop_sock {
00033         int sock;
00034         void *eloop_data;
00035         void *user_data;
00036         void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
00037 };
00038 
00039 struct eloop_timeout {
00040         struct timeval time;
00041         void *eloop_data;
00042         void *user_data;
00043         void (*handler)(void *eloop_ctx, void *sock_ctx);
00044         struct eloop_timeout *next;
00045 };
00046 
00047 struct eloop_signal {
00048         int sig;
00049         void *user_data;
00050         void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
00051         int signaled;
00052 };
00053 
00054 struct eloop_data {
00055         void *user_data;
00056 
00057         int max_sock, reader_count;
00058         struct eloop_sock *readers;
00059 
00060         struct eloop_timeout *timeout;
00061 
00062         int signal_count;
00063         struct eloop_signal *signals;
00064         int signaled;
00065         int pending_terminate;
00066 
00067         int terminate;
00068         int reader_table_changed;
00069 };
00070 
00071 static struct eloop_data eloop;
00072 
00073 
00074 void eloop_init(void *user_data)
00075 {
00076         memset(&eloop, 0, sizeof(eloop));
00077         eloop.user_data = user_data;
00078 }
00079 
00080 
00081 int eloop_register_read_sock(int sock,
00082                              void (*handler)(int sock, void *eloop_ctx,
00083                                              void *sock_ctx),
00084                              void *eloop_data, void *user_data)
00085 {
00086         struct eloop_sock *tmp;
00087 
00088         tmp = (struct eloop_sock *)
00089                 realloc(eloop.readers,
00090                         (eloop.reader_count + 1) * sizeof(struct eloop_sock));
00091         if (tmp == NULL)
00092                 return -1;
00093 
00094         tmp[eloop.reader_count].sock = sock;
00095         tmp[eloop.reader_count].eloop_data = eloop_data;
00096         tmp[eloop.reader_count].user_data = user_data;
00097         tmp[eloop.reader_count].handler = handler;
00098         eloop.reader_count++;
00099         eloop.readers = tmp;
00100         if (sock > eloop.max_sock)
00101                 eloop.max_sock = sock;
00102         eloop.reader_table_changed = 1;
00103 
00104         return 0;
00105 }
00106 
00107 
00108 void eloop_unregister_read_sock(int sock)
00109 {
00110         int i;
00111 
00112         if (eloop.readers == NULL || eloop.reader_count == 0)
00113                 return;
00114 
00115         for (i = 0; i < eloop.reader_count; i++) {
00116                 if (eloop.readers[i].sock == sock)
00117                         break;
00118         }
00119         if (i == eloop.reader_count)
00120                 return;
00121         if (i != eloop.reader_count - 1) {
00122                 memmove(&eloop.readers[i], &eloop.readers[i + 1],
00123                         (eloop.reader_count - i - 1) *
00124                         sizeof(struct eloop_sock));
00125         }
00126         eloop.reader_count--;
00127         eloop.reader_table_changed = 1;
00128 }
00129 
00130 
00131 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
00132                            void (*handler)(void *eloop_ctx, void *timeout_ctx),
00133                            void *eloop_data, void *user_data)
00134 {
00135         struct eloop_timeout *timeout, *tmp, *prev;
00136 
00137         timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
00138         if (timeout == NULL)
00139                 return -1;
00140         gettimeofday(&timeout->time, NULL);
00141         timeout->time.tv_sec += secs;
00142         timeout->time.tv_usec += usecs;
00143         while (timeout->time.tv_usec >= 1000000) {
00144                 timeout->time.tv_sec++;
00145                 timeout->time.tv_usec -= 1000000;
00146         }
00147         timeout->eloop_data = eloop_data;
00148         timeout->user_data = user_data;
00149         timeout->handler = handler;
00150         timeout->next = NULL;
00151 
00152         if (eloop.timeout == NULL) {
00153                 eloop.timeout = timeout;
00154                 return 0;
00155         }
00156 
00157         prev = NULL;
00158         tmp = eloop.timeout;
00159         while (tmp != NULL) {
00160                 if (timercmp(&timeout->time, &tmp->time, <))
00161                         break;
00162                 prev = tmp;
00163                 tmp = tmp->next;
00164         }
00165 
00166         if (prev == NULL) {
00167                 timeout->next = eloop.timeout;
00168                 eloop.timeout = timeout;
00169         } else {
00170                 timeout->next = prev->next;
00171                 prev->next = timeout;
00172         }
00173 
00174         return 0;
00175 }
00176 
00177 
00178 int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
00179                          void *eloop_data, void *user_data)
00180 {
00181         struct eloop_timeout *timeout, *prev, *next;
00182         int removed = 0;
00183 
00184         prev = NULL;
00185         timeout = eloop.timeout;
00186         while (timeout != NULL) {
00187                 next = timeout->next;
00188 
00189                 if (timeout->handler == handler &&
00190                     (timeout->eloop_data == eloop_data ||
00191                      eloop_data == ELOOP_ALL_CTX) &&
00192                     (timeout->user_data == user_data ||
00193                      user_data == ELOOP_ALL_CTX)) {
00194                         if (prev == NULL)
00195                                 eloop.timeout = next;
00196                         else
00197                                 prev->next = next;
00198                         free(timeout);
00199                         removed++;
00200                 } else
00201                         prev = timeout;
00202 
00203                 timeout = next;
00204         }
00205 
00206         return removed;
00207 }
00208 
00209 
00210 #ifndef CONFIG_NATIVE_WINDOWS
00211 static void eloop_handle_alarm(int sig)
00212 {
00213         fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
00214                 "seconds. Looks like there\n"
00215                 "is a bug that ends up in a busy loop that "
00216                 "prevents clean shutdown.\n"
00217                 "Killing program forcefully.\n");
00218         exit(1);
00219 }
00220 #endif /* CONFIG_NATIVE_WINDOWS */
00221 
00222 
00223 static void eloop_handle_signal(int sig)
00224 {
00225         int i;
00226 
00227 #ifndef CONFIG_NATIVE_WINDOWS
00228         if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
00229                 /* Use SIGALRM to break out from potential busy loops that
00230                  * would not allow the program to be killed. */
00231                 eloop.pending_terminate = 1;
00232                 signal(SIGALRM, eloop_handle_alarm);
00233                 alarm(2);
00234         }
00235 #endif /* CONFIG_NATIVE_WINDOWS */
00236 
00237         eloop.signaled++;
00238         for (i = 0; i < eloop.signal_count; i++) {
00239                 if (eloop.signals[i].sig == sig) {
00240                         eloop.signals[i].signaled++;
00241                         break;
00242                 }
00243         }
00244 }
00245 
00246 
00247 static void eloop_process_pending_signals(void)
00248 {
00249         int i;
00250 
00251         if (eloop.signaled == 0)
00252                 return;
00253         eloop.signaled = 0;
00254 
00255         if (eloop.pending_terminate) {
00256 #ifndef CONFIG_NATIVE_WINDOWS
00257                 alarm(0);
00258 #endif /* CONFIG_NATIVE_WINDOWS */
00259                 eloop.pending_terminate = 0;
00260         }
00261 
00262         for (i = 0; i < eloop.signal_count; i++) {
00263                 if (eloop.signals[i].signaled) {
00264                         eloop.signals[i].signaled = 0;
00265                         eloop.signals[i].handler(eloop.signals[i].sig,
00266                                                  eloop.user_data,
00267                                                  eloop.signals[i].user_data);
00268                 }
00269         }
00270 }
00271 
00272 
00273 int eloop_register_signal(int sig,
00274                           void (*handler)(int sig, void *eloop_ctx,
00275                                           void *signal_ctx),
00276                           void *user_data)
00277 {
00278         struct eloop_signal *tmp;
00279 
00280         tmp = (struct eloop_signal *)
00281                 realloc(eloop.signals,
00282                         (eloop.signal_count + 1) *
00283                         sizeof(struct eloop_signal));
00284         if (tmp == NULL)
00285                 return -1;
00286 
00287         tmp[eloop.signal_count].sig = sig;
00288         tmp[eloop.signal_count].user_data = user_data;
00289         tmp[eloop.signal_count].handler = handler;
00290         tmp[eloop.signal_count].signaled = 0;
00291         eloop.signal_count++;
00292         eloop.signals = tmp;
00293         signal(sig, eloop_handle_signal);
00294 
00295         return 0;
00296 }
00297 
00298 
00299 void eloop_run(void)
00300 {
00301         fd_set *rfds;
00302         int i, res;
00303         struct timeval tv, now;
00304 
00305         rfds = malloc(sizeof(*rfds));
00306         if (rfds == NULL) {
00307                 printf("eloop_run - malloc failed\n");
00308                 return;
00309         }
00310 
00311         while (!eloop.terminate &&
00312                 (eloop.timeout || eloop.reader_count > 0)) {
00313                 if (eloop.timeout) {
00314                         gettimeofday(&now, NULL);
00315                         if (timercmp(&now, &eloop.timeout->time, <))
00316                                 timersub(&eloop.timeout->time, &now, &tv);
00317                         else
00318                                 tv.tv_sec = tv.tv_usec = 0;
00319 #if 0
00320                         printf("next timeout in %lu.%06lu sec\n",
00321                                tv.tv_sec, tv.tv_usec);
00322 #endif
00323                 }
00324 
00325                 FD_ZERO(rfds);
00326                 for (i = 0; i < eloop.reader_count; i++)
00327                         FD_SET(eloop.readers[i].sock, rfds);
00328                 res = select(eloop.max_sock + 1, rfds, NULL, NULL,
00329                              eloop.timeout ? &tv : NULL);
00330                 if (res < 0 && errno != EINTR) {
00331                         perror("select");
00332                         free(rfds);
00333                         return;
00334                 }
00335                 eloop_process_pending_signals();
00336 
00337                 /* check if some registered timeouts have occurred */
00338                 if (eloop.timeout) {
00339                         struct eloop_timeout *tmp;
00340 
00341                         gettimeofday(&now, NULL);
00342                         if (!timercmp(&now, &eloop.timeout->time, <)) {
00343                                 tmp = eloop.timeout;
00344                                 eloop.timeout = eloop.timeout->next;
00345                                 tmp->handler(tmp->eloop_data,
00346                                              tmp->user_data);
00347                                 free(tmp);
00348                         }
00349 
00350                 }
00351 
00352                 if (res <= 0)
00353                         continue;
00354 
00355                 eloop.reader_table_changed = 0;
00356                 for (i = 0; i < eloop.reader_count; i++) {
00357                         if (FD_ISSET(eloop.readers[i].sock, rfds)) {
00358                                 eloop.readers[i].handler(
00359                                         eloop.readers[i].sock,
00360                                         eloop.readers[i].eloop_data,
00361                                         eloop.readers[i].user_data);
00362                                 if (eloop.reader_table_changed)
00363                                         break;
00364                         }
00365                 }
00366         }
00367 
00368         free(rfds);
00369 }
00370 
00371 
00372 void eloop_terminate(void)
00373 {
00374         eloop.terminate = 1;
00375 }
00376 
00377 
00378 void eloop_destroy(void)
00379 {
00380         struct eloop_timeout *timeout, *prev;
00381 
00382         timeout = eloop.timeout;
00383         while (timeout != NULL) {
00384                 prev = timeout;
00385                 timeout = timeout->next;
00386                 free(prev);
00387         }
00388         free(eloop.readers);
00389         free(eloop.signals);
00390 }
00391 
00392 
00393 int eloop_terminated(void)
00394 {
00395         return eloop.terminate;
00396 }
00397 

Generated on Sat May 6 21:13:37 2006 for wpa_supplicant by  doxygen 1.4.2