LCOV - code coverage report
Current view: top level - lib/util - fd_group.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 80 207 38.6 %
Date: 2024-07-12 21:29:49 Functions: 6 13 46.2 %

          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 :         return spdk_fd_group_add_for_events(fgrp, efd, EPOLLIN, fn, arg, name);
     232             : }
     233             : 
     234             : int
     235          59 : spdk_fd_group_add_for_events(struct spdk_fd_group *fgrp, int efd, uint32_t events,
     236             :                              spdk_fd_fn fn, void *arg, const char *name)
     237             : {
     238          59 :         struct event_handler *ehdlr = NULL;
     239          59 :         struct epoll_event epevent = {0};
     240             :         int rc;
     241             :         int epfd;
     242             : 
     243             :         /* parameter checking */
     244          59 :         if (fgrp == NULL || efd < 0 || fn == NULL) {
     245           0 :                 return -EINVAL;
     246             :         }
     247             : 
     248             :         /* check if there is already one function registered for this fd */
     249          96 :         TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
     250          37 :                 if (ehdlr->fd == efd) {
     251           0 :                         return -EEXIST;
     252             :                 }
     253             :         }
     254             : 
     255             :         /* create a new event src */
     256          59 :         ehdlr = calloc(1, sizeof(*ehdlr));
     257          59 :         if (ehdlr == NULL) {
     258           0 :                 return -errno;
     259             :         }
     260             : 
     261          59 :         ehdlr->fd = efd;
     262          59 :         ehdlr->fn = fn;
     263          59 :         ehdlr->fn_arg = arg;
     264          59 :         ehdlr->state = EVENT_HANDLER_STATE_WAITING;
     265          59 :         ehdlr->events = events;
     266          59 :         snprintf(ehdlr->name, sizeof(ehdlr->name), "%s", name);
     267             : 
     268          59 :         if (fgrp->parent) {
     269           0 :                 epfd = fgrp->parent->epfd;
     270             :         } else {
     271          59 :                 epfd = fgrp->epfd;
     272             :         }
     273             : 
     274          59 :         epevent.events = ehdlr->events;
     275          59 :         epevent.data.ptr = ehdlr;
     276          59 :         rc = epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &epevent);
     277          59 :         if (rc < 0) {
     278           0 :                 free(ehdlr);
     279           0 :                 return -errno;
     280             :         }
     281             : 
     282          59 :         TAILQ_INSERT_TAIL(&fgrp->event_handlers, ehdlr, next);
     283          59 :         fgrp->num_fds++;
     284             : 
     285          59 :         return 0;
     286             : }
     287             : 
     288             : void
     289          59 : spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
     290             : {
     291             :         struct event_handler *ehdlr;
     292             :         int rc;
     293             :         int epfd;
     294             : 
     295          59 :         if (fgrp == NULL || efd < 0) {
     296           0 :                 SPDK_ERRLOG("Invalid to remvoe efd(%d) from fd_group(%p).\n", efd, fgrp);
     297           0 :                 assert(0);
     298             :                 return;
     299             :         }
     300             : 
     301             : 
     302          90 :         TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
     303          90 :                 if (ehdlr->fd == efd) {
     304          59 :                         break;
     305             :                 }
     306             :         }
     307             : 
     308          59 :         if (ehdlr == NULL) {
     309           0 :                 SPDK_ERRLOG("efd(%d) is not existed in fgrp(%p)\n", efd, fgrp);
     310           0 :                 return;
     311             :         }
     312             : 
     313          59 :         assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
     314             : 
     315          59 :         if (fgrp->parent) {
     316           0 :                 epfd = fgrp->parent->epfd;
     317             :         } else {
     318          59 :                 epfd = fgrp->epfd;
     319             :         }
     320             : 
     321          59 :         rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
     322          59 :         if (rc < 0) {
     323           0 :                 SPDK_ERRLOG("Failed to delete the fd(%d) from the epoll group(%p)\n", efd, fgrp);
     324           0 :                 return;
     325             :         }
     326             : 
     327          59 :         assert(fgrp->num_fds > 0);
     328          59 :         fgrp->num_fds--;
     329          59 :         TAILQ_REMOVE(&fgrp->event_handlers, ehdlr, next);
     330             : 
     331             :         /* Delay ehdlr's free in case it is waiting for execution in fgrp wait loop */
     332          59 :         if (ehdlr->state == EVENT_HANDLER_STATE_RUNNING) {
     333           0 :                 ehdlr->state = EVENT_HANDLER_STATE_REMOVED;
     334             :         } else {
     335          59 :                 free(ehdlr);
     336             :         }
     337             : }
     338             : 
     339             : int
     340           0 : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
     341             :                            int efd, int event_types)
     342             : {
     343           0 :         struct epoll_event epevent;
     344             :         struct event_handler *ehdlr;
     345             :         int epfd;
     346             : 
     347           0 :         if (fgrp == NULL || efd < 0) {
     348           0 :                 return -EINVAL;
     349             :         }
     350             : 
     351           0 :         TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
     352           0 :                 if (ehdlr->fd == efd) {
     353           0 :                         break;
     354             :                 }
     355             :         }
     356             : 
     357           0 :         if (ehdlr == NULL) {
     358           0 :                 return -EINVAL;
     359             :         }
     360             : 
     361           0 :         assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
     362             : 
     363           0 :         ehdlr->events = event_types;
     364             : 
     365           0 :         if (fgrp->parent) {
     366           0 :                 epfd = fgrp->parent->epfd;
     367             :         } else {
     368           0 :                 epfd = fgrp->epfd;
     369             :         }
     370             : 
     371           0 :         epevent.events = ehdlr->events;
     372           0 :         epevent.data.ptr = ehdlr;
     373             : 
     374           0 :         return epoll_ctl(epfd, EPOLL_CTL_MOD, ehdlr->fd, &epevent);
     375             : }
     376             : 
     377             : int
     378          28 : spdk_fd_group_create(struct spdk_fd_group **_egrp)
     379             : {
     380             :         struct spdk_fd_group *fgrp;
     381             : 
     382          28 :         if (_egrp == NULL) {
     383           0 :                 return -EINVAL;
     384             :         }
     385             : 
     386          28 :         fgrp = calloc(1, sizeof(*fgrp));
     387          28 :         if (fgrp == NULL) {
     388           0 :                 return -ENOMEM;
     389             :         }
     390             : 
     391             :         /* init the event source head */
     392          28 :         TAILQ_INIT(&fgrp->event_handlers);
     393             : 
     394          28 :         fgrp->num_fds = 0;
     395          28 :         fgrp->epfd = epoll_create1(EPOLL_CLOEXEC);
     396          28 :         if (fgrp->epfd < 0) {
     397           0 :                 free(fgrp);
     398           0 :                 return -errno;
     399             :         }
     400             : 
     401          28 :         *_egrp = fgrp;
     402             : 
     403          28 :         return 0;
     404             : }
     405             : 
     406             : void
     407          28 : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
     408             : {
     409          28 :         if (fgrp == NULL || fgrp->num_fds > 0) {
     410           0 :                 SPDK_ERRLOG("Invalid fd_group(%p) to destroy.\n", fgrp);
     411           0 :                 assert(0);
     412             :                 return;
     413             :         }
     414             : 
     415          28 :         close(fgrp->epfd);
     416          28 :         free(fgrp);
     417             : 
     418          28 :         return;
     419             : }
     420             : 
     421             : int
     422           2 : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
     423           2 : {
     424           2 :         int totalfds = fgrp->num_fds;
     425           2 :         struct epoll_event events[totalfds];
     426             :         struct event_handler *ehdlr;
     427             :         int n;
     428             :         int nfds;
     429             : 
     430           2 :         if (fgrp->parent != NULL) {
     431           0 :                 if (timeout < 0) {
     432           0 :                         SPDK_ERRLOG("Calling spdk_fd_group_wait on a group nested in another group without a timeout will block indefinitely.\n");
     433           0 :                         assert(false);
     434             :                         return -EINVAL;
     435             :                 } else {
     436           0 :                         SPDK_WARNLOG("Calling spdk_fd_group_wait on a group nested in another group will never find any events\n");
     437           0 :                         return 0;
     438             :                 }
     439             :         }
     440             : 
     441           2 :         nfds = epoll_wait(fgrp->epfd, events, totalfds, timeout);
     442           2 :         if (nfds < 0) {
     443           0 :                 if (errno != EINTR) {
     444           0 :                         SPDK_ERRLOG("fgrp epoll_wait returns with fail. errno is %d\n", errno);
     445             :                 }
     446             : 
     447           0 :                 return -errno;
     448           2 :         } else if (nfds == 0) {
     449           1 :                 return 0;
     450             :         }
     451             : 
     452           2 :         for (n = 0; n < nfds; n++) {
     453             :                 /* find the event_handler */
     454           1 :                 ehdlr = events[n].data.ptr;
     455             : 
     456           1 :                 if (ehdlr == NULL) {
     457           0 :                         continue;
     458             :                 }
     459             : 
     460             :                 /* Tag ehdlr as running state in case that it is removed
     461             :                  * during this wait loop but before or when it get executed.
     462             :                  */
     463           1 :                 assert(ehdlr->state == EVENT_HANDLER_STATE_WAITING);
     464           1 :                 ehdlr->state = EVENT_HANDLER_STATE_RUNNING;
     465             :         }
     466             : 
     467           2 :         for (n = 0; n < nfds; n++) {
     468             :                 /* find the event_handler */
     469           1 :                 ehdlr = events[n].data.ptr;
     470             : 
     471           1 :                 if (ehdlr == NULL || ehdlr->fn == NULL) {
     472           0 :                         continue;
     473             :                 }
     474             : 
     475             :                 /* It is possible that the ehdlr was removed
     476             :                  * during this wait loop but before it get executed.
     477             :                  */
     478           1 :                 if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
     479           0 :                         free(ehdlr);
     480           0 :                         continue;
     481             :                 }
     482             : 
     483           1 :                 g_event = &events[n];
     484             :                 /* call the interrupt response function */
     485           1 :                 ehdlr->fn(ehdlr->fn_arg);
     486           1 :                 g_event = NULL;
     487             : 
     488             :                 /* It is possible that the ehdlr was removed
     489             :                  * during this wait loop when it get executed.
     490             :                  */
     491           1 :                 if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
     492           0 :                         free(ehdlr);
     493             :                 } else {
     494           1 :                         ehdlr->state = EVENT_HANDLER_STATE_WAITING;
     495             :                 }
     496             :         }
     497             : 
     498           1 :         return nfds;
     499             : }
     500             : 
     501             : #else
     502             : 
     503             : int
     504             : spdk_fd_group_get_epoll_event(struct epoll_event *event)
     505             : {
     506             :         return -ENOTSUP;
     507             : }
     508             : 
     509             : int
     510             : spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
     511             :                   void *arg, const char *name)
     512             : {
     513             :         return -ENOTSUP;
     514             : }
     515             : 
     516             : int
     517             : spdk_fd_group_add_for_events(struct spdk_fd_group *fgrp, int efd, uint32_t events, spdk_fd_fn fn,
     518             :                              void *arg, const char *name)
     519             : {
     520             :         return -ENOTSUP;
     521             : }
     522             : 
     523             : void
     524             : spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
     525             : {
     526             : }
     527             : 
     528             : int
     529             : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
     530             :                            int efd, int event_types)
     531             : {
     532             :         return -ENOTSUP;
     533             : }
     534             : 
     535             : int
     536             : spdk_fd_group_create(struct spdk_fd_group **fgrp)
     537             : {
     538             :         return -ENOTSUP;
     539             : }
     540             : 
     541             : void
     542             : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
     543             : {
     544             : }
     545             : 
     546             : int
     547             : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
     548             : {
     549             :         return -ENOTSUP;
     550             : }
     551             : 
     552             : int
     553             : spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
     554             : {
     555             :         return -ENOTSUP;
     556             : }
     557             : 
     558             : int
     559             : spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
     560             : {
     561             :         return -ENOTSUP;
     562             : }
     563             : 
     564             : #endif

Generated by: LCOV version 1.15