14126Szf162725 /* 2*6860Sdanmcd * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 34126Szf162725 * Use is subject to license terms. 44126Szf162725 */ 54126Szf162725 64126Szf162725 /* 74126Szf162725 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> 84126Szf162725 * Sun elects to license this software under the BSD license. 94126Szf162725 * See README for more details. 104126Szf162725 */ 114126Szf162725 124126Szf162725 #pragma ident "%Z%%M% %I% %E% SMI" 134126Szf162725 144126Szf162725 #include <stdio.h> 154126Szf162725 #include <stdlib.h> 164126Szf162725 #include <string.h> 174126Szf162725 #include <sys/time.h> 184126Szf162725 #include <unistd.h> 194126Szf162725 #include <errno.h> 204126Szf162725 #include <signal.h> 214126Szf162725 #include <poll.h> 224126Szf162725 234126Szf162725 #include "eloop.h" 244126Szf162725 254126Szf162725 static struct eloop_data eloop; 264126Szf162725 /* 274126Szf162725 * Initialize global event loop data - must be called before any other eloop_* 284126Szf162725 * function. user_data is a pointer to global data structure and will be passed 294126Szf162725 * as eloop_ctx to signal handlers. 304126Szf162725 */ 314126Szf162725 void 324126Szf162725 eloop_init(void *user_data) 334126Szf162725 { 344126Szf162725 (void) memset(&eloop, 0, sizeof (eloop)); 354126Szf162725 eloop.user_data = user_data; 364126Szf162725 } 374126Szf162725 384126Szf162725 /* 394126Szf162725 * Register handler for read event 404126Szf162725 */ 414126Szf162725 int 424126Szf162725 eloop_register_read_sock(int sock, 434126Szf162725 void (*handler)(int sock, void *eloop_ctx, 444126Szf162725 void *sock_ctx), void *eloop_data, void *user_data) 454126Szf162725 { 464126Szf162725 struct eloop_sock *tmp; 474126Szf162725 484126Szf162725 tmp = (struct eloop_sock *)realloc(eloop.readers, 494126Szf162725 (eloop.reader_count + 1) * sizeof (struct eloop_sock)); 504126Szf162725 if (tmp == NULL) 514126Szf162725 return (-1); 524126Szf162725 534126Szf162725 tmp[eloop.reader_count].sock = sock; 544126Szf162725 tmp[eloop.reader_count].eloop_data = eloop_data; 554126Szf162725 tmp[eloop.reader_count].user_data = user_data; 564126Szf162725 tmp[eloop.reader_count].handler = handler; 574126Szf162725 eloop.reader_count++; 584126Szf162725 eloop.readers = tmp; 594126Szf162725 if (sock > eloop.max_sock) 604126Szf162725 eloop.max_sock = sock; 614126Szf162725 624126Szf162725 return (0); 634126Szf162725 } 644126Szf162725 654126Szf162725 void 664126Szf162725 eloop_unregister_read_sock(int sock) 674126Szf162725 { 684126Szf162725 int i; 694126Szf162725 704126Szf162725 if (eloop.readers == NULL || eloop.reader_count == 0) 714126Szf162725 return; 724126Szf162725 734126Szf162725 for (i = 0; i < eloop.reader_count; i++) { 744126Szf162725 if (eloop.readers[i].sock == sock) 754126Szf162725 break; 764126Szf162725 } 774126Szf162725 if (i == eloop.reader_count) 784126Szf162725 return; 794126Szf162725 if (i != eloop.reader_count - 1) { 804126Szf162725 (void) memmove(&eloop.readers[i], &eloop.readers[i + 1], 814126Szf162725 (eloop.reader_count - i - 1) * 824126Szf162725 sizeof (struct eloop_sock)); 834126Szf162725 } 844126Szf162725 eloop.reader_count--; 854126Szf162725 } 864126Szf162725 874126Szf162725 /* 884126Szf162725 * Register timeout routines 894126Szf162725 */ 904126Szf162725 int 914126Szf162725 eloop_register_timeout(unsigned int secs, unsigned int usecs, 924126Szf162725 void (*handler)(void *eloop_ctx, void *timeout_ctx), 934126Szf162725 void *eloop_data, void *user_data) 944126Szf162725 { 954126Szf162725 struct eloop_timeout *timeout, *tmp, *prev; 964126Szf162725 974126Szf162725 timeout = (struct eloop_timeout *)malloc(sizeof (*timeout)); 984126Szf162725 if (timeout == NULL) 994126Szf162725 return (-1); 1004126Szf162725 (void) gettimeofday(&timeout->time, NULL); 1014126Szf162725 timeout->time.tv_sec += secs; 1024126Szf162725 timeout->time.tv_usec += usecs; 1034126Szf162725 while (timeout->time.tv_usec >= 1000000) { 1044126Szf162725 timeout->time.tv_sec++; 1054126Szf162725 timeout->time.tv_usec -= 1000000; 1064126Szf162725 } 1074126Szf162725 timeout->eloop_data = eloop_data; 1084126Szf162725 timeout->user_data = user_data; 1094126Szf162725 timeout->handler = handler; 1104126Szf162725 timeout->next = NULL; 1114126Szf162725 1124126Szf162725 if (eloop.timeout == NULL) { 1134126Szf162725 eloop.timeout = timeout; 1144126Szf162725 return (0); 1154126Szf162725 } 1164126Szf162725 1174126Szf162725 prev = NULL; 1184126Szf162725 tmp = eloop.timeout; 1194126Szf162725 while (tmp != NULL) { 1204126Szf162725 if (timercmp(&timeout->time, &tmp->time, < /* */)) 1214126Szf162725 break; 1224126Szf162725 prev = tmp; 1234126Szf162725 tmp = tmp->next; 1244126Szf162725 } 1254126Szf162725 1264126Szf162725 if (prev == NULL) { 1274126Szf162725 timeout->next = eloop.timeout; 1284126Szf162725 eloop.timeout = timeout; 1294126Szf162725 } else { 1304126Szf162725 timeout->next = prev->next; 1314126Szf162725 prev->next = timeout; 1324126Szf162725 } 1334126Szf162725 1344126Szf162725 return (0); 1354126Szf162725 } 1364126Szf162725 1374126Szf162725 /* 1384126Szf162725 * Cancel timeouts matching <handler,eloop_data,user_data>. 1394126Szf162725 * ELOOP_ALL_CTX can be used as a wildcard for cancelling all timeouts 1404126Szf162725 * regardless of eloop_data/user_data. 1414126Szf162725 */ 1424126Szf162725 void 1434126Szf162725 eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx), 1444126Szf162725 void *eloop_data, void *user_data) 1454126Szf162725 { 1464126Szf162725 struct eloop_timeout *timeout, *prev, *next; 1474126Szf162725 1484126Szf162725 prev = NULL; 1494126Szf162725 timeout = eloop.timeout; 1504126Szf162725 while (timeout != NULL) { 1514126Szf162725 next = timeout->next; 1524126Szf162725 1534126Szf162725 if (timeout->handler == handler && 1544126Szf162725 (timeout->eloop_data == eloop_data || 1554126Szf162725 eloop_data == ELOOP_ALL_CTX) && 1564126Szf162725 (timeout->user_data == user_data || 1574126Szf162725 user_data == ELOOP_ALL_CTX)) { 1584126Szf162725 if (prev == NULL) 1594126Szf162725 eloop.timeout = next; 1604126Szf162725 else 1614126Szf162725 prev->next = next; 1624126Szf162725 free(timeout); 1634126Szf162725 } else 1644126Szf162725 prev = timeout; 1654126Szf162725 1664126Szf162725 timeout = next; 1674126Szf162725 } 1684126Szf162725 } 1694126Szf162725 1704126Szf162725 static void eloop_handle_signal(int sig) 1714126Szf162725 { 1724126Szf162725 int i; 1734126Szf162725 1744126Szf162725 eloop.signaled++; 1754126Szf162725 for (i = 0; i < eloop.signal_count; i++) { 1764126Szf162725 if (eloop.signals[i].sig == sig) { 1774126Szf162725 eloop.signals[i].signaled++; 1784126Szf162725 break; 1794126Szf162725 } 1804126Szf162725 } 1814126Szf162725 } 1824126Szf162725 1834126Szf162725 static void eloop_process_pending_signals(void) 1844126Szf162725 { 1854126Szf162725 int i; 1864126Szf162725 1874126Szf162725 if (eloop.signaled == 0) 1884126Szf162725 return; 1894126Szf162725 eloop.signaled = 0; 1904126Szf162725 1914126Szf162725 for (i = 0; i < eloop.signal_count; i++) { 1924126Szf162725 if (eloop.signals[i].signaled) { 1934126Szf162725 eloop.signals[i].signaled = 0; 1944126Szf162725 eloop.signals[i].handler(eloop.signals[i].sig, 1954126Szf162725 eloop.user_data, eloop.signals[i].user_data); 1964126Szf162725 } 1974126Szf162725 } 1984126Szf162725 } 1994126Szf162725 2004126Szf162725 /* 2014126Szf162725 * Register handler for signal. 2024126Szf162725 * Note: signals are 'global' events and there is no local eloop_data pointer 2034126Szf162725 * like with other handlers. The (global) pointer given to eloop_init() will be 2044126Szf162725 * used as eloop_ctx for signal handlers. 2054126Szf162725 */ 2064126Szf162725 int 2074126Szf162725 eloop_register_signal(int sig, 2084126Szf162725 void (*handler)(int sig, void *eloop_ctx, void *signal_ctx), 2094126Szf162725 void *user_data) 2104126Szf162725 { 2114126Szf162725 struct eloop_signal *tmp; 2124126Szf162725 2134126Szf162725 tmp = (struct eloop_signal *) 2144126Szf162725 realloc(eloop.signals, 2154126Szf162725 (eloop.signal_count + 1) * 2164126Szf162725 sizeof (struct eloop_signal)); 2174126Szf162725 if (tmp == NULL) 2184126Szf162725 return (-1); 2194126Szf162725 2204126Szf162725 tmp[eloop.signal_count].sig = sig; 2214126Szf162725 tmp[eloop.signal_count].user_data = user_data; 2224126Szf162725 tmp[eloop.signal_count].handler = handler; 2234126Szf162725 tmp[eloop.signal_count].signaled = 0; 2244126Szf162725 eloop.signal_count++; 2254126Szf162725 eloop.signals = tmp; 2264126Szf162725 (void) signal(sig, eloop_handle_signal); 2274126Szf162725 2284126Szf162725 return (0); 2294126Szf162725 } 2304126Szf162725 2314126Szf162725 /* 2324126Szf162725 * Start event loop and continue running as long as there are any registered 2334126Szf162725 * event handlers. 2344126Szf162725 */ 2354126Szf162725 void 2364126Szf162725 eloop_run(void) 2374126Szf162725 { 2384126Szf162725 struct pollfd pfds[MAX_POLLFDS]; /* array of polled fd */ 2394126Szf162725 int i, res; 2404126Szf162725 int default_t, t; 2414126Szf162725 struct timeval tv, now; 2424126Szf162725 2434126Szf162725 default_t = 5 * 1000; /* 5 seconds */ 2444126Szf162725 while (!eloop.terminate && 245*6860Sdanmcd (eloop.timeout || eloop.reader_count > 0)) { 2464126Szf162725 if (eloop.timeout) { 2474126Szf162725 (void) gettimeofday(&now, NULL); 2484126Szf162725 if (timercmp(&now, &eloop.timeout->time, < /* */)) 2494126Szf162725 timersub(&eloop.timeout->time, &now, &tv); 2504126Szf162725 else 2514126Szf162725 tv.tv_sec = tv.tv_usec = 0; 2524126Szf162725 } 2534126Szf162725 2544126Szf162725 t = (eloop.timeout == NULL ? 2554126Szf162725 default_t : (tv.tv_sec * 1000 + tv.tv_usec / 1000)); 2564126Szf162725 for (i = 0; i < eloop.reader_count; i++) { 2574126Szf162725 pfds[i].fd = eloop.readers[i].sock; 2584126Szf162725 pfds[i].events = POLLIN | POLLPRI; 2594126Szf162725 } 2604126Szf162725 res = poll(pfds, eloop.reader_count, t); 2614126Szf162725 if (res < 0 && errno != EINTR) 2624126Szf162725 return; 2634126Szf162725 2644126Szf162725 eloop_process_pending_signals(); 2654126Szf162725 2664126Szf162725 /* check if some registered timeouts have occurred */ 2674126Szf162725 if (eloop.timeout) { 2684126Szf162725 struct eloop_timeout *tmp; 2694126Szf162725 2704126Szf162725 (void) gettimeofday(&now, NULL); 2714126Szf162725 if (!timercmp(&now, &eloop.timeout->time, < /* */)) { 2724126Szf162725 tmp = eloop.timeout; 2734126Szf162725 eloop.timeout = eloop.timeout->next; 2744126Szf162725 tmp->handler(tmp->eloop_data, tmp->user_data); 2754126Szf162725 free(tmp); 2764126Szf162725 } 2774126Szf162725 2784126Szf162725 } 2794126Szf162725 2804126Szf162725 if (res <= 0) 2814126Szf162725 continue; 2824126Szf162725 2834126Szf162725 for (i = 0; i < eloop.reader_count; i++) { 2844126Szf162725 if (pfds[i].revents) { 2854126Szf162725 eloop.readers[i].handler( 2864126Szf162725 eloop.readers[i].sock, 2874126Szf162725 eloop.readers[i].eloop_data, 2884126Szf162725 eloop.readers[i].user_data); 2894126Szf162725 } 2904126Szf162725 } 2914126Szf162725 } 2924126Szf162725 } 2934126Szf162725 2944126Szf162725 /* 2954126Szf162725 * Terminate event loop even if there are registered events. 2964126Szf162725 */ 2974126Szf162725 void 2984126Szf162725 eloop_terminate(void) 2994126Szf162725 { 3004126Szf162725 eloop.terminate = 1; 3014126Szf162725 } 3024126Szf162725 3034126Szf162725 3044126Szf162725 /* 3054126Szf162725 * Free any reserved resources. After calling eloop_destoy(), other eloop_* 3064126Szf162725 * functions must not be called before re-running eloop_init(). 3074126Szf162725 */ 3084126Szf162725 void 3094126Szf162725 eloop_destroy(void) 3104126Szf162725 { 3114126Szf162725 struct eloop_timeout *timeout, *prev; 3124126Szf162725 3134126Szf162725 timeout = eloop.timeout; 3144126Szf162725 while (timeout != NULL) { 3154126Szf162725 prev = timeout; 3164126Szf162725 timeout = timeout->next; 3174126Szf162725 free(prev); 3184126Szf162725 } 3194126Szf162725 free(eloop.readers); 3204126Szf162725 free(eloop.signals); 3214126Szf162725 } 322