2 Unix SMB/CIFS implementation.
3 main select loop and event handling
4 Copyright (C) Andrew Tridgell 2003-2005
5 Copyright (C) Stefan Metzmacher 2005
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 This is SAMBA's default event loop code
25 - we try to use epoll if configure detected support for it
26 otherwise we use select()
27 - if epoll is broken on the system or the kernel doesn't support it
28 at runtime we fallback to select()
32 #include "system/filesys.h"
33 #include "dlinklist.h"
34 #include "lib/events/events.h"
35 #include "lib/events/events_internal.h"
37 /* use epoll if it is available */
38 #if defined(HAVE_EPOLL_CREATE) && defined(HAVE_SYS_EPOLL_H)
43 #include <sys/epoll.h>
46 struct std_event_context {
47 /* list of filedescriptor events */
48 struct fd_event *fd_events;
50 /* list of timed events */
51 struct timed_event *timed_events;
53 /* the maximum file descriptor number in fd_events */
56 /* information for exiting from the event loop */
59 /* this is changed by the destructors for the fd event
60 type. It is used to detect event destruction by event
61 handlers, which means the code that is calling the event
62 handler needs to assume that the linked list is no longer
65 uint32_t destruction_count;
68 /* when using epoll this is the handle from epoll_create */
74 destroy an event context
76 static int std_event_context_destructor(void *ptr)
79 struct event_context *ev = talloc_get_type(ptr, struct event_context);
80 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
81 struct std_event_context);
82 if (std_ev->epoll_fd != -1) {
83 close(std_ev->epoll_fd);
84 std_ev->epoll_fd = -1;
91 create a std_event_context structure.
93 static int std_event_context_init(struct event_context *ev, void *privata_data)
95 struct std_event_context *std_ev;
97 std_ev = talloc_zero(ev, struct std_event_context);
98 if (!std_ev) return -1;
101 std_ev->epoll_fd = epoll_create(64);
104 ev->additional_data = std_ev;
106 talloc_set_destructor(ev, std_event_context_destructor);
112 recalculate the maxfd
114 static void calc_maxfd(struct event_context *ev)
116 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
117 struct std_event_context);
118 struct fd_event *fde;
121 for (fde = std_ev->fd_events; fde; fde = fde->next) {
122 if (fde->fd > std_ev->maxfd) {
123 std_ev->maxfd = fde->fd;
129 /* to mark the ev->maxfd invalid
130 * this means we need to recalculate it
132 #define EVENT_INVALID_MAXFD (-1)
137 called when a epoll call fails, and we should fallback
140 static void epoll_fallback_to_select(struct event_context *ev, const char *reason)
142 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
143 struct std_event_context);
144 DEBUG(0,("%s (%s) - falling back to select()\n", reason, strerror(errno)));
145 close(std_ev->epoll_fd);
146 std_ev->epoll_fd = -1;
153 map from EVENT_FD_* to EPOLLIN/EPOLLOUT
155 static uint32_t epoll_map_flags(uint16_t flags)
158 if (flags & EVENT_FD_READ) ret |= EPOLLIN;
159 if (flags & EVENT_FD_WRITE) ret |= EPOLLOUT;
167 static int std_event_fd_destructor(void *ptr)
169 struct fd_event *fde = talloc_get_type(ptr, struct fd_event);
170 struct event_context *ev = fde->event_ctx;
171 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
172 struct std_event_context);
174 if (std_ev->maxfd == fde->fd) {
175 std_ev->maxfd = EVENT_INVALID_MAXFD;
177 DLIST_REMOVE(std_ev->fd_events, fde);
178 std_ev->destruction_count++;
180 if (std_ev->epoll_fd != -1) {
181 struct epoll_event event;
183 event.events = epoll_map_flags(fde->flags);
184 event.data.ptr = fde;
185 epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
193 return NULL on failure (memory allocation error)
195 static struct fd_event *std_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
196 int fd, uint16_t flags,
197 event_fd_handler_t handler,
200 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
201 struct std_event_context);
202 struct fd_event *fde;
204 fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event);
205 if (!fde) return NULL;
210 fde->handler = handler;
211 fde->private_data = private_data;
212 fde->additional_data = NULL;
214 DLIST_ADD(std_ev->fd_events, fde);
216 if (fde->fd > std_ev->maxfd) {
217 std_ev->maxfd = fde->fd;
220 talloc_set_destructor(fde, std_event_fd_destructor);
223 if (std_ev->epoll_fd != -1) {
224 struct epoll_event event;
226 event.events = epoll_map_flags(flags);
227 event.data.ptr = fde;
228 if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
229 epoll_fallback_to_select(ev, "EPOLL_CTL_ADD failed");
239 return the fd event flags
241 static uint16_t std_event_get_fd_flags(struct fd_event *fde)
243 return fde?fde->flags:0;
247 set the fd event flags
249 static void std_event_set_fd_flags(struct fd_event *fde, uint16_t flags)
252 struct event_context *ev;
253 struct std_event_context *std_ev;
255 fde->flags == flags) {
259 std_ev = talloc_get_type(ev->additional_data, struct std_event_context);
260 if (std_ev->epoll_fd != -1) {
261 struct epoll_event event;
263 event.events = epoll_map_flags(flags);
264 event.data.ptr = fde;
265 if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
266 epoll_fallback_to_select(ev, "EPOLL_CTL_MOD failed");
276 destroy a timed event
278 static int std_event_timed_destructor(void *ptr)
280 struct timed_event *te = talloc_get_type(ptr, struct timed_event);
281 struct std_event_context *std_ev = talloc_get_type(te->event_ctx->additional_data,
282 struct std_event_context);
283 DLIST_REMOVE(std_ev->timed_events, te);
289 return NULL on failure (memory allocation error)
291 static struct timed_event *std_event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx,
292 struct timeval next_event,
293 event_timed_handler_t handler,
296 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
297 struct std_event_context);
298 struct timed_event *te, *last_te, *cur_te;
300 te = talloc(mem_ctx?mem_ctx:ev, struct timed_event);
301 if (te == NULL) return NULL;
304 te->next_event = next_event;
305 te->handler = handler;
306 te->private_data = private_data;
307 te->additional_data = NULL;
309 /* keep the list ordered */
311 for (cur_te = std_ev->timed_events; cur_te; cur_te = cur_te->next) {
312 /* if the new event comes before the current one break */
313 if (!timeval_is_zero(&cur_te->next_event) &&
314 timeval_compare(&cur_te->next_event, &te->next_event) < 0) {
321 DLIST_ADD_AFTER(std_ev->timed_events, te, last_te);
323 talloc_set_destructor(te, std_event_timed_destructor);
329 a timer has gone off - call it
331 static void std_event_loop_timer(struct event_context *ev)
333 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
334 struct std_event_context);
335 struct timeval t = timeval_current();
336 struct timed_event *te = std_ev->timed_events;
338 te->next_event = timeval_zero();
340 te->handler(ev, te, t, te->private_data);
342 /* note the care taken to prevent referencing a event
343 that could have been freed by the handler */
344 if (std_ev->timed_events) {
345 if (timeval_is_zero(&std_ev->timed_events->next_event)) {
353 event loop handling using epoll
355 static int std_event_loop_epoll(struct event_context *ev, struct timeval *tvalp)
357 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
358 struct std_event_context);
360 const int maxevents = 8;
361 struct epoll_event events[maxevents];
362 uint32_t destruction_count = std_ev->destruction_count;
366 /* it's better to trigger timed events a bit later than to early */
367 timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
370 ret = epoll_wait(std_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 std_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|EPOLLHUP|EPOLLERR))
392 flags |= EVENT_FD_READ;
393 if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE;
395 fde->handler(ev, fde, flags, fde->private_data);
396 if (destruction_count != std_ev->destruction_count) {
407 event loop handling using select()
409 static int std_event_loop_select(struct event_context *ev, struct timeval *tvalp)
411 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
412 struct std_event_context);
414 struct fd_event *fde;
416 uint32_t destruction_count = std_ev->destruction_count;
418 /* we maybe need to recalculate the maxfd */
419 if (std_ev->maxfd == EVENT_INVALID_MAXFD) {
426 /* setup any fd events */
427 for (fde = std_ev->fd_events; fde; fde = fde->next) {
428 if (fde->flags & EVENT_FD_READ) {
429 FD_SET(fde->fd, &r_fds);
431 if (fde->flags & EVENT_FD_WRITE) {
432 FD_SET(fde->fd, &w_fds);
436 selrtn = select(std_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
438 if (selrtn == -1 && errno == EBADF) {
439 /* the socket is dead! this should never
440 happen as the socket should have first been
441 made readable and that should have removed
442 the event, so this must be a bug. This is a
444 DEBUG(0,("ERROR: EBADF on std_event_loop_once\n"));
445 std_ev->exit_code = EBADF;
449 if (selrtn == 0 && tvalp) {
450 std_event_loop_timer(ev);
455 /* at least one file descriptor is ready - check
456 which ones and call the handler, being careful to allow
457 the handler to remove itself when called */
458 for (fde = std_ev->fd_events; fde; fde = fde->next) {
461 if (FD_ISSET(fde->fd, &r_fds)) flags |= EVENT_FD_READ;
462 if (FD_ISSET(fde->fd, &w_fds)) flags |= EVENT_FD_WRITE;
464 fde->handler(ev, fde, flags, fde->private_data);
465 if (destruction_count != std_ev->destruction_count) {
476 do a single event loop using the events defined in ev
478 static int std_event_loop_once(struct event_context *ev)
480 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
481 struct std_event_context);
482 struct timeval tval, *tvalp;
486 /* work out the right timeout for all timed events */
487 if (std_ev->timed_events) {
488 struct timeval t = timeval_current();
490 tval = timeval_diff(&std_ev->timed_events->next_event, &t);
492 if (timeval_is_zero(tvalp)) {
493 std_event_loop_timer(ev);
499 if (std_ev->epoll_fd != -1) {
500 if (std_event_loop_epoll(ev, tvalp) == 0) {
506 return std_event_loop_select(ev, tvalp);
510 return on failure or (with 0) if all fd events are removed
512 static int std_event_loop_wait(struct event_context *ev)
514 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
515 struct std_event_context);
516 std_ev->exit_code = 0;
517 std_ev->maxfd = EVENT_INVALID_MAXFD;
519 while (std_ev->fd_events && std_ev->exit_code == 0) {
520 if (std_event_loop_once(ev) != 0) {
525 return std_ev->exit_code;
528 static const struct event_ops std_event_ops = {
529 .context_init = std_event_context_init,
530 .add_fd = std_event_add_fd,
531 .get_fd_flags = std_event_get_fd_flags,
532 .set_fd_flags = std_event_set_fd_flags,
533 .add_timed = std_event_add_timed,
534 .loop_once = std_event_loop_once,
535 .loop_wait = std_event_loop_wait,
538 const struct event_ops *event_standard_get_ops(void)
540 return &std_event_ops;