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 /* this #undef is needed on my SuSE 9.2 Box with glibc-devel-2.3.3-118 */
71 #include <sys/epoll.h>
74 struct event_context {
75 /* list of filedescriptor events */
77 struct event_context *event_ctx;
78 struct fd_event *next, *prev;
80 uint16_t flags; /* see EVENT_FD_* flags */
81 event_fd_handler_t handler;
85 /* list of timed events */
87 struct event_context *event_ctx;
88 struct timed_event *next, *prev;
89 struct timeval next_event;
90 event_timed_handler_t handler;
94 /* the maximum file descriptor number in fd_events */
97 /* information for exiting from the event loop */
100 /* this is changed by the destructors for the fd event
101 type. It is used to detect event destruction by event
102 handlers, which means the code that is calling the event
103 handler needs to assume that the linked list is no longer
106 uint32_t destruction_count;
109 /* when using epoll this is the handle from epoll_create */
116 create a event_context structure. This must be the first events
117 call, and all subsequent calls pass this event_context as the first
118 element. Event handlers also receive this as their first argument.
120 struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
122 struct event_context *ev;
124 ev = talloc_zero(mem_ctx, struct event_context);
125 if (!ev) return NULL;
128 ev->epoll_fd = epoll_create(64);
136 recalculate the maxfd
138 static void calc_maxfd(struct event_context *ev)
142 for (e=ev->fd_events; e; e=e->next) {
143 if (e->fd > ev->maxfd) {
150 /* to mark the ev->maxfd invalid
151 * this means we need to recalculate it
153 #define EVENT_INVALID_MAXFD (-1)
158 called when a epoll call fails, and we should fallback
161 static void epoll_fallback_to_select(struct event_context *ev, const char *reason)
163 DEBUG(0,("%s (%s) - falling back to select()\n", reason, strerror(errno)));
172 map from EVENT_FD_* to EPOLLIN/EPOLLOUT
174 static uint32_t epoll_map_flags(uint16_t flags)
177 if (flags & EVENT_FD_READ) ret |= EPOLLIN;
178 if (flags & EVENT_FD_WRITE) ret |= EPOLLOUT;
186 static int event_fd_destructor(void *ptr)
188 struct fd_event *fde = talloc_get_type(ptr, struct fd_event);
189 struct event_context *ev = fde->event_ctx;
191 if (ev->maxfd == fde->fd) {
192 ev->maxfd = EVENT_INVALID_MAXFD;
194 DLIST_REMOVE(ev->fd_events, fde);
195 ev->destruction_count++;
197 if (ev->epoll_fd != -1) {
198 struct epoll_event event;
200 event.events = epoll_map_flags(fde->flags);
201 event.data.ptr = fde;
202 epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
210 return NULL on failure (memory allocation error)
212 struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
213 int fd, uint16_t flags, event_fd_handler_t handler,
216 struct fd_event *e = talloc(ev, struct fd_event);
222 e->handler = handler;
223 e->private = private;
225 DLIST_ADD(ev->fd_events, e);
227 if (e->fd > ev->maxfd) {
231 talloc_set_destructor(e, event_fd_destructor);
233 talloc_steal(mem_ctx, e);
237 if (ev->epoll_fd != -1) {
238 struct epoll_event event;
240 event.events = epoll_map_flags(flags);
242 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_ADD, e->fd, &event) != 0) {
243 epoll_fallback_to_select(ev, "EPOLL_CTL_ADD failed");
253 return the fd event flags
255 uint16_t event_fd_flags(struct fd_event *fde)
257 return fde?fde->flags:0;
261 set the fd event flags
263 void event_fd_setflags(struct fd_event *fde, uint16_t flags)
266 struct event_context *ev;
268 fde->flags == flags) {
272 if (ev->epoll_fd != -1) {
273 struct epoll_event event;
275 event.events = epoll_map_flags(flags);
276 event.data.ptr = fde;
277 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
278 epoll_fallback_to_select(ev, "EPOLL_CTL_MOD failed");
288 destroy a timed event
290 static int event_timed_destructor(void *ptr)
292 struct timed_event *te = talloc_get_type(ptr, struct timed_event);
293 DLIST_REMOVE(te->event_ctx->timed_events, te);
299 return NULL on failure (memory allocation error)
301 struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx,
302 struct timeval next_event,
303 event_timed_handler_t handler,
306 struct timed_event *te, *e;
308 e = talloc(mem_ctx?mem_ctx:ev, struct timed_event);
309 if (e == NULL) return NULL;
312 e->next_event = next_event;
313 e->handler = handler;
314 e->private = private;
316 /* keep the list ordered */
317 if (ev->timed_events == NULL ||
318 timeval_compare(&e->next_event, &ev->timed_events->next_event) > 0) {
319 DLIST_ADD(ev->timed_events, e);
321 for (te=ev->timed_events;te && te->next;te=te->next) {
322 if (!timeval_is_zero(&te->next->next_event) &&
323 timeval_compare(&te->next->next_event, &e->next_event) < 0) {
327 DLIST_ADD_AFTER(ev->timed_events, e, te);
330 talloc_set_destructor(e, event_timed_destructor);
336 a timer has gone off - call it
338 static void event_loop_timer(struct event_context *ev)
340 struct timeval t = timeval_current();
341 struct timed_event *te = ev->timed_events;
343 te->next_event = timeval_zero();
345 te->handler(ev, te, t, te->private);
347 /* note the care taken to prevent referencing a event
348 that could have been freed by the handler */
349 if (ev->timed_events && timeval_is_zero(&ev->timed_events->next_event)) {
350 talloc_free(ev->timed_events);
356 event loop handling using epoll
358 static int event_loop_epoll(struct event_context *ev, struct timeval *tvalp)
361 const int maxevents = 8;
362 struct epoll_event events[maxevents];
363 uint32_t destruction_count = ev->destruction_count;
367 timeout = (tvalp->tv_usec / 1000) + (tvalp->tv_sec*1000);
370 ret = epoll_wait(ev->epoll_fd, events, maxevents, timeout);
372 if (ret == -1 && errno != EINTR) {
373 epoll_fallback_to_select(ev, "epoll_wait() failed");
377 if (ret == 0 && tvalp) {
378 event_loop_timer(ev);
382 for (i=0;i<ret;i++) {
383 struct fd_event *fde = talloc_get_type(events[i].data.ptr,
388 epoll_fallback_to_select(ev, "epoll_wait() gave bad data");
391 if (events[i].events & EPOLLIN) flags |= EVENT_FD_READ;
392 if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE;
394 fde->handler(ev, fde, flags, fde->private);
395 if (destruction_count != ev->destruction_count) {
406 event loop handling using select()
408 static int event_loop_select(struct event_context *ev, struct timeval *tvalp)
412 uint32_t destruction_count = ev->destruction_count;
415 /* we maybe need to recalculate the maxfd */
416 if (ev->maxfd == EVENT_INVALID_MAXFD) {
423 /* setup any fd events */
424 for (fe=ev->fd_events; fe; ) {
425 struct fd_event *next = fe->next;
426 if (fe->flags & EVENT_FD_READ) {
427 FD_SET(fe->fd, &r_fds);
429 if (fe->flags & EVENT_FD_WRITE) {
430 FD_SET(fe->fd, &w_fds);
435 selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
437 if (selrtn == -1 && errno == EBADF) {
438 /* the socket is dead! this should never
439 happen as the socket should have first been
440 made readable and that should have removed
441 the event, so this must be a bug. This is a
443 DEBUG(0,("ERROR: EBADF on event_loop_once\n"));
444 ev->exit_code = EBADF;
448 if (selrtn == 0 && tvalp) {
449 event_loop_timer(ev);
454 /* at least one file descriptor is ready - check
455 which ones and call the handler, being careful to allow
456 the handler to remove itself when called */
457 for (fe=ev->fd_events; fe; fe=fe->next) {
459 if (FD_ISSET(fe->fd, &r_fds)) flags |= EVENT_FD_READ;
460 if (FD_ISSET(fe->fd, &w_fds)) flags |= EVENT_FD_WRITE;
462 fe->handler(ev, fe, flags, fe->private);
463 if (destruction_count != ev->destruction_count) {
474 do a single event loop using the events defined in ev
476 int event_loop_once(struct event_context *ev)
478 struct timeval tval, *tvalp;
482 /* work out the right timeout for all timed events */
483 if (ev->timed_events) {
484 struct timeval t = timeval_current();
485 tval = timeval_diff(&ev->timed_events->next_event, &t);
487 if (timeval_is_zero(tvalp)) {
488 event_loop_timer(ev);
494 if (ev->epoll_fd != -1) {
495 if (event_loop_epoll(ev, tvalp) == 0) {
501 return event_loop_select(ev, tvalp);
505 go into an event loop using the events defined in ev this function
506 will return with the specified code if one of the handlers calls
509 also return (with code 0) if all fd events are removed
511 int event_loop_wait(struct event_context *ev)
514 ev->maxfd = EVENT_INVALID_MAXFD;
516 while (ev->fd_events && ev->exit_code == 0) {
517 if (event_loop_once(ev) != 0) {
522 return ev->exit_code;