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
eloop_init(void * user_data)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
eloop_register_read_sock(int sock,void (* handler)(int sock,void * eloop_ctx,void * sock_ctx),void * eloop_data,void * user_data)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
eloop_unregister_read_sock(int sock)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
eloop_register_timeout(unsigned int secs,unsigned int usecs,void (* handler)(void * eloop_ctx,void * timeout_ctx),void * eloop_data,void * user_data)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
eloop_cancel_timeout(void (* handler)(void * eloop_ctx,void * sock_ctx),void * eloop_data,void * user_data)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
eloop_handle_signal(int sig)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
eloop_process_pending_signals(void)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
eloop_register_signal(int sig,void (* handler)(int sig,void * eloop_ctx,void * signal_ctx),void * user_data)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
eloop_run(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
eloop_terminate(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
eloop_destroy(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