1ae8c6e27Sflorian /* 2ae8c6e27Sflorian * mini-event.h - micro implementation of libevent api, using select() only. 3ae8c6e27Sflorian * 4ae8c6e27Sflorian * Copyright (c) 2007, NLnet Labs. All rights reserved. 5ae8c6e27Sflorian * 6ae8c6e27Sflorian * This software is open source. 7ae8c6e27Sflorian * 8ae8c6e27Sflorian * Redistribution and use in source and binary forms, with or without 9ae8c6e27Sflorian * modification, are permitted provided that the following conditions 10ae8c6e27Sflorian * are met: 11ae8c6e27Sflorian * 12ae8c6e27Sflorian * Redistributions of source code must retain the above copyright notice, 13ae8c6e27Sflorian * this list of conditions and the following disclaimer. 14ae8c6e27Sflorian * 15ae8c6e27Sflorian * Redistributions in binary form must reproduce the above copyright notice, 16ae8c6e27Sflorian * this list of conditions and the following disclaimer in the documentation 17ae8c6e27Sflorian * and/or other materials provided with the distribution. 18ae8c6e27Sflorian * 19ae8c6e27Sflorian * Neither the name of the NLNET LABS nor the names of its contributors may 20ae8c6e27Sflorian * be used to endorse or promote products derived from this software without 21ae8c6e27Sflorian * specific prior written permission. 22ae8c6e27Sflorian * 23ae8c6e27Sflorian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24ae8c6e27Sflorian * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25ae8c6e27Sflorian * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26ae8c6e27Sflorian * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27ae8c6e27Sflorian * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28ae8c6e27Sflorian * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29ae8c6e27Sflorian * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30ae8c6e27Sflorian * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31ae8c6e27Sflorian * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32ae8c6e27Sflorian * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33ae8c6e27Sflorian * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34ae8c6e27Sflorian */ 35ae8c6e27Sflorian 36ae8c6e27Sflorian /** 37ae8c6e27Sflorian * \file 38ae8c6e27Sflorian * This file implements part of the event(3) libevent api. 39ae8c6e27Sflorian * The back end is only select. Max number of fds is limited. 40ae8c6e27Sflorian * Max number of signals is limited, one handler per signal only. 41ae8c6e27Sflorian * And one handler per fd. 42ae8c6e27Sflorian * 43ae8c6e27Sflorian * Although limited to select() and a max (1024) open fds, it 44ae8c6e27Sflorian * is efficient: 45ae8c6e27Sflorian * o dispatch call caches fd_sets to use. 46ae8c6e27Sflorian * o handler calling takes time ~ to the number of fds. 47ae8c6e27Sflorian * o timeouts are stored in a redblack tree, sorted, so take log(n). 48ae8c6e27Sflorian * Timeouts are only accurate to the second (no subsecond accuracy). 49ae8c6e27Sflorian * To avoid cpu hogging, fractional timeouts are rounded up to a whole second. 50ae8c6e27Sflorian */ 51ae8c6e27Sflorian 52ae8c6e27Sflorian #ifndef MINI_EVENT_H 53ae8c6e27Sflorian #define MINI_EVENT_H 54ae8c6e27Sflorian 55ae8c6e27Sflorian #if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK) 56ae8c6e27Sflorian 57*f4f0f0ceSflorian #ifdef HAVE_SYS_SELECT_H 58*f4f0f0ceSflorian /* for fd_set on OpenBSD */ 59*f4f0f0ceSflorian #include <sys/select.h> 60*f4f0f0ceSflorian #endif 61e47fef9eSflorian #include <sys/time.h> 62e47fef9eSflorian 63ae8c6e27Sflorian #ifndef HAVE_EVENT_BASE_FREE 64ae8c6e27Sflorian #define HAVE_EVENT_BASE_FREE 65ae8c6e27Sflorian #endif 66ae8c6e27Sflorian 67ae8c6e27Sflorian /* redefine to use our own namespace so that on platforms where 68ae8c6e27Sflorian * linkers crosslink library-private symbols with other symbols, it works */ 69ae8c6e27Sflorian #define event_init minievent_init 70ae8c6e27Sflorian #define event_get_version minievent_get_version 71ae8c6e27Sflorian #define event_get_method minievent_get_method 72ae8c6e27Sflorian #define event_base_dispatch minievent_base_dispatch 73ae8c6e27Sflorian #define event_base_loopexit minievent_base_loopexit 74ae8c6e27Sflorian #define event_base_free minievent_base_free 75ae8c6e27Sflorian #define event_set minievent_set 76ae8c6e27Sflorian #define event_base_set minievent_base_set 77ae8c6e27Sflorian #define event_add minievent_add 78ae8c6e27Sflorian #define event_del minievent_del 79ae8c6e27Sflorian #define signal_add minisignal_add 80ae8c6e27Sflorian #define signal_del minisignal_del 81ae8c6e27Sflorian 82ae8c6e27Sflorian /** event timeout */ 83ae8c6e27Sflorian #define EV_TIMEOUT 0x01 84ae8c6e27Sflorian /** event fd readable */ 85ae8c6e27Sflorian #define EV_READ 0x02 86ae8c6e27Sflorian /** event fd writable */ 87ae8c6e27Sflorian #define EV_WRITE 0x04 88ae8c6e27Sflorian /** event signal */ 89ae8c6e27Sflorian #define EV_SIGNAL 0x08 90ae8c6e27Sflorian /** event must persist */ 91ae8c6e27Sflorian #define EV_PERSIST 0x10 92ae8c6e27Sflorian 93ae8c6e27Sflorian /* needs our redblack tree */ 94ae8c6e27Sflorian #include "rbtree.h" 95ae8c6e27Sflorian 96ae8c6e27Sflorian /** max number of file descriptors to support */ 97ae8c6e27Sflorian #define MAX_FDS 1024 98ae8c6e27Sflorian /** max number of signals to support */ 99ae8c6e27Sflorian #define MAX_SIG 32 100ae8c6e27Sflorian 101ae8c6e27Sflorian /** event base */ 102ae8c6e27Sflorian struct event_base 103ae8c6e27Sflorian { 104ae8c6e27Sflorian /** sorted by timeout (absolute), ptr */ 105ae8c6e27Sflorian rbtree_type* times; 106ae8c6e27Sflorian /** array of 0 - maxfd of ptr to event for it */ 107ae8c6e27Sflorian struct event** fds; 108ae8c6e27Sflorian /** max fd in use */ 109ae8c6e27Sflorian int maxfd; 110ae8c6e27Sflorian /** capacity - size of the fds array */ 111ae8c6e27Sflorian int capfd; 112ae8c6e27Sflorian /* fdset for read write, for fds ready, and added */ 113ae8c6e27Sflorian fd_set 114ae8c6e27Sflorian /** fds for reading */ 115ae8c6e27Sflorian reads, 116ae8c6e27Sflorian /** fds for writing */ 117ae8c6e27Sflorian writes, 118ae8c6e27Sflorian /** fds determined ready for use */ 119ae8c6e27Sflorian ready, 120ae8c6e27Sflorian /** ready plus newly added events. */ 121ae8c6e27Sflorian content; 122ae8c6e27Sflorian /** array of 0 - maxsig of ptr to event for it */ 123ae8c6e27Sflorian struct event** signals; 124ae8c6e27Sflorian /** if we need to exit */ 125ae8c6e27Sflorian int need_to_exit; 126ae8c6e27Sflorian /** where to store time in seconds */ 127ae8c6e27Sflorian time_t* time_secs; 128ae8c6e27Sflorian /** where to store time in microseconds */ 129ae8c6e27Sflorian struct timeval* time_tv; 130ae8c6e27Sflorian }; 131ae8c6e27Sflorian 132ae8c6e27Sflorian /** 133ae8c6e27Sflorian * Event structure. Has some of the event elements. 134ae8c6e27Sflorian */ 135ae8c6e27Sflorian struct event { 136ae8c6e27Sflorian /** node in timeout rbtree */ 137ae8c6e27Sflorian rbnode_type node; 138ae8c6e27Sflorian /** is event already added */ 139ae8c6e27Sflorian int added; 140ae8c6e27Sflorian 141ae8c6e27Sflorian /** event base it belongs to */ 142ae8c6e27Sflorian struct event_base *ev_base; 143ae8c6e27Sflorian /** fd to poll or -1 for timeouts. signal number for sigs. */ 144ae8c6e27Sflorian int ev_fd; 145ae8c6e27Sflorian /** what events this event is interested in, see EV_.. above. */ 146ae8c6e27Sflorian short ev_events; 147ae8c6e27Sflorian /** timeout value */ 148ae8c6e27Sflorian struct timeval ev_timeout; 149ae8c6e27Sflorian 150ae8c6e27Sflorian /** callback to call: fd, eventbits, userarg */ 151ae8c6e27Sflorian void (*ev_callback)(int, short, void *arg); 152ae8c6e27Sflorian /** callback user arg */ 153ae8c6e27Sflorian void *ev_arg; 154ae8c6e27Sflorian }; 155ae8c6e27Sflorian 156ae8c6e27Sflorian /* function prototypes (some are as they appear in event.h) */ 157ae8c6e27Sflorian /** create event base */ 158ae8c6e27Sflorian void *event_init(time_t* time_secs, struct timeval* time_tv); 159ae8c6e27Sflorian /** get version */ 160ae8c6e27Sflorian const char *event_get_version(void); 161ae8c6e27Sflorian /** get polling method, select */ 162ae8c6e27Sflorian const char *event_get_method(void); 163ae8c6e27Sflorian /** run select in a loop */ 164ae8c6e27Sflorian int event_base_dispatch(struct event_base *); 165ae8c6e27Sflorian /** exit that loop */ 166ae8c6e27Sflorian int event_base_loopexit(struct event_base *, struct timeval *); 167ae8c6e27Sflorian /** free event base. Free events yourself */ 168ae8c6e27Sflorian void event_base_free(struct event_base *); 169ae8c6e27Sflorian /** set content of event */ 170ae8c6e27Sflorian void event_set(struct event *, int, short, void (*)(int, short, void *), void *); 171ae8c6e27Sflorian /** add event to a base. You *must* call this for every event. */ 172ae8c6e27Sflorian int event_base_set(struct event_base *, struct event *); 173ae8c6e27Sflorian /** add event to make it active. You may not change it with event_set anymore */ 174ae8c6e27Sflorian int event_add(struct event *, struct timeval *); 175ae8c6e27Sflorian /** remove event. You may change it again */ 176ae8c6e27Sflorian int event_del(struct event *); 177ae8c6e27Sflorian 178ae8c6e27Sflorian /** add a timer */ 179ae8c6e27Sflorian #define evtimer_add(ev, tv) event_add(ev, tv) 180ae8c6e27Sflorian /** remove a timer */ 181ae8c6e27Sflorian #define evtimer_del(ev) event_del(ev) 182ae8c6e27Sflorian 183ae8c6e27Sflorian /* uses different implementation. Cannot mix fd/timeouts and signals inside 184ae8c6e27Sflorian * the same struct event. create several event structs for that. */ 185ae8c6e27Sflorian /** install signal handler */ 186ae8c6e27Sflorian int signal_add(struct event *, struct timeval *); 187ae8c6e27Sflorian /** set signal event contents */ 188ae8c6e27Sflorian #define signal_set(ev, x, cb, arg) \ 189ae8c6e27Sflorian event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) 190ae8c6e27Sflorian /** remove signal handler */ 191ae8c6e27Sflorian int signal_del(struct event *); 192ae8c6e27Sflorian 193ae8c6e27Sflorian #endif /* USE_MINI_EVENT and not USE_WINSOCK */ 194ae8c6e27Sflorian 195ae8c6e27Sflorian /** compare events in tree, based on timevalue, ptr for uniqueness */ 196ae8c6e27Sflorian int mini_ev_cmp(const void* a, const void* b); 197ae8c6e27Sflorian 198ae8c6e27Sflorian #endif /* MINI_EVENT_H */ 199