1933707f3Ssthen /* 2933707f3Ssthen * mini-event.h - micro implementation of libevent api, using select() only. 3933707f3Ssthen * 4933707f3Ssthen * Copyright (c) 2007, NLnet Labs. All rights reserved. 5933707f3Ssthen * 6933707f3Ssthen * This software is open source. 7933707f3Ssthen * 8933707f3Ssthen * Redistribution and use in source and binary forms, with or without 9933707f3Ssthen * modification, are permitted provided that the following conditions 10933707f3Ssthen * are met: 11933707f3Ssthen * 12933707f3Ssthen * Redistributions of source code must retain the above copyright notice, 13933707f3Ssthen * this list of conditions and the following disclaimer. 14933707f3Ssthen * 15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice, 16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation 17933707f3Ssthen * and/or other materials provided with the distribution. 18933707f3Ssthen * 19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may 20933707f3Ssthen * be used to endorse or promote products derived from this software without 21933707f3Ssthen * specific prior written permission. 22933707f3Ssthen * 23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34933707f3Ssthen */ 35933707f3Ssthen 36933707f3Ssthen /** 37933707f3Ssthen * \file 38933707f3Ssthen * This file implements part of the event(3) libevent api. 39933707f3Ssthen * The back end is only select. Max number of fds is limited. 40933707f3Ssthen * Max number of signals is limited, one handler per signal only. 41933707f3Ssthen * And one handler per fd. 42933707f3Ssthen * 43933707f3Ssthen * Although limited to select() and a max (1024) open fds, it 44933707f3Ssthen * is efficient: 45933707f3Ssthen * o dispatch call caches fd_sets to use. 46933707f3Ssthen * o handler calling takes time ~ to the number of fds. 47933707f3Ssthen * o timeouts are stored in a redblack tree, sorted, so take log(n). 48933707f3Ssthen * Timeouts are only accurate to the second (no subsecond accuracy). 49933707f3Ssthen * To avoid cpu hogging, fractional timeouts are rounded up to a whole second. 50933707f3Ssthen */ 51933707f3Ssthen 52933707f3Ssthen #ifndef MINI_EVENT_H 53933707f3Ssthen #define MINI_EVENT_H 54933707f3Ssthen 55933707f3Ssthen #if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK) 56933707f3Ssthen 57*2c144df0Ssthen #ifdef HAVE_SYS_SELECT_H 58*2c144df0Ssthen /* for fd_set on OpenBSD */ 59*2c144df0Ssthen #include <sys/select.h> 60*2c144df0Ssthen #endif 61a3167c07Ssthen #include <sys/time.h> 62a3167c07Ssthen 63933707f3Ssthen #ifndef HAVE_EVENT_BASE_FREE 64933707f3Ssthen #define HAVE_EVENT_BASE_FREE 65933707f3Ssthen #endif 66933707f3Ssthen 6798f3ca02Sbrad /* redefine to use our own namespace so that on platforms where 6898f3ca02Sbrad * linkers crosslink library-private symbols with other symbols, it works */ 6998f3ca02Sbrad #define event_init minievent_init 7098f3ca02Sbrad #define event_get_version minievent_get_version 7198f3ca02Sbrad #define event_get_method minievent_get_method 7298f3ca02Sbrad #define event_base_dispatch minievent_base_dispatch 7398f3ca02Sbrad #define event_base_loopexit minievent_base_loopexit 7498f3ca02Sbrad #define event_base_free minievent_base_free 7598f3ca02Sbrad #define event_set minievent_set 7698f3ca02Sbrad #define event_base_set minievent_base_set 7798f3ca02Sbrad #define event_add minievent_add 7898f3ca02Sbrad #define event_del minievent_del 7998f3ca02Sbrad #define signal_add minisignal_add 8098f3ca02Sbrad #define signal_del minisignal_del 8198f3ca02Sbrad 82933707f3Ssthen /** event timeout */ 83933707f3Ssthen #define EV_TIMEOUT 0x01 84933707f3Ssthen /** event fd readable */ 85933707f3Ssthen #define EV_READ 0x02 86933707f3Ssthen /** event fd writable */ 87933707f3Ssthen #define EV_WRITE 0x04 88933707f3Ssthen /** event signal */ 89933707f3Ssthen #define EV_SIGNAL 0x08 90933707f3Ssthen /** event must persist */ 91933707f3Ssthen #define EV_PERSIST 0x10 92933707f3Ssthen 93933707f3Ssthen /* needs our redblack tree */ 94933707f3Ssthen #include "rbtree.h" 95933707f3Ssthen 96933707f3Ssthen /** max number of file descriptors to support */ 97933707f3Ssthen #define MAX_FDS 1024 98933707f3Ssthen /** max number of signals to support */ 99933707f3Ssthen #define MAX_SIG 32 100933707f3Ssthen 101933707f3Ssthen /** event base */ 102933707f3Ssthen struct event_base 103933707f3Ssthen { 104933707f3Ssthen /** sorted by timeout (absolute), ptr */ 10577079be7Ssthen rbtree_type* times; 106933707f3Ssthen /** array of 0 - maxfd of ptr to event for it */ 107933707f3Ssthen struct event** fds; 108933707f3Ssthen /** max fd in use */ 109933707f3Ssthen int maxfd; 110933707f3Ssthen /** capacity - size of the fds array */ 111933707f3Ssthen int capfd; 112933707f3Ssthen /* fdset for read write, for fds ready, and added */ 113933707f3Ssthen fd_set 114933707f3Ssthen /** fds for reading */ 115933707f3Ssthen reads, 116933707f3Ssthen /** fds for writing */ 117933707f3Ssthen writes, 118933707f3Ssthen /** fds determined ready for use */ 119933707f3Ssthen ready, 120933707f3Ssthen /** ready plus newly added events. */ 121933707f3Ssthen content; 122933707f3Ssthen /** array of 0 - maxsig of ptr to event for it */ 123933707f3Ssthen struct event** signals; 124933707f3Ssthen /** if we need to exit */ 125933707f3Ssthen int need_to_exit; 126933707f3Ssthen /** where to store time in seconds */ 127229e174cSsthen time_t* time_secs; 128933707f3Ssthen /** where to store time in microseconds */ 129933707f3Ssthen struct timeval* time_tv; 130933707f3Ssthen }; 131933707f3Ssthen 132933707f3Ssthen /** 133933707f3Ssthen * Event structure. Has some of the event elements. 134933707f3Ssthen */ 135933707f3Ssthen struct event { 136933707f3Ssthen /** node in timeout rbtree */ 13777079be7Ssthen rbnode_type node; 138933707f3Ssthen /** is event already added */ 139933707f3Ssthen int added; 140933707f3Ssthen 141933707f3Ssthen /** event base it belongs to */ 142933707f3Ssthen struct event_base *ev_base; 143933707f3Ssthen /** fd to poll or -1 for timeouts. signal number for sigs. */ 144933707f3Ssthen int ev_fd; 145933707f3Ssthen /** what events this event is interested in, see EV_.. above. */ 146933707f3Ssthen short ev_events; 147933707f3Ssthen /** timeout value */ 148933707f3Ssthen struct timeval ev_timeout; 149933707f3Ssthen 150933707f3Ssthen /** callback to call: fd, eventbits, userarg */ 151933707f3Ssthen void (*ev_callback)(int, short, void *arg); 152933707f3Ssthen /** callback user arg */ 153933707f3Ssthen void *ev_arg; 154933707f3Ssthen }; 155933707f3Ssthen 156933707f3Ssthen /* function prototypes (some are as they appear in event.h) */ 157933707f3Ssthen /** create event base */ 158229e174cSsthen void *event_init(time_t* time_secs, struct timeval* time_tv); 159933707f3Ssthen /** get version */ 160933707f3Ssthen const char *event_get_version(void); 161933707f3Ssthen /** get polling method, select */ 162933707f3Ssthen const char *event_get_method(void); 163933707f3Ssthen /** run select in a loop */ 164933707f3Ssthen int event_base_dispatch(struct event_base *); 165933707f3Ssthen /** exit that loop */ 166933707f3Ssthen int event_base_loopexit(struct event_base *, struct timeval *); 167933707f3Ssthen /** free event base. Free events yourself */ 168933707f3Ssthen void event_base_free(struct event_base *); 169933707f3Ssthen /** set content of event */ 170933707f3Ssthen void event_set(struct event *, int, short, void (*)(int, short, void *), void *); 171933707f3Ssthen /** add event to a base. You *must* call this for every event. */ 172933707f3Ssthen int event_base_set(struct event_base *, struct event *); 173933707f3Ssthen /** add event to make it active. You may not change it with event_set anymore */ 174933707f3Ssthen int event_add(struct event *, struct timeval *); 175933707f3Ssthen /** remove event. You may change it again */ 176933707f3Ssthen int event_del(struct event *); 177933707f3Ssthen 178933707f3Ssthen /** add a timer */ 179933707f3Ssthen #define evtimer_add(ev, tv) event_add(ev, tv) 180933707f3Ssthen /** remove a timer */ 181933707f3Ssthen #define evtimer_del(ev) event_del(ev) 182933707f3Ssthen 183933707f3Ssthen /* uses different implementation. Cannot mix fd/timeouts and signals inside 184933707f3Ssthen * the same struct event. create several event structs for that. */ 185933707f3Ssthen /** install signal handler */ 186933707f3Ssthen int signal_add(struct event *, struct timeval *); 187933707f3Ssthen /** set signal event contents */ 188933707f3Ssthen #define signal_set(ev, x, cb, arg) \ 189933707f3Ssthen event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) 190933707f3Ssthen /** remove signal handler */ 191933707f3Ssthen int signal_del(struct event *); 192933707f3Ssthen 193933707f3Ssthen #endif /* USE_MINI_EVENT and not USE_WINSOCK */ 194933707f3Ssthen 195933707f3Ssthen /** compare events in tree, based on timevalue, ptr for uniqueness */ 196933707f3Ssthen int mini_ev_cmp(const void* a, const void* b); 197933707f3Ssthen 198933707f3Ssthen #endif /* MINI_EVENT_H */ 199