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