]>
git.saurik.com Git - apple/network_cmds.git/blob - unbound/util/mini_event.c
40dca375a0153b7ce1988ed237a69b355fea30fd
2 * mini_event.c - implementation of part of libevent api, portably.
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * fake libevent implementation. Less broad in functionality, and only
49 #if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
51 #include "util/mini_event.h"
52 #include "util/fptr_wlist.h"
54 /** compare events in tree, based on timevalue, ptr for uniqueness */
55 int mini_ev_cmp(const void* a
, const void* b
)
57 const struct event
*e
= (const struct event
*)a
;
58 const struct event
*f
= (const struct event
*)b
;
59 if(e
->ev_timeout
.tv_sec
< f
->ev_timeout
.tv_sec
)
61 if(e
->ev_timeout
.tv_sec
> f
->ev_timeout
.tv_sec
)
63 if(e
->ev_timeout
.tv_usec
< f
->ev_timeout
.tv_usec
)
65 if(e
->ev_timeout
.tv_usec
> f
->ev_timeout
.tv_usec
)
76 settime(struct event_base
* base
)
78 if(gettimeofday(base
->time_tv
, NULL
) < 0) {
82 *base
->time_secs
= (time_t)base
->time_tv
->tv_sec
;
87 /** create event base */
88 void *event_init(time_t* time_secs
, struct timeval
* time_tv
)
90 struct event_base
* base
= (struct event_base
*)malloc(
91 sizeof(struct event_base
));
94 memset(base
, 0, sizeof(*base
));
95 base
->time_secs
= time_secs
;
96 base
->time_tv
= time_tv
;
97 if(settime(base
) < 0) {
98 event_base_free(base
);
101 base
->times
= rbtree_create(mini_ev_cmp
);
103 event_base_free(base
);
106 base
->capfd
= MAX_FDS
;
108 if((int)FD_SETSIZE
< base
->capfd
)
109 base
->capfd
= (int)FD_SETSIZE
;
111 base
->fds
= (struct event
**)calloc((size_t)base
->capfd
,
112 sizeof(struct event
*));
114 event_base_free(base
);
117 base
->signals
= (struct event
**)calloc(MAX_SIG
, sizeof(struct event
*));
119 event_base_free(base
);
123 FD_ZERO(&base
->reads
);
124 FD_ZERO(&base
->writes
);
130 const char *event_get_version(void)
132 return "mini-event-"PACKAGE_VERSION
;
135 /** get polling method, select */
136 const char *event_get_method(void)
141 /** call timeouts handlers, and return how long to wait for next one or -1 */
142 static void handle_timeouts(struct event_base
* base
, struct timeval
* now
,
143 struct timeval
* wait
)
147 wait
->tv_sec
= (time_t)-1;
150 while((rbnode_t
*)(p
= (struct event
*)rbtree_first(base
->times
))
153 if(p
->ev_timeout
.tv_sec
> now
->tv_sec
||
154 (p
->ev_timeout
.tv_sec
==now
->tv_sec
&&
155 p
->ev_timeout
.tv_usec
> now
->tv_usec
)) {
156 /* there is a next larger timeout. wait for it */
157 wait
->tv_sec
= p
->ev_timeout
.tv_sec
- now
->tv_sec
;
158 if(now
->tv_usec
> p
->ev_timeout
.tv_usec
) {
160 wait
->tv_usec
= 1000000 - (now
->tv_usec
-
161 p
->ev_timeout
.tv_usec
);
163 wait
->tv_usec
= p
->ev_timeout
.tv_usec
169 /* event times out, remove it */
170 (void)rbtree_delete(base
->times
, p
);
171 p
->ev_events
&= ~EV_TIMEOUT
;
172 fptr_ok(fptr_whitelist_event(p
->ev_callback
));
173 (*p
->ev_callback
)(p
->ev_fd
, EV_TIMEOUT
, p
->ev_arg
);
177 /** call select and callbacks for that */
178 static int handle_select(struct event_base
* base
, struct timeval
* wait
)
184 if(wait
->tv_sec
==(time_t)-1)
187 memmove(&r
, &base
->reads
, sizeof(fd_set
));
188 memmove(&w
, &base
->writes
, sizeof(fd_set
));
189 memmove(&base
->ready
, &base
->content
, sizeof(fd_set
));
191 if((ret
= select(base
->maxfd
+1, &r
, &w
, NULL
, wait
)) == -1) {
193 if(settime(base
) < 0)
196 if(ret
== EAGAIN
|| ret
== EINTR
)
200 if(settime(base
) < 0)
203 for(i
=0; i
<base
->maxfd
+1; i
++) {
205 if(!base
->fds
[i
] || !(FD_ISSET(i
, &base
->ready
))) {
208 if(FD_ISSET(i
, &r
)) {
212 if(FD_ISSET(i
, &w
)) {
216 bits
&= base
->fds
[i
]->ev_events
;
218 fptr_ok(fptr_whitelist_event(
219 base
->fds
[i
]->ev_callback
));
220 (*base
->fds
[i
]->ev_callback
)(base
->fds
[i
]->ev_fd
,
221 bits
, base
->fds
[i
]->ev_arg
);
229 /** run select in a loop */
230 int event_base_dispatch(struct event_base
* base
)
233 if(settime(base
) < 0)
235 while(!base
->need_to_exit
)
237 /* see if timeouts need handling */
238 handle_timeouts(base
, base
->time_tv
, &wait
);
239 if(base
->need_to_exit
)
242 if(handle_select(base
, &wait
) < 0) {
243 if(base
->need_to_exit
)
251 /** exit that loop */
252 int event_base_loopexit(struct event_base
* base
,
253 struct timeval
* ATTR_UNUSED(tv
))
255 base
->need_to_exit
= 1;
259 /* free event base, free events yourself */
260 void event_base_free(struct event_base
* base
)
273 /** set content of event */
274 void event_set(struct event
* ev
, int fd
, short bits
,
275 void (*cb
)(int, short, void *), void* arg
)
279 ev
->ev_events
= bits
;
280 ev
->ev_callback
= cb
;
281 fptr_ok(fptr_whitelist_event(ev
->ev_callback
));
286 /* add event to a base */
287 int event_base_set(struct event_base
* base
, struct event
* ev
)
294 /* add event to make it active, you may not change it with event_set anymore */
295 int event_add(struct event
* ev
, struct timeval
* tv
)
299 if(ev
->ev_fd
!= -1 && ev
->ev_fd
>= ev
->ev_base
->capfd
)
301 if( (ev
->ev_events
&(EV_READ
|EV_WRITE
)) && ev
->ev_fd
!= -1) {
302 ev
->ev_base
->fds
[ev
->ev_fd
] = ev
;
303 if(ev
->ev_events
&EV_READ
) {
304 FD_SET(FD_SET_T ev
->ev_fd
, &ev
->ev_base
->reads
);
306 if(ev
->ev_events
&EV_WRITE
) {
307 FD_SET(FD_SET_T ev
->ev_fd
, &ev
->ev_base
->writes
);
309 FD_SET(FD_SET_T ev
->ev_fd
, &ev
->ev_base
->content
);
310 FD_CLR(FD_SET_T ev
->ev_fd
, &ev
->ev_base
->ready
);
311 if(ev
->ev_fd
> ev
->ev_base
->maxfd
)
312 ev
->ev_base
->maxfd
= ev
->ev_fd
;
314 if(tv
&& (ev
->ev_events
&EV_TIMEOUT
)) {
316 struct timeval
*now
= ev
->ev_base
->time_tv
;
317 ev
->ev_timeout
.tv_sec
= tv
->tv_sec
+ now
->tv_sec
;
318 ev
->ev_timeout
.tv_usec
= tv
->tv_usec
+ now
->tv_usec
;
319 while(ev
->ev_timeout
.tv_usec
> 1000000) {
320 ev
->ev_timeout
.tv_usec
-= 1000000;
321 ev
->ev_timeout
.tv_sec
++;
324 (void)rbtree_insert(ev
->ev_base
->times
, &ev
->node
);
330 /* remove event, you may change it again */
331 int event_del(struct event
* ev
)
333 if(ev
->ev_fd
!= -1 && ev
->ev_fd
>= ev
->ev_base
->capfd
)
335 if((ev
->ev_events
&EV_TIMEOUT
))
336 (void)rbtree_delete(ev
->ev_base
->times
, &ev
->node
);
337 if((ev
->ev_events
&(EV_READ
|EV_WRITE
)) && ev
->ev_fd
!= -1) {
338 ev
->ev_base
->fds
[ev
->ev_fd
] = NULL
;
339 FD_CLR(FD_SET_T ev
->ev_fd
, &ev
->ev_base
->reads
);
340 FD_CLR(FD_SET_T ev
->ev_fd
, &ev
->ev_base
->writes
);
341 FD_CLR(FD_SET_T ev
->ev_fd
, &ev
->ev_base
->ready
);
342 FD_CLR(FD_SET_T ev
->ev_fd
, &ev
->ev_base
->content
);
348 /** which base gets to handle signals */
349 static struct event_base
* signal_base
= NULL
;
350 /** signal handler */
351 static RETSIGTYPE
sigh(int sig
)
354 if(!signal_base
|| sig
< 0 || sig
>= MAX_SIG
)
356 ev
= signal_base
->signals
[sig
];
359 fptr_ok(fptr_whitelist_event(ev
->ev_callback
));
360 (*ev
->ev_callback
)(sig
, EV_SIGNAL
, ev
->ev_arg
);
363 /** install signal handler */
364 int signal_add(struct event
* ev
, struct timeval
* ATTR_UNUSED(tv
))
366 if(ev
->ev_fd
== -1 || ev
->ev_fd
>= MAX_SIG
)
368 signal_base
= ev
->ev_base
;
369 ev
->ev_base
->signals
[ev
->ev_fd
] = ev
;
371 if(signal(ev
->ev_fd
, sigh
) == SIG_ERR
) {
377 /** remove signal handler */
378 int signal_del(struct event
* ev
)
380 if(ev
->ev_fd
== -1 || ev
->ev_fd
>= MAX_SIG
)
382 ev
->ev_base
->signals
[ev
->ev_fd
] = NULL
;
387 #else /* USE_MINI_EVENT */
389 int mini_ev_cmp(const void* ATTR_UNUSED(a
), const void* ATTR_UNUSED(b
))
393 #endif /* not USE_WINSOCK */
394 #endif /* USE_MINI_EVENT */