LCOV - code coverage report
Current view: top level - lib/util - fd_group.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 78 205 38.0 %
Date: 2024-07-11 23:29:16 Functions: 5 12 41.7 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2020 Intel Corporation. All rights reserved.
       3             :  *   All rights reserved.
       4             :  */
       5             : 
       6             : #include "spdk_internal/usdt.h"
       7             : 
       8             : #include "spdk/env.h"
       9             : #include "spdk/log.h"
      10             : #include "spdk/queue.h"
      11             : 
      12             : #include "spdk/fd_group.h"
      13             : 
      14             : #ifdef __linux__
      15             : #include <sys/epoll.h>
      16             : #endif
      17             : 
      18             : #define SPDK_MAX_EVENT_NAME_LEN 256
      19             : 
      20             : enum event_handler_state {
      21             :         /* The event_handler is added into an fd_group waiting for event,
      22             :          * but not currently in the execution of a wait loop.
      23             :          */
      24             :         EVENT_HANDLER_STATE_WAITING,
      25             : 
      26             :         /* The event_handler is currently in the execution of a wait loop. */
      27             :         EVENT_HANDLER_STATE_RUNNING,
      28             : 
      29             :         /* The event_handler was removed during the execution of a wait loop. */
      30             :         EVENT_HANDLER_STATE_REMOVED,
      31             : };
      32             : 
      33             : /* file descriptor of the interrupt event */
      34             : 
      35             : /* Taking "ehdlr" as short name for file descriptor handler of the interrupt event. */
      36             : struct event_handler {
      37             :         TAILQ_ENTRY(event_handler)      next;
      38             :         enum event_handler_state        state;
      39             : 
      40             :         spdk_fd_fn                      fn;
      41             :         void                            *fn_arg;
      42             :         /* file descriptor of the interrupt event */
      43             :         int                             fd;
      44             :         uint32_t                        events;
      45             :         char                            name[SPDK_MAX_EVENT_NAME_LEN + 1];
      46             : };
      47             : 
      48             : struct spdk_fd_group {
      49             :         int epfd;
      50             :         int num_fds; /* Number of fds registered in this group. */
      51             : 
      52             :         struct spdk_fd_group *parent;
      53             : 
      54             :         /* interrupt sources list */
      55             :         TAILQ_HEAD(, event_handler) event_handlers;
      56             : };
      57             : 
      58             : int
      59           0 : spdk_fd_group_get_fd(struct spdk_fd_group *fgrp)
      60             : {
      61           0 :         return fgrp->epfd;
      62             : }
      63             : 
      64             : #ifdef __linux__
      65             : 
      66             : static __thread struct epoll_event *g_event = NULL;
      67             : 
      68             : int
      69           0 : spdk_fd_group_get_epoll_event(struct epoll_event *event)
      70             : {
      71           0 :         if (g_event == NULL) {
      72           0 :                 return -EINVAL;
      73             :         }
      74           0 :         *event = *g_event;
      75           0 :         return 0;
      76             : }
      77             : 
      78             : static int
      79           0 : _fd_group_del_all(int epfd, struct spdk_fd_group *grp)
      80             : {
      81           0 :         struct event_handler *ehdlr = NULL;
      82           0 :         struct epoll_event epevent = {0};
      83             :         int rc;
      84           0 :         int ret = 0;
      85             : 
      86           0 :         TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
      87           0 :                 rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
      88           0 :                 if (rc < 0) {
      89           0 :                         if (errno == ENOENT) {
      90             :                                 /* This is treated as success. It happens if there are multiple
      91             :                                  * attempts to remove fds from the group.
      92             :                                  */
      93           0 :                                 continue;
      94             :                         }
      95             : 
      96           0 :                         ret = -errno;
      97           0 :                         SPDK_ERRLOG("Failed to remove fd %d from group: %s\n", ehdlr->fd, strerror(errno));
      98           0 :                         goto recover;
      99             :                 }
     100             :         }
     101             : 
     102           0 :         return 0;
     103             : 
     104           0 : recover:
     105             :         /* We failed to remove everything. Let's try to get everything put back into
     106             :          * the original group. */
     107           0 :         TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
     108           0 :                 epevent.events = ehdlr->events;
     109           0 :                 epevent.data.ptr = ehdlr;
     110           0 :                 rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
     111           0 :                 if (rc < 0) {
     112           0 :                         if (errno == EEXIST) {
     113             :                                 /* This is fine. Keep going. */
     114           0 :                                 continue;
     115             :                         }
     116             : 
     117             :                         /* Continue on even though we've failed. But indicate
     118             :                          * this is a fatal error. */
     119           0 :                         SPDK_ERRLOG("Failed to recover fd_group_del_all: %s\n", strerror(errno));
     120           0 :                         ret = -ENOTRECOVERABLE;
     121             :                 }
     122             :         }
     123             : 
     124           0 :         return ret;
     125             : }
     126             : 
     127             : static int
     128           0 : _fd_group_add_all(int epfd, struct spdk_fd_group *grp)
     129             : {
     130           0 :         struct event_handler *ehdlr = NULL;
     131           0 :         struct epoll_event epevent = {0};
     132             :         int rc;
     133           0 :         int ret = 0;
     134             : 
     135             :         /* Hoist the fds from the child up into the parent */
     136           0 :         TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
     137           0 :                 epevent.events = ehdlr->events;
     138           0 :                 epevent.data.ptr = ehdlr;
     139           0 :                 rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
     140           0 :                 if (rc < 0) {
     141           0 :                         if (errno == EEXIST) {
     142             :                                 /* This is treated as success */
     143           0 :                                 continue;
     144             :                         }
     145             : 
     146           0 :                         ret = -errno;
     147           0 :                         SPDK_ERRLOG("Failed to add fd to fd group: %s\n", strerror(errno));
     148           0 :                         goto recover;
     149             :                 }
     150             :         }
     151             : 
     152           0 :         return 0;
     153             : 
     154           0 : recover:
     155             :         /* We failed to add everything, so try to remove what we did add. */
     156           0 :         TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
     157           0 :                 rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
     158           0 :                 if (rc < 0) {
     159           0 :                         if (errno == ENOENT) {
     160             :                                 /* This is treated as success. */
     161           0 :                                 continue;
     162             :                         }
     163             : 
     164             : 
     165             :                         /* Continue on even though we've failed. But indicate
     166             :                          * this is a fatal error. */
     167           0 :                         SPDK_ERRLOG("Failed to recover fd_group_del_all: %s\n", strerror(errno));
     168           0 :                         ret = -ENOTRECOVERABLE;
     169             :                 }
     170             :         }
     171             : 
     172           0 :         return ret;
     173             : }
     174             : 
     175             : int
     176           0 : spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
     177             : {
     178             :         int rc;
     179             : 
     180           0 :         if (parent == NULL || child == NULL) {
     181           0 :                 return -EINVAL;
     182             :         }
     183             : 
     184           0 :         if (child->parent != parent) {
     185           0 :                 return -EINVAL;
     186             :         }
     187             : 
     188           0 :         rc = _fd_group_del_all(parent->epfd, child);
     189           0 :         if (rc < 0) {
     190           0 :                 return rc;
     191             :         }
     192             : 
     193           0 :         child->parent = NULL;
     194             : 
     195           0 :         return _fd_group_add_all(child->epfd, child);
     196             : }
     197             : 
     198             : int
     199           0 : spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
     200             : {
     201             :         int rc;
     202             : 
     203           0 :         if (parent == NULL || child == NULL) {
     204           0 :                 return -EINVAL;
     205             :         }
     206             : 
     207           0 :         if (child->parent) {
     208           0 :                 return -EINVAL;
     209             :         }
     210             : 
     211           0 :         if (parent->parent) {
     212             :                 /* More than one layer of nesting is not currently supported */
     213           0 :                 assert(false);
     214             :                 return -ENOTSUP;
     215             :         }
     216             : 
     217           0 :         rc = _fd_group_del_all(child->epfd, child);
     218           0 :         if (rc < 0) {
     219           0 :                 return rc;
     220             :         }
     221             : 
     222           0 :         child->parent = parent;
     223             : 
     224           0 :         return _fd_group_add_all(parent->epfd, child);
     225             : }
     226             : 
     227             : int
     228          59 : spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
     229             :                   void *arg, const char *name)
     230             : {
     231          59 :         struct event_handler *ehdlr = NULL;
     232          59 :         struct epoll_event epevent = {0};
     233             :         int rc;
     234             :         int epfd;
     235             : 
     236             :         /* parameter checking */
     237          59 :         if (fgrp == NULL || efd < 0 || fn == NULL) {
     238           0 :                 return -EINVAL;
     239             :         }
     240             : 
     241             :         /* check if there is already one function registered for this fd */
     242          96 :         TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
     243          37 :                 if (ehdlr->fd == efd) {
     244           0 :                         return -EEXIST;
     245             :                 }
     246             :         }
     247             : 
     248             :         /* create a new event src */
     249          59 :         ehdlr = calloc(1, sizeof(*ehdlr));
     250          59 :         if (ehdlr == NULL) {
     251           0 :                 return -errno;
     252             :         }
     253             : 
     254          59 :         ehdlr->fd = efd;
     255          59 :         ehdlr->fn = fn;
     256          59 :         ehdlr->fn_arg = arg;
     257          59 :         ehdlr->state = EVENT_HANDLER_STATE_WAITING;
     258          59 :         ehdlr->events = EPOLLIN;
     259          59 :         snprintf(ehdlr->name, sizeof(ehdlr->name), "%s", name);
     260             : 
     261          59 :         if (fgrp->parent) {
     262           0 :                 epfd = fgrp->parent->epfd;
     263             :         } else {
     264          59 :                 epfd = fgrp->epfd;
     265             :         }
     266             : 
     267          59 :         epevent.events = ehdlr->events;
     268          59 :         epevent.data.ptr = ehdlr;
     269          59 :         rc = epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &epevent);
     270          59 :         if (rc < 0) {
     271           0 :                 free(ehdlr);
     272           0 :                 return -errno;
     273             :         }
     274             : 
     275          59 :         TAILQ_INSERT_TAIL(&fgrp->event_handlers, ehdlr, next);
     276          59 :         fgrp->num_fds++;
     277             : 
     278          59 :         return 0;
     279             : }
     280             : 
     281             : void
     282          59 : spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
     283             : {
     284             :         struct event_handler *ehdlr;
     285             :         int rc;
     286             :         int epfd;
     287             : 
     288          59 :         if (fgrp == NULL || efd < 0) {
     289           0 :                 SPDK_ERRLOG("Invalid to remvoe efd(%d) from fd_group(%p).\n", efd, fgrp);
     290           0 :                 assert(0);
     291             :                 return;
     292             :         }
     293             : 
     294             : 
     295          90 :         TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
     296          90 :                 if (ehdlr->fd == efd) {
     297          59 :                         break;
     298             :                 }
     299             :         }
     300             : 
     301          59 :         if (ehdlr == NULL) {
     302           0 :                 SPDK_ERRLOG("efd(%d) is not existed in fgrp(%p)\n", efd, fgrp);
     303           0 :                 return;
     304             :         }
     305             : 
     306          59 :         assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
     307             : 
     308          59 :         if (fgrp->parent) {
     309           0 :                 epfd = fgrp->parent->epfd;
     310             :         } else {
     311          59 :                 epfd = fgrp->epfd;
     312             :         }
     313             : 
     314          59 :         rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
     315          59 :         if (rc < 0) {
     316           0 :                 SPDK_ERRLOG("Failed to delete the fd(%d) from the epoll group(%p)\n", efd, fgrp);
     317           0 :                 return;
     318             :         }
     319             : 
     320          59 :         assert(fgrp->num_fds > 0);
     321          59 :         fgrp->num_fds--;
     322          59 :         TAILQ_REMOVE(&fgrp->event_handlers, ehdlr, next);
     323             : 
     324             :         /* Delay ehdlr's free in case it is waiting for execution in fgrp wait loop */
     325          59 :         if (ehdlr->state == EVENT_HANDLER_STATE_RUNNING) {
     326           0 :                 ehdlr->state = EVENT_HANDLER_STATE_REMOVED;
     327             :         } else {
     328          59 :                 free(ehdlr);
     329             :         }
     330             : }
     331             : 
     332             : int
     333           0 : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
     334             :                            int efd, int event_types)
     335             : {
     336           0 :         struct epoll_event epevent;
     337             :         struct event_handler *ehdlr;
     338             :         int epfd;
     339             : 
     340           0 :         if (fgrp == NULL || efd < 0) {
     341           0 :                 return -EINVAL;
     342             :         }
     343             : 
     344           0 :         TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
     345           0 :                 if (ehdlr->fd == efd) {
     346           0 :                         break;
     347             :                 }
     348             :         }
     349             : 
     350           0 :         if (ehdlr == NULL) {
     351           0 :                 return -EINVAL;
     352             :         }
     353             : 
     354           0 :         assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
     355             : 
     356           0 :         ehdlr->events = event_types;
     357             : 
     358           0 :         if (fgrp->parent) {
     359           0 :                 epfd = fgrp->parent->epfd;
     360             :         } else {
     361           0 :                 epfd = fgrp->epfd;
     362             :         }
     363             : 
     364           0 :         epevent.events = ehdlr->events;
     365           0 :         epevent.data.ptr = ehdlr;
     366             : 
     367           0 :         return epoll_ctl(epfd, EPOLL_CTL_MOD, ehdlr->fd, &epevent);
     368             : }
     369             : 
     370             : int
     371          28 : spdk_fd_group_create(struct spdk_fd_group **_egrp)
     372             : {
     373             :         struct spdk_fd_group *fgrp;
     374             : 
     375          28 :         if (_egrp == NULL) {
     376           0 :                 return -EINVAL;
     377             :         }
     378             : 
     379          28 :         fgrp = calloc(1, sizeof(*fgrp));
     380          28 :         if (fgrp == NULL) {
     381           0 :                 return -ENOMEM;
     382             :         }
     383             : 
     384             :         /* init the event source head */
     385          28 :         TAILQ_INIT(&fgrp->event_handlers);
     386             : 
     387          28 :         fgrp->num_fds = 0;
     388          28 :         fgrp->epfd = epoll_create1(EPOLL_CLOEXEC);
     389          28 :         if (fgrp->epfd < 0) {
     390           0 :                 free(fgrp);
     391           0 :                 return -errno;
     392             :         }
     393             : 
     394          28 :         *_egrp = fgrp;
     395             : 
     396          28 :         return 0;
     397             : }
     398             : 
     399             : void
     400          28 : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
     401             : {
     402          28 :         if (fgrp == NULL || fgrp->num_fds > 0) {
     403           0 :                 SPDK_ERRLOG("Invalid fd_group(%p) to destroy.\n", fgrp);
     404           0 :                 assert(0);
     405             :                 return;
     406             :         }
     407             : 
     408          28 :         close(fgrp->epfd);
     409          28 :         free(fgrp);
     410             : 
     411          28 :         return;
     412             : }
     413             : 
     414             : int
     415           2 : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
     416           2 : {
     417           2 :         int totalfds = fgrp->num_fds;
     418           2 :         struct epoll_event events[totalfds];
     419             :         struct event_handler *ehdlr;
     420             :         int n;
     421             :         int nfds;
     422             : 
     423           2 :         if (fgrp->parent != NULL) {
     424           0 :                 if (timeout < 0) {
     425           0 :                         SPDK_ERRLOG("Calling spdk_fd_group_wait on a group nested in another group without a timeout will block indefinitely.\n");
     426           0 :                         assert(false);
     427             :                         return -EINVAL;
     428             :                 } else {
     429           0 :                         SPDK_WARNLOG("Calling spdk_fd_group_wait on a group nested in another group will never find any events\n");
     430           0 :                         return 0;
     431             :                 }
     432             :         }
     433             : 
     434           2 :         nfds = epoll_wait(fgrp->epfd, events, totalfds, timeout);
     435           2 :         if (nfds < 0) {
     436           0 :                 if (errno != EINTR) {
     437           0 :                         SPDK_ERRLOG("fgrp epoll_wait returns with fail. errno is %d\n", errno);
     438             :                 }
     439             : 
     440           0 :                 return -errno;
     441           2 :         } else if (nfds == 0) {
     442           1 :                 return 0;
     443             :         }
     444             : 
     445           2 :         for (n = 0; n < nfds; n++) {
     446             :                 /* find the event_handler */
     447           1 :                 ehdlr = events[n].data.ptr;
     448             : 
     449           1 :                 if (ehdlr == NULL) {
     450           0 :                         continue;
     451             :                 }
     452             : 
     453             :                 /* Tag ehdlr as running state in case that it is removed
     454             :                  * during this wait loop but before or when it get executed.
     455             :                  */
     456           1 :                 assert(ehdlr->state == EVENT_HANDLER_STATE_WAITING);
     457           1 :                 ehdlr->state = EVENT_HANDLER_STATE_RUNNING;
     458             :         }
     459             : 
     460           2 :         for (n = 0; n < nfds; n++) {
     461             :                 /* find the event_handler */
     462           1 :                 ehdlr = events[n].data.ptr;
     463             : 
     464           1 :                 if (ehdlr == NULL || ehdlr->fn == NULL) {
     465           0 :                         continue;
     466             :                 }
     467             : 
     468             :                 /* It is possible that the ehdlr was removed
     469             :                  * during this wait loop but before it get executed.
     470             :                  */
     471           1 :                 if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
     472           0 :                         free(ehdlr);
     473           0 :                         continue;
     474             :                 }
     475             : 
     476           1 :                 g_event = &events[n];
     477             :                 /* call the interrupt response function */
     478           1 :                 ehdlr->fn(ehdlr->fn_arg);
     479           1 :                 g_event = NULL;
     480             : 
     481             :                 /* It is possible that the ehdlr was removed
     482             :                  * during this wait loop when it get executed.
     483             :                  */
     484           1 :                 if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
     485           0 :                         free(ehdlr);
     486             :                 } else {
     487           1 :                         ehdlr->state = EVENT_HANDLER_STATE_WAITING;
     488             :                 }
     489             :         }
     490             : 
     491           1 :         return nfds;
     492             : }
     493             : 
     494             : #else
     495             : 
     496             : int
     497             : spdk_fd_group_get_epoll_event(struct epoll_event *event)
     498             : {
     499             :         return -ENOTSUP;
     500             : }
     501             : 
     502             : int
     503             : spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
     504             :                   void *arg, const char *name)
     505             : {
     506             :         return -ENOTSUP;
     507             : }
     508             : 
     509             : void
     510             : spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
     511             : {
     512             : }
     513             : 
     514             : int
     515             : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
     516             :                            int efd, int event_types)
     517             : {
     518             :         return -ENOTSUP;
     519             : }
     520             : 
     521             : int
     522             : spdk_fd_group_create(struct spdk_fd_group **fgrp)
     523             : {
     524             :         return -ENOTSUP;
     525             : }
     526             : 
     527             : void
     528             : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
     529             : {
     530             : }
     531             : 
     532             : int
     533             : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
     534             : {
     535             :         return -ENOTSUP;
     536             : }
     537             : 
     538             : int
     539             : spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
     540             : {
     541             :         return -ENOTSUP;
     542             : }
     543             : 
     544             : int
     545             : spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
     546             : {
     547             :         return -ENOTSUP;
     548             : }
     549             : 
     550             : #endif

Generated by: LCOV version 1.15