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_REPORT_ERROR (1<<1)
51 #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2)
52 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX (1<<3)
54 #ifdef TEST_PANIC_FALLBACK
56 static int epoll_create1_panic_fallback(struct epoll_event_context
*epoll_ev
,
59 if (epoll_ev
->panic_fallback
== NULL
) {
60 return epoll_create1(flags
);
63 /* 50% of the time, fail... */
64 if ((random() % 2) == 0) {
69 return epoll_create1(flags
);
72 static int epoll_ctl_panic_fallback(struct epoll_event_context
*epoll_ev
,
73 int epfd
, int op
, int fd
,
74 struct epoll_event
*event
)
76 if (epoll_ev
->panic_fallback
== NULL
) {
77 return epoll_ctl(epfd
, op
, fd
, event
);
80 /* 50% of the time, fail... */
81 if ((random() % 2) == 0) {
86 return epoll_ctl(epfd
, op
, fd
, event
);
89 static int epoll_wait_panic_fallback(struct epoll_event_context
*epoll_ev
,
91 struct epoll_event
*events
,
95 if (epoll_ev
->panic_fallback
== NULL
) {
96 return epoll_wait(epfd
, events
, maxevents
, timeout
);
99 /* 50% of the time, fail... */
100 if ((random() % 2) == 0) {
105 return epoll_wait(epfd
, events
, maxevents
, timeout
);
108 #define epoll_create1(_flags) \
109 epoll_create1_panic_fallback(epoll_ev, _flags)
110 #define epoll_ctl(_epfd, _op, _fd, _event) \
111 epoll_ctl_panic_fallback(epoll_ev,_epfd, _op, _fd, _event)
112 #define epoll_wait(_epfd, _events, _maxevents, _timeout) \
113 epoll_wait_panic_fallback(epoll_ev, _epfd, _events, _maxevents, _timeout)
117 called to set the panic fallback function.
119 _PRIVATE_
void tevent_epoll_set_panic_fallback(struct tevent_context
*ev
,
120 bool (*panic_fallback
)(struct tevent_context
*ev
,
123 struct epoll_event_context
*epoll_ev
=
124 talloc_get_type_abort(ev
->additional_data
,
125 struct epoll_event_context
);
127 epoll_ev
->panic_fallback
= panic_fallback
;
131 called when a epoll call fails
133 static void epoll_panic(struct epoll_event_context
*epoll_ev
,
134 const char *reason
, bool replay
)
136 struct tevent_context
*ev
= epoll_ev
->ev
;
137 bool (*panic_fallback
)(struct tevent_context
*ev
, bool replay
);
139 panic_fallback
= epoll_ev
->panic_fallback
;
141 if (epoll_ev
->panic_state
!= NULL
) {
142 *epoll_ev
->panic_state
= true;
145 if (epoll_ev
->panic_force_replay
) {
149 TALLOC_FREE(ev
->additional_data
);
151 if (panic_fallback
== NULL
) {
152 tevent_debug(ev
, TEVENT_DEBUG_FATAL
,
153 "%s (%s) replay[%u] - calling abort()\n",
154 reason
, strerror(errno
), (unsigned)replay
);
158 tevent_debug(ev
, TEVENT_DEBUG_ERROR
,
159 "%s (%s) replay[%u] - calling panic_fallback\n",
160 reason
, strerror(errno
), (unsigned)replay
);
162 if (!panic_fallback(ev
, replay
)) {
163 /* Fallback failed. */
164 tevent_debug(ev
, TEVENT_DEBUG_FATAL
,
165 "%s (%s) replay[%u] - calling abort()\n",
166 reason
, strerror(errno
), (unsigned)replay
);
172 map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
174 static uint32_t epoll_map_flags(uint16_t flags
)
177 if (flags
& TEVENT_FD_READ
) ret
|= (EPOLLIN
| EPOLLERR
| EPOLLHUP
);
178 if (flags
& TEVENT_FD_WRITE
) ret
|= (EPOLLOUT
| EPOLLERR
| EPOLLHUP
);
185 static int epoll_ctx_destructor(struct epoll_event_context
*epoll_ev
)
187 close(epoll_ev
->epoll_fd
);
188 epoll_ev
->epoll_fd
= -1;
195 static int epoll_init_ctx(struct epoll_event_context
*epoll_ev
)
197 epoll_ev
->epoll_fd
= epoll_create1(EPOLL_CLOEXEC
);
198 if (epoll_ev
->epoll_fd
== -1) {
199 tevent_debug(epoll_ev
->ev
, TEVENT_DEBUG_FATAL
,
200 "Failed to create epoll handle (%s).\n",
205 epoll_ev
->pid
= tevent_cached_getpid();
206 talloc_set_destructor(epoll_ev
, epoll_ctx_destructor
);
211 static void epoll_update_event(struct epoll_event_context
*epoll_ev
, struct tevent_fd
*fde
);
214 reopen the epoll handle when our pid changes
215 see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
216 demonstration of why this is needed
218 static void epoll_check_reopen(struct epoll_event_context
*epoll_ev
)
220 struct tevent_fd
*fde
;
221 bool *caller_panic_state
= epoll_ev
->panic_state
;
222 bool panic_triggered
= false;
223 pid_t pid
= tevent_cached_getpid();
225 if (epoll_ev
->pid
== pid
) {
229 close(epoll_ev
->epoll_fd
);
230 epoll_ev
->epoll_fd
= epoll_create1(EPOLL_CLOEXEC
);
231 if (epoll_ev
->epoll_fd
== -1) {
232 epoll_panic(epoll_ev
, "epoll_create() failed", false);
237 epoll_ev
->panic_state
= &panic_triggered
;
238 for (fde
=epoll_ev
->ev
->fd_events
;fde
;fde
=fde
->next
) {
239 fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
;
241 for (fde
=epoll_ev
->ev
->fd_events
;fde
;fde
=fde
->next
) {
242 epoll_update_event(epoll_ev
, fde
);
244 if (panic_triggered
) {
245 if (caller_panic_state
!= NULL
) {
246 *caller_panic_state
= true;
251 epoll_ev
->panic_state
= NULL
;
255 epoll cannot add the same file descriptor twice, once
256 with read, once with write which is allowed by the
257 tevent backend. Multiplex the existing fde, flag it
258 as such so we can search for the correct fde on
262 static int epoll_add_multiplex_fd(struct epoll_event_context
*epoll_ev
,
263 struct tevent_fd
*add_fde
)
265 struct epoll_event event
;
266 struct tevent_fd
*mpx_fde
;
269 /* Find the existing fde that caused the EEXIST error. */
270 for (mpx_fde
= epoll_ev
->ev
->fd_events
; mpx_fde
; mpx_fde
= mpx_fde
->next
) {
271 if (mpx_fde
->fd
!= add_fde
->fd
) {
275 if (mpx_fde
== add_fde
) {
281 if (mpx_fde
== NULL
) {
282 tevent_debug(epoll_ev
->ev
, TEVENT_DEBUG_FATAL
,
283 "can't find multiplex fde for fd[%d]",
288 if (mpx_fde
->additional_flags
& EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX
) {
289 /* Logic error. Can't have more than 2 multiplexed fde's. */
290 tevent_debug(epoll_ev
->ev
, TEVENT_DEBUG_FATAL
,
291 "multiplex fde for fd[%d] is already multiplexed\n",
297 * The multiplex fde must have the same fd, and also
298 * already have an epoll event attached.
300 if (!(mpx_fde
->additional_flags
& EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
)) {
301 /* Logic error. Can't have more than 2 multiplexed fde's. */
302 tevent_debug(epoll_ev
->ev
, TEVENT_DEBUG_FATAL
,
303 "multiplex fde for fd[%d] has no event\n",
308 /* Modify the mpx_fde to add in the new flags. */
310 event
.events
= epoll_map_flags(mpx_fde
->flags
);
311 event
.events
|= epoll_map_flags(add_fde
->flags
);
312 event
.data
.ptr
= mpx_fde
;
313 ret
= epoll_ctl(epoll_ev
->epoll_fd
, EPOLL_CTL_MOD
, mpx_fde
->fd
, &event
);
314 if (ret
!= 0 && errno
== EBADF
) {
315 tevent_debug(epoll_ev
->ev
, TEVENT_DEBUG_ERROR
,
316 "EPOLL_CTL_MOD EBADF for "
317 "add_fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
318 add_fde
, mpx_fde
, add_fde
->fd
);
319 DLIST_REMOVE(epoll_ev
->ev
->fd_events
, mpx_fde
);
320 mpx_fde
->wrapper
= NULL
;
321 mpx_fde
->event_ctx
= NULL
;
322 DLIST_REMOVE(epoll_ev
->ev
->fd_events
, add_fde
);
323 add_fde
->wrapper
= NULL
;
324 add_fde
->event_ctx
= NULL
;
326 } else if (ret
!= 0) {
331 * Make each fde->additional_data pointers point at each other
332 * so we can look them up from each other. They are now paired.
334 mpx_fde
->additional_data
= (struct tevent_fd
*)add_fde
;
335 add_fde
->additional_data
= (struct tevent_fd
*)mpx_fde
;
337 /* Now flag both fde's as being multiplexed. */
338 mpx_fde
->additional_flags
|= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX
;
339 add_fde
->additional_flags
|= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX
;
341 /* we need to keep the GOT_ERROR flag */
342 if (mpx_fde
->additional_flags
& EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR
) {
343 add_fde
->additional_flags
|= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR
;
350 add the epoll event to the given fd_event
352 static void epoll_add_event(struct epoll_event_context
*epoll_ev
, struct tevent_fd
*fde
)
354 struct epoll_event event
;
356 struct tevent_fd
*mpx_fde
= NULL
;
358 fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
;
359 fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR
;
361 if (fde
->additional_flags
& EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX
) {
363 * This is a multiplexed fde, we need to include both
364 * flags in the modified event.
366 mpx_fde
= talloc_get_type_abort(fde
->additional_data
,
369 mpx_fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
;
370 mpx_fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR
;
374 event
.events
= epoll_map_flags(fde
->flags
);
375 if (mpx_fde
!= NULL
) {
376 event
.events
|= epoll_map_flags(mpx_fde
->flags
);
378 event
.data
.ptr
= fde
;
379 ret
= epoll_ctl(epoll_ev
->epoll_fd
, EPOLL_CTL_ADD
, fde
->fd
, &event
);
380 if (ret
!= 0 && errno
== EBADF
) {
381 tevent_debug(epoll_ev
->ev
, TEVENT_DEBUG_ERROR
,
382 "EPOLL_CTL_ADD EBADF for "
383 "fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
384 fde
, mpx_fde
, fde
->fd
);
385 DLIST_REMOVE(epoll_ev
->ev
->fd_events
, fde
);
387 fde
->event_ctx
= NULL
;
388 if (mpx_fde
!= NULL
) {
389 DLIST_REMOVE(epoll_ev
->ev
->fd_events
, mpx_fde
);
390 mpx_fde
->wrapper
= NULL
;
391 mpx_fde
->event_ctx
= NULL
;
394 } else if (ret
!= 0 && errno
== EEXIST
&& mpx_fde
== NULL
) {
395 ret
= epoll_add_multiplex_fd(epoll_ev
, fde
);
397 epoll_panic(epoll_ev
, "epoll_add_multiplex_fd failed",
401 } else if (ret
!= 0) {
402 epoll_panic(epoll_ev
, "EPOLL_CTL_ADD failed", false);
406 fde
->additional_flags
|= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
;
407 /* only if we want to read we want to tell the event handler about errors */
408 if (fde
->flags
& TEVENT_FD_READ
) {
409 fde
->additional_flags
|= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR
;
412 if (mpx_fde
== NULL
) {
416 mpx_fde
->additional_flags
|= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
;
417 /* only if we want to read we want to tell the event handler about errors */
418 if (mpx_fde
->flags
& TEVENT_FD_READ
) {
419 mpx_fde
->additional_flags
|= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR
;
424 delete the epoll event for given fd_event
426 static void epoll_del_event(struct epoll_event_context
*epoll_ev
, struct tevent_fd
*fde
)
428 struct epoll_event event
;
430 struct tevent_fd
*mpx_fde
= NULL
;
432 fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
;
433 fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR
;
435 if (fde
->additional_flags
& EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX
) {
437 * This is a multiplexed fde, we need to modify both events.
439 mpx_fde
= talloc_get_type_abort(fde
->additional_data
,
442 mpx_fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
;
443 mpx_fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR
;
447 ret
= epoll_ctl(epoll_ev
->epoll_fd
, EPOLL_CTL_DEL
, fde
->fd
, &event
);
448 if (ret
!= 0 && errno
== ENOENT
) {
450 * This can happen after a epoll_check_reopen
451 * within epoll_event_fd_destructor.
453 TEVENT_DEBUG(epoll_ev
->ev
, TEVENT_DEBUG_TRACE
,
454 "EPOLL_CTL_DEL ignoring ENOENT for fd[%d]\n",
457 } else if (ret
!= 0 && errno
== EBADF
) {
458 tevent_debug(epoll_ev
->ev
, TEVENT_DEBUG_WARNING
,
459 "EPOLL_CTL_DEL EBADF for "
460 "fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
461 fde
, mpx_fde
, fde
->fd
);
462 DLIST_REMOVE(epoll_ev
->ev
->fd_events
, fde
);
464 fde
->event_ctx
= NULL
;
465 if (mpx_fde
!= NULL
) {
466 DLIST_REMOVE(epoll_ev
->ev
->fd_events
, mpx_fde
);
467 mpx_fde
->wrapper
= NULL
;
468 mpx_fde
->event_ctx
= NULL
;
471 } else if (ret
!= 0) {
472 epoll_panic(epoll_ev
, "EPOLL_CTL_DEL failed", false);
478 change the epoll event to the given fd_event
480 static void epoll_mod_event(struct epoll_event_context
*epoll_ev
, struct tevent_fd
*fde
)
482 struct tevent_fd
*mpx_fde
= NULL
;
483 struct epoll_event event
;
486 fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
;
487 fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR
;
489 if (fde
->additional_flags
& EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX
) {
491 * This is a multiplexed fde, we need to include both
492 * flags in the modified event.
494 mpx_fde
= talloc_get_type_abort(fde
->additional_data
,
497 mpx_fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
;
498 mpx_fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR
;
502 event
.events
= epoll_map_flags(fde
->flags
);
503 if (mpx_fde
!= NULL
) {
504 event
.events
|= epoll_map_flags(mpx_fde
->flags
);
506 event
.data
.ptr
= fde
;
507 ret
= epoll_ctl(epoll_ev
->epoll_fd
, EPOLL_CTL_MOD
, fde
->fd
, &event
);
508 if (ret
!= 0 && errno
== EBADF
) {
509 tevent_debug(epoll_ev
->ev
, TEVENT_DEBUG_ERROR
,
510 "EPOLL_CTL_MOD EBADF for "
511 "fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
512 fde
, mpx_fde
, fde
->fd
);
513 DLIST_REMOVE(epoll_ev
->ev
->fd_events
, fde
);
515 fde
->event_ctx
= NULL
;
516 if (mpx_fde
!= NULL
) {
517 DLIST_REMOVE(epoll_ev
->ev
->fd_events
, mpx_fde
);
518 mpx_fde
->wrapper
= NULL
;
519 mpx_fde
->event_ctx
= NULL
;
522 } else if (ret
!= 0) {
523 epoll_panic(epoll_ev
, "EPOLL_CTL_MOD failed", false);
527 fde
->additional_flags
|= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
;
528 /* only if we want to read we want to tell the event handler about errors */
529 if (fde
->flags
& TEVENT_FD_READ
) {
530 fde
->additional_flags
|= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR
;
533 if (mpx_fde
== NULL
) {
537 mpx_fde
->additional_flags
|= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
;
538 /* only if we want to read we want to tell the event handler about errors */
539 if (mpx_fde
->flags
& TEVENT_FD_READ
) {
540 mpx_fde
->additional_flags
|= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR
;
544 static void epoll_update_event(struct epoll_event_context
*epoll_ev
, struct tevent_fd
*fde
)
546 bool got_error
= (fde
->additional_flags
& EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR
);
547 bool want_read
= (fde
->flags
& TEVENT_FD_READ
);
548 bool want_write
= (fde
->flags
& TEVENT_FD_WRITE
);
549 struct tevent_fd
*mpx_fde
= NULL
;
551 if (fde
->additional_flags
& EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX
) {
553 * work out what the multiplexed fde wants.
555 mpx_fde
= talloc_get_type_abort(fde
->additional_data
,
558 if (mpx_fde
->flags
& TEVENT_FD_READ
) {
562 if (mpx_fde
->flags
& TEVENT_FD_WRITE
) {
567 /* there's already an event */
568 if (fde
->additional_flags
& EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
) {
569 if (want_read
|| (want_write
&& !got_error
)) {
570 epoll_mod_event(epoll_ev
, fde
);
574 * if we want to match the select behavior, we need to remove the epoll_event
575 * when the caller isn't interested in events.
577 * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
579 epoll_del_event(epoll_ev
, fde
);
583 /* there's no epoll_event attached to the fde */
584 if (want_read
|| (want_write
&& !got_error
)) {
585 epoll_add_event(epoll_ev
, fde
);
591 Cope with epoll returning EPOLLHUP|EPOLLERR on an event.
592 Return true if there's nothing else to do, false if
593 this event needs further handling.
595 static bool epoll_handle_hup_or_err(struct epoll_event_context
*epoll_ev
,
596 struct tevent_fd
*fde
)
599 /* Nothing to do if no event. */
603 fde
->additional_flags
|= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR
;
605 * if we only wait for TEVENT_FD_WRITE, we should not tell the
606 * event handler about it, and remove the epoll_event,
607 * as we only report errors when waiting for read events,
608 * to match the select() behavior
610 if (!(fde
->additional_flags
& EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR
)) {
612 * Do the same as the poll backend and
613 * remove the writeable flag.
615 fde
->flags
&= ~TEVENT_FD_WRITE
;
618 /* This has TEVENT_FD_READ set, we're not finished. */
623 event loop handling using epoll
625 static int epoll_event_loop(struct epoll_event_context
*epoll_ev
, struct timeval
*tvalp
)
629 struct epoll_event events
[MAXEVENTS
];
634 /* it's better to trigger timed events a bit later than too early */
635 timeout
= ((tvalp
->tv_usec
+999) / 1000) + (tvalp
->tv_sec
*1000);
638 if (epoll_ev
->ev
->signal_events
&&
639 tevent_common_check_signal(epoll_ev
->ev
)) {
643 tevent_trace_point_callback(epoll_ev
->ev
, TEVENT_TRACE_BEFORE_WAIT
);
644 ret
= epoll_wait(epoll_ev
->epoll_fd
, events
, MAXEVENTS
, timeout
);
646 tevent_trace_point_callback(epoll_ev
->ev
, TEVENT_TRACE_AFTER_WAIT
);
648 if (ret
== -1 && wait_errno
== EINTR
&& epoll_ev
->ev
->signal_events
) {
649 if (tevent_common_check_signal(epoll_ev
->ev
)) {
654 if (ret
== -1 && wait_errno
!= EINTR
) {
655 epoll_panic(epoll_ev
, "epoll_wait() failed", true);
659 if (ret
== 0 && tvalp
) {
660 /* we don't care about a possible delay here */
661 tevent_common_loop_timer_delay(epoll_ev
->ev
);
665 for (i
=0;i
<ret
;i
++) {
666 struct tevent_fd
*fde
= talloc_get_type(events
[i
].data
.ptr
,
669 struct tevent_fd
*mpx_fde
= NULL
;
672 epoll_panic(epoll_ev
, "epoll_wait() gave bad data", true);
675 if (fde
->additional_flags
& EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX
) {
677 * Save off the multiplexed event in case we need
678 * to use it to call the handler function.
680 mpx_fde
= talloc_get_type_abort(fde
->additional_data
,
683 if (events
[i
].events
& (EPOLLHUP
|EPOLLERR
)) {
684 bool handled_fde
= epoll_handle_hup_or_err(epoll_ev
, fde
);
685 bool handled_mpx
= epoll_handle_hup_or_err(epoll_ev
, mpx_fde
);
687 if (handled_fde
&& handled_mpx
) {
688 epoll_update_event(epoll_ev
, fde
);
694 * If the mpx event was the one that needs
695 * further handling, it's the TEVENT_FD_READ
696 * event so switch over and call that handler.
701 flags
|= TEVENT_FD_READ
;
703 if (events
[i
].events
& EPOLLIN
) flags
|= TEVENT_FD_READ
;
704 if (events
[i
].events
& EPOLLOUT
) flags
|= TEVENT_FD_WRITE
;
706 if (flags
& TEVENT_FD_WRITE
) {
707 if (fde
->flags
& TEVENT_FD_WRITE
) {
710 if (mpx_fde
&& mpx_fde
->flags
& TEVENT_FD_WRITE
) {
717 /* Ensure we got the right fde. */
718 if ((flags
& fde
->flags
) == 0) {
725 * make sure we only pass the flags
726 * the handler is expecting.
730 return tevent_common_invoke_fd_handler(fde
, flags
, NULL
);
738 create a epoll_event_context structure.
740 static int epoll_event_context_init(struct tevent_context
*ev
)
743 struct epoll_event_context
*epoll_ev
;
746 * We might be called during tevent_re_initialise()
747 * which means we need to free our old additional_data.
749 TALLOC_FREE(ev
->additional_data
);
751 epoll_ev
= talloc_zero(ev
, struct epoll_event_context
);
752 if (!epoll_ev
) return -1;
754 epoll_ev
->epoll_fd
= -1;
756 ret
= epoll_init_ctx(epoll_ev
);
758 talloc_free(epoll_ev
);
762 ev
->additional_data
= epoll_ev
;
769 static int epoll_event_fd_destructor(struct tevent_fd
*fde
)
771 struct tevent_context
*ev
= fde
->event_ctx
;
772 struct epoll_event_context
*epoll_ev
= NULL
;
773 bool panic_triggered
= false;
774 struct tevent_fd
*mpx_fde
= NULL
;
775 int flags
= fde
->flags
;
778 return tevent_common_fd_destructor(fde
);
781 epoll_ev
= talloc_get_type_abort(ev
->additional_data
,
782 struct epoll_event_context
);
785 * we must remove the event from the list
786 * otherwise a panic fallback handler may
787 * reuse invalid memory
789 DLIST_REMOVE(ev
->fd_events
, fde
);
791 if (fde
->additional_flags
& EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX
) {
792 mpx_fde
= talloc_get_type_abort(fde
->additional_data
,
795 fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX
;
796 mpx_fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX
;
798 fde
->additional_data
= NULL
;
799 mpx_fde
->additional_data
= NULL
;
801 fde
->additional_flags
&= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
;
804 epoll_ev
->panic_state
= &panic_triggered
;
805 if (epoll_ev
->pid
!= tevent_cached_getpid()) {
806 epoll_check_reopen(epoll_ev
);
807 if (panic_triggered
) {
808 return tevent_common_fd_destructor(fde
);
812 if (mpx_fde
!= NULL
) {
813 epoll_update_event(epoll_ev
, mpx_fde
);
814 if (panic_triggered
) {
815 return tevent_common_fd_destructor(fde
);
820 epoll_update_event(epoll_ev
, fde
);
822 if (panic_triggered
) {
823 return tevent_common_fd_destructor(fde
);
825 epoll_ev
->panic_state
= NULL
;
827 return tevent_common_fd_destructor(fde
);
832 return NULL on failure (memory allocation error)
834 static struct tevent_fd
*epoll_event_add_fd(struct tevent_context
*ev
, TALLOC_CTX
*mem_ctx
,
835 int fd
, uint16_t flags
,
836 tevent_fd_handler_t handler
,
838 const char *handler_name
,
839 const char *location
)
841 struct epoll_event_context
*epoll_ev
=
842 talloc_get_type_abort(ev
->additional_data
,
843 struct epoll_event_context
);
844 struct tevent_fd
*fde
;
845 bool panic_triggered
= false;
846 pid_t old_pid
= epoll_ev
->pid
;
848 fde
= tevent_common_add_fd(ev
, mem_ctx
, fd
, flags
,
849 handler
, private_data
,
850 handler_name
, location
);
851 if (!fde
) return NULL
;
853 talloc_set_destructor(fde
, epoll_event_fd_destructor
);
855 if (epoll_ev
->pid
!= tevent_cached_getpid()) {
856 epoll_ev
->panic_state
= &panic_triggered
;
857 epoll_check_reopen(epoll_ev
);
858 if (panic_triggered
) {
861 epoll_ev
->panic_state
= NULL
;
864 if (epoll_ev
->pid
== old_pid
) {
865 epoll_update_event(epoll_ev
, fde
);
872 set the fd event flags
874 static void epoll_event_set_fd_flags(struct tevent_fd
*fde
, uint16_t flags
)
876 struct tevent_context
*ev
;
877 struct epoll_event_context
*epoll_ev
;
878 bool panic_triggered
= false;
881 if (fde
->flags
== flags
) return;
884 epoll_ev
= talloc_get_type_abort(ev
->additional_data
,
885 struct epoll_event_context
);
886 old_pid
= epoll_ev
->pid
;
890 if (epoll_ev
->pid
!= tevent_cached_getpid()) {
891 epoll_ev
->panic_state
= &panic_triggered
;
892 epoll_check_reopen(epoll_ev
);
893 if (panic_triggered
) {
896 epoll_ev
->panic_state
= NULL
;
899 if (epoll_ev
->pid
== old_pid
) {
900 epoll_update_event(epoll_ev
, fde
);
905 do a single event loop using the events defined in ev
907 static int epoll_event_loop_once(struct tevent_context
*ev
, const char *location
)
909 struct epoll_event_context
*epoll_ev
=
910 talloc_get_type_abort(ev
->additional_data
,
911 struct epoll_event_context
);
913 bool panic_triggered
= false;
915 if (ev
->signal_events
&&
916 tevent_common_check_signal(ev
)) {
920 if (ev
->threaded_contexts
!= NULL
) {
921 tevent_common_threaded_activate_immediate(ev
);
924 if (ev
->immediate_events
&&
925 tevent_common_loop_immediate(ev
)) {
929 tval
= tevent_common_loop_timer_delay(ev
);
930 if (tevent_timeval_is_zero(&tval
)) {
934 if (epoll_ev
->pid
!= tevent_cached_getpid()) {
935 epoll_ev
->panic_state
= &panic_triggered
;
936 epoll_ev
->panic_force_replay
= true;
937 epoll_check_reopen(epoll_ev
);
938 if (panic_triggered
) {
942 epoll_ev
->panic_force_replay
= false;
943 epoll_ev
->panic_state
= NULL
;
946 return epoll_event_loop(epoll_ev
, &tval
);
949 static const struct tevent_ops epoll_event_ops
= {
950 .context_init
= epoll_event_context_init
,
951 .add_fd
= epoll_event_add_fd
,
952 .set_fd_close_fn
= tevent_common_fd_set_close_fn
,
953 .get_fd_flags
= tevent_common_fd_get_flags
,
954 .set_fd_flags
= epoll_event_set_fd_flags
,
955 .add_timer
= tevent_common_add_timer_v2
,
956 .schedule_immediate
= tevent_common_schedule_immediate
,
957 .add_signal
= tevent_common_add_signal
,
958 .loop_once
= epoll_event_loop_once
,
959 .loop_wait
= tevent_common_loop_wait
,
962 _PRIVATE_
bool tevent_epoll_init(void)
964 return tevent_register_backend("epoll", &epoll_event_ops
);