1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> 8 * Sun elects to license this software under the BSD license. 9 * See README for more details. 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <sys/time.h> 16 #include <unistd.h> 17 #include <errno.h> 18 #include <signal.h> 19 #include <poll.h> 20 21 #include "eloop.h" 22 23 static struct eloop_data eloop; 24 /* 25 * Initialize global event loop data - must be called before any other eloop_* 26 * function. user_data is a pointer to global data structure and will be passed 27 * as eloop_ctx to signal handlers. 28 */ 29 void 30 eloop_init(void *user_data) 31 { 32 (void) memset(&eloop, 0, sizeof (eloop)); 33 eloop.user_data = user_data; 34 } 35 36 /* 37 * Register handler for read event 38 */ 39 int 40 eloop_register_read_sock(int sock, 41 void (*handler)(int sock, void *eloop_ctx, 42 void *sock_ctx), void *eloop_data, void *user_data) 43 { 44 struct eloop_sock *tmp; 45 46 tmp = (struct eloop_sock *)realloc(eloop.readers, 47 (eloop.reader_count + 1) * sizeof (struct eloop_sock)); 48 if (tmp == NULL) 49 return (-1); 50 51 tmp[eloop.reader_count].sock = sock; 52 tmp[eloop.reader_count].eloop_data = eloop_data; 53 tmp[eloop.reader_count].user_data = user_data; 54 tmp[eloop.reader_count].handler = handler; 55 eloop.reader_count++; 56 eloop.readers = tmp; 57 if (sock > eloop.max_sock) 58 eloop.max_sock = sock; 59 60 return (0); 61 } 62 63 void 64 eloop_unregister_read_sock(int sock) 65 { 66 int i; 67 68 if (eloop.readers == NULL || eloop.reader_count == 0) 69 return; 70 71 for (i = 0; i < eloop.reader_count; i++) { 72 if (eloop.readers[i].sock == sock) 73 break; 74 } 75 if (i == eloop.reader_count) 76 return; 77 if (i != eloop.reader_count - 1) { 78 (void) memmove(&eloop.readers[i], &eloop.readers[i + 1], 79 (eloop.reader_count - i - 1) * 80 sizeof (struct eloop_sock)); 81 } 82 eloop.reader_count--; 83 } 84 85 /* 86 * Register timeout routines 87 */ 88 int 89 eloop_register_timeout(unsigned int secs, unsigned int usecs, 90 void (*handler)(void *eloop_ctx, void *timeout_ctx), 91 void *eloop_data, void *user_data) 92 { 93 struct eloop_timeout *timeout, *tmp, *prev; 94 95 timeout = (struct eloop_timeout *)malloc(sizeof (*timeout)); 96 if (timeout == NULL) 97 return (-1); 98 (void) gettimeofday(&timeout->time, NULL); 99 timeout->time.tv_sec += secs; 100 timeout->time.tv_usec += usecs; 101 while (timeout->time.tv_usec >= 1000000) { 102 timeout->time.tv_sec++; 103 timeout->time.tv_usec -= 1000000; 104 } 105 timeout->eloop_data = eloop_data; 106 timeout->user_data = user_data; 107 timeout->handler = handler; 108 timeout->next = NULL; 109 110 if (eloop.timeout == NULL) { 111 eloop.timeout = timeout; 112 return (0); 113 } 114 115 prev = NULL; 116 tmp = eloop.timeout; 117 while (tmp != NULL) { 118 if (timercmp(&timeout->time, &tmp->time, < /* */)) 119 break; 120 prev = tmp; 121 tmp = tmp->next; 122 } 123 124 if (prev == NULL) { 125 timeout->next = eloop.timeout; 126 eloop.timeout = timeout; 127 } else { 128 timeout->next = prev->next; 129 prev->next = timeout; 130 } 131 132 return (0); 133 } 134 135 /* 136 * Cancel timeouts matching <handler,eloop_data,user_data>. 137 * ELOOP_ALL_CTX can be used as a wildcard for cancelling all timeouts 138 * regardless of eloop_data/user_data. 139 */ 140 void 141 eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx), 142 void *eloop_data, void *user_data) 143 { 144 struct eloop_timeout *timeout, *prev, *next; 145 146 prev = NULL; 147 timeout = eloop.timeout; 148 while (timeout != NULL) { 149 next = timeout->next; 150 151 if (timeout->handler == handler && 152 (timeout->eloop_data == eloop_data || 153 eloop_data == ELOOP_ALL_CTX) && 154 (timeout->user_data == user_data || 155 user_data == ELOOP_ALL_CTX)) { 156 if (prev == NULL) 157 eloop.timeout = next; 158 else 159 prev->next = next; 160 free(timeout); 161 } else 162 prev = timeout; 163 164 timeout = next; 165 } 166 } 167 168 static void eloop_handle_signal(int sig) 169 { 170 int i; 171 172 eloop.signaled++; 173 for (i = 0; i < eloop.signal_count; i++) { 174 if (eloop.signals[i].sig == sig) { 175 eloop.signals[i].signaled++; 176 break; 177 } 178 } 179 } 180 181 static void eloop_process_pending_signals(void) 182 { 183 int i; 184 185 if (eloop.signaled == 0) 186 return; 187 eloop.signaled = 0; 188 189 for (i = 0; i < eloop.signal_count; i++) { 190 if (eloop.signals[i].signaled) { 191 eloop.signals[i].signaled = 0; 192 eloop.signals[i].handler(eloop.signals[i].sig, 193 eloop.user_data, eloop.signals[i].user_data); 194 } 195 } 196 } 197 198 /* 199 * Register handler for signal. 200 * Note: signals are 'global' events and there is no local eloop_data pointer 201 * like with other handlers. The (global) pointer given to eloop_init() will be 202 * used as eloop_ctx for signal handlers. 203 */ 204 int 205 eloop_register_signal(int sig, 206 void (*handler)(int sig, void *eloop_ctx, void *signal_ctx), 207 void *user_data) 208 { 209 struct eloop_signal *tmp; 210 211 tmp = (struct eloop_signal *) 212 realloc(eloop.signals, 213 (eloop.signal_count + 1) * 214 sizeof (struct eloop_signal)); 215 if (tmp == NULL) 216 return (-1); 217 218 tmp[eloop.signal_count].sig = sig; 219 tmp[eloop.signal_count].user_data = user_data; 220 tmp[eloop.signal_count].handler = handler; 221 tmp[eloop.signal_count].signaled = 0; 222 eloop.signal_count++; 223 eloop.signals = tmp; 224 (void) signal(sig, eloop_handle_signal); 225 226 return (0); 227 } 228 229 /* 230 * Start event loop and continue running as long as there are any registered 231 * event handlers. 232 */ 233 void 234 eloop_run(void) 235 { 236 struct pollfd pfds[MAX_POLLFDS]; /* array of polled fd */ 237 int i, res; 238 int default_t, t; 239 struct timeval tv, now; 240 241 default_t = 5 * 1000; /* 5 seconds */ 242 while (!eloop.terminate && 243 (eloop.timeout || eloop.reader_count > 0)) { 244 if (eloop.timeout) { 245 (void) gettimeofday(&now, NULL); 246 if (timercmp(&now, &eloop.timeout->time, < /* */)) 247 timersub(&eloop.timeout->time, &now, &tv); 248 else 249 tv.tv_sec = tv.tv_usec = 0; 250 } 251 252 t = (eloop.timeout == NULL ? 253 default_t : (tv.tv_sec * 1000 + tv.tv_usec / 1000)); 254 for (i = 0; i < eloop.reader_count; i++) { 255 pfds[i].fd = eloop.readers[i].sock; 256 pfds[i].events = POLLIN | POLLPRI; 257 } 258 res = poll(pfds, eloop.reader_count, t); 259 if (res < 0 && errno != EINTR) 260 return; 261 262 eloop_process_pending_signals(); 263 264 /* check if some registered timeouts have occurred */ 265 if (eloop.timeout) { 266 struct eloop_timeout *tmp; 267 268 (void) gettimeofday(&now, NULL); 269 if (!timercmp(&now, &eloop.timeout->time, < /* */)) { 270 tmp = eloop.timeout; 271 eloop.timeout = eloop.timeout->next; 272 tmp->handler(tmp->eloop_data, tmp->user_data); 273 free(tmp); 274 } 275 276 } 277 278 if (res <= 0) 279 continue; 280 281 for (i = 0; i < eloop.reader_count; i++) { 282 if (pfds[i].revents) { 283 eloop.readers[i].handler( 284 eloop.readers[i].sock, 285 eloop.readers[i].eloop_data, 286 eloop.readers[i].user_data); 287 } 288 } 289 } 290 } 291 292 /* 293 * Terminate event loop even if there are registered events. 294 */ 295 void 296 eloop_terminate(void) 297 { 298 eloop.terminate = 1; 299 } 300 301 302 /* 303 * Free any reserved resources. After calling eloop_destoy(), other eloop_* 304 * functions must not be called before re-running eloop_init(). 305 */ 306 void 307 eloop_destroy(void) 308 { 309 struct eloop_timeout *timeout, *prev; 310 311 timeout = eloop.timeout; 312 while (timeout != NULL) { 313 prev = timeout; 314 timeout = timeout->next; 315 free(prev); 316 } 317 free(eloop.readers); 318 free(eloop.signals); 319 } 320