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 57933707f3Ssthen #ifndef HAVE_EVENT_BASE_FREE 58933707f3Ssthen #define HAVE_EVENT_BASE_FREE 59933707f3Ssthen #endif 60933707f3Ssthen 6198f3ca02Sbrad /* redefine to use our own namespace so that on platforms where 6298f3ca02Sbrad * linkers crosslink library-private symbols with other symbols, it works */ 6398f3ca02Sbrad #define event_init minievent_init 6498f3ca02Sbrad #define event_get_version minievent_get_version 6598f3ca02Sbrad #define event_get_method minievent_get_method 6698f3ca02Sbrad #define event_base_dispatch minievent_base_dispatch 6798f3ca02Sbrad #define event_base_loopexit minievent_base_loopexit 6898f3ca02Sbrad #define event_base_free minievent_base_free 6998f3ca02Sbrad #define event_set minievent_set 7098f3ca02Sbrad #define event_base_set minievent_base_set 7198f3ca02Sbrad #define event_add minievent_add 7298f3ca02Sbrad #define event_del minievent_del 7398f3ca02Sbrad #define signal_add minisignal_add 7498f3ca02Sbrad #define signal_del minisignal_del 7598f3ca02Sbrad 76933707f3Ssthen /** event timeout */ 77933707f3Ssthen #define EV_TIMEOUT 0x01 78933707f3Ssthen /** event fd readable */ 79933707f3Ssthen #define EV_READ 0x02 80933707f3Ssthen /** event fd writable */ 81933707f3Ssthen #define EV_WRITE 0x04 82933707f3Ssthen /** event signal */ 83933707f3Ssthen #define EV_SIGNAL 0x08 84933707f3Ssthen /** event must persist */ 85933707f3Ssthen #define EV_PERSIST 0x10 86933707f3Ssthen 87933707f3Ssthen /* needs our redblack tree */ 88933707f3Ssthen #include "rbtree.h" 89933707f3Ssthen 90933707f3Ssthen /** max number of file descriptors to support */ 91933707f3Ssthen #define MAX_FDS 1024 92933707f3Ssthen /** max number of signals to support */ 93933707f3Ssthen #define MAX_SIG 32 94933707f3Ssthen 95933707f3Ssthen /** event base */ 96933707f3Ssthen struct event_base 97933707f3Ssthen { 98933707f3Ssthen /** sorted by timeout (absolute), ptr */ 99*77079be7Ssthen rbtree_type* times; 100933707f3Ssthen /** array of 0 - maxfd of ptr to event for it */ 101933707f3Ssthen struct event** fds; 102933707f3Ssthen /** max fd in use */ 103933707f3Ssthen int maxfd; 104933707f3Ssthen /** capacity - size of the fds array */ 105933707f3Ssthen int capfd; 106933707f3Ssthen /* fdset for read write, for fds ready, and added */ 107933707f3Ssthen fd_set 108933707f3Ssthen /** fds for reading */ 109933707f3Ssthen reads, 110933707f3Ssthen /** fds for writing */ 111933707f3Ssthen writes, 112933707f3Ssthen /** fds determined ready for use */ 113933707f3Ssthen ready, 114933707f3Ssthen /** ready plus newly added events. */ 115933707f3Ssthen content; 116933707f3Ssthen /** array of 0 - maxsig of ptr to event for it */ 117933707f3Ssthen struct event** signals; 118933707f3Ssthen /** if we need to exit */ 119933707f3Ssthen int need_to_exit; 120933707f3Ssthen /** where to store time in seconds */ 121229e174cSsthen time_t* time_secs; 122933707f3Ssthen /** where to store time in microseconds */ 123933707f3Ssthen struct timeval* time_tv; 124933707f3Ssthen }; 125933707f3Ssthen 126933707f3Ssthen /** 127933707f3Ssthen * Event structure. Has some of the event elements. 128933707f3Ssthen */ 129933707f3Ssthen struct event { 130933707f3Ssthen /** node in timeout rbtree */ 131*77079be7Ssthen rbnode_type node; 132933707f3Ssthen /** is event already added */ 133933707f3Ssthen int added; 134933707f3Ssthen 135933707f3Ssthen /** event base it belongs to */ 136933707f3Ssthen struct event_base *ev_base; 137933707f3Ssthen /** fd to poll or -1 for timeouts. signal number for sigs. */ 138933707f3Ssthen int ev_fd; 139933707f3Ssthen /** what events this event is interested in, see EV_.. above. */ 140933707f3Ssthen short ev_events; 141933707f3Ssthen /** timeout value */ 142933707f3Ssthen struct timeval ev_timeout; 143933707f3Ssthen 144933707f3Ssthen /** callback to call: fd, eventbits, userarg */ 145933707f3Ssthen void (*ev_callback)(int, short, void *arg); 146933707f3Ssthen /** callback user arg */ 147933707f3Ssthen void *ev_arg; 148933707f3Ssthen }; 149933707f3Ssthen 150933707f3Ssthen /* function prototypes (some are as they appear in event.h) */ 151933707f3Ssthen /** create event base */ 152229e174cSsthen void *event_init(time_t* time_secs, struct timeval* time_tv); 153933707f3Ssthen /** get version */ 154933707f3Ssthen const char *event_get_version(void); 155933707f3Ssthen /** get polling method, select */ 156933707f3Ssthen const char *event_get_method(void); 157933707f3Ssthen /** run select in a loop */ 158933707f3Ssthen int event_base_dispatch(struct event_base *); 159933707f3Ssthen /** exit that loop */ 160933707f3Ssthen int event_base_loopexit(struct event_base *, struct timeval *); 161933707f3Ssthen /** free event base. Free events yourself */ 162933707f3Ssthen void event_base_free(struct event_base *); 163933707f3Ssthen /** set content of event */ 164933707f3Ssthen void event_set(struct event *, int, short, void (*)(int, short, void *), void *); 165933707f3Ssthen /** add event to a base. You *must* call this for every event. */ 166933707f3Ssthen int event_base_set(struct event_base *, struct event *); 167933707f3Ssthen /** add event to make it active. You may not change it with event_set anymore */ 168933707f3Ssthen int event_add(struct event *, struct timeval *); 169933707f3Ssthen /** remove event. You may change it again */ 170933707f3Ssthen int event_del(struct event *); 171933707f3Ssthen 172933707f3Ssthen /** add a timer */ 173933707f3Ssthen #define evtimer_add(ev, tv) event_add(ev, tv) 174933707f3Ssthen /** remove a timer */ 175933707f3Ssthen #define evtimer_del(ev) event_del(ev) 176933707f3Ssthen 177933707f3Ssthen /* uses different implementation. Cannot mix fd/timeouts and signals inside 178933707f3Ssthen * the same struct event. create several event structs for that. */ 179933707f3Ssthen /** install signal handler */ 180933707f3Ssthen int signal_add(struct event *, struct timeval *); 181933707f3Ssthen /** set signal event contents */ 182933707f3Ssthen #define signal_set(ev, x, cb, arg) \ 183933707f3Ssthen event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) 184933707f3Ssthen /** remove signal handler */ 185933707f3Ssthen int signal_del(struct event *); 186933707f3Ssthen 187933707f3Ssthen #endif /* USE_MINI_EVENT and not USE_WINSOCK */ 188933707f3Ssthen 189933707f3Ssthen /** compare events in tree, based on timevalue, ptr for uniqueness */ 190933707f3Ssthen int mini_ev_cmp(const void* a, const void* b); 191933707f3Ssthen 192933707f3Ssthen #endif /* MINI_EVENT_H */ 193