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 "dlinklist.h"
61 #include "lib/events/events.h"
63 /* use epoll if it is available */
64 #if defined(HAVE_EPOLL_CREATE) && defined(HAVE_SYS_EPOLL_H)
69 #include <sys/epoll.h>
72 struct event_context {
73 /* list of filedescriptor events */
75 struct event_context *event_ctx;
76 struct fd_event *next, *prev;
78 uint16_t flags; /* see EVENT_FD_* flags */
79 event_fd_handler_t handler;
83 /* list of timed events */
85 struct event_context *event_ctx;
86 struct timed_event *next, *prev;
87 struct timeval next_event;
88 event_timed_handler_t handler;
92 /* the maximum file descriptor number in fd_events */
95 /* information for exiting from the event loop */
98 /* this is changed by the destructors for the fd event
99 type. It is used to detect event destruction by event
100 handlers, which means the code that is calling the event
101 handler needs to assume that the linked list is no longer
104 uint32_t destruction_count;
107 /* when using epoll this is the handle from epoll_create */
114 create a event_context structure. This must be the first events
115 call, and all subsequent calls pass this event_context as the first
116 element. Event handlers also receive this as their first argument.
118 struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
120 struct event_context *ev;
122 ev = talloc_zero(mem_ctx, struct event_context);
123 if (!ev) return NULL;
126 ev->epoll_fd = epoll_create(64);
134 recalculate the maxfd
136 static void calc_maxfd(struct event_context *ev)
140 for (e=ev->fd_events; e; e=e->next) {
141 if (e->fd > ev->maxfd) {
148 /* to mark the ev->maxfd invalid
149 * this means we need to recalculate it
151 #define EVENT_INVALID_MAXFD (-1)
156 called when a epoll call fails, and we should fallback
159 static void epoll_fallback_to_select(struct event_context *ev, const char *reason)
161 DEBUG(0,("%s (%s) - falling back to select()\n", reason, strerror(errno)));
170 map from EVENT_FD_* to EPOLLIN/EPOLLOUT
172 static uint32_t epoll_map_flags(uint16_t flags)
175 if (flags & EVENT_FD_READ) ret |= EPOLLIN;
176 if (flags & EVENT_FD_WRITE) ret |= EPOLLOUT;
184 static int event_fd_destructor(void *ptr)
186 struct fd_event *fde = talloc_get_type(ptr, struct fd_event);
187 struct event_context *ev = fde->event_ctx;
189 if (ev->maxfd == fde->fd) {
190 ev->maxfd = EVENT_INVALID_MAXFD;
192 DLIST_REMOVE(ev->fd_events, fde);
193 ev->destruction_count++;
195 if (ev->epoll_fd != -1) {
196 struct epoll_event event;
198 event.events = epoll_map_flags(fde->flags);
199 event.data.ptr = fde;
200 epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
208 return NULL on failure (memory allocation error)
210 struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
211 int fd, uint16_t flags, event_fd_handler_t handler,
214 struct fd_event *e = talloc(ev, struct fd_event);
220 e->handler = handler;
221 e->private = private;
223 DLIST_ADD(ev->fd_events, e);
225 if (e->fd > ev->maxfd) {
229 talloc_set_destructor(e, event_fd_destructor);
231 talloc_steal(mem_ctx, e);
235 if (ev->epoll_fd != -1) {
236 struct epoll_event event;
238 event.events = epoll_map_flags(flags);
240 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_ADD, e->fd, &event) != 0) {
241 epoll_fallback_to_select(ev, "EPOLL_CTL_ADD failed");
251 return the fd event flags
253 uint16_t event_fd_flags(struct fd_event *fde)
255 return fde?fde->flags:0;
259 set the fd event flags
261 void event_fd_setflags(struct fd_event *fde, uint16_t flags)
264 struct event_context *ev;
266 fde->flags == flags) {
270 if (ev->epoll_fd != -1) {
271 struct epoll_event event;
273 event.events = epoll_map_flags(flags);
274 event.data.ptr = fde;
275 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
276 epoll_fallback_to_select(ev, "EPOLL_CTL_MOD failed");
286 destroy a timed event
288 static int event_timed_destructor(void *ptr)
290 struct timed_event *te = talloc_get_type(ptr, struct timed_event);
291 DLIST_REMOVE(te->event_ctx->timed_events, te);
297 return NULL on failure (memory allocation error)
299 struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx,
300 struct timeval next_event,
301 event_timed_handler_t handler,
304 struct timed_event *te, *e;
306 e = talloc(mem_ctx?mem_ctx:ev, struct timed_event);
307 if (e == NULL) return NULL;
310 e->next_event = next_event;
311 e->handler = handler;
312 e->private = private;
314 /* keep the list ordered */
315 if (ev->timed_events == NULL ||
316 timeval_compare(&e->next_event, &ev->timed_events->next_event) > 0) {
317 DLIST_ADD(ev->timed_events, e);
319 for (te=ev->timed_events;te && te->next;te=te->next) {
320 if (!timeval_is_zero(&te->next_event) &&
321 timeval_compare(&te->next_event, &e->next_event) < 0) {
325 DLIST_ADD_AFTER(ev->timed_events, e, te);
328 talloc_set_destructor(e, event_timed_destructor);
334 a timer has gone off - call it
336 static void event_loop_timer(struct event_context *ev)
338 struct timeval t = timeval_current();
339 struct timed_event *te = ev->timed_events;
341 te->next_event = timeval_zero();
343 te->handler(ev, te, t, te->private);
345 /* note the care taken to prevent referencing a event
346 that could have been freed by the handler */
347 if (ev->timed_events && timeval_is_zero(&ev->timed_events->next_event)) {
348 talloc_free(ev->timed_events);
354 event loop handling using epoll
356 static int event_loop_epoll(struct event_context *ev, struct timeval *tvalp)
359 const int maxevents = 8;
360 struct epoll_event events[maxevents];
361 uint32_t destruction_count = ev->destruction_count;
365 timeout = (tvalp->tv_usec / 1000) + (tvalp->tv_sec*1000);
368 ret = epoll_wait(ev->epoll_fd, events, maxevents, timeout);
370 if (ret == -1 && errno != EINTR) {
371 epoll_fallback_to_select(ev, "epoll_wait() failed");
375 if (ret == 0 && tvalp) {
376 event_loop_timer(ev);
380 for (i=0;i<ret;i++) {
381 struct fd_event *fde = talloc_get_type(events[i].data.ptr,
386 epoll_fallback_to_select(ev, "epoll_wait() gave bad data");
389 if (events[i].events & EPOLLIN) flags |= EVENT_FD_READ;
390 if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE;
392 fde->handler(ev, fde, flags, fde->private);
393 if (destruction_count != ev->destruction_count) {
404 event loop handling using select()
406 static int event_loop_select(struct event_context *ev, struct timeval *tvalp)
410 uint32_t destruction_count = ev->destruction_count;
413 /* we maybe need to recalculate the maxfd */
414 if (ev->maxfd == EVENT_INVALID_MAXFD) {
421 /* setup any fd events */
422 for (fe=ev->fd_events; fe; ) {
423 struct fd_event *next = fe->next;
424 if (fe->flags & EVENT_FD_READ) {
425 FD_SET(fe->fd, &r_fds);
427 if (fe->flags & EVENT_FD_WRITE) {
428 FD_SET(fe->fd, &w_fds);
433 selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
435 if (selrtn == -1 && errno == EBADF) {
436 /* the socket is dead! this should never
437 happen as the socket should have first been
438 made readable and that should have removed
439 the event, so this must be a bug. This is a
441 DEBUG(0,("ERROR: EBADF on event_loop_once\n"));
442 ev->exit_code = EBADF;
446 if (selrtn == 0 && tvalp) {
447 event_loop_timer(ev);
452 /* at least one file descriptor is ready - check
453 which ones and call the handler, being careful to allow
454 the handler to remove itself when called */
455 for (fe=ev->fd_events; fe; fe=fe->next) {
457 if (FD_ISSET(fe->fd, &r_fds)) flags |= EVENT_FD_READ;
458 if (FD_ISSET(fe->fd, &w_fds)) flags |= EVENT_FD_WRITE;
460 fe->handler(ev, fe, flags, fe->private);
461 if (destruction_count != ev->destruction_count) {
472 do a single event loop using the events defined in ev
474 int event_loop_once(struct event_context *ev)
476 struct timeval tval, *tvalp;
480 /* work out the right timeout for all timed events */
481 if (ev->timed_events) {
482 struct timeval t = timeval_current();
483 tval = timeval_diff(&ev->timed_events->next_event, &t);
485 if (timeval_is_zero(tvalp)) {
486 event_loop_timer(ev);
492 if (ev->epoll_fd != -1) {
493 if (event_loop_epoll(ev, tvalp) == 0) {
499 return event_loop_select(ev, tvalp);
503 go into an event loop using the events defined in ev this function
504 will return with the specified code if one of the handlers calls
507 also return (with code 0) if all fd events are removed
509 int event_loop_wait(struct event_context *ev)
512 ev->maxfd = EVENT_INVALID_MAXFD;
514 while (ev->fd_events && ev->exit_code == 0) {
515 if (event_loop_once(ev) != 0) {
520 return ev->exit_code;