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