xref: /openbsd-src/usr.sbin/nsd/mini_event.c (revision 3f21e8cc40aa89506971c1c4154dcba359c18fc3)
1d3fecca9Ssthen /*
2d3fecca9Ssthen  * mini_event.c - implementation of part of libevent api, portably.
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 /**
38d3fecca9Ssthen  * \file
39d3fecca9Ssthen  * fake libevent implementation. Less broad in functionality, and only
40d3fecca9Ssthen  * supports select(2).
41d3fecca9Ssthen  */
42d3fecca9Ssthen 
43d3fecca9Ssthen #include "config.h"
44d3fecca9Ssthen #ifdef HAVE_TIME_H
45d3fecca9Ssthen #include <time.h>
46d3fecca9Ssthen #endif
47d3fecca9Ssthen #include <string.h>
48d3fecca9Ssthen #include <errno.h>
49d3fecca9Ssthen #include <sys/time.h>
50d3fecca9Ssthen 
51d3fecca9Ssthen #if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
52d3fecca9Ssthen #ifdef HAVE_WINSOCK2_H
53d3fecca9Ssthen #define FD_SET_T (u_int)
54d3fecca9Ssthen #else
55d3fecca9Ssthen #define FD_SET_T
56d3fecca9Ssthen #endif
57d3fecca9Ssthen 
58d3fecca9Ssthen #include <signal.h>
59d3fecca9Ssthen #include "mini_event.h"
60d3fecca9Ssthen #include "util.h"
61d3fecca9Ssthen 
62d3fecca9Ssthen /** compare events in tree, based on timevalue, ptr for uniqueness */
63d3fecca9Ssthen int
mini_ev_cmp(const void * a,const void * b)64d3fecca9Ssthen mini_ev_cmp(const void* a, const void* b)
65d3fecca9Ssthen {
66d3fecca9Ssthen 	const struct event* e = (const struct event*)a;
67d3fecca9Ssthen 	const struct event* f = (const struct event*)b;
68d3fecca9Ssthen 	if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
69d3fecca9Ssthen 		return -1;
70d3fecca9Ssthen 	if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
71d3fecca9Ssthen 		return 1;
72d3fecca9Ssthen 	if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
73d3fecca9Ssthen 		return -1;
74d3fecca9Ssthen 	if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
75d3fecca9Ssthen 		return 1;
76d3fecca9Ssthen 	if(e < f)
77d3fecca9Ssthen 		return -1;
78d3fecca9Ssthen 	if(e > f)
79d3fecca9Ssthen 		return 1;
80d3fecca9Ssthen 	return 0;
81d3fecca9Ssthen }
82d3fecca9Ssthen 
83d3fecca9Ssthen /** set time */
84d3fecca9Ssthen static int
settime(struct event_base * base)85d3fecca9Ssthen settime(struct event_base* base)
86d3fecca9Ssthen {
87d3fecca9Ssthen 	if(gettimeofday(base->time_tv, NULL) < 0) {
88d3fecca9Ssthen 		return -1;
89d3fecca9Ssthen 	}
90d3fecca9Ssthen #ifndef S_SPLINT_S
91d3fecca9Ssthen 	*base->time_secs = (time_t)base->time_tv->tv_sec;
92d3fecca9Ssthen #endif
93d3fecca9Ssthen 	return 0;
94d3fecca9Ssthen }
95d3fecca9Ssthen 
96d3fecca9Ssthen /** create event base */
97d3fecca9Ssthen void *
event_init(time_t * time_secs,struct timeval * time_tv)98d3fecca9Ssthen event_init(time_t* time_secs, struct timeval* time_tv)
99d3fecca9Ssthen {
100d3fecca9Ssthen 	struct event_base* base = (struct event_base*)malloc(
101d3fecca9Ssthen 		sizeof(struct event_base));
102d3fecca9Ssthen 	if(!base)
103d3fecca9Ssthen 		return NULL;
104d3fecca9Ssthen 	memset(base, 0, sizeof(*base));
105d3fecca9Ssthen 	base->region = region_create(xalloc, free);
106d3fecca9Ssthen 	if(!base->region) {
107d3fecca9Ssthen 		free(base);
108d3fecca9Ssthen 		return NULL;
109d3fecca9Ssthen 	}
110d3fecca9Ssthen 	base->time_secs = time_secs;
111d3fecca9Ssthen 	base->time_tv = time_tv;
112d3fecca9Ssthen 	if(settime(base) < 0) {
113d3fecca9Ssthen 		event_base_free(base);
114d3fecca9Ssthen 		return NULL;
115d3fecca9Ssthen 	}
116d3fecca9Ssthen 	base->times = rbtree_create(base->region, mini_ev_cmp);
117d3fecca9Ssthen 	if(!base->times) {
118d3fecca9Ssthen 		event_base_free(base);
119d3fecca9Ssthen 		return NULL;
120d3fecca9Ssthen 	}
121d3fecca9Ssthen 	base->capfd = MAX_FDS;
122d3fecca9Ssthen #ifdef FD_SETSIZE
123d3fecca9Ssthen 	if((int)FD_SETSIZE < base->capfd)
124d3fecca9Ssthen 		base->capfd = (int)FD_SETSIZE;
125d3fecca9Ssthen #endif
126d3fecca9Ssthen 	base->fds = (struct event**)calloc((size_t)base->capfd,
127d3fecca9Ssthen 		sizeof(struct event*));
128d3fecca9Ssthen 	if(!base->fds) {
129d3fecca9Ssthen 		event_base_free(base);
130d3fecca9Ssthen 		return NULL;
131d3fecca9Ssthen 	}
132d3fecca9Ssthen 	base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*));
133d3fecca9Ssthen 	if(!base->signals) {
134d3fecca9Ssthen 		event_base_free(base);
135d3fecca9Ssthen 		return NULL;
136d3fecca9Ssthen 	}
137d3fecca9Ssthen #ifndef S_SPLINT_S
138d3fecca9Ssthen 	FD_ZERO(&base->reads);
139d3fecca9Ssthen 	FD_ZERO(&base->writes);
140d3fecca9Ssthen #endif
141d3fecca9Ssthen 	return base;
142d3fecca9Ssthen }
143d3fecca9Ssthen 
144d3fecca9Ssthen /** get version */
145d3fecca9Ssthen const char *
event_get_version(void)146d3fecca9Ssthen event_get_version(void)
147d3fecca9Ssthen {
148d3fecca9Ssthen 	return "mini-event-"PACKAGE_VERSION;
149d3fecca9Ssthen }
150d3fecca9Ssthen 
151d3fecca9Ssthen /** get polling method, select */
152d3fecca9Ssthen const char *
event_get_method(void)153d3fecca9Ssthen event_get_method(void)
154d3fecca9Ssthen {
155d3fecca9Ssthen 	return "select";
156d3fecca9Ssthen }
157d3fecca9Ssthen 
158d3fecca9Ssthen /** call timeouts handlers, and return how long to wait for next one or -1 */
159d3fecca9Ssthen static int
handle_timeouts(struct event_base * base,struct timeval * now,struct timeval * wait)160d3fecca9Ssthen handle_timeouts(struct event_base* base, struct timeval* now,
161d3fecca9Ssthen 	struct timeval* wait)
162d3fecca9Ssthen {
163d3fecca9Ssthen 	struct event* p;
164d3fecca9Ssthen 	int tofired = 0;
165d3fecca9Ssthen #ifndef S_SPLINT_S
166d3fecca9Ssthen 	wait->tv_sec = (time_t)-1;
167d3fecca9Ssthen #endif
168d3fecca9Ssthen 
169fe5fe5f6Sflorian 	while((rbnode_type*)(p = (struct event*)rbtree_first(base->times))
170d3fecca9Ssthen 		!=RBTREE_NULL) {
171d3fecca9Ssthen #ifndef S_SPLINT_S
172d3fecca9Ssthen 		if(p->ev_timeout.tv_sec > now->tv_sec ||
173d3fecca9Ssthen 			(p->ev_timeout.tv_sec==now->tv_sec &&
174d3fecca9Ssthen 		 	p->ev_timeout.tv_usec > now->tv_usec)) {
175d3fecca9Ssthen 			/* there is a next larger timeout. wait for it */
176d3fecca9Ssthen 			wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
177d3fecca9Ssthen 			if(now->tv_usec > p->ev_timeout.tv_usec) {
178d3fecca9Ssthen 				wait->tv_sec--;
179d3fecca9Ssthen 				wait->tv_usec = 1000000 - (now->tv_usec -
180d3fecca9Ssthen 					p->ev_timeout.tv_usec);
181d3fecca9Ssthen 			} else {
182d3fecca9Ssthen 				wait->tv_usec = p->ev_timeout.tv_usec
183d3fecca9Ssthen 					- now->tv_usec;
184d3fecca9Ssthen 			}
185d3fecca9Ssthen 			return tofired;
186d3fecca9Ssthen 		}
187d3fecca9Ssthen #endif
188d3fecca9Ssthen 		/* event times out, remove it */
189d3fecca9Ssthen 		tofired = 1;
190d3fecca9Ssthen 		(void)rbtree_delete(base->times, p);
191d3fecca9Ssthen 		p->ev_flags &= ~EV_TIMEOUT;
192d3fecca9Ssthen 		(*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
193d3fecca9Ssthen 	}
194d3fecca9Ssthen 	return tofired;
195d3fecca9Ssthen }
196d3fecca9Ssthen 
197d3fecca9Ssthen /** call select and callbacks for that */
198d3fecca9Ssthen static int
handle_select(struct event_base * base,struct timeval * wait)199d3fecca9Ssthen handle_select(struct event_base* base, struct timeval* wait)
200d3fecca9Ssthen {
201d3fecca9Ssthen 	fd_set r, w;
202d3fecca9Ssthen 	int ret, i;
203d3fecca9Ssthen 
204d3fecca9Ssthen #ifndef S_SPLINT_S
205d3fecca9Ssthen 	if(wait->tv_sec==(time_t)-1)
206d3fecca9Ssthen 		wait = NULL;
207d3fecca9Ssthen #endif
208d3fecca9Ssthen 	memmove(&r, &base->reads, sizeof(fd_set));
209d3fecca9Ssthen 	memmove(&w, &base->writes, sizeof(fd_set));
210d3fecca9Ssthen 	memmove(&base->ready, &base->content, sizeof(fd_set));
211d3fecca9Ssthen 
212d3fecca9Ssthen 	if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) {
213d3fecca9Ssthen 		ret = errno;
214d3fecca9Ssthen 		if(settime(base) < 0)
215d3fecca9Ssthen 			return -1;
216d3fecca9Ssthen 		errno = ret;
217d3fecca9Ssthen 		if(ret == EAGAIN || ret == EINTR)
218d3fecca9Ssthen 			return 0;
219d3fecca9Ssthen 		return -1;
220d3fecca9Ssthen 	}
221d3fecca9Ssthen 	if(settime(base) < 0)
222d3fecca9Ssthen 		return -1;
223d3fecca9Ssthen 
224d3fecca9Ssthen 	for(i=0; i<base->maxfd+1; i++) {
225d3fecca9Ssthen 		short bits = 0;
226d3fecca9Ssthen 		if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) {
227d3fecca9Ssthen 			continue;
228d3fecca9Ssthen 		}
229d3fecca9Ssthen 		if(FD_ISSET(i, &r)) {
230d3fecca9Ssthen 			bits |= EV_READ;
231d3fecca9Ssthen 			ret--;
232d3fecca9Ssthen 		}
233d3fecca9Ssthen 		if(FD_ISSET(i, &w)) {
234d3fecca9Ssthen 			bits |= EV_WRITE;
235d3fecca9Ssthen 			ret--;
236d3fecca9Ssthen 		}
237d3fecca9Ssthen 		bits &= base->fds[i]->ev_flags;
238d3fecca9Ssthen 		if(bits) {
239d3fecca9Ssthen 			(*base->fds[i]->ev_callback)(base->fds[i]->ev_fd,
240d3fecca9Ssthen 				bits, base->fds[i]->ev_arg);
241d3fecca9Ssthen 			if(ret==0)
242d3fecca9Ssthen 				break;
243d3fecca9Ssthen 		}
244d3fecca9Ssthen 	}
245d3fecca9Ssthen 	return 0;
246d3fecca9Ssthen }
247d3fecca9Ssthen 
248d3fecca9Ssthen /** run select once */
249d3fecca9Ssthen int
event_base_loop(struct event_base * base,int flags)250d3fecca9Ssthen event_base_loop(struct event_base* base, int flags)
251d3fecca9Ssthen {
252d3fecca9Ssthen 	struct timeval wait;
253d3fecca9Ssthen 	if(!(flags & EVLOOP_ONCE))
254d3fecca9Ssthen 		return event_base_dispatch(base);
255d3fecca9Ssthen 	/* see if timeouts need handling */
256d3fecca9Ssthen 	if(handle_timeouts(base, base->time_tv, &wait))
257d3fecca9Ssthen 		return 0; /* there were timeouts, end of loop */
258d3fecca9Ssthen 	if(base->need_to_exit)
259d3fecca9Ssthen 		return 0;
260d3fecca9Ssthen 	/* do select */
261d3fecca9Ssthen 	if(handle_select(base, &wait) < 0) {
262d3fecca9Ssthen 		if(base->need_to_exit)
263d3fecca9Ssthen 			return 0;
264d3fecca9Ssthen 		return -1;
265d3fecca9Ssthen 	}
266d3fecca9Ssthen 	return 0;
267d3fecca9Ssthen }
268d3fecca9Ssthen 
269d3fecca9Ssthen /** run select in a loop */
270d3fecca9Ssthen int
event_base_dispatch(struct event_base * base)271d3fecca9Ssthen event_base_dispatch(struct event_base* base)
272d3fecca9Ssthen {
273d3fecca9Ssthen 	struct timeval wait;
274d3fecca9Ssthen 	if(settime(base) < 0)
275d3fecca9Ssthen 		return -1;
276d3fecca9Ssthen 	while(!base->need_to_exit)
277d3fecca9Ssthen 	{
278d3fecca9Ssthen 		/* see if timeouts need handling */
279d3fecca9Ssthen 		(void)handle_timeouts(base, base->time_tv, &wait);
280d3fecca9Ssthen 		if(base->need_to_exit)
281d3fecca9Ssthen 			return 0;
282d3fecca9Ssthen 		/* do select */
283d3fecca9Ssthen 		if(handle_select(base, &wait) < 0) {
284d3fecca9Ssthen 			if(base->need_to_exit)
285d3fecca9Ssthen 				return 0;
286d3fecca9Ssthen 			return -1;
287d3fecca9Ssthen 		}
288d3fecca9Ssthen 	}
289d3fecca9Ssthen 	return 0;
290d3fecca9Ssthen }
291d3fecca9Ssthen 
292d3fecca9Ssthen /** exit that loop */
293d3fecca9Ssthen int
event_base_loopexit(struct event_base * base,struct timeval * ATTR_UNUSED (tv))294d3fecca9Ssthen event_base_loopexit(struct event_base* base,
295d3fecca9Ssthen 	struct timeval* ATTR_UNUSED(tv))
296d3fecca9Ssthen {
297d3fecca9Ssthen 	base->need_to_exit = 1;
298d3fecca9Ssthen 	return 0;
299d3fecca9Ssthen }
300d3fecca9Ssthen 
event_base_loopbreak(struct event_base * base)301*3f21e8ccSflorian int event_base_loopbreak(struct event_base * base)
302*3f21e8ccSflorian {
303*3f21e8ccSflorian 	return event_base_loopexit(base, NULL);
304*3f21e8ccSflorian }
305*3f21e8ccSflorian 
306d3fecca9Ssthen /* free event base, free events yourself */
307d3fecca9Ssthen void
event_base_free(struct event_base * base)308d3fecca9Ssthen event_base_free(struct event_base* base)
309d3fecca9Ssthen {
310d3fecca9Ssthen 	if(!base)
311d3fecca9Ssthen 		return;
312eab1363eSsthen 	/* base->times is allocated in region and is freed with the region */
313d3fecca9Ssthen 	if(base->fds)
314d3fecca9Ssthen 		free(base->fds);
315d3fecca9Ssthen 	if(base->signals)
316d3fecca9Ssthen 		free(base->signals);
317d3fecca9Ssthen 	region_destroy(base->region);
318d3fecca9Ssthen 	free(base);
319d3fecca9Ssthen }
320d3fecca9Ssthen 
321d3fecca9Ssthen /** set content of event */
322d3fecca9Ssthen void
event_set(struct event * ev,int fd,short bits,void (* cb)(int,short,void *),void * arg)323d3fecca9Ssthen event_set(struct event* ev, int fd, short bits,
324d3fecca9Ssthen 	void (*cb)(int, short, void *), void* arg)
325d3fecca9Ssthen {
326d3fecca9Ssthen 	ev->node.key = ev;
327d3fecca9Ssthen 	ev->ev_fd = fd;
328d3fecca9Ssthen 	ev->ev_flags = bits;
329d3fecca9Ssthen 	ev->ev_callback = cb;
330d3fecca9Ssthen 	ev->ev_arg = arg;
331d3fecca9Ssthen 	ev->added = 0;
332d3fecca9Ssthen }
333d3fecca9Ssthen 
334d3fecca9Ssthen /* add event to a base */
335d3fecca9Ssthen int
event_base_set(struct event_base * base,struct event * ev)336d3fecca9Ssthen event_base_set(struct event_base* base, struct event* ev)
337d3fecca9Ssthen {
338d3fecca9Ssthen 	ev->ev_base = base;
339d3fecca9Ssthen 	ev->added = 0;
340d3fecca9Ssthen 	return 0;
341d3fecca9Ssthen }
342d3fecca9Ssthen 
343d3fecca9Ssthen /* add event to make it active, you may not change it with event_set anymore */
344d3fecca9Ssthen int
event_add(struct event * ev,struct timeval * tv)345d3fecca9Ssthen event_add(struct event* ev, struct timeval* tv)
346d3fecca9Ssthen {
347d3fecca9Ssthen 	if(ev->added)
348d3fecca9Ssthen 		event_del(ev);
349d3fecca9Ssthen 	if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
350d3fecca9Ssthen 		return -1;
351d3fecca9Ssthen 	if( (ev->ev_flags&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
352d3fecca9Ssthen 		ev->ev_base->fds[ev->ev_fd] = ev;
353d3fecca9Ssthen 		if(ev->ev_flags&EV_READ) {
354d3fecca9Ssthen 			FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
355d3fecca9Ssthen 		}
356d3fecca9Ssthen 		if(ev->ev_flags&EV_WRITE) {
357d3fecca9Ssthen 			FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
358d3fecca9Ssthen 		}
359d3fecca9Ssthen 		FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content);
360d3fecca9Ssthen 		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
361d3fecca9Ssthen 		if(ev->ev_fd > ev->ev_base->maxfd)
362d3fecca9Ssthen 			ev->ev_base->maxfd = ev->ev_fd;
363d3fecca9Ssthen 	}
364d3fecca9Ssthen 	if(tv && (ev->ev_flags&EV_TIMEOUT)) {
365d3fecca9Ssthen #ifndef S_SPLINT_S
366d3fecca9Ssthen 		struct timeval* now = ev->ev_base->time_tv;
367d3fecca9Ssthen 		ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
368d3fecca9Ssthen 		ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
369eab1363eSsthen 		while(ev->ev_timeout.tv_usec >= 1000000) {
370d3fecca9Ssthen 			ev->ev_timeout.tv_usec -= 1000000;
371d3fecca9Ssthen 			ev->ev_timeout.tv_sec++;
372d3fecca9Ssthen 		}
373d3fecca9Ssthen #endif
374d3fecca9Ssthen 		(void)rbtree_insert(ev->ev_base->times, &ev->node);
375d3fecca9Ssthen 	}
376d3fecca9Ssthen 	ev->added = 1;
377d3fecca9Ssthen 	return 0;
378d3fecca9Ssthen }
379d3fecca9Ssthen 
380d3fecca9Ssthen /* remove event, you may change it again */
381d3fecca9Ssthen int
event_del(struct event * ev)382d3fecca9Ssthen event_del(struct event* ev)
383d3fecca9Ssthen {
384d3fecca9Ssthen 	if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
385d3fecca9Ssthen 		return -1;
386d3fecca9Ssthen 	if((ev->ev_flags&EV_TIMEOUT))
387d3fecca9Ssthen 		(void)rbtree_delete(ev->ev_base->times, &ev->node);
388d3fecca9Ssthen 	if((ev->ev_flags&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
389d3fecca9Ssthen 		ev->ev_base->fds[ev->ev_fd] = NULL;
390d3fecca9Ssthen 		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
391d3fecca9Ssthen 		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
392d3fecca9Ssthen 		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
393d3fecca9Ssthen 		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content);
394d3fecca9Ssthen 	}
395d3fecca9Ssthen 	ev->added = 0;
396d3fecca9Ssthen 	return 0;
397d3fecca9Ssthen }
398d3fecca9Ssthen 
399d3fecca9Ssthen /** which base gets to handle signals */
400d3fecca9Ssthen static struct event_base* signal_base = NULL;
401d3fecca9Ssthen 
402d3fecca9Ssthen /** signal handler */
403d3fecca9Ssthen static RETSIGTYPE
sigh(int sig)404d3fecca9Ssthen sigh(int sig)
405d3fecca9Ssthen {
406d3fecca9Ssthen 	struct event* ev;
407d3fecca9Ssthen 	if(!signal_base || sig < 0 || sig >= MAX_SIG)
408d3fecca9Ssthen 		return;
409d3fecca9Ssthen 	ev = signal_base->signals[sig];
410d3fecca9Ssthen 	if(!ev)
411d3fecca9Ssthen 		return;
412d3fecca9Ssthen 	(*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
413d3fecca9Ssthen }
414d3fecca9Ssthen 
415d3fecca9Ssthen /** install signal handler */
416d3fecca9Ssthen int
signal_add(struct event * ev,struct timeval * ATTR_UNUSED (tv))417d3fecca9Ssthen signal_add(struct event* ev, struct timeval* ATTR_UNUSED(tv))
418d3fecca9Ssthen {
419d3fecca9Ssthen 	struct sigaction action;
420d3fecca9Ssthen 	if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
421d3fecca9Ssthen 		return -1;
422d3fecca9Ssthen 	signal_base = ev->ev_base;
423d3fecca9Ssthen 	ev->ev_base->signals[ev->ev_fd] = ev;
424d3fecca9Ssthen 	ev->added = 1;
425d3fecca9Ssthen 	action.sa_handler = sigh;
426d3fecca9Ssthen 	sigfillset(&action.sa_mask);
427d3fecca9Ssthen 	action.sa_flags = 0;
428d3fecca9Ssthen 	return sigaction(ev->ev_fd, &action, NULL);
429d3fecca9Ssthen }
430d3fecca9Ssthen 
431d3fecca9Ssthen /** remove signal handler */
432d3fecca9Ssthen int
signal_del(struct event * ev)433d3fecca9Ssthen signal_del(struct event* ev)
434d3fecca9Ssthen {
435d3fecca9Ssthen 	if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
436d3fecca9Ssthen 		return -1;
437d3fecca9Ssthen 	ev->ev_base->signals[ev->ev_fd] = NULL;
438d3fecca9Ssthen 	ev->added = 0;
439d3fecca9Ssthen 	return 0;
440d3fecca9Ssthen }
441d3fecca9Ssthen 
442d3fecca9Ssthen #else /* USE_MINI_EVENT */
443d3fecca9Ssthen #ifndef USE_WINSOCK
444d3fecca9Ssthen int
mini_ev_cmp(const void * ATTR_UNUSED (a),const void * ATTR_UNUSED (b))445d3fecca9Ssthen mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
446d3fecca9Ssthen {
447d3fecca9Ssthen 	return 0;
448d3fecca9Ssthen }
449d3fecca9Ssthen #endif /* not USE_WINSOCK */
450d3fecca9Ssthen #endif /* USE_MINI_EVENT */
451