s3:utils: Fix the auth function to print correct values to the user
[Samba.git] / lib / tevent / tevent_epoll.c
blob2771a83fdd2669ff7cddc68b6067ada9871fb23c
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_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,
57 int flags)
59 if (epoll_ev->panic_fallback == NULL) {
60 return epoll_create1(flags);
63 /* 50% of the time, fail... */
64 if ((random() % 2) == 0) {
65 errno = EINVAL;
66 return -1;
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) {
82 errno = EINVAL;
83 return -1;
86 return epoll_ctl(epfd, op, fd, event);
89 static int epoll_wait_panic_fallback(struct epoll_event_context *epoll_ev,
90 int epfd,
91 struct epoll_event *events,
92 int maxevents,
93 int timeout)
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) {
101 errno = EINVAL;
102 return -1;
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)
114 #endif
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,
121 bool replay))
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) {
146 replay = true;
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);
155 abort();
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);
167 abort();
172 map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
174 static uint32_t epoll_map_flags(uint16_t flags)
176 uint32_t ret = 0;
177 if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
178 if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
179 return ret;
183 free the epoll fd
185 static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev)
187 close(epoll_ev->epoll_fd);
188 epoll_ev->epoll_fd = -1;
189 return 0;
193 init the epoll fd
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",
201 strerror(errno));
202 return -1;
205 epoll_ev->pid = tevent_cached_getpid();
206 talloc_set_destructor(epoll_ev, epoll_ctx_destructor);
208 return 0;
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) {
226 return;
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);
233 return;
236 epoll_ev->pid = pid;
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;
248 return;
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
259 event triggering.
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;
267 int ret;
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) {
272 continue;
275 if (mpx_fde == add_fde) {
276 continue;
279 break;
281 if (mpx_fde == NULL) {
282 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
283 "can't find multiplex fde for fd[%d]",
284 add_fde->fd);
285 return -1;
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",
292 mpx_fde->fd);
293 return -1;
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",
304 mpx_fde->fd);
305 return -1;
308 /* Modify the mpx_fde to add in the new flags. */
309 ZERO_STRUCT(event);
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;
325 return 0;
326 } else if (ret != 0) {
327 return ret;
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;
346 return 0;
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;
355 int ret;
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,
367 struct tevent_fd);
369 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
370 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
373 ZERO_STRUCT(event);
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);
386 fde->wrapper = NULL;
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;
393 return;
394 } else if (ret != 0 && errno == EEXIST && mpx_fde == NULL) {
395 ret = epoll_add_multiplex_fd(epoll_ev, fde);
396 if (ret != 0) {
397 epoll_panic(epoll_ev, "epoll_add_multiplex_fd failed",
398 false);
399 return;
401 } else if (ret != 0) {
402 epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed", false);
403 return;
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) {
413 return;
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;
429 int ret;
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,
440 struct tevent_fd);
442 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
443 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
446 ZERO_STRUCT(event);
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",
455 fde->fd);
456 return;
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);
463 fde->wrapper = NULL;
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;
470 return;
471 } else if (ret != 0) {
472 epoll_panic(epoll_ev, "EPOLL_CTL_DEL failed", false);
473 return;
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;
484 int ret;
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,
495 struct tevent_fd);
497 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
498 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
501 ZERO_STRUCT(event);
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);
514 fde->wrapper = NULL;
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;
521 return;
522 } else if (ret != 0) {
523 epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false);
524 return;
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) {
534 return;
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,
556 struct tevent_fd);
558 if (mpx_fde->flags & TEVENT_FD_READ) {
559 want_read = true;
562 if (mpx_fde->flags & TEVENT_FD_WRITE) {
563 want_write = true;
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);
571 return;
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);
580 return;
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);
586 return;
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)
598 if (fde == NULL) {
599 /* Nothing to do if no event. */
600 return true;
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;
616 return true;
618 /* This has TEVENT_FD_READ set, we're not finished. */
619 return false;
623 event loop handling using epoll
625 static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
627 int ret, i;
628 #define MAXEVENTS 1
629 struct epoll_event events[MAXEVENTS];
630 int timeout = -1;
631 int wait_errno;
633 if (tvalp) {
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)) {
640 return 0;
643 tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
644 ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
645 wait_errno = errno;
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)) {
650 return 0;
654 if (ret == -1 && wait_errno != EINTR) {
655 epoll_panic(epoll_ev, "epoll_wait() failed", true);
656 return -1;
659 if (ret == 0 && tvalp) {
660 /* we don't care about a possible delay here */
661 tevent_common_loop_timer_delay(epoll_ev->ev);
662 return 0;
665 for (i=0;i<ret;i++) {
666 struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
667 struct tevent_fd);
668 uint16_t flags = 0;
669 struct tevent_fd *mpx_fde = NULL;
671 if (fde == NULL) {
672 epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
673 return -1;
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,
681 struct tevent_fd);
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);
689 continue;
692 if (!handled_mpx) {
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.
698 fde = mpx_fde;
699 mpx_fde = NULL;
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) {
708 mpx_fde = NULL;
710 if (mpx_fde && mpx_fde->flags & TEVENT_FD_WRITE) {
711 fde = mpx_fde;
712 mpx_fde = NULL;
716 if (mpx_fde) {
717 /* Ensure we got the right fde. */
718 if ((flags & fde->flags) == 0) {
719 fde = mpx_fde;
720 mpx_fde = NULL;
725 * make sure we only pass the flags
726 * the handler is expecting.
728 flags &= fde->flags;
729 if (flags) {
730 return tevent_common_invoke_fd_handler(fde, flags, NULL);
734 return 0;
738 create a epoll_event_context structure.
740 static int epoll_event_context_init(struct tevent_context *ev)
742 int ret;
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;
753 epoll_ev->ev = ev;
754 epoll_ev->epoll_fd = -1;
756 ret = epoll_init_ctx(epoll_ev);
757 if (ret != 0) {
758 talloc_free(epoll_ev);
759 return ret;
762 ev->additional_data = epoll_ev;
763 return 0;
767 destroy an fd_event
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;
777 if (ev == NULL) {
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,
793 struct tevent_fd);
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);
819 fde->flags = 0;
820 epoll_update_event(epoll_ev, fde);
821 fde->flags = flags;
822 if (panic_triggered) {
823 return tevent_common_fd_destructor(fde);
825 epoll_ev->panic_state = NULL;
827 return tevent_common_fd_destructor(fde);
831 add a fd based event
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,
837 void *private_data,
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) {
859 return fde;
861 epoll_ev->panic_state = NULL;
864 if (epoll_ev->pid == old_pid) {
865 epoll_update_event(epoll_ev, fde);
868 return 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;
879 pid_t old_pid;
881 if (fde->flags == flags) return;
883 ev = fde->event_ctx;
884 epoll_ev = talloc_get_type_abort(ev->additional_data,
885 struct epoll_event_context);
886 old_pid = epoll_ev->pid;
888 fde->flags = flags;
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) {
894 return;
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);
912 struct timeval tval;
913 bool panic_triggered = false;
915 if (ev->signal_events &&
916 tevent_common_check_signal(ev)) {
917 return 0;
920 if (ev->threaded_contexts != NULL) {
921 tevent_common_threaded_activate_immediate(ev);
924 if (ev->immediate_events &&
925 tevent_common_loop_immediate(ev)) {
926 return 0;
929 tval = tevent_common_loop_timer_delay(ev);
930 if (tevent_timeval_is_zero(&tval)) {
931 return 0;
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) {
939 errno = EINVAL;
940 return -1;
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);