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"
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 - using select() - %s\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 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 0) {
201 epoll_fallback_to_select(ev, "EPOLL_CTL_DEL failed");
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;
267 if (fde == NULL) return;
269 if (ev->epoll_fd != -1) {
270 struct epoll_event event;
272 event.events = epoll_map_flags(flags);
273 event.data.ptr = fde;
274 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
275 epoll_fallback_to_select(ev, "EPOLL_CTL_MOD failed");
285 destroy a timed event
287 static int event_timed_destructor(void *ptr)
289 struct timed_event *te = talloc_get_type(ptr, struct timed_event);
290 DLIST_REMOVE(te->event_ctx->timed_events, te);
296 return NULL on failure (memory allocation error)
298 struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx,
299 struct timeval next_event,
300 event_timed_handler_t handler,
303 struct timed_event *te, *e;
305 e = talloc(mem_ctx?mem_ctx:ev, struct timed_event);
306 if (e == NULL) return NULL;
309 e->next_event = next_event;
310 e->handler = handler;
311 e->private = private;
313 /* keep the list ordered */
314 if (ev->timed_events == NULL ||
315 timeval_compare(&e->next_event, &ev->timed_events->next_event) > 0) {
316 DLIST_ADD(ev->timed_events, e);
318 for (te=ev->timed_events;te && te->next;te=te->next) {
319 if (!timeval_is_zero(&te->next_event) &&
320 timeval_compare(&te->next_event, &e->next_event) < 0) {
324 DLIST_ADD_AFTER(ev->timed_events, e, te);
327 talloc_set_destructor(e, event_timed_destructor);
333 a timer has gone off - call it
335 static void event_loop_timer(struct event_context *ev)
337 struct timeval t = timeval_current();
338 struct timed_event *te = ev->timed_events;
340 te->next_event = timeval_zero();
342 te->handler(ev, te, t, te->private);
344 /* note the care taken to prevent referencing a event
345 that could have been freed by the handler */
346 if (ev->timed_events && timeval_is_zero(&ev->timed_events->next_event)) {
347 talloc_free(ev->timed_events);
353 event loop handling using epoll
355 static int event_loop_epoll(struct event_context *ev, struct timeval *tvalp)
358 const int maxevents = 8;
359 struct epoll_event events[maxevents];
360 uint32_t destruction_count = ev->destruction_count;
364 timeout = (tvalp->tv_usec / 1000) + (tvalp->tv_sec*1000);
367 ret = epoll_wait(ev->epoll_fd, events, maxevents, timeout);
369 if (ret == -1 && errno != EINTR) {
370 epoll_fallback_to_select(ev, "epoll_wait() failed");
374 if (ret == 0 && tvalp) {
375 event_loop_timer(ev);
379 for (i=0;i<ret;i++) {
380 struct fd_event *fde = talloc_get_type(events[i].data.ptr,
385 epoll_fallback_to_select(ev, "epoll_wait() gave bad data");
388 if (events[i].events & EPOLLIN) flags |= EVENT_FD_READ;
389 if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE;
391 fde->handler(ev, fde, flags, fde->private);
392 if (destruction_count != ev->destruction_count) {
403 event loop handling using select()
405 static int event_loop_select(struct event_context *ev, struct timeval *tvalp)
409 uint32_t destruction_count = ev->destruction_count;
412 /* we maybe need to recalculate the maxfd */
413 if (ev->maxfd == EVENT_INVALID_MAXFD) {
420 /* setup any fd events */
421 for (fe=ev->fd_events; fe; ) {
422 struct fd_event *next = fe->next;
423 if (fe->flags & EVENT_FD_READ) {
424 FD_SET(fe->fd, &r_fds);
426 if (fe->flags & EVENT_FD_WRITE) {
427 FD_SET(fe->fd, &w_fds);
432 selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
434 if (selrtn == -1 && errno == EBADF) {
435 /* the socket is dead! this should never
436 happen as the socket should have first been
437 made readable and that should have removed
438 the event, so this must be a bug. This is a
440 DEBUG(0,("ERROR: EBADF on event_loop_once\n"));
441 ev->exit_code = EBADF;
445 if (selrtn == 0 && tvalp) {
446 event_loop_timer(ev);
451 /* at least one file descriptor is ready - check
452 which ones and call the handler, being careful to allow
453 the handler to remove itself when called */
454 for (fe=ev->fd_events; fe; fe=fe->next) {
456 if (FD_ISSET(fe->fd, &r_fds)) flags |= EVENT_FD_READ;
457 if (FD_ISSET(fe->fd, &w_fds)) flags |= EVENT_FD_WRITE;
459 fe->handler(ev, fe, flags, fe->private);
460 if (destruction_count != ev->destruction_count) {
471 do a single event loop using the events defined in ev
473 int event_loop_once(struct event_context *ev)
475 struct timeval tval, *tvalp;
479 /* work out the right timeout for all timed events */
480 if (ev->timed_events) {
481 struct timeval t = timeval_current();
482 tval = timeval_diff(&ev->timed_events->next_event, &t);
484 if (timeval_is_zero(tvalp)) {
485 event_loop_timer(ev);
491 if (ev->epoll_fd != -1) {
492 if (event_loop_epoll(ev, tvalp) == 0) {
498 return event_loop_select(ev, tvalp);
502 go into an event loop using the events defined in ev this function
503 will return with the specified code if one of the handlers calls
506 also return (with code 0) if all fd events are removed
508 int event_loop_wait(struct event_context *ev)
511 ev->maxfd = EVENT_INVALID_MAXFD;
513 while (ev->fd_events && ev->exit_code == 0) {
514 if (event_loop_once(ev) != 0) {
519 return ev->exit_code;