xref: /openbsd-src/sbin/unwind/libunbound/util/mini_event.h (revision f4f0f0ce53ba055713381fcb2c94fe46f8380a1e)
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