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