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