1238106Sdes/* 2238106Sdes * mini-event.h - micro implementation of libevent api, using select() only. 3238106Sdes * 4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24266114Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25266114Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26266114Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27266114Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28266114Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29266114Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30266114Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31266114Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32266114Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33266114Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * This file implements part of the event(3) libevent api. 39238106Sdes * The back end is only select. Max number of fds is limited. 40238106Sdes * Max number of signals is limited, one handler per signal only. 41238106Sdes * And one handler per fd. 42238106Sdes * 43238106Sdes * Although limited to select() and a max (1024) open fds, it 44238106Sdes * is efficient: 45238106Sdes * o dispatch call caches fd_sets to use. 46238106Sdes * o handler calling takes time ~ to the number of fds. 47238106Sdes * o timeouts are stored in a redblack tree, sorted, so take log(n). 48238106Sdes * Timeouts are only accurate to the second (no subsecond accuracy). 49238106Sdes * To avoid cpu hogging, fractional timeouts are rounded up to a whole second. 50238106Sdes */ 51238106Sdes 52238106Sdes#ifndef MINI_EVENT_H 53238106Sdes#define MINI_EVENT_H 54238106Sdes 55238106Sdes#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK) 56238106Sdes 57238106Sdes#ifndef HAVE_EVENT_BASE_FREE 58238106Sdes#define HAVE_EVENT_BASE_FREE 59238106Sdes#endif 60238106Sdes 61276605Sdes/* redefine to use our own namespace so that on platforms where 62276605Sdes * linkers crosslink library-private symbols with other symbols, it works */ 63276605Sdes#define event_init minievent_init 64276605Sdes#define event_get_version minievent_get_version 65276605Sdes#define event_get_method minievent_get_method 66276605Sdes#define event_base_dispatch minievent_base_dispatch 67276605Sdes#define event_base_loopexit minievent_base_loopexit 68276605Sdes#define event_base_free minievent_base_free 69276605Sdes#define event_set minievent_set 70276605Sdes#define event_base_set minievent_base_set 71276605Sdes#define event_add minievent_add 72276605Sdes#define event_del minievent_del 73276605Sdes#define signal_add minisignal_add 74276605Sdes#define signal_del minisignal_del 75276605Sdes 76238106Sdes/** event timeout */ 77238106Sdes#define EV_TIMEOUT 0x01 78238106Sdes/** event fd readable */ 79238106Sdes#define EV_READ 0x02 80238106Sdes/** event fd writable */ 81238106Sdes#define EV_WRITE 0x04 82238106Sdes/** event signal */ 83238106Sdes#define EV_SIGNAL 0x08 84238106Sdes/** event must persist */ 85238106Sdes#define EV_PERSIST 0x10 86238106Sdes 87238106Sdes/* needs our redblack tree */ 88238106Sdes#include "rbtree.h" 89238106Sdes 90238106Sdes/** max number of file descriptors to support */ 91238106Sdes#define MAX_FDS 1024 92238106Sdes/** max number of signals to support */ 93238106Sdes#define MAX_SIG 32 94238106Sdes 95238106Sdes/** event base */ 96238106Sdesstruct event_base 97238106Sdes{ 98238106Sdes /** sorted by timeout (absolute), ptr */ 99238106Sdes rbtree_t* times; 100238106Sdes /** array of 0 - maxfd of ptr to event for it */ 101238106Sdes struct event** fds; 102238106Sdes /** max fd in use */ 103238106Sdes int maxfd; 104238106Sdes /** capacity - size of the fds array */ 105238106Sdes int capfd; 106238106Sdes /* fdset for read write, for fds ready, and added */ 107238106Sdes fd_set 108238106Sdes /** fds for reading */ 109238106Sdes reads, 110238106Sdes /** fds for writing */ 111238106Sdes writes, 112238106Sdes /** fds determined ready for use */ 113238106Sdes ready, 114238106Sdes /** ready plus newly added events. */ 115238106Sdes content; 116238106Sdes /** array of 0 - maxsig of ptr to event for it */ 117238106Sdes struct event** signals; 118238106Sdes /** if we need to exit */ 119238106Sdes int need_to_exit; 120238106Sdes /** where to store time in seconds */ 121266114Sdes time_t* time_secs; 122238106Sdes /** where to store time in microseconds */ 123238106Sdes struct timeval* time_tv; 124238106Sdes}; 125238106Sdes 126238106Sdes/** 127238106Sdes * Event structure. Has some of the event elements. 128238106Sdes */ 129238106Sdesstruct event { 130238106Sdes /** node in timeout rbtree */ 131238106Sdes rbnode_t node; 132238106Sdes /** is event already added */ 133238106Sdes int added; 134238106Sdes 135238106Sdes /** event base it belongs to */ 136238106Sdes struct event_base *ev_base; 137238106Sdes /** fd to poll or -1 for timeouts. signal number for sigs. */ 138238106Sdes int ev_fd; 139238106Sdes /** what events this event is interested in, see EV_.. above. */ 140238106Sdes short ev_events; 141238106Sdes /** timeout value */ 142238106Sdes struct timeval ev_timeout; 143238106Sdes 144238106Sdes /** callback to call: fd, eventbits, userarg */ 145238106Sdes void (*ev_callback)(int, short, void *arg); 146238106Sdes /** callback user arg */ 147238106Sdes void *ev_arg; 148238106Sdes}; 149238106Sdes 150238106Sdes/* function prototypes (some are as they appear in event.h) */ 151238106Sdes/** create event base */ 152266114Sdesvoid *event_init(time_t* time_secs, struct timeval* time_tv); 153238106Sdes/** get version */ 154238106Sdesconst char *event_get_version(void); 155238106Sdes/** get polling method, select */ 156238106Sdesconst char *event_get_method(void); 157238106Sdes/** run select in a loop */ 158238106Sdesint event_base_dispatch(struct event_base *); 159238106Sdes/** exit that loop */ 160238106Sdesint event_base_loopexit(struct event_base *, struct timeval *); 161238106Sdes/** free event base. Free events yourself */ 162238106Sdesvoid event_base_free(struct event_base *); 163238106Sdes/** set content of event */ 164238106Sdesvoid event_set(struct event *, int, short, void (*)(int, short, void *), void *); 165238106Sdes/** add event to a base. You *must* call this for every event. */ 166238106Sdesint event_base_set(struct event_base *, struct event *); 167238106Sdes/** add event to make it active. You may not change it with event_set anymore */ 168238106Sdesint event_add(struct event *, struct timeval *); 169238106Sdes/** remove event. You may change it again */ 170238106Sdesint event_del(struct event *); 171238106Sdes 172238106Sdes/** add a timer */ 173238106Sdes#define evtimer_add(ev, tv) event_add(ev, tv) 174238106Sdes/** remove a timer */ 175238106Sdes#define evtimer_del(ev) event_del(ev) 176238106Sdes 177238106Sdes/* uses different implementation. Cannot mix fd/timeouts and signals inside 178238106Sdes * the same struct event. create several event structs for that. */ 179238106Sdes/** install signal handler */ 180238106Sdesint signal_add(struct event *, struct timeval *); 181238106Sdes/** set signal event contents */ 182238106Sdes#define signal_set(ev, x, cb, arg) \ 183238106Sdes event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) 184238106Sdes/** remove signal handler */ 185238106Sdesint signal_del(struct event *); 186238106Sdes 187238106Sdes#endif /* USE_MINI_EVENT and not USE_WINSOCK */ 188238106Sdes 189238106Sdes/** compare events in tree, based on timevalue, ptr for uniqueness */ 190238106Sdesint mini_ev_cmp(const void* a, const void* b); 191238106Sdes 192238106Sdes#endif /* MINI_EVENT_H */ 193