2 Unix SMB/CIFS implementation.
3 main select loop and event handling
4 Copyright (C) Andrew Tridgell 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 PLEASE READ THIS BEFORE MODIFYING!
24 This module is a general abstraction for the main select loop and
25 event handling. Do not ever put any localised hacks in here, instead
26 register one of the possible event types and implement that event
29 There are 2 types of event handling that are handled in this module:
31 1) a file descriptor becoming readable or writeable. This is mostly
32 used for network sockets, but can be used for any type of file
33 descriptor. You may only register one handler for each file
34 descriptor/io combination or you will get unpredictable results
35 (this means that you can have a handler for read events, and a
36 separate handler for write events, but not two handlers that are
37 both handling read events)
39 2) a timed event. You can register an event that happens at a
40 specific time. You can register as many of these as you
41 like. They are single shot - add a new timed event in the event
42 handler to get another event.
44 To setup a set of events you first need to create a event_context
45 structure using the function event_context_init(); This returns a
46 'struct event_context' that you use in all subsequent calls.
48 After that you can add/remove events that you are interested in
49 using event_add_*() and talloc_free()
51 Finally, you call event_loop_wait() to block waiting for one of the
52 events to occor. In normal operation event_loop_wait() will loop
58 #include "system/time.h"
59 #include "system/select.h"
60 #include "system/filesys.h"
61 #include "dlinklist.h"
62 #include "lib/events/events.h"
64 /* use epoll if it is available */
65 #if defined(HAVE_EPOLL_CREATE) && defined(HAVE_SYS_EPOLL_H)
70 #include <sys/epoll.h>
73 struct event_context
{
74 /* list of filedescriptor events */
76 struct event_context
*event_ctx
;
77 struct fd_event
*next
, *prev
;
79 uint16_t flags
; /* see EVENT_FD_* flags */
80 event_fd_handler_t handler
;
84 /* list of timed events */
86 struct event_context
*event_ctx
;
87 struct timed_event
*next
, *prev
;
88 struct timeval next_event
;
89 event_timed_handler_t handler
;
93 /* the maximum file descriptor number in fd_events */
96 /* information for exiting from the event loop */
99 /* this is changed by the destructors for the fd event
100 type. It is used to detect event destruction by event
101 handlers, which means the code that is calling the event
102 handler needs to assume that the linked list is no longer
105 uint32_t destruction_count
;
108 /* when using epoll this is the handle from epoll_create */
115 destroy an event context
117 static int event_context_destructor(void *ptr
)
120 struct event_context
*ev
= talloc_get_type(ptr
, struct event_context
);
121 if (ev
->epoll_fd
!= -1) {
130 create a event_context structure. This must be the first events
131 call, and all subsequent calls pass this event_context as the first
132 element. Event handlers also receive this as their first argument.
134 struct event_context
*event_context_init(TALLOC_CTX
*mem_ctx
)
136 struct event_context
*ev
;
138 ev
= talloc_zero(mem_ctx
, struct event_context
);
139 if (!ev
) return NULL
;
142 ev
->epoll_fd
= epoll_create(64);
145 talloc_set_destructor(ev
, event_context_destructor
);
152 recalculate the maxfd
154 static void calc_maxfd(struct event_context
*ev
)
158 for (e
=ev
->fd_events
; e
; e
=e
->next
) {
159 if (e
->fd
> ev
->maxfd
) {
166 /* to mark the ev->maxfd invalid
167 * this means we need to recalculate it
169 #define EVENT_INVALID_MAXFD (-1)
174 called when a epoll call fails, and we should fallback
177 static void epoll_fallback_to_select(struct event_context
*ev
, const char *reason
)
179 DEBUG(0,("%s (%s) - falling back to select()\n", reason
, strerror(errno
)));
188 map from EVENT_FD_* to EPOLLIN/EPOLLOUT
190 static uint32_t epoll_map_flags(uint16_t flags
)
193 if (flags
& EVENT_FD_READ
) ret
|= EPOLLIN
;
194 if (flags
& EVENT_FD_WRITE
) ret
|= EPOLLOUT
;
202 static int event_fd_destructor(void *ptr
)
204 struct fd_event
*fde
= talloc_get_type(ptr
, struct fd_event
);
205 struct event_context
*ev
= fde
->event_ctx
;
207 if (ev
->maxfd
== fde
->fd
) {
208 ev
->maxfd
= EVENT_INVALID_MAXFD
;
210 DLIST_REMOVE(ev
->fd_events
, fde
);
211 ev
->destruction_count
++;
213 if (ev
->epoll_fd
!= -1) {
214 struct epoll_event event
;
216 event
.events
= epoll_map_flags(fde
->flags
);
217 event
.data
.ptr
= fde
;
218 epoll_ctl(ev
->epoll_fd
, EPOLL_CTL_DEL
, fde
->fd
, &event
);
226 return NULL on failure (memory allocation error)
228 struct fd_event
*event_add_fd(struct event_context
*ev
, TALLOC_CTX
*mem_ctx
,
229 int fd
, uint16_t flags
, event_fd_handler_t handler
,
232 struct fd_event
*e
= talloc(ev
, struct fd_event
);
238 e
->handler
= handler
;
239 e
->private = private;
241 DLIST_ADD(ev
->fd_events
, e
);
243 if (e
->fd
> ev
->maxfd
) {
247 talloc_set_destructor(e
, event_fd_destructor
);
249 talloc_steal(mem_ctx
, e
);
253 if (ev
->epoll_fd
!= -1) {
254 struct epoll_event event
;
256 event
.events
= epoll_map_flags(flags
);
258 if (epoll_ctl(ev
->epoll_fd
, EPOLL_CTL_ADD
, e
->fd
, &event
) != 0) {
259 epoll_fallback_to_select(ev
, "EPOLL_CTL_ADD failed");
269 return the fd event flags
271 uint16_t event_fd_flags(struct fd_event
*fde
)
273 return fde
?fde
->flags
:0;
277 set the fd event flags
279 void event_fd_setflags(struct fd_event
*fde
, uint16_t flags
)
282 struct event_context
*ev
;
284 fde
->flags
== flags
) {
288 if (ev
->epoll_fd
!= -1) {
289 struct epoll_event event
;
291 event
.events
= epoll_map_flags(flags
);
292 event
.data
.ptr
= fde
;
293 if (epoll_ctl(ev
->epoll_fd
, EPOLL_CTL_MOD
, fde
->fd
, &event
) != 0) {
294 epoll_fallback_to_select(ev
, "EPOLL_CTL_MOD failed");
304 destroy a timed event
306 static int event_timed_destructor(void *ptr
)
308 struct timed_event
*te
= talloc_get_type(ptr
, struct timed_event
);
309 DLIST_REMOVE(te
->event_ctx
->timed_events
, te
);
315 return NULL on failure (memory allocation error)
317 struct timed_event
*event_add_timed(struct event_context
*ev
, TALLOC_CTX
*mem_ctx
,
318 struct timeval next_event
,
319 event_timed_handler_t handler
,
322 struct timed_event
*te
, *e
;
324 e
= talloc(mem_ctx
?mem_ctx
:ev
, struct timed_event
);
325 if (e
== NULL
) return NULL
;
328 e
->next_event
= next_event
;
329 e
->handler
= handler
;
330 e
->private = private;
332 /* keep the list ordered */
333 if (ev
->timed_events
== NULL
||
334 timeval_compare(&e
->next_event
, &ev
->timed_events
->next_event
) > 0) {
335 DLIST_ADD(ev
->timed_events
, e
);
337 for (te
=ev
->timed_events
;te
&& te
->next
;te
=te
->next
) {
338 if (!timeval_is_zero(&te
->next
->next_event
) &&
339 timeval_compare(&te
->next
->next_event
, &e
->next_event
) < 0) {
343 DLIST_ADD_AFTER(ev
->timed_events
, e
, te
);
346 talloc_set_destructor(e
, event_timed_destructor
);
352 a timer has gone off - call it
354 static void event_loop_timer(struct event_context
*ev
)
356 struct timeval t
= timeval_current();
357 struct timed_event
*te
= ev
->timed_events
;
359 te
->next_event
= timeval_zero();
361 te
->handler(ev
, te
, t
, te
->private);
363 /* note the care taken to prevent referencing a event
364 that could have been freed by the handler */
365 if (ev
->timed_events
&& timeval_is_zero(&ev
->timed_events
->next_event
)) {
366 talloc_free(ev
->timed_events
);
372 event loop handling using epoll
374 static int event_loop_epoll(struct event_context
*ev
, struct timeval
*tvalp
)
377 const int maxevents
= 8;
378 struct epoll_event events
[maxevents
];
379 uint32_t destruction_count
= ev
->destruction_count
;
383 timeout
= (tvalp
->tv_usec
/ 1000) + (tvalp
->tv_sec
*1000);
386 ret
= epoll_wait(ev
->epoll_fd
, events
, maxevents
, timeout
);
388 if (ret
== -1 && errno
!= EINTR
) {
389 epoll_fallback_to_select(ev
, "epoll_wait() failed");
393 if (ret
== 0 && tvalp
) {
394 event_loop_timer(ev
);
398 for (i
=0;i
<ret
;i
++) {
399 struct fd_event
*fde
= talloc_get_type(events
[i
].data
.ptr
,
404 epoll_fallback_to_select(ev
, "epoll_wait() gave bad data");
407 if (events
[i
].events
& (EPOLLIN
|EPOLLHUP
|EPOLLERR
))
408 flags
|= EVENT_FD_READ
;
409 if (events
[i
].events
& EPOLLOUT
) flags
|= EVENT_FD_WRITE
;
411 fde
->handler(ev
, fde
, flags
, fde
->private);
412 if (destruction_count
!= ev
->destruction_count
) {
423 event loop handling using select()
425 static int event_loop_select(struct event_context
*ev
, struct timeval
*tvalp
)
429 uint32_t destruction_count
= ev
->destruction_count
;
432 /* we maybe need to recalculate the maxfd */
433 if (ev
->maxfd
== EVENT_INVALID_MAXFD
) {
440 /* setup any fd events */
441 for (fe
=ev
->fd_events
; fe
; ) {
442 struct fd_event
*next
= fe
->next
;
443 if (fe
->flags
& EVENT_FD_READ
) {
444 FD_SET(fe
->fd
, &r_fds
);
446 if (fe
->flags
& EVENT_FD_WRITE
) {
447 FD_SET(fe
->fd
, &w_fds
);
452 selrtn
= select(ev
->maxfd
+1, &r_fds
, &w_fds
, NULL
, tvalp
);
454 if (selrtn
== -1 && errno
== EBADF
) {
455 /* the socket is dead! this should never
456 happen as the socket should have first been
457 made readable and that should have removed
458 the event, so this must be a bug. This is a
460 DEBUG(0,("ERROR: EBADF on event_loop_once\n"));
461 ev
->exit_code
= EBADF
;
465 if (selrtn
== 0 && tvalp
) {
466 event_loop_timer(ev
);
471 /* at least one file descriptor is ready - check
472 which ones and call the handler, being careful to allow
473 the handler to remove itself when called */
474 for (fe
=ev
->fd_events
; fe
; fe
=fe
->next
) {
476 if (FD_ISSET(fe
->fd
, &r_fds
)) flags
|= EVENT_FD_READ
;
477 if (FD_ISSET(fe
->fd
, &w_fds
)) flags
|= EVENT_FD_WRITE
;
479 fe
->handler(ev
, fe
, flags
, fe
->private);
480 if (destruction_count
!= ev
->destruction_count
) {
491 do a single event loop using the events defined in ev
493 int event_loop_once(struct event_context
*ev
)
495 struct timeval tval
, *tvalp
;
499 /* work out the right timeout for all timed events */
500 if (ev
->timed_events
) {
501 struct timeval t
= timeval_current();
502 tval
= timeval_diff(&ev
->timed_events
->next_event
, &t
);
504 if (timeval_is_zero(tvalp
)) {
505 event_loop_timer(ev
);
511 if (ev
->epoll_fd
!= -1) {
512 if (event_loop_epoll(ev
, tvalp
) == 0) {
518 return event_loop_select(ev
, tvalp
);
522 go into an event loop using the events defined in ev this function
523 will return with the specified code if one of the handlers calls
526 also return (with code 0) if all fd events are removed
528 int event_loop_wait(struct event_context
*ev
)
531 ev
->maxfd
= EVENT_INVALID_MAXFD
;
533 while (ev
->fd_events
&& ev
->exit_code
== 0) {
534 if (event_loop_once(ev
) != 0) {
539 return ev
->exit_code
;