pidl:Wireshark Fix the type of array of pointerse to hf_ values
[Samba.git] / lib / tevent / tevent_epoll.c
blobe56bd026887a5d2c6a9e886f9033893e13bdadc4
1 /*
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
12 ** under the LGPL
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/>.
28 #include "replace.h"
29 #include "system/filesys.h"
30 #include "system/select.h"
31 #include "tevent.h"
32 #include "tevent_internal.h"
33 #include "tevent_util.h"
35 struct epoll_event_context {
36 /* a pointer back to the generic event_context */
37 struct tevent_context *ev;
39 /* when using epoll this is the handle from epoll_create1(2) */
40 int epoll_fd;
42 pid_t pid;
44 bool panic_force_replay;
45 bool *panic_state;
46 bool (*panic_fallback)(struct tevent_context *ev, bool replay);
49 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0)
50 #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<1)
52 #ifdef TEST_PANIC_FALLBACK
54 static int epoll_create1_panic_fallback(struct epoll_event_context *epoll_ev,
55 int flags)
57 if (epoll_ev->panic_fallback == NULL) {
58 return epoll_create1(flags);
61 /* 50% of the time, fail... */
62 if ((random() % 2) == 0) {
63 errno = EINVAL;
64 return -1;
67 return epoll_create1(flags);
70 static int epoll_ctl_panic_fallback(struct epoll_event_context *epoll_ev,
71 int epfd, int op, int fd,
72 struct epoll_event *event)
74 if (epoll_ev->panic_fallback == NULL) {
75 return epoll_ctl(epfd, op, fd, event);
78 /* 50% of the time, fail... */
79 if ((random() % 2) == 0) {
80 errno = EINVAL;
81 return -1;
84 return epoll_ctl(epfd, op, fd, event);
87 static int epoll_wait_panic_fallback(struct epoll_event_context *epoll_ev,
88 int epfd,
89 struct epoll_event *events,
90 int maxevents,
91 int timeout)
93 if (epoll_ev->panic_fallback == NULL) {
94 return epoll_wait(epfd, events, maxevents, timeout);
97 /* 50% of the time, fail... */
98 if ((random() % 2) == 0) {
99 errno = EINVAL;
100 return -1;
103 return epoll_wait(epfd, events, maxevents, timeout);
106 #define epoll_create1(_flags) \
107 epoll_create1_panic_fallback(epoll_ev, _flags)
108 #define epoll_ctl(_epfd, _op, _fd, _event) \
109 epoll_ctl_panic_fallback(epoll_ev,_epfd, _op, _fd, _event)
110 #define epoll_wait(_epfd, _events, _maxevents, _timeout) \
111 epoll_wait_panic_fallback(epoll_ev, _epfd, _events, _maxevents, _timeout)
112 #endif
115 called to set the panic fallback function.
117 _PRIVATE_ void tevent_epoll_set_panic_fallback(struct tevent_context *ev,
118 bool (*panic_fallback)(struct tevent_context *ev,
119 bool replay))
121 struct epoll_event_context *epoll_ev =
122 talloc_get_type_abort(ev->additional_data,
123 struct epoll_event_context);
125 epoll_ev->panic_fallback = panic_fallback;
129 called when a epoll call fails
131 static void epoll_panic(struct epoll_event_context *epoll_ev,
132 const char *reason, bool replay)
134 struct tevent_context *ev = epoll_ev->ev;
135 bool (*panic_fallback)(struct tevent_context *ev, bool replay);
137 panic_fallback = epoll_ev->panic_fallback;
139 if (epoll_ev->panic_state != NULL) {
140 *epoll_ev->panic_state = true;
143 if (epoll_ev->panic_force_replay) {
144 replay = true;
147 TALLOC_FREE(ev->additional_data);
149 if (panic_fallback == NULL) {
150 tevent_debug(ev, TEVENT_DEBUG_FATAL,
151 "%s (%s) replay[%u] - calling abort()\n",
152 reason, strerror(errno), (unsigned)replay);
153 abort();
156 tevent_debug(ev, TEVENT_DEBUG_ERROR,
157 "%s (%s) replay[%u] - calling panic_fallback\n",
158 reason, strerror(errno), (unsigned)replay);
160 if (!panic_fallback(ev, replay)) {
161 /* Fallback failed. */
162 tevent_debug(ev, TEVENT_DEBUG_FATAL,
163 "%s (%s) replay[%u] - calling abort()\n",
164 reason, strerror(errno), (unsigned)replay);
165 abort();
170 map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
172 static uint32_t epoll_map_flags(uint16_t flags)
174 uint32_t ret = 0;
177 * we do not need to specify EPOLLERR | EPOLLHUP
178 * they are always reported.
181 if (flags & TEVENT_FD_READ) {
183 * Note that EPOLLRDHUP always
184 * returns EPOLLIN in addition,
185 * so EPOLLRDHUP is not strictly needed,
186 * but we want to make it explicit.
188 ret |= EPOLLIN | EPOLLRDHUP;
190 if (flags & TEVENT_FD_WRITE) {
191 ret |= EPOLLOUT;
193 if (flags & TEVENT_FD_ERROR) {
194 ret |= EPOLLRDHUP;
196 return ret;
200 free the epoll fd
202 static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev)
204 close(epoll_ev->epoll_fd);
205 epoll_ev->epoll_fd = -1;
206 return 0;
210 init the epoll fd
212 static int epoll_init_ctx(struct epoll_event_context *epoll_ev)
214 epoll_ev->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
215 if (epoll_ev->epoll_fd == -1) {
216 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
217 "Failed to create epoll handle (%s).\n",
218 strerror(errno));
219 return -1;
222 epoll_ev->pid = tevent_cached_getpid();
223 talloc_set_destructor(epoll_ev, epoll_ctx_destructor);
225 return 0;
228 static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
231 reopen the epoll handle when our pid changes
232 see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
233 demonstration of why this is needed
235 static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
237 struct tevent_fd *fde;
238 bool *caller_panic_state = epoll_ev->panic_state;
239 bool panic_triggered = false;
240 pid_t pid = tevent_cached_getpid();
242 if (epoll_ev->pid == pid) {
243 return;
246 close(epoll_ev->epoll_fd);
247 epoll_ev->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
248 if (epoll_ev->epoll_fd == -1) {
249 epoll_panic(epoll_ev, "epoll_create() failed", false);
250 return;
253 epoll_ev->pid = pid;
254 epoll_ev->panic_state = &panic_triggered;
255 for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
257 * We leave the mpx mappings alive
258 * so that we'll just re-add events for
259 * the existing primary events in the loop
260 * below.
262 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
264 for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
265 epoll_update_event(epoll_ev, fde);
267 if (panic_triggered) {
268 if (caller_panic_state != NULL) {
269 *caller_panic_state = true;
271 return;
274 epoll_ev->panic_state = NULL;
278 epoll cannot add the same file descriptor twice, once
279 with read, once with write which is allowed by the
280 tevent poll backend. Multiplex the existing fde, flag it
281 as such so we can search for the correct fde on
282 event triggering.
285 static int epoll_add_multiplex_fd(struct epoll_event_context *epoll_ev,
286 struct tevent_fd *add_fde)
288 struct tevent_fd *primary = NULL;
289 uint16_t effective_flags;
290 struct epoll_event event;
291 uint64_t clear_flags = 0;
292 uint64_t add_flags = 0;
293 int ret;
296 * Check if there is another fde we can attach to
298 primary = tevent_common_fd_mpx_add(add_fde);
299 if (primary == NULL) {
300 /* the caller calls epoll_panic() */
301 return -1;
305 * First propagate the HAS_EVENT flag from
306 * the primary to all others (mainly add_fde)
308 if (primary->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
309 add_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
310 tevent_common_fd_mpx_additional_flags(primary, 0, add_flags);
314 * Update the mpx internals and check if
315 * there is an update needed.
317 primary = tevent_common_fd_mpx_update(primary);
318 if (primary == NULL) {
320 * It seems the primary was already
321 * watching (at least) the same flags
322 * as add_fde, so we are done.
324 return 0;
328 * Before me modify the low level epoll state,
329 * we clear HAS_EVENT on all fdes.
331 clear_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
332 tevent_common_fd_mpx_additional_flags(primary, clear_flags, 0);
334 effective_flags = tevent_common_fd_mpx_flags(primary);
337 * Modify the low level epoll state to reflect
338 * the effective flags we want to monitor.
340 ZERO_STRUCT(event);
341 event.events = epoll_map_flags(effective_flags);
342 event.data.ptr = primary;
343 ret = epoll_ctl(epoll_ev->epoll_fd,
344 EPOLL_CTL_MOD,
345 primary->fd,
346 &event);
347 if (ret != 0 && errno == EBADF) {
348 struct tevent_common_fd_buf pbuf = {};
349 TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_ERROR,
350 "EPOLL_CTL_MOD EBADF for "
351 "%s - disabling\n",
352 tevent_common_fd_str(&pbuf, "primary", primary));
353 tevent_common_fd_mpx_disarm_all(primary);
354 return 0;
355 } else if (ret != 0) {
356 struct tevent_common_fd_buf pbuf = {};
357 TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_FATAL,
358 "EPOLL_CTL_MOD for %s - failed - %s",
359 tevent_common_fd_str(&pbuf, "primary", primary),
360 strerror(errno));
361 /* the caller calls epoll_panic() */
362 return ret;
366 * Finally re-add HAS_EVENT to all fdes
368 add_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
369 tevent_common_fd_mpx_additional_flags(primary, 0, add_flags);
371 return 0;
375 add the epoll event to the given fd_event
377 static void epoll_add_event(struct epoll_event_context *epoll_ev,
378 struct tevent_fd *_primary)
380 struct tevent_fd *primary = tevent_common_fd_mpx_primary(_primary);
381 uint16_t effective_flags = tevent_common_fd_mpx_flags(primary);
382 struct epoll_event event;
383 uint64_t clear_flags = 0;
384 uint64_t add_flags = 0;
385 int ret;
388 * Before me modify the low level epoll state,
389 * we clear HAS_EVENT on all fdes.
391 clear_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
392 tevent_common_fd_mpx_additional_flags(primary, clear_flags, 0);
395 * Modify the low level epoll state to reflect
396 * the effective flags we want to monitor.
398 * Most likely we won't trigger the EEXIST
399 * case, so it's much cheaper to try and
400 * react on EEXIST if needed, than to always
401 * scan the list of all existing events.
403 ZERO_STRUCT(event);
404 event.events = epoll_map_flags(effective_flags);
405 event.data.ptr = primary;
406 ret = epoll_ctl(epoll_ev->epoll_fd,
407 EPOLL_CTL_ADD,
408 primary->fd,
409 &event);
410 if (ret != 0 && errno == EBADF) {
411 struct tevent_common_fd_buf pbuf = {};
412 TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_ERROR,
413 "EPOLL_CTL_ADD EBADF for "
414 "%s - disabling\n",
415 tevent_common_fd_str(&pbuf, "primary", primary));
416 tevent_common_fd_mpx_disarm_all(primary);
417 return;
418 } else if (ret != 0 && errno == EEXIST) {
419 ret = epoll_add_multiplex_fd(epoll_ev, primary);
420 if (ret != 0) {
421 epoll_panic(epoll_ev, "epoll_add_multiplex_fd failed",
422 false);
423 return;
426 * epoll_add_multiplex_fd() already
427 * added EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
429 return;
430 } else if (ret != 0) {
431 epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed", false);
432 return;
436 * Finally re-add HAS_EVENT to all fdes
438 add_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
439 tevent_common_fd_mpx_additional_flags(primary, 0, add_flags);
443 delete the epoll event for given fd_event
445 static void epoll_del_event(struct epoll_event_context *epoll_ev,
446 struct tevent_fd *_primary)
448 struct tevent_fd *primary = tevent_common_fd_mpx_primary(_primary);
449 struct epoll_event event;
450 uint64_t clear_flags = 0;
451 int ret;
454 * Before me delete the low level epoll state,
455 * we clear HAS_EVENT on all fdes.
457 clear_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
458 tevent_common_fd_mpx_additional_flags(primary, clear_flags, 0);
461 * Delete the low level epoll state to reflect
462 * the effective flags we want to monitor.
464 ZERO_STRUCT(event);
465 ret = epoll_ctl(epoll_ev->epoll_fd,
466 EPOLL_CTL_DEL,
467 primary->fd,
468 &event);
469 if (ret != 0 && errno == ENOENT) {
470 struct tevent_common_fd_buf pbuf = {};
472 * This can happen after a epoll_check_reopen
473 * within epoll_event_fd_destructor.
475 TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_TRACE,
476 "EPOLL_CTL_DEL ignoring ENOENT for %s\n",
477 tevent_common_fd_str(&pbuf, "primary", primary));
478 return;
479 } else if (ret != 0 && errno == EBADF) {
480 struct tevent_common_fd_buf pbuf = {};
481 TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_WARNING,
482 "EPOLL_CTL_DEL EBADF for %s - disabling\n",
483 tevent_common_fd_str(&pbuf, "primary", primary));
484 tevent_common_fd_mpx_disarm_all(primary);
485 return;
486 } else if (ret != 0) {
487 struct tevent_common_fd_buf pbuf = {};
488 TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_FATAL,
489 "EPOLL_CTL_DEL for %s - failed - %s",
490 tevent_common_fd_str(&pbuf, "primary", primary),
491 strerror(errno));
492 epoll_panic(epoll_ev, "EPOLL_CTL_DEL failed", false);
493 return;
498 change the epoll event to the given fd_event
500 static void epoll_mod_event(struct epoll_event_context *epoll_ev,
501 struct tevent_fd *_primary)
503 struct tevent_fd *primary = tevent_common_fd_mpx_primary(_primary);
504 uint16_t effective_flags = tevent_common_fd_mpx_flags(primary);
505 struct epoll_event event;
506 uint64_t clear_flags = 0;
507 uint64_t add_flags = 0;
508 int ret;
511 * Before me modify the low level epoll state,
512 * we clear HAS_EVENT on all fdes.
514 clear_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
515 tevent_common_fd_mpx_additional_flags(primary, clear_flags, 0);
518 * Modify the low level epoll state to reflect
519 * the effective flags we want to monitor.
521 ZERO_STRUCT(event);
522 event.events = epoll_map_flags(effective_flags);
523 event.data.ptr = primary;
524 ret = epoll_ctl(epoll_ev->epoll_fd,
525 EPOLL_CTL_MOD,
526 primary->fd,
527 &event);
528 if (ret != 0 && errno == EBADF) {
529 struct tevent_common_fd_buf pbuf = {};
530 TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_ERROR,
531 "EPOLL_CTL_MOD EBADF for %s - disabling\n",
532 tevent_common_fd_str(&pbuf, "primary", primary));
533 tevent_common_fd_mpx_disarm_all(primary);
534 return;
535 } else if (ret != 0) {
536 struct tevent_common_fd_buf pbuf = {};
537 TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_FATAL,
538 "EPOLL_CTL_MOD for %s - failed - %s",
539 tevent_common_fd_str(&pbuf, "primary", primary),
540 strerror(errno));
541 epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false);
542 return;
546 * Finally re-add HAS_EVENT to all fdes
548 add_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
549 tevent_common_fd_mpx_additional_flags(primary, 0, add_flags);
552 static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
554 struct tevent_fd *primary = tevent_common_fd_mpx_primary(fde);
555 uint64_t _paf = primary->additional_flags;
556 bool got_error = (_paf & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
557 uint16_t effective_flags = tevent_common_fd_mpx_flags(primary);
558 bool want_read = (effective_flags & TEVENT_FD_READ);
559 bool want_write= (effective_flags & TEVENT_FD_WRITE);
560 bool want_error= (effective_flags & TEVENT_FD_ERROR);
562 /* there's already an event */
563 if (primary->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
564 if (want_read || want_error || (want_write && !got_error)) {
565 epoll_mod_event(epoll_ev, primary);
566 return;
569 * if we want to match the select behavior, we need to remove the epoll_event
570 * when the caller isn't interested in events.
572 * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
574 epoll_del_event(epoll_ev, primary);
575 return;
578 /* there's no epoll_event attached to the fde */
579 if (want_read || want_error || (want_write && !got_error)) {
580 epoll_add_event(epoll_ev, primary);
581 return;
586 event loop handling using epoll
588 static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
590 int ret, i;
591 #define MAXEVENTS 1
592 struct epoll_event events[MAXEVENTS];
593 int timeout = -1;
594 int wait_errno;
596 if (tvalp) {
597 /* it's better to trigger timed events a bit later than too early */
598 timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
601 if (epoll_ev->ev->signal_events &&
602 tevent_common_check_signal(epoll_ev->ev)) {
603 return 0;
606 tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
607 ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
608 wait_errno = errno;
609 tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
611 if (ret == -1 && wait_errno == EINTR && epoll_ev->ev->signal_events) {
612 if (tevent_common_check_signal(epoll_ev->ev)) {
613 return 0;
617 if (ret == -1 && wait_errno != EINTR) {
618 epoll_panic(epoll_ev, "epoll_wait() failed", true);
619 return -1;
622 if (ret == 0 && tvalp) {
623 /* we don't care about a possible delay here */
624 tevent_common_loop_timer_delay(epoll_ev->ev);
625 return 0;
628 for (i=0;i<ret;i++) {
629 struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
630 struct tevent_fd);
631 struct tevent_fd *selected = NULL;
632 uint16_t effective_flags;
633 uint16_t flags = 0;
634 bool got_error = false;
636 if (fde == NULL) {
637 epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
638 return -1;
640 effective_flags = tevent_common_fd_mpx_flags(fde);
641 if (events[i].events & (EPOLLHUP|EPOLLERR|EPOLLRDHUP)) {
642 uint64_t add_flags = 0;
644 add_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
645 tevent_common_fd_mpx_additional_flags(fde,
647 add_flags);
649 if (effective_flags & TEVENT_FD_ERROR) {
650 flags |= TEVENT_FD_ERROR;
652 if (effective_flags & TEVENT_FD_READ) {
653 flags |= TEVENT_FD_READ;
656 if (events[i].events & EPOLLIN) {
657 if (effective_flags & TEVENT_FD_READ) {
658 flags |= TEVENT_FD_READ;
661 if (events[i].events & EPOLLOUT) {
662 if (effective_flags & TEVENT_FD_WRITE) {
663 flags |= TEVENT_FD_WRITE;
667 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR)
669 got_error = true;
672 selected = tevent_common_fd_mpx_select(fde, flags, got_error);
673 if (selected == NULL) {
674 if (got_error) {
676 * if we only wait for TEVENT_FD_WRITE, we
677 * should not tell the event handler about it,
678 * and remove the epoll_event, as we only
679 * report errors when waiting for read events,
680 * to match the select() behavior
682 * Do the same as the poll backend and
683 * remove the writeable flag.
685 tevent_common_fd_mpx_clear_writeable(fde);
686 epoll_update_event(epoll_ev, fde);
688 continue;
692 * make sure we only pass the flags
693 * the handler is expecting.
695 flags &= selected->flags;
696 return tevent_common_invoke_fd_handler(selected,
697 flags,
698 NULL);
701 return 0;
705 create a epoll_event_context structure.
707 static int epoll_event_context_init(struct tevent_context *ev)
709 int ret;
710 struct epoll_event_context *epoll_ev;
713 * We might be called during tevent_re_initialise()
714 * which means we need to free our old additional_data.
716 TALLOC_FREE(ev->additional_data);
718 epoll_ev = talloc_zero(ev, struct epoll_event_context);
719 if (!epoll_ev) return -1;
720 epoll_ev->ev = ev;
721 epoll_ev->epoll_fd = -1;
723 ret = epoll_init_ctx(epoll_ev);
724 if (ret != 0) {
725 talloc_free(epoll_ev);
726 return ret;
729 ev->additional_data = epoll_ev;
730 return 0;
734 destroy an fd_event
736 static int epoll_event_fd_destructor(struct tevent_fd *fde)
738 struct tevent_fd *old_primary = NULL;
739 struct tevent_fd *new_primary = NULL;
740 struct tevent_fd *update_primary = NULL;
741 struct tevent_context *ev = fde->event_ctx;
742 struct epoll_event_context *epoll_ev = NULL;
743 bool panic_triggered = false;
745 if (ev == NULL) {
746 tevent_common_fd_mpx_reinit(fde);
747 return tevent_common_fd_destructor(fde);
750 epoll_ev = talloc_get_type_abort(ev->additional_data,
751 struct epoll_event_context);
754 * we must remove the event from the list
755 * otherwise a panic fallback handler may
756 * reuse invalid memory
758 DLIST_REMOVE(ev->fd_events, fde);
760 epoll_ev->panic_state = &panic_triggered;
761 if (epoll_ev->pid != tevent_cached_getpid()) {
762 epoll_check_reopen(epoll_ev);
763 if (panic_triggered) {
764 tevent_common_fd_mpx_reinit(fde);
765 return tevent_common_fd_destructor(fde);
769 old_primary = tevent_common_fd_mpx_primary(fde);
771 if (old_primary == fde) {
772 epoll_del_event(epoll_ev, fde);
773 if (panic_triggered) {
774 tevent_common_fd_mpx_reinit(fde);
775 return tevent_common_fd_destructor(fde);
779 new_primary = tevent_common_fd_mpx_remove(fde);
780 if (new_primary == NULL) {
781 epoll_ev->panic_state = NULL;
782 return tevent_common_fd_destructor(fde);
784 update_primary = tevent_common_fd_mpx_update(new_primary);
785 if (update_primary == NULL) {
786 epoll_ev->panic_state = NULL;
787 return tevent_common_fd_destructor(fde);
790 epoll_update_event(epoll_ev, update_primary);
791 if (panic_triggered) {
792 return tevent_common_fd_destructor(fde);
794 epoll_ev->panic_state = NULL;
796 return tevent_common_fd_destructor(fde);
800 add a fd based event
801 return NULL on failure (memory allocation error)
803 static struct tevent_fd *epoll_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
804 int fd, uint16_t flags,
805 tevent_fd_handler_t handler,
806 void *private_data,
807 const char *handler_name,
808 const char *location)
810 struct epoll_event_context *epoll_ev =
811 talloc_get_type_abort(ev->additional_data,
812 struct epoll_event_context);
813 struct tevent_fd *fde;
814 bool panic_triggered = false;
815 pid_t old_pid = epoll_ev->pid;
817 fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
818 handler, private_data,
819 handler_name, location);
820 if (!fde) return NULL;
822 talloc_set_destructor(fde, epoll_event_fd_destructor);
825 * prepare for tevent_common_fd_mpx_flags()
826 * in epoll_update_event()
828 tevent_common_fd_mpx_update_flags(fde);
830 if (epoll_ev->pid != tevent_cached_getpid()) {
831 epoll_ev->panic_state = &panic_triggered;
832 epoll_check_reopen(epoll_ev);
833 if (panic_triggered) {
834 return fde;
836 epoll_ev->panic_state = NULL;
839 if (epoll_ev->pid == old_pid) {
840 epoll_update_event(epoll_ev, fde);
843 return fde;
847 set the fd event flags
849 static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
851 struct tevent_context *ev;
852 struct epoll_event_context *epoll_ev;
853 bool panic_triggered = false;
854 pid_t old_pid;
856 if (fde->flags == flags) return;
858 ev = fde->event_ctx;
859 epoll_ev = talloc_get_type_abort(ev->additional_data,
860 struct epoll_event_context);
861 old_pid = epoll_ev->pid;
863 fde->flags = flags;
865 * prepare for tevent_common_fd_mpx_flags()
866 * in epoll_update_event()
868 tevent_common_fd_mpx_update_flags(fde);
870 if (epoll_ev->pid != tevent_cached_getpid()) {
871 epoll_ev->panic_state = &panic_triggered;
872 epoll_check_reopen(epoll_ev);
873 if (panic_triggered) {
874 return;
876 epoll_ev->panic_state = NULL;
879 if (epoll_ev->pid == old_pid) {
880 epoll_update_event(epoll_ev, fde);
885 do a single event loop using the events defined in ev
887 static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
889 struct epoll_event_context *epoll_ev =
890 talloc_get_type_abort(ev->additional_data,
891 struct epoll_event_context);
892 struct timeval tval;
893 bool panic_triggered = false;
895 if (ev->signal_events &&
896 tevent_common_check_signal(ev)) {
897 return 0;
900 if (ev->threaded_contexts != NULL) {
901 tevent_common_threaded_activate_immediate(ev);
904 if (ev->immediate_events &&
905 tevent_common_loop_immediate(ev)) {
906 return 0;
909 tval = tevent_common_loop_timer_delay(ev);
910 if (tevent_timeval_is_zero(&tval)) {
911 return 0;
914 if (epoll_ev->pid != tevent_cached_getpid()) {
915 epoll_ev->panic_state = &panic_triggered;
916 epoll_ev->panic_force_replay = true;
917 epoll_check_reopen(epoll_ev);
918 if (panic_triggered) {
919 errno = EINVAL;
920 return -1;
922 epoll_ev->panic_force_replay = false;
923 epoll_ev->panic_state = NULL;
926 return epoll_event_loop(epoll_ev, &tval);
929 static const struct tevent_ops epoll_event_ops = {
930 .context_init = epoll_event_context_init,
931 .add_fd = epoll_event_add_fd,
932 .set_fd_close_fn = tevent_common_fd_set_close_fn,
933 .get_fd_flags = tevent_common_fd_get_flags,
934 .set_fd_flags = epoll_event_set_fd_flags,
935 .add_timer = tevent_common_add_timer_v2,
936 .schedule_immediate = tevent_common_schedule_immediate,
937 .add_signal = tevent_common_add_signal,
938 .loop_once = epoll_event_loop_once,
939 .loop_wait = tevent_common_loop_wait,
942 _PRIVATE_ bool tevent_epoll_init(void)
944 return tevent_register_backend("epoll", &epoll_event_ops);