[v2] eal/interrupts: add function to allow interruptible epoll

Message ID 20200903232822.19167-1-stephen@networkplumber.org (mailing list archive)
State Accepted, archived
Delegated to: Thomas Monjalon
Headers
Series [v2] eal/interrupts: add function to allow interruptible epoll |

Checks

Context Check Description
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-testing success Testing PASS
ci/travis-robot success Travis build: passed
ci/iol-mellanox-Performance success Performance Testing PASS
ci/Intel-compilation success Compilation OK
ci/checkpatch warning coding style issues

Commit Message

Stephen Hemminger Sept. 3, 2020, 11:28 p.m. UTC
  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 <stephen@networkplumber.org>
Reviewed-by: Harman Kalra <hkalra@marvell.com>
---
v2 -- rebase onto current code organization
      simplify logic to make it clear how common the code is

      Note: the documentation of the new version is intentionally the
      the same as the original one.

 lib/librte_eal/freebsd/eal_interrupts.c     | 12 +++++++++
 lib/librte_eal/include/rte_eal_interrupts.h | 23 +++++++++++++++++
 lib/librte_eal/linux/eal_interrupts.c       | 28 +++++++++++++++++----
 lib/librte_eal/rte_eal_version.map          |  3 +++
 4 files changed, 61 insertions(+), 5 deletions(-)
  

Comments

David Marchand Sept. 14, 2020, 8:56 a.m. UTC | #1
On Fri, Sep 4, 2020 at 1:28 AM Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> 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 <stephen@networkplumber.org>
> Reviewed-by: Harman Kalra <hkalra@marvell.com>

You will certainly argue that the existing function had no unit test
but we want to fix this at some point.
Can a unit test be added?


Thanks.
  
Stephen Hemminger Sept. 14, 2020, 4:39 p.m. UTC | #2
On Mon, 14 Sep 2020 10:56:33 +0200
David Marchand <david.marchand@redhat.com> wrote:

> On Fri, Sep 4, 2020 at 1:28 AM Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> >
> > 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 <stephen@networkplumber.org>
> > Reviewed-by: Harman Kalra <hkalra@marvell.com>  
> 
> You will certainly argue that the existing function had no unit test
> but we want to fix this at some point.
> Can a unit test be added?

The whole interrupt system really has no test, if it did then epoll
would be part of that.
  
Thomas Monjalon Oct. 19, 2020, 10:15 a.m. UTC | #3
04/09/2020 01:28, Stephen Hemminger:
> 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 <stephen@networkplumber.org>
> Reviewed-by: Harman Kalra <hkalra@marvell.com>

Applied, thanks
  

Patch

diff --git a/lib/librte_eal/freebsd/eal_interrupts.c b/lib/librte_eal/freebsd/eal_interrupts.c
index 6d53d33c81a9..b07cff639318 100644
--- a/lib/librte_eal/freebsd/eal_interrupts.c
+++ b/lib/librte_eal/freebsd/eal_interrupts.c
@@ -684,6 +684,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/include/rte_eal_interrupts.h b/lib/librte_eal/include/rte_eal_interrupts.h
index b1e8a2934e78..7d808a22624a 100644
--- a/lib/librte_eal/include/rte_eal_interrupts.h
+++ b/lib/librte_eal/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/linux/eal_interrupts.c b/lib/librte_eal/linux/eal_interrupts.c
index 13db5c4e8aee..26b5dd4ca86b 100644
--- a/lib/librte_eal/linux/eal_interrupts.c
+++ b/lib/librte_eal/linux/eal_interrupts.c
@@ -1275,9 +1275,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;
@@ -1298,8 +1298,12 @@  rte_epoll_wait(int epfd, struct rte_epoll_event *events,
 			rc = eal_epoll_process_event(evs, rc, events);
 			break;
 		} else if (rc < 0) {
-			if (errno == EINTR)
-				continue;
+			if (errno == EINTR) {
+				if (interruptible)
+					return -1;
+				else
+					continue;
+			}
 			/* epoll_wait fail */
 			RTE_LOG(ERR, EAL, "epoll_wait returns with fail %s\n",
 				strerror(errno));
@@ -1314,6 +1318,20 @@  rte_epoll_wait(int epfd, struct rte_epoll_event *events,
 	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 0b18e2ef85f9..a31a7cf5791a 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -397,6 +397,9 @@  EXPERIMENTAL {
 	rte_mp_disable;
 	rte_thread_register;
 	rte_thread_unregister;
+
+	# added in 20.11
+	rte_epoll_wait_interruptible;
 };
 
 INTERNAL {