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