The existing definition of rte_epoll_wait retries if interrupted by a signal. This behavior makes it hard to use rte_epoll_wait for applications that want to use signals do do things like exit polling loop and shutdown.
Since changing existing semantic might break applications, add a new rte_epoll_wait_interruptible() function that does the same thing as rte_epoll_wait but will return -1 and errno of EINTR if it receives a signal. Signed-off-by: Stephen Hemminger <step...@networkplumber.org> --- .../common/include/rte_eal_interrupts.h | 23 +++++++++ lib/librte_eal/freebsd/eal/eal_interrupts.c | 12 +++++ lib/librte_eal/linux/eal/eal_interrupts.c | 47 ++++++++++++------- lib/librte_eal/rte_eal_version.map | 1 + 4 files changed, 65 insertions(+), 18 deletions(-) diff --git a/lib/librte_eal/common/include/rte_eal_interrupts.h b/lib/librte_eal/common/include/rte_eal_interrupts.h index b370c0d26458..ac1c830f37a1 100644 --- a/lib/librte_eal/common/include/rte_eal_interrupts.h +++ b/lib/librte_eal/common/include/rte_eal_interrupts.h @@ -87,6 +87,7 @@ struct rte_intr_handle { /** * It waits for events on the epoll instance. + * Retries if signal received. * * @param epfd * Epoll instance fd on which the caller wait for events. @@ -105,6 +106,28 @@ int rte_epoll_wait(int epfd, struct rte_epoll_event *events, int maxevents, int timeout); +/** + * It waits for events on the epoll instance. + * Does not retry if signal received. + * + * @param epfd + * Epoll instance fd on which the caller wait for events. + * @param events + * Memory area contains the events that will be available for the caller. + * @param maxevents + * Up to maxevents are returned, must greater than zero. + * @param timeout + * Specifying a timeout of -1 causes a block indefinitely. + * Specifying a timeout equal to zero cause to return immediately. + * @return + * - On success, returns the number of available event. + * - On failure, a negative value. + */ +__rte_experimental +int +rte_epoll_wait_interruptible(int epfd, struct rte_epoll_event *events, + int maxevents, int timeout); + /** * It performs control operations on epoll instance referred by the epfd. * It requests that the operation op be performed for the target fd. diff --git a/lib/librte_eal/freebsd/eal/eal_interrupts.c b/lib/librte_eal/freebsd/eal/eal_interrupts.c index f6831b7902c5..d3f8fd78a1ee 100644 --- a/lib/librte_eal/freebsd/eal/eal_interrupts.c +++ b/lib/librte_eal/freebsd/eal/eal_interrupts.c @@ -649,6 +649,18 @@ rte_epoll_wait(int epfd, struct rte_epoll_event *events, return -ENOTSUP; } +int +rte_epoll_wait_interruptible(int epfd, struct rte_epoll_event *events, + int maxevents, int timeout) +{ + RTE_SET_USED(epfd); + RTE_SET_USED(events); + RTE_SET_USED(maxevents); + RTE_SET_USED(timeout); + + return -ENOTSUP; +} + int rte_epoll_ctl(int epfd, int op, int fd, struct rte_epoll_event *event) { diff --git a/lib/librte_eal/linux/eal/eal_interrupts.c b/lib/librte_eal/linux/eal/eal_interrupts.c index 1955324d3045..b6ae12a282e7 100644 --- a/lib/librte_eal/linux/eal/eal_interrupts.c +++ b/lib/librte_eal/linux/eal/eal_interrupts.c @@ -1239,9 +1239,9 @@ rte_intr_tls_epfd(void) return RTE_PER_LCORE(_epfd); } -int -rte_epoll_wait(int epfd, struct rte_epoll_event *events, - int maxevents, int timeout) +static int +eal_epoll_wait(int epfd, struct rte_epoll_event *events, + int maxevents, int timeout, bool interruptible) { struct epoll_event evs[maxevents]; int rc; @@ -1255,29 +1255,40 @@ rte_epoll_wait(int epfd, struct rte_epoll_event *events, if (epfd == RTE_EPOLL_PER_THREAD) epfd = rte_intr_tls_epfd(); - while (1) { - rc = epoll_wait(epfd, evs, maxevents, timeout); - if (likely(rc > 0)) { - /* epoll_wait has at least one fd ready to read */ - rc = eal_epoll_process_event(evs, rc, events); - break; - } else if (rc < 0) { - if (errno == EINTR) - continue; +retry: + rc = epoll_wait(epfd, evs, maxevents, timeout); + if (likely(rc > 0)) { + /* epoll_wait has at least one fd ready to read */ + rc = eal_epoll_process_event(evs, rc, events); + } else if (rc < 0) { + if (errno == EINTR) { + if (!interruptible) + goto retry; + } else { /* epoll_wait fail */ - RTE_LOG(ERR, EAL, "epoll_wait returns with fail %s\n", + RTE_LOG(ERR, EAL, + "epoll_wait returns with fail %s\n", strerror(errno)); - rc = -1; - break; - } else { - /* rc == 0, epoll_wait timed out */ - break; } } return rc; } +int +rte_epoll_wait(int epfd, struct rte_epoll_event *events, + int maxevents, int timeout) +{ + return eal_epoll_wait(epfd, events, maxevents, timeout, false); +} + +int +rte_epoll_wait_interruptible(int epfd, struct rte_epoll_event *events, + int maxevents, int timeout) +{ + return eal_epoll_wait(epfd, events, maxevents, timeout, true); +} + static inline void eal_epoll_data_safe_free(struct rte_epoll_event *ev) { diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map index 234487787994..e1aeb99ba9c8 100644 --- a/lib/librte_eal/rte_eal_version.map +++ b/lib/librte_eal/rte_eal_version.map @@ -331,6 +331,7 @@ EXPERIMENTAL { rte_dev_hotplug_handle_enable; rte_dev_iterator_init; rte_dev_iterator_next; + rte_epoll_wait_interruptible; rte_extmem_attach; rte_extmem_detach; rte_extmem_register; -- 2.20.1