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
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
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
00230
00231 eloop.pending_terminate = 1;
00232 signal(SIGALRM, eloop_handle_alarm);
00233 alarm(2);
00234 }
00235 #endif
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
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
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