2 Unix SMB/CIFS implementation.
4 main select loop and event handling - epoll implementation
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Stefan Metzmacher 2005-2013
8 Copyright (C) Jeremy Allison 2013
10 ** NOTE! The following LGPL license applies to the tevent
11 ** library. This does NOT imply that all of Samba is released
14 This library is free software; you can redistribute it and/or
15 modify it under the terms of the GNU Lesser General Public
16 License as published by the Free Software Foundation; either
17 version 3 of the License, or (at your option) any later version.
19 This library is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 Lesser General Public License for more details.
24 You should have received a copy of the GNU Lesser General Public
25 License along with this library; if not, see <http://www.gnu.org/licenses/>.
29 #include "system/filesys.h"
30 #include "system/select.h"
32 #include "tevent_internal.h"
33 #include "tevent_util.h"
35 #define TEST_PANIC_FALLBACK
37 struct epoll_event_context {
38 /* a pointer back to the generic event_context */
39 struct tevent_context *ev;
41 /* when using epoll this is the handle from epoll_create */
46 bool panic_force_replay;
48 bool (*panic_fallback)(struct tevent_context *ev, bool replay);
51 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0)
52 #define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1)
53 #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2)
54 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX (1<<3)
56 #ifdef TEST_PANIC_FALLBACK
58 static int epoll_create_panic_fallback(struct epoll_event_context *epoll_ev,
61 if (epoll_ev->panic_fallback == NULL) {
62 return epoll_create(size);
65 /* 50% of the time, fail... */
66 if ((random() % 2) == 0) {
71 return epoll_create(size);
74 static int epoll_ctl_panic_fallback(struct epoll_event_context *epoll_ev,
75 int epfd, int op, int fd,
76 struct epoll_event *event)
78 if (epoll_ev->panic_fallback == NULL) {
79 return epoll_ctl(epfd, op, fd, event);
82 /* 50% of the time, fail... */
83 if ((random() % 2) == 0) {
88 return epoll_ctl(epfd, op, fd, event);
91 static int epoll_wait_panic_fallback(struct epoll_event_context *epoll_ev,
93 struct epoll_event *events,
97 if (epoll_ev->panic_fallback == NULL) {
98 return epoll_wait(epfd, events, maxevents, timeout);
101 /* 50% of the time, fail... */
102 if ((random() % 2) == 0) {
107 return epoll_wait(epfd, events, maxevents, timeout);
110 #define epoll_create(_size) \
111 epoll_create_panic_fallback(epoll_ev, _size)
112 #define epoll_ctl(_epfd, _op, _fd, _event) \
113 epoll_ctl_panic_fallback(epoll_ev,_epfd, _op, _fd, _event)
114 #define epoll_wait(_epfd, _events, _maxevents, _timeout) \
115 epoll_wait_panic_fallback(epoll_ev, _epfd, _events, _maxevents, _timeout)
119 called to set the panic fallback function.
121 _PRIVATE_ bool tevent_epoll_set_panic_fallback(struct tevent_context *ev,
122 bool (*panic_fallback)(struct tevent_context *ev,
125 struct epoll_event_context *epoll_ev;
127 if (ev->additional_data == NULL) {
131 epoll_ev = talloc_get_type(ev->additional_data,
132 struct epoll_event_context);
133 if (epoll_ev == NULL) {
136 epoll_ev->panic_fallback = panic_fallback;
141 called when a epoll call fails
143 static void epoll_panic(struct epoll_event_context *epoll_ev,
144 const char *reason, bool replay)
146 struct tevent_context *ev = epoll_ev->ev;
147 bool (*panic_fallback)(struct tevent_context *ev, bool replay);
149 panic_fallback = epoll_ev->panic_fallback;
151 if (epoll_ev->panic_state != NULL) {
152 *epoll_ev->panic_state = true;
155 if (epoll_ev->panic_force_replay) {
159 TALLOC_FREE(ev->additional_data);
161 if (panic_fallback == NULL) {
162 tevent_debug(ev, TEVENT_DEBUG_FATAL,
163 "%s (%s) replay[%u] - calling abort()\n",
164 reason, strerror(errno), (unsigned)replay);
168 tevent_debug(ev, TEVENT_DEBUG_ERROR,
169 "%s (%s) replay[%u] - calling panic_fallback\n",
170 reason, strerror(errno), (unsigned)replay);
172 if (!panic_fallback(ev, replay)) {
173 /* Fallback failed. */
174 tevent_debug(ev, TEVENT_DEBUG_FATAL,
175 "%s (%s) replay[%u] - calling abort()\n",
176 reason, strerror(errno), (unsigned)replay);
182 map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
184 static uint32_t epoll_map_flags(uint16_t flags)
187 if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
188 if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
195 static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev)
197 close(epoll_ev->epoll_fd);
198 epoll_ev->epoll_fd = -1;
205 static int epoll_init_ctx(struct epoll_event_context *epoll_ev)
207 epoll_ev->epoll_fd = epoll_create(64);
208 if (epoll_ev->epoll_fd == -1) {
209 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
210 "Failed to create epoll handle.\n");
214 if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) {
215 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
216 "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
219 epoll_ev->pid = getpid();
220 talloc_set_destructor(epoll_ev, epoll_ctx_destructor);
225 static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
228 reopen the epoll handle when our pid changes
229 see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
230 demonstration of why this is needed
232 static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
234 struct tevent_fd *fde;
235 bool *caller_panic_state = epoll_ev->panic_state;
236 bool panic_triggered = false;
238 if (epoll_ev->pid == getpid()) {
242 close(epoll_ev->epoll_fd);
243 epoll_ev->epoll_fd = epoll_create(64);
244 if (epoll_ev->epoll_fd == -1) {
245 epoll_panic(epoll_ev, "epoll_create() failed", false);
249 if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) {
250 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
251 "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
254 epoll_ev->pid = getpid();
255 epoll_ev->panic_state = &panic_triggered;
256 for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
257 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
258 epoll_update_event(epoll_ev, fde);
260 if (panic_triggered) {
261 if (caller_panic_state != NULL) {
262 *caller_panic_state = true;
267 epoll_ev->panic_state = NULL;
271 epoll cannot add the same file descriptor twice, once
272 with read, once with write which is allowed by the
273 tevent backend. Multiplex the existing fde, flag it
274 as such so we can search for the correct fde on
278 static int epoll_add_multiplex_fd(struct epoll_event_context *epoll_ev,
279 struct tevent_fd *add_fde)
281 struct epoll_event event;
282 struct tevent_fd *mpx_fde;
285 /* Find the existing fde that caused the EEXIST error. */
286 for (mpx_fde = epoll_ev->ev->fd_events; mpx_fde; mpx_fde = mpx_fde->next) {
287 if (mpx_fde->fd != add_fde->fd) {
291 if (mpx_fde == add_fde) {
297 if (mpx_fde == NULL) {
298 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
299 "can't find multiplex fde for fd[%d]",
304 if (mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
305 /* Logic error. Can't have more than 2 multiplexed fde's. */
306 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
307 "multiplex fde for fd[%d] is already multiplexed\n",
313 * The multiplex fde must have the same fd, and also
314 * already have an epoll event attached.
316 if (!(mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) {
317 /* Logic error. Can't have more than 2 multiplexed fde's. */
318 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
319 "multiplex fde for fd[%d] has no event\n",
324 /* Modify the orig_fde to add in the new flags. */
326 event.events = epoll_map_flags(mpx_fde->flags);
327 event.events |= epoll_map_flags(add_fde->flags);
328 event.data.ptr = mpx_fde;
329 ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, mpx_fde->fd, &event);
330 if (ret != 0 && errno == EBADF) {
331 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR,
332 "EPOLL_CTL_MOD EBADF for "
333 "add_fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
334 add_fde, mpx_fde, add_fde->fd);
335 DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
336 mpx_fde->event_ctx = NULL;
337 DLIST_REMOVE(epoll_ev->ev->fd_events, add_fde);
338 add_fde->event_ctx = NULL;
340 } else if (ret != 0) {
345 * Make each fde->additional_data pointers point at each other
346 * so we can look them up from each other. They are now paired.
348 mpx_fde->additional_data = (struct tevent_fd *)add_fde;
349 add_fde->additional_data = (struct tevent_fd *)mpx_fde;
351 /* Now flag both fde's as being multiplexed. */
352 mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
353 add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
355 /* we need to keep the GOT_ERROR flag */
356 if (mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR) {
357 add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
364 add the epoll event to the given fd_event
366 static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
368 struct epoll_event event;
370 struct tevent_fd *mpx_fde = NULL;
372 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
373 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
375 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
377 * This is a multiplexed fde, we need to include both
378 * flags in the modified event.
380 mpx_fde = talloc_get_type_abort(fde->additional_data,
383 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
384 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
388 event.events = epoll_map_flags(fde->flags);
389 if (mpx_fde != NULL) {
390 event.events |= epoll_map_flags(mpx_fde->flags);
392 event.data.ptr = fde;
393 ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event);
394 if (ret != 0 && errno == EBADF) {
395 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR,
396 "EPOLL_CTL_ADD EBADF for "
397 "fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
398 fde, mpx_fde, fde->fd);
399 DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
400 fde->event_ctx = NULL;
401 if (mpx_fde != NULL) {
402 DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
403 mpx_fde->event_ctx = NULL;
406 } else if (ret != 0 && errno == EEXIST && mpx_fde == NULL) {
407 ret = epoll_add_multiplex_fd(epoll_ev, fde);
409 epoll_panic(epoll_ev, "epoll_add_multiplex_fd failed",
413 } else if (ret != 0) {
414 epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed", false);
418 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
419 /* only if we want to read we want to tell the event handler about errors */
420 if (fde->flags & TEVENT_FD_READ) {
421 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
424 if (mpx_fde == NULL) {
428 mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
429 /* only if we want to read we want to tell the event handler about errors */
430 if (mpx_fde->flags & TEVENT_FD_READ) {
431 mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
436 delete the epoll event for given fd_event
438 static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
440 struct epoll_event event;
442 struct tevent_fd *mpx_fde = NULL;
444 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
445 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
447 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
449 * This is a multiplexed fde, we need to modify both events.
451 mpx_fde = talloc_get_type_abort(fde->additional_data,
454 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
455 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
459 ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
460 if (ret != 0 && errno == ENOENT) {
462 * This can happen after a epoll_check_reopen
463 * within epoll_event_fd_destructor.
465 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_TRACE,
466 "EPOLL_CTL_DEL ignoring ENOENT for fd[%d]\n",
469 } else if (ret != 0 && errno == EBADF) {
470 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
471 "EPOLL_CTL_DEL EBADF for "
472 "fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
473 fde, mpx_fde, fde->fd);
474 DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
475 fde->event_ctx = NULL;
476 if (mpx_fde != NULL) {
477 DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
478 mpx_fde->event_ctx = NULL;
481 } else if (ret != 0) {
482 epoll_panic(epoll_ev, "EPOLL_CTL_DEL failed", false);
488 change the epoll event to the given fd_event
490 static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
492 struct tevent_fd *mpx_fde = NULL;
493 struct epoll_event event;
496 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
497 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
499 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
501 * This is a multiplexed fde, we need to include both
502 * flags in the modified event.
504 mpx_fde = talloc_get_type_abort(fde->additional_data,
507 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
508 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
512 event.events = epoll_map_flags(fde->flags);
513 if (mpx_fde != NULL) {
514 event.events |= epoll_map_flags(mpx_fde->flags);
516 event.data.ptr = fde;
517 ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event);
518 if (ret != 0 && errno == EBADF) {
519 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR,
520 "EPOLL_CTL_MOD EBADF for "
521 "fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
522 fde, mpx_fde, fde->fd);
523 DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
524 fde->event_ctx = NULL;
525 if (mpx_fde != NULL) {
526 DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
527 mpx_fde->event_ctx = NULL;
530 } else if (ret != 0) {
531 epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false);
535 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
536 /* only if we want to read we want to tell the event handler about errors */
537 if (fde->flags & TEVENT_FD_READ) {
538 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
541 if (mpx_fde == NULL) {
545 mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
546 /* only if we want to read we want to tell the event handler about errors */
547 if (mpx_fde->flags & TEVENT_FD_READ) {
548 mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
552 static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
554 bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
555 bool want_read = (fde->flags & TEVENT_FD_READ);
556 bool want_write= (fde->flags & TEVENT_FD_WRITE);
557 struct tevent_fd *mpx_fde = NULL;
559 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
561 * work out what the multiplexed fde wants.
563 mpx_fde = talloc_get_type_abort(fde->additional_data,
566 if (mpx_fde->flags & TEVENT_FD_READ) {
570 if (mpx_fde->flags & TEVENT_FD_WRITE) {
575 /* there's already an event */
576 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
577 if (want_read || (want_write && !got_error)) {
578 epoll_mod_event(epoll_ev, fde);
582 * if we want to match the select behavior, we need to remove the epoll_event
583 * when the caller isn't interested in events.
585 * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
587 epoll_del_event(epoll_ev, fde);
591 /* there's no epoll_event attached to the fde */
592 if (want_read || (want_write && !got_error)) {
593 epoll_add_event(epoll_ev, fde);
599 Cope with epoll returning EPOLLHUP|EPOLLERR on an event.
600 Return true if there's nothing else to do, false if
601 this event needs further handling.
603 static bool epoll_handle_hup_or_err(struct epoll_event_context *epoll_ev,
604 struct tevent_fd *fde)
607 /* Nothing to do if no event. */
611 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
613 * if we only wait for TEVENT_FD_WRITE, we should not tell the
614 * event handler about it, and remove the epoll_event,
615 * as we only report errors when waiting for read events,
616 * to match the select() behavior
618 if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
620 * Do the same as the poll backend and
621 * remove the writeable flag.
623 fde->flags &= ~TEVENT_FD_WRITE;
626 /* This has TEVENT_FD_READ set, we're not finished. */
631 event loop handling using epoll
633 static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
637 struct epoll_event events[MAXEVENTS];
642 /* it's better to trigger timed events a bit later than too early */
643 timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
646 if (epoll_ev->ev->signal_events &&
647 tevent_common_check_signal(epoll_ev->ev)) {
651 tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
652 ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
654 tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
656 if (ret == -1 && wait_errno == EINTR && epoll_ev->ev->signal_events) {
657 if (tevent_common_check_signal(epoll_ev->ev)) {
662 if (ret == -1 && wait_errno != EINTR) {
663 epoll_panic(epoll_ev, "epoll_wait() failed", true);
667 if (ret == 0 && tvalp) {
668 /* we don't care about a possible delay here */
669 tevent_common_loop_timer_delay(epoll_ev->ev);
673 for (i=0;i<ret;i++) {
674 struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
677 struct tevent_fd *mpx_fde = NULL;
680 epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
683 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
685 * Save off the multiplexed event in case we need
686 * to use it to call the handler function.
688 mpx_fde = talloc_get_type_abort(fde->additional_data,
691 if (events[i].events & (EPOLLHUP|EPOLLERR)) {
692 bool handled_fde = epoll_handle_hup_or_err(epoll_ev, fde);
693 bool handled_mpx = epoll_handle_hup_or_err(epoll_ev, mpx_fde);
695 if (handled_fde && handled_mpx) {
696 epoll_update_event(epoll_ev, fde);
702 * If the mpx event was the one that needs
703 * further handling, it's the TEVENT_FD_READ
704 * event so switch over and call that handler.
709 flags |= TEVENT_FD_READ;
711 if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
712 if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
714 if (flags & TEVENT_FD_WRITE) {
715 if (fde->flags & TEVENT_FD_WRITE) {
718 if (mpx_fde && mpx_fde->flags & TEVENT_FD_WRITE) {
725 /* Ensure we got the right fde. */
726 if ((flags & fde->flags) == 0) {
733 * make sure we only pass the flags
734 * the handler is expecting.
738 fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
747 create a epoll_event_context structure.
749 static int epoll_event_context_init(struct tevent_context *ev)
752 struct epoll_event_context *epoll_ev;
755 * We might be called during tevent_re_initialise()
756 * which means we need to free our old additional_data.
758 TALLOC_FREE(ev->additional_data);
760 epoll_ev = talloc_zero(ev, struct epoll_event_context);
761 if (!epoll_ev) return -1;
763 epoll_ev->epoll_fd = -1;
765 ret = epoll_init_ctx(epoll_ev);
767 talloc_free(epoll_ev);
771 ev->additional_data = epoll_ev;
778 static int epoll_event_fd_destructor(struct tevent_fd *fde)
780 struct tevent_context *ev = fde->event_ctx;
781 struct epoll_event_context *epoll_ev = NULL;
782 bool panic_triggered = false;
783 struct tevent_fd *mpx_fde = NULL;
784 int flags = fde->flags;
787 return tevent_common_fd_destructor(fde);
790 epoll_ev = talloc_get_type_abort(ev->additional_data,
791 struct epoll_event_context);
794 * we must remove the event from the list
795 * otherwise a panic fallback handler may
796 * reuse invalid memory
798 DLIST_REMOVE(ev->fd_events, fde);
800 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
801 mpx_fde = talloc_get_type_abort(fde->additional_data,
804 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
805 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
807 fde->additional_data = NULL;
808 mpx_fde->additional_data = NULL;
810 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
813 epoll_ev->panic_state = &panic_triggered;
814 epoll_check_reopen(epoll_ev);
815 if (panic_triggered) {
816 return tevent_common_fd_destructor(fde);
819 if (mpx_fde != NULL) {
820 epoll_update_event(epoll_ev, mpx_fde);
821 if (panic_triggered) {
822 return tevent_common_fd_destructor(fde);
827 epoll_update_event(epoll_ev, fde);
829 if (panic_triggered) {
830 return tevent_common_fd_destructor(fde);
832 epoll_ev->panic_state = NULL;
834 return tevent_common_fd_destructor(fde);
839 return NULL on failure (memory allocation error)
841 static struct tevent_fd *epoll_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
842 int fd, uint16_t flags,
843 tevent_fd_handler_t handler,
845 const char *handler_name,
846 const char *location)
848 struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
849 struct epoll_event_context);
850 struct tevent_fd *fde;
851 bool panic_triggered = false;
853 fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
854 handler, private_data,
855 handler_name, location);
856 if (!fde) return NULL;
858 talloc_set_destructor(fde, epoll_event_fd_destructor);
860 epoll_ev->panic_state = &panic_triggered;
861 epoll_check_reopen(epoll_ev);
862 if (panic_triggered) {
865 epoll_ev->panic_state = NULL;
867 epoll_update_event(epoll_ev, fde);
873 set the fd event flags
875 static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
877 struct tevent_context *ev;
878 struct epoll_event_context *epoll_ev;
879 bool panic_triggered = false;
881 if (fde->flags == flags) return;
884 epoll_ev = talloc_get_type(ev->additional_data, struct epoll_event_context);
888 epoll_ev->panic_state = &panic_triggered;
889 epoll_check_reopen(epoll_ev);
890 if (panic_triggered) {
893 epoll_ev->panic_state = NULL;
895 epoll_update_event(epoll_ev, fde);
899 do a single event loop using the events defined in ev
901 static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
903 struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
904 struct epoll_event_context);
906 bool panic_triggered = false;
908 if (ev->signal_events &&
909 tevent_common_check_signal(ev)) {
913 if (ev->immediate_events &&
914 tevent_common_loop_immediate(ev)) {
918 tval = tevent_common_loop_timer_delay(ev);
919 if (tevent_timeval_is_zero(&tval)) {
923 epoll_ev->panic_state = &panic_triggered;
924 epoll_ev->panic_force_replay = true;
925 epoll_check_reopen(epoll_ev);
926 if (panic_triggered) {
930 epoll_ev->panic_force_replay = false;
931 epoll_ev->panic_state = NULL;
933 return epoll_event_loop(epoll_ev, &tval);
936 static const struct tevent_ops epoll_event_ops = {
937 .context_init = epoll_event_context_init,
938 .add_fd = epoll_event_add_fd,
939 .set_fd_close_fn = tevent_common_fd_set_close_fn,
940 .get_fd_flags = tevent_common_fd_get_flags,
941 .set_fd_flags = epoll_event_set_fd_flags,
942 .add_timer = tevent_common_add_timer_v2,
943 .schedule_immediate = tevent_common_schedule_immediate,
944 .add_signal = tevent_common_add_signal,
945 .loop_once = epoll_event_loop_once,
946 .loop_wait = tevent_common_loop_wait,
949 _PRIVATE_ bool tevent_epoll_init(void)
951 return tevent_register_backend("epoll", &epoll_event_ops);