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 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) */
44 bool panic_force_replay
;
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
,
57 if (epoll_ev
->panic_fallback
== NULL
) {
58 return epoll_create1(flags
);
61 /* 50% of the time, fail... */
62 if ((random() % 2) == 0) {
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) {
84 return epoll_ctl(epfd
, op
, fd
, event
);
87 static int epoll_wait_panic_fallback(struct epoll_event_context
*epoll_ev
,
89 struct epoll_event
*events
,
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) {
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)
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
,
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
) {
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
);
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
);
170 map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
172 static uint32_t epoll_map_flags(uint16_t flags
)
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
) {
193 if (flags
& TEVENT_FD_ERROR
) {
202 static int epoll_ctx_destructor(struct epoll_event_context
*epoll_ev
)
204 close(epoll_ev
->epoll_fd
);
205 epoll_ev
->epoll_fd
= -1;
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",
222 epoll_ev
->pid
= tevent_cached_getpid();
223 talloc_set_destructor(epoll_ev
, epoll_ctx_destructor
);
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
) {
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);
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
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;
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
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;
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() */
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.
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.
341 event
.events
= epoll_map_flags(effective_flags
);
342 event
.data
.ptr
= primary
;
343 ret
= epoll_ctl(epoll_ev
->epoll_fd
,
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 "
352 tevent_common_fd_str(&pbuf
, "primary", primary
));
353 tevent_common_fd_mpx_disarm_all(primary
);
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
),
361 /* the caller calls epoll_panic() */
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
);
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;
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.
404 event
.events
= epoll_map_flags(effective_flags
);
405 event
.data
.ptr
= primary
;
406 ret
= epoll_ctl(epoll_ev
->epoll_fd
,
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 "
415 tevent_common_fd_str(&pbuf
, "primary", primary
));
416 tevent_common_fd_mpx_disarm_all(primary
);
418 } else if (ret
!= 0 && errno
== EEXIST
) {
419 ret
= epoll_add_multiplex_fd(epoll_ev
, primary
);
421 epoll_panic(epoll_ev
, "epoll_add_multiplex_fd failed",
426 * epoll_add_multiplex_fd() already
427 * added EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
430 } else if (ret
!= 0) {
431 epoll_panic(epoll_ev
, "EPOLL_CTL_ADD failed", false);
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;
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.
465 ret
= epoll_ctl(epoll_ev
->epoll_fd
,
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
));
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
);
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
),
492 epoll_panic(epoll_ev
, "EPOLL_CTL_DEL failed", false);
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;
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.
522 event
.events
= epoll_map_flags(effective_flags
);
523 event
.data
.ptr
= primary
;
524 ret
= epoll_ctl(epoll_ev
->epoll_fd
,
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
);
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
),
541 epoll_panic(epoll_ev
, "EPOLL_CTL_MOD failed", false);
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
);
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
);
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
);
586 event loop handling using epoll
588 static int epoll_event_loop(struct epoll_event_context
*epoll_ev
, struct timeval
*tvalp
)
592 struct epoll_event events
[MAXEVENTS
];
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
)) {
606 tevent_trace_point_callback(epoll_ev
->ev
, TEVENT_TRACE_BEFORE_WAIT
);
607 ret
= epoll_wait(epoll_ev
->epoll_fd
, events
, MAXEVENTS
, timeout
);
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
)) {
617 if (ret
== -1 && wait_errno
!= EINTR
) {
618 epoll_panic(epoll_ev
, "epoll_wait() failed", true);
622 if (ret
== 0 && tvalp
) {
623 /* we don't care about a possible delay here */
624 tevent_common_loop_timer_delay(epoll_ev
->ev
);
628 for (i
=0;i
<ret
;i
++) {
629 struct tevent_fd
*fde
= talloc_get_type(events
[i
].data
.ptr
,
631 struct tevent_fd
*selected
= NULL
;
632 uint16_t effective_flags
;
634 bool got_error
= false;
637 epoll_panic(epoll_ev
, "epoll_wait() gave bad data", true);
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
,
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
)
672 selected
= tevent_common_fd_mpx_select(fde
, flags
, got_error
);
673 if (selected
== NULL
) {
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
);
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
,
705 create a epoll_event_context structure.
707 static int epoll_event_context_init(struct tevent_context
*ev
)
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;
721 epoll_ev
->epoll_fd
= -1;
723 ret
= epoll_init_ctx(epoll_ev
);
725 talloc_free(epoll_ev
);
729 ev
->additional_data
= epoll_ev
;
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;
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
);
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
,
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
) {
836 epoll_ev
->panic_state
= NULL
;
839 if (epoll_ev
->pid
== old_pid
) {
840 epoll_update_event(epoll_ev
, 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;
856 if (fde
->flags
== flags
) return;
859 epoll_ev
= talloc_get_type_abort(ev
->additional_data
,
860 struct epoll_event_context
);
861 old_pid
= epoll_ev
->pid
;
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
) {
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
);
893 bool panic_triggered
= false;
895 if (ev
->signal_events
&&
896 tevent_common_check_signal(ev
)) {
900 if (ev
->threaded_contexts
!= NULL
) {
901 tevent_common_threaded_activate_immediate(ev
);
904 if (ev
->immediate_events
&&
905 tevent_common_loop_immediate(ev
)) {
909 tval
= tevent_common_loop_timer_delay(ev
);
910 if (tevent_timeval_is_zero(&tval
)) {
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
) {
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
);