LCOV - code coverage report
Current view: top level - lib/tevent - tevent_epoll.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 304 374 81.3 %
Date: 2024-04-21 15:09:00 Functions: 18 18 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    main select loop and event handling - epoll implementation
       5             : 
       6             :    Copyright (C) Andrew Tridgell        2003-2005
       7             :    Copyright (C) Stefan Metzmacher      2005-2013
       8             :    Copyright (C) Jeremy Allison         2013
       9             : 
      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
      13             : 
      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.
      18             : 
      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.
      23             : 
      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/>.
      26             : */
      27             : 
      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"
      34             : 
      35             : struct epoll_event_context {
      36             :         /* a pointer back to the generic event_context */
      37             :         struct tevent_context *ev;
      38             : 
      39             :         /* when using epoll this is the handle from epoll_create1(2) */
      40             :         int epoll_fd;
      41             : 
      42             :         pid_t pid;
      43             : 
      44             :         bool panic_force_replay;
      45             :         bool *panic_state;
      46             :         bool (*panic_fallback)(struct tevent_context *ev, bool replay);
      47             : };
      48             : 
      49             : #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT      (1<<0)
      50             : #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR      (1<<1)
      51             : 
      52             : #ifdef TEST_PANIC_FALLBACK
      53             : 
      54             : static int epoll_create1_panic_fallback(struct epoll_event_context *epoll_ev,
      55             :                                         int flags)
      56             : {
      57             :         if (epoll_ev->panic_fallback == NULL) {
      58             :                 return epoll_create1(flags);
      59             :         }
      60             : 
      61             :         /* 50% of the time, fail... */
      62             :         if ((random() % 2) == 0) {
      63             :                 errno = EINVAL;
      64             :                 return -1;
      65             :         }
      66             : 
      67             :         return epoll_create1(flags);
      68             : }
      69             : 
      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)
      73             : {
      74             :         if (epoll_ev->panic_fallback == NULL) {
      75             :                 return epoll_ctl(epfd, op, fd, event);
      76             :         }
      77             : 
      78             :         /* 50% of the time, fail... */
      79             :         if ((random() % 2) == 0) {
      80             :                 errno = EINVAL;
      81             :                 return -1;
      82             :         }
      83             : 
      84             :         return epoll_ctl(epfd, op, fd, event);
      85             : }
      86             : 
      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)
      92             : {
      93             :         if (epoll_ev->panic_fallback == NULL) {
      94             :                 return epoll_wait(epfd, events, maxevents, timeout);
      95             :         }
      96             : 
      97             :         /* 50% of the time, fail... */
      98             :         if ((random() % 2) == 0) {
      99             :                 errno = EINVAL;
     100             :                 return -1;
     101             :         }
     102             : 
     103             :         return epoll_wait(epfd, events, maxevents, timeout);
     104             : }
     105             : 
     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
     113             : 
     114             : /*
     115             :   called to set the panic fallback function.
     116             : */
     117    83086473 : _PRIVATE_ void tevent_epoll_set_panic_fallback(struct tevent_context *ev,
     118             :                                 bool (*panic_fallback)(struct tevent_context *ev,
     119             :                                                        bool replay))
     120             : {
     121     3110088 :         struct epoll_event_context *epoll_ev =
     122    83086473 :                 talloc_get_type_abort(ev->additional_data,
     123             :                 struct epoll_event_context);
     124             : 
     125    83086475 :         epoll_ev->panic_fallback = panic_fallback;
     126    83086475 : }
     127             : 
     128             : /*
     129             :   called when a epoll call fails
     130             : */
     131           5 : static void epoll_panic(struct epoll_event_context *epoll_ev,
     132             :                         const char *reason, bool replay)
     133             : {
     134           5 :         struct tevent_context *ev = epoll_ev->ev;
     135           0 :         bool (*panic_fallback)(struct tevent_context *ev, bool replay);
     136             : 
     137           5 :         panic_fallback = epoll_ev->panic_fallback;
     138             : 
     139           5 :         if (epoll_ev->panic_state != NULL) {
     140           0 :                 *epoll_ev->panic_state = true;
     141             :         }
     142             : 
     143           5 :         if (epoll_ev->panic_force_replay) {
     144           0 :                 replay = true;
     145             :         }
     146             : 
     147           5 :         TALLOC_FREE(ev->additional_data);
     148             : 
     149           5 :         if (panic_fallback == NULL) {
     150           0 :                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
     151             :                         "%s (%s) replay[%u] - calling abort()\n",
     152           0 :                         reason, strerror(errno), (unsigned)replay);
     153           0 :                 abort();
     154             :         }
     155             : 
     156           5 :         tevent_debug(ev, TEVENT_DEBUG_ERROR,
     157             :                      "%s (%s) replay[%u] - calling panic_fallback\n",
     158           5 :                      reason, strerror(errno), (unsigned)replay);
     159             : 
     160           5 :         if (!panic_fallback(ev, replay)) {
     161             :                 /* Fallback failed. */
     162           0 :                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
     163             :                         "%s (%s) replay[%u] - calling abort()\n",
     164           0 :                         reason, strerror(errno), (unsigned)replay);
     165           0 :                 abort();
     166             :         }
     167           5 : }
     168             : 
     169             : /*
     170             :   map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
     171             : */
     172    21362477 : static uint32_t epoll_map_flags(uint16_t flags)
     173             : {
     174    21362477 :         uint32_t ret = 0;
     175             : 
     176             :         /*
     177             :          * we do not need to specify EPOLLERR | EPOLLHUP
     178             :          * they are always reported.
     179             :          */
     180             : 
     181    21362477 :         if (flags & TEVENT_FD_READ) {
     182             :                 /*
     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.
     187             :                  */
     188    21301718 :                 ret |= EPOLLIN | EPOLLRDHUP;
     189             :         }
     190    21362477 :         if (flags & TEVENT_FD_WRITE) {
     191     2559045 :                 ret |= EPOLLOUT;
     192             :         }
     193    21362477 :         if (flags & TEVENT_FD_ERROR) {
     194     3771244 :                 ret |= EPOLLRDHUP;
     195             :         }
     196    21362477 :         return ret;
     197             : }
     198             : 
     199             : /*
     200             :  free the epoll fd
     201             : */
     202    83060738 : static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev)
     203             : {
     204    83060738 :         close(epoll_ev->epoll_fd);
     205    83060738 :         epoll_ev->epoll_fd = -1;
     206    83060738 :         return 0;
     207             : }
     208             : 
     209             : /*
     210             :  init the epoll fd
     211             : */
     212    83086484 : static int epoll_init_ctx(struct epoll_event_context *epoll_ev)
     213             : {
     214    83086484 :         epoll_ev->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
     215    83086484 :         if (epoll_ev->epoll_fd == -1) {
     216           0 :                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
     217             :                              "Failed to create epoll handle (%s).\n",
     218           0 :                              strerror(errno));
     219           0 :                 return -1;
     220             :         }
     221             : 
     222    83086484 :         epoll_ev->pid = tevent_cached_getpid();
     223    83086484 :         talloc_set_destructor(epoll_ev, epoll_ctx_destructor);
     224             : 
     225    83086484 :         return 0;
     226             : }
     227             : 
     228             : static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
     229             : 
     230             : /*
     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
     234             :  */
     235       71792 : static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
     236             : {
     237        1814 :         struct tevent_fd *fde;
     238       71792 :         bool *caller_panic_state = epoll_ev->panic_state;
     239       71792 :         bool panic_triggered = false;
     240       71792 :         pid_t pid = tevent_cached_getpid();
     241             : 
     242       71792 :         if (epoll_ev->pid == pid) {
     243           0 :                 return;
     244             :         }
     245             : 
     246       71792 :         close(epoll_ev->epoll_fd);
     247       71792 :         epoll_ev->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
     248       71792 :         if (epoll_ev->epoll_fd == -1) {
     249           0 :                 epoll_panic(epoll_ev, "epoll_create() failed", false);
     250           0 :                 return;
     251             :         }
     252             : 
     253       71792 :         epoll_ev->pid = pid;
     254       71792 :         epoll_ev->panic_state = &panic_triggered;
     255      662169 :         for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
     256             :                 /*
     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.
     261             :                  */
     262      590377 :                 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
     263             :         }
     264      662169 :         for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
     265      590377 :                 epoll_update_event(epoll_ev, fde);
     266             : 
     267      590377 :                 if (panic_triggered) {
     268           0 :                         if (caller_panic_state != NULL) {
     269           0 :                                 *caller_panic_state = true;
     270             :                         }
     271           0 :                         return;
     272             :                 }
     273             :         }
     274       71792 :         epoll_ev->panic_state = NULL;
     275             : }
     276             : 
     277             : /*
     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.
     283             : */
     284             : 
     285       37687 : static int epoll_add_multiplex_fd(struct epoll_event_context *epoll_ev,
     286             :                                   struct tevent_fd *add_fde)
     287             : {
     288       37687 :         struct tevent_fd *primary = NULL;
     289         960 :         uint16_t effective_flags;
     290         960 :         struct epoll_event event;
     291       37687 :         uint64_t clear_flags = 0;
     292       37687 :         uint64_t add_flags = 0;
     293         960 :         int ret;
     294             : 
     295             :         /*
     296             :          * Check if there is another fde we can attach to
     297             :          */
     298       37687 :         primary = tevent_common_fd_mpx_add(add_fde);
     299       37687 :         if (primary == NULL) {
     300             :                 /* the caller calls epoll_panic() */
     301           0 :                 return -1;
     302             :         }
     303             : 
     304             :         /*
     305             :          * First propagate the HAS_EVENT flag from
     306             :          * the primary to all others (mainly add_fde)
     307             :          */
     308       37687 :         if (primary->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
     309       37687 :                 add_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
     310       37687 :                 tevent_common_fd_mpx_additional_flags(primary, 0, add_flags);
     311             :         }
     312             : 
     313             :         /*
     314             :          * Update the mpx internals and check if
     315             :          * there is an update needed.
     316             :          */
     317       37687 :         primary = tevent_common_fd_mpx_update(primary);
     318       37687 :         if (primary == NULL) {
     319             :                 /*
     320             :                  * It seems the primary was already
     321             :                  * watching (at least) the same flags
     322             :                  * as add_fde, so we are done.
     323             :                  */
     324           0 :                 return 0;
     325             :         }
     326             : 
     327             :         /*
     328             :          * Before me modify the low level epoll state,
     329             :          * we clear HAS_EVENT on all fdes.
     330             :          */
     331       37653 :         clear_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
     332       37653 :         tevent_common_fd_mpx_additional_flags(primary, clear_flags, 0);
     333             : 
     334       37653 :         effective_flags = tevent_common_fd_mpx_flags(primary);
     335             : 
     336             :         /*
     337             :          * Modify the low level epoll state to reflect
     338             :          * the effective flags we want to monitor.
     339             :          */
     340       37653 :         ZERO_STRUCT(event);
     341       37653 :         event.events = epoll_map_flags(effective_flags);
     342       37653 :         event.data.ptr = primary;
     343       37653 :         ret = epoll_ctl(epoll_ev->epoll_fd,
     344             :                         EPOLL_CTL_MOD,
     345             :                         primary->fd,
     346             :                         &event);
     347       37653 :         if (ret != 0 && errno == EBADF) {
     348           0 :                 struct tevent_common_fd_buf pbuf = {};
     349           0 :                 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           0 :                 tevent_common_fd_mpx_disarm_all(primary);
     354           0 :                 return 0;
     355       37653 :         } else if (ret != 0) {
     356           0 :                 struct tevent_common_fd_buf pbuf = {};
     357           0 :                 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           0 :                 return ret;
     363             :         }
     364             : 
     365             :         /*
     366             :          * Finally re-add HAS_EVENT to all fdes
     367             :          */
     368       37653 :         add_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
     369       37653 :         tevent_common_fd_mpx_additional_flags(primary, 0, add_flags);
     370             : 
     371       36727 :         return 0;
     372             : }
     373             : 
     374             : /*
     375             :  add the epoll event to the given fd_event
     376             : */
     377    16809446 : static void epoll_add_event(struct epoll_event_context *epoll_ev,
     378             :                             struct tevent_fd *_primary)
     379             : {
     380    16809446 :         struct tevent_fd *primary = tevent_common_fd_mpx_primary(_primary);
     381    16809446 :         uint16_t effective_flags = tevent_common_fd_mpx_flags(primary);
     382       62651 :         struct epoll_event event;
     383    16809446 :         uint64_t clear_flags = 0;
     384    16809446 :         uint64_t add_flags = 0;
     385       62651 :         int ret;
     386             : 
     387             :         /*
     388             :          * Before me modify the low level epoll state,
     389             :          * we clear HAS_EVENT on all fdes.
     390             :          */
     391    16809446 :         clear_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
     392    16809446 :         tevent_common_fd_mpx_additional_flags(primary, clear_flags, 0);
     393             : 
     394             :         /*
     395             :          * Modify the low level epoll state to reflect
     396             :          * the effective flags we want to monitor.
     397             :          *
     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.
     402             :          */
     403    16809446 :         ZERO_STRUCT(event);
     404    16809446 :         event.events = epoll_map_flags(effective_flags);
     405    16809446 :         event.data.ptr = primary;
     406    16809446 :         ret = epoll_ctl(epoll_ev->epoll_fd,
     407             :                         EPOLL_CTL_ADD,
     408             :                         primary->fd,
     409             :                         &event);
     410    16809446 :         if (ret != 0 && errno == EBADF) {
     411           0 :                 struct tevent_common_fd_buf pbuf = {};
     412           0 :                 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           0 :                 tevent_common_fd_mpx_disarm_all(primary);
     417           0 :                 return;
     418    16809446 :         } else if (ret != 0 && errno == EEXIST) {
     419       37687 :                 ret = epoll_add_multiplex_fd(epoll_ev, primary);
     420       37687 :                 if (ret != 0) {
     421           0 :                         epoll_panic(epoll_ev, "epoll_add_multiplex_fd failed",
     422             :                                     false);
     423           0 :                         return;
     424             :                 }
     425             :                 /*
     426             :                  * epoll_add_multiplex_fd() already
     427             :                  * added EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
     428             :                  */
     429       36727 :                 return;
     430    16771759 :         } else if (ret != 0) {
     431           5 :                 epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed", false);
     432           5 :                 return;
     433             :         }
     434             : 
     435             :         /*
     436             :          * Finally re-add HAS_EVENT to all fdes
     437             :          */
     438    16771754 :         add_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
     439    16833445 :         tevent_common_fd_mpx_additional_flags(primary, 0, add_flags);
     440             : }
     441             : 
     442             : /*
     443             :  delete the epoll event for given fd_event
     444             : */
     445    15113682 : static void epoll_del_event(struct epoll_event_context *epoll_ev,
     446             :                             struct tevent_fd *_primary)
     447             : {
     448    15113682 :         struct tevent_fd *primary = tevent_common_fd_mpx_primary(_primary);
     449       47423 :         struct epoll_event event;
     450    15113682 :         uint64_t clear_flags = 0;
     451       47423 :         int ret;
     452             : 
     453             :         /*
     454             :          * Before me delete the low level epoll state,
     455             :          * we clear HAS_EVENT on all fdes.
     456             :          */
     457    15113682 :         clear_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
     458    15113682 :         tevent_common_fd_mpx_additional_flags(primary, clear_flags, 0);
     459             : 
     460             :         /*
     461             :          * Delete the low level epoll state to reflect
     462             :          * the effective flags we want to monitor.
     463             :          */
     464    15113682 :         ZERO_STRUCT(event);
     465    15113682 :         ret = epoll_ctl(epoll_ev->epoll_fd,
     466             :                         EPOLL_CTL_DEL,
     467             :                         primary->fd,
     468             :                         &event);
     469    15113682 :         if (ret != 0 && errno == ENOENT) {
     470       76064 :                 struct tevent_common_fd_buf pbuf = {};
     471             :                 /*
     472             :                  * This can happen after a epoll_check_reopen
     473             :                  * within epoll_event_fd_destructor.
     474             :                  */
     475       76064 :                 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       76064 :                 return;
     479    15037618 :         } else if (ret != 0 && errno == EBADF) {
     480           1 :                 struct tevent_common_fd_buf pbuf = {};
     481           1 :                 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           1 :                 tevent_common_fd_mpx_disarm_all(primary);
     485           1 :                 return;
     486    15037617 :         } else if (ret != 0) {
     487           0 :                 struct tevent_common_fd_buf pbuf = {};
     488           0 :                 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           0 :                 epoll_panic(epoll_ev, "EPOLL_CTL_DEL failed", false);
     493           0 :                 return;
     494             :         }
     495             : }
     496             : 
     497             : /*
     498             :  change the epoll event to the given fd_event
     499             : */
     500     4515378 : static void epoll_mod_event(struct epoll_event_context *epoll_ev,
     501             :                             struct tevent_fd *_primary)
     502             : {
     503     4515378 :         struct tevent_fd *primary = tevent_common_fd_mpx_primary(_primary);
     504     4515378 :         uint16_t effective_flags = tevent_common_fd_mpx_flags(primary);
     505       10375 :         struct epoll_event event;
     506     4515378 :         uint64_t clear_flags = 0;
     507     4515378 :         uint64_t add_flags = 0;
     508       10375 :         int ret;
     509             : 
     510             :         /*
     511             :          * Before me modify the low level epoll state,
     512             :          * we clear HAS_EVENT on all fdes.
     513             :          */
     514     4515378 :         clear_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
     515     4515378 :         tevent_common_fd_mpx_additional_flags(primary, clear_flags, 0);
     516             : 
     517             :         /*
     518             :          * Modify the low level epoll state to reflect
     519             :          * the effective flags we want to monitor.
     520             :          */
     521     4515378 :         ZERO_STRUCT(event);
     522     4515378 :         event.events = epoll_map_flags(effective_flags);
     523     4515378 :         event.data.ptr = primary;
     524     4515378 :         ret = epoll_ctl(epoll_ev->epoll_fd,
     525             :                         EPOLL_CTL_MOD,
     526             :                         primary->fd,
     527             :                         &event);
     528     4515378 :         if (ret != 0 && errno == EBADF) {
     529           0 :                 struct tevent_common_fd_buf pbuf = {};
     530           0 :                 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           0 :                 tevent_common_fd_mpx_disarm_all(primary);
     534           0 :                 return;
     535     4515378 :         } else if (ret != 0) {
     536           0 :                 struct tevent_common_fd_buf pbuf = {};
     537           0 :                 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           0 :                 epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false);
     542           0 :                 return;
     543             :         }
     544             : 
     545             :         /*
     546             :          * Finally re-add HAS_EVENT to all fdes
     547             :          */
     548     4515378 :         add_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
     549     4525753 :         tevent_common_fd_mpx_additional_flags(primary, 0, add_flags);
     550             : }
     551             : 
     552    21751682 : static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
     553             : {
     554    21751682 :         struct tevent_fd *primary = tevent_common_fd_mpx_primary(fde);
     555    21751682 :         uint64_t _paf = primary->additional_flags;
     556    21751682 :         bool got_error = (_paf & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
     557    21751682 :         uint16_t effective_flags = tevent_common_fd_mpx_flags(primary);
     558    21751682 :         bool want_read = (effective_flags & TEVENT_FD_READ);
     559    21751682 :         bool want_write= (effective_flags & TEVENT_FD_WRITE);
     560    21751682 :         bool want_error= (effective_flags & TEVENT_FD_ERROR);
     561             : 
     562             :         /* there's already an event */
     563    21751682 :         if (primary->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
     564     4660396 :                 if (want_read || want_error || (want_write && !got_error)) {
     565     4515378 :                         epoll_mod_event(epoll_ev, primary);
     566     4515378 :                         return;
     567             :                 }
     568             :                 /* 
     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.
     571             :                  *
     572             :                  * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
     573             :                  */
     574      145018 :                 epoll_del_event(epoll_ev, primary);
     575      145018 :                 return;
     576             :         }
     577             : 
     578             :         /* there's no epoll_event attached to the fde */
     579    17091286 :         if (want_read || want_error || (want_write && !got_error)) {
     580    16809446 :                 epoll_add_event(epoll_ev, primary);
     581    16809446 :                 return;
     582             :         }
     583             : }
     584             : 
     585             : /*
     586             :   event loop handling using epoll
     587             : */
     588   189006120 : static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
     589             : {
     590    15510415 :         int ret, i;
     591             : #define MAXEVENTS 1
     592    15510415 :         struct epoll_event events[MAXEVENTS];
     593   189006120 :         int timeout = -1;
     594    15510415 :         int wait_errno;
     595             : 
     596   189006120 :         if (tvalp) {
     597             :                 /* it's better to trigger timed events a bit later than too early */
     598   189006120 :                 timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
     599             :         }
     600             : 
     601   334179695 :         if (epoll_ev->ev->signal_events &&
     602   145173575 :             tevent_common_check_signal(epoll_ev->ev)) {
     603           1 :                 return 0;
     604             :         }
     605             : 
     606   189006119 :         tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
     607   189006119 :         ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
     608   189006119 :         wait_errno = errno;
     609   189006119 :         tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
     610             : 
     611   189006119 :         if (ret == -1 && wait_errno == EINTR && epoll_ev->ev->signal_events) {
     612    33383414 :                 if (tevent_common_check_signal(epoll_ev->ev)) {
     613    33137201 :                         return 0;
     614             :                 }
     615             :         }
     616             : 
     617   155622745 :         if (ret == -1 && wait_errno != EINTR) {
     618           0 :                 epoll_panic(epoll_ev, "epoll_wait() failed", true);
     619           0 :                 return -1;
     620             :         }
     621             : 
     622   155622745 :         if (ret == 0 && tvalp) {
     623             :                 /* we don't care about a possible delay here */
     624     1738632 :                 tevent_common_loop_timer_delay(epoll_ev->ev);
     625     1738598 :                 return 0;
     626             :         }
     627             : 
     628   153884113 :         for (i=0;i<ret;i++) {
     629   153883944 :                 struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
     630             :                                                        struct tevent_fd);
     631   153883944 :                 struct tevent_fd *selected = NULL;
     632    15254331 :                 uint16_t effective_flags;
     633   153883944 :                 uint16_t flags = 0;
     634   153883944 :                 bool got_error = false;
     635             : 
     636   153883944 :                 if (fde == NULL) {
     637           0 :                         epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
     638           0 :                         return -1;
     639             :                 }
     640   153883944 :                 effective_flags = tevent_common_fd_mpx_flags(fde);
     641   153883944 :                 if (events[i].events & (EPOLLHUP|EPOLLERR|EPOLLRDHUP)) {
     642    10005325 :                         uint64_t add_flags = 0;
     643             : 
     644    10005325 :                         add_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
     645    10005325 :                         tevent_common_fd_mpx_additional_flags(fde,
     646             :                                                               0,
     647             :                                                               add_flags);
     648             : 
     649    10005325 :                         if (effective_flags & TEVENT_FD_ERROR) {
     650      326671 :                                 flags |= TEVENT_FD_ERROR;
     651             :                         }
     652    10005325 :                         if (effective_flags & TEVENT_FD_READ) {
     653    10005320 :                                 flags |= TEVENT_FD_READ;
     654             :                         }
     655             :                 }
     656   153883944 :                 if (events[i].events & EPOLLIN) {
     657   111080343 :                         if (effective_flags & TEVENT_FD_READ) {
     658   111080343 :                                 flags |= TEVENT_FD_READ;
     659             :                         }
     660             :                 }
     661   153883944 :                 if (events[i].events & EPOLLOUT) {
     662    33196377 :                         if (effective_flags & TEVENT_FD_WRITE) {
     663    33196377 :                                 flags |= TEVENT_FD_WRITE;
     664             :                         }
     665             :                 }
     666             : 
     667   153883944 :                 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR)
     668             :                 {
     669    10005325 :                         got_error = true;
     670             :                 }
     671             : 
     672   153883944 :                 selected = tevent_common_fd_mpx_select(fde, flags, got_error);
     673   153883944 :                 if (selected == NULL) {
     674           0 :                         if (got_error) {
     675             :                                 /*
     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
     681             :                                  *
     682             :                                  * Do the same as the poll backend and
     683             :                                  * remove the writeable flag.
     684             :                                  */
     685           0 :                                 tevent_common_fd_mpx_clear_writeable(fde);
     686           0 :                                 epoll_update_event(epoll_ev, fde);
     687             :                         }
     688           0 :                         continue;
     689             :                 }
     690             : 
     691             :                 /*
     692             :                  * make sure we only pass the flags
     693             :                  * the handler is expecting.
     694             :                  */
     695   153883944 :                 flags &= selected->flags;
     696   153883944 :                 return tevent_common_invoke_fd_handler(selected,
     697             :                                                        flags,
     698             :                                                        NULL);
     699             :         }
     700             : 
     701         169 :         return 0;
     702             : }
     703             : 
     704             : /*
     705             :   create a epoll_event_context structure.
     706             : */
     707    83086484 : static int epoll_event_context_init(struct tevent_context *ev)
     708             : {
     709     3110099 :         int ret;
     710     3110099 :         struct epoll_event_context *epoll_ev;
     711             : 
     712             :         /*
     713             :          * We might be called during tevent_re_initialise()
     714             :          * which means we need to free our old additional_data.
     715             :          */
     716    83086484 :         TALLOC_FREE(ev->additional_data);
     717             : 
     718    83086484 :         epoll_ev = talloc_zero(ev, struct epoll_event_context);
     719    83086484 :         if (!epoll_ev) return -1;
     720    83086484 :         epoll_ev->ev = ev;
     721    83086484 :         epoll_ev->epoll_fd = -1;
     722             : 
     723    83086484 :         ret = epoll_init_ctx(epoll_ev);
     724    83086484 :         if (ret != 0) {
     725           0 :                 talloc_free(epoll_ev);
     726           0 :                 return ret;
     727             :         }
     728             : 
     729    83086484 :         ev->additional_data = epoll_ev;
     730    83086484 :         return 0;
     731             : }
     732             : 
     733             : /*
     734             :   destroy an fd_event
     735             : */
     736    24837311 : static int epoll_event_fd_destructor(struct tevent_fd *fde)
     737             : {
     738    24837311 :         struct tevent_fd *old_primary = NULL;
     739    24837311 :         struct tevent_fd *new_primary = NULL;
     740    24837311 :         struct tevent_fd *update_primary = NULL;
     741    24837311 :         struct tevent_context *ev = fde->event_ctx;
     742    24837311 :         struct epoll_event_context *epoll_ev = NULL;
     743    24837311 :         bool panic_triggered = false;
     744             : 
     745    24837311 :         if (ev == NULL) {
     746     9833628 :                 tevent_common_fd_mpx_reinit(fde);
     747     9833628 :                 return tevent_common_fd_destructor(fde);
     748             :         }
     749             : 
     750    15003683 :         epoll_ev = talloc_get_type_abort(ev->additional_data,
     751             :                                          struct epoll_event_context);
     752             : 
     753             :         /*
     754             :          * we must remove the event from the list
     755             :          * otherwise a panic fallback handler may
     756             :          * reuse invalid memory
     757             :          */
     758    15003683 :         DLIST_REMOVE(ev->fd_events, fde);
     759             : 
     760    15003683 :         epoll_ev->panic_state = &panic_triggered;
     761    15003683 :         if (epoll_ev->pid != tevent_cached_getpid()) {
     762       64075 :                 epoll_check_reopen(epoll_ev);
     763       64075 :                 if (panic_triggered) {
     764           0 :                         tevent_common_fd_mpx_reinit(fde);
     765           0 :                         return tevent_common_fd_destructor(fde);
     766             :                 }
     767             :         }
     768             : 
     769    15003683 :         old_primary = tevent_common_fd_mpx_primary(fde);
     770             : 
     771    15003683 :         if (old_primary == fde) {
     772    14968664 :                 epoll_del_event(epoll_ev, fde);
     773    14968664 :                 if (panic_triggered) {
     774           0 :                         tevent_common_fd_mpx_reinit(fde);
     775           0 :                         return tevent_common_fd_destructor(fde);
     776             :                 }
     777             :         }
     778             : 
     779    15003683 :         new_primary = tevent_common_fd_mpx_remove(fde);
     780    15003683 :         if (new_primary == NULL) {
     781    14966030 :                 epoll_ev->panic_state = NULL;
     782    14966030 :                 return tevent_common_fd_destructor(fde);
     783             :         }
     784       37653 :         update_primary = tevent_common_fd_mpx_update(new_primary);
     785       37653 :         if (update_primary == NULL) {
     786           2 :                 epoll_ev->panic_state = NULL;
     787           2 :                 return tevent_common_fd_destructor(fde);
     788             :         }
     789             : 
     790       37651 :         epoll_update_event(epoll_ev, update_primary);
     791       37651 :         if (panic_triggered) {
     792           0 :                 return tevent_common_fd_destructor(fde);
     793             :         }
     794       37651 :         epoll_ev->panic_state = NULL;
     795             : 
     796       37651 :         return tevent_common_fd_destructor(fde);
     797             : }
     798             : 
     799             : /*
     800             :   add a fd based event
     801             :   return NULL on failure (memory allocation error)
     802             : */
     803    16091153 : 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)
     809             : {
     810       56715 :         struct epoll_event_context *epoll_ev =
     811    16091153 :                 talloc_get_type_abort(ev->additional_data,
     812             :                 struct epoll_event_context);
     813       56715 :         struct tevent_fd *fde;
     814    16091153 :         bool panic_triggered = false;
     815    16091153 :         pid_t old_pid = epoll_ev->pid;
     816             : 
     817    16091153 :         fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
     818             :                                    handler, private_data,
     819             :                                    handler_name, location);
     820    16091153 :         if (!fde) return NULL;
     821             : 
     822    16091153 :         talloc_set_destructor(fde, epoll_event_fd_destructor);
     823             : 
     824             :         /*
     825             :          * prepare for tevent_common_fd_mpx_flags()
     826             :          * in epoll_update_event()
     827             :          */
     828    16091153 :         tevent_common_fd_mpx_update_flags(fde);
     829             : 
     830    16091153 :         if (epoll_ev->pid != tevent_cached_getpid()) {
     831         410 :                 epoll_ev->panic_state = &panic_triggered;
     832         410 :                 epoll_check_reopen(epoll_ev);
     833         410 :                 if (panic_triggered) {
     834           0 :                         return fde;
     835             :                 }
     836         410 :                 epoll_ev->panic_state = NULL;
     837             :         }
     838             : 
     839    16091153 :         if (epoll_ev->pid == old_pid) {
     840    16090743 :                 epoll_update_event(epoll_ev, fde);
     841             :         }
     842             : 
     843    16034438 :         return fde;
     844             : }
     845             : 
     846             : /*
     847             :   set the fd event flags
     848             : */
     849    25863085 : static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
     850             : {
     851       77473 :         struct tevent_context *ev;
     852       77473 :         struct epoll_event_context *epoll_ev;
     853    25863085 :         bool panic_triggered = false;
     854       77473 :         pid_t old_pid;
     855             : 
     856    25863085 :         if (fde->flags == flags) return;
     857             : 
     858     5040218 :         ev = fde->event_ctx;
     859     5040218 :         epoll_ev = talloc_get_type_abort(ev->additional_data,
     860             :                                          struct epoll_event_context);
     861     5040218 :         old_pid = epoll_ev->pid;
     862             : 
     863     5040218 :         fde->flags = flags;
     864             :         /*
     865             :          * prepare for tevent_common_fd_mpx_flags()
     866             :          * in epoll_update_event()
     867             :          */
     868     5040218 :         tevent_common_fd_mpx_update_flags(fde);
     869             : 
     870     5040218 :         if (epoll_ev->pid != tevent_cached_getpid()) {
     871        7307 :                 epoll_ev->panic_state = &panic_triggered;
     872        7307 :                 epoll_check_reopen(epoll_ev);
     873        7307 :                 if (panic_triggered) {
     874           0 :                         return;
     875             :                 }
     876        7307 :                 epoll_ev->panic_state = NULL;
     877             :         }
     878             : 
     879     5040218 :         if (epoll_ev->pid == old_pid) {
     880     5032911 :                 epoll_update_event(epoll_ev, fde);
     881             :         }
     882             : }
     883             : 
     884             : /*
     885             :   do a single event loop using the events defined in ev
     886             : */
     887   424035667 : static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
     888             : {
     889    22243027 :         struct epoll_event_context *epoll_ev =
     890   424035667 :                 talloc_get_type_abort(ev->additional_data,
     891             :                 struct epoll_event_context);
     892    22243025 :         struct timeval tval;
     893   424035665 :         bool panic_triggered = false;
     894             : 
     895   587122826 :         if (ev->signal_events &&
     896   163087172 :             tevent_common_check_signal(ev)) {
     897      258055 :                 return 0;
     898             :         }
     899             : 
     900   423080341 :         if (ev->threaded_contexts != NULL) {
     901     1560354 :                 tevent_common_threaded_activate_immediate(ev);
     902             :         }
     903             : 
     904   452043880 :         if (ev->immediate_events &&
     905    28979738 :             tevent_common_loop_immediate(ev)) {
     906    28678577 :                 return 0;
     907             :         }
     908             : 
     909   394100603 :         tval = tevent_common_loop_timer_delay(ev);
     910   394100555 :         if (tevent_timeval_is_zero(&tval)) {
     911   199344114 :                 return 0;
     912             :         }
     913             : 
     914   189006120 :         if (epoll_ev->pid != tevent_cached_getpid()) {
     915           0 :                 epoll_ev->panic_state = &panic_triggered;
     916           0 :                 epoll_ev->panic_force_replay = true;
     917           0 :                 epoll_check_reopen(epoll_ev);
     918           0 :                 if (panic_triggered) {
     919           0 :                         errno = EINVAL;
     920           0 :                         return -1;
     921             :                 }
     922           0 :                 epoll_ev->panic_force_replay = false;
     923           0 :                 epoll_ev->panic_state = NULL;
     924             :         }
     925             : 
     926   189006120 :         return epoll_event_loop(epoll_ev, &tval);
     927             : }
     928             : 
     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,
     940             : };
     941             : 
     942       76842 : _PRIVATE_ bool tevent_epoll_init(void)
     943             : {
     944       76842 :         return tevent_register_backend("epoll", &epoll_event_ops);
     945             : }

Generated by: LCOV version 1.14