xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.lib/wpad/eloop.c (revision 6860:dcb7dcfde54c)
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