* Re: [RFC 2/2] testpmd: cleanup cleanly from signal
2022-10-14 17:23 ` [RFC 2/2] testpmd: cleanup cleanly from signal Stephen Hemminger
@ 2022-11-06 10:50 ` Andrew Rybchenko
2022-11-08 18:16 ` Stephen Hemminger
2022-11-08 18:53 ` [PATCH v2] " Stephen Hemminger
` (6 subsequent siblings)
7 siblings, 1 reply; 48+ messages in thread
From: Andrew Rybchenko @ 2022-11-06 10:50 UTC (permalink / raw)
To: Stephen Hemminger, dev
On 10/14/22 20:23, Stephen Hemminger wrote:
> The original behavior of testpmd was to kill itself when
> it received a SIGINT or SIGTERM. This makes it hard to use
> testpmd in test automation where forwarding loop is started
> and then stopped via SIGTERM.
Can automatic stop it using SIGINT?
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
[snip]
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [RFC 2/2] testpmd: cleanup cleanly from signal
2022-11-06 10:50 ` Andrew Rybchenko
@ 2022-11-08 18:16 ` Stephen Hemminger
0 siblings, 0 replies; 48+ messages in thread
From: Stephen Hemminger @ 2022-11-08 18:16 UTC (permalink / raw)
To: Andrew Rybchenko; +Cc: dev
On Sun, 6 Nov 2022 13:50:36 +0300
Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru> wrote:
> On 10/14/22 20:23, Stephen Hemminger wrote:
> > The original behavior of testpmd was to kill itself when
> > it received a SIGINT or SIGTERM. This makes it hard to use
> > testpmd in test automation where forwarding loop is started
> > and then stopped via SIGTERM.
>
> Can automatic stop it using SIGINT?
Doesn't matter the testpmd code has same bug in SIGINT and SIGTERM.
The fundamental problem is that regular signals in Unix model are delivered
to the process and any thread may receive them.
In the case of testpmd, the signal may arrive inside some driver which
is doing some operations with hardware and even holding a lock.
Then signal_handler() is called. This code does operations that
may interact with driver and other parts of the system.
It is a broken way to handle this.
There are two ways to handle this problem. One way would be to block
the signals and use signalfd() and epoll() to handle them. This would
be more difficult and invasive in the testpmd logic.
The simpler way is to just set a flag and do the cleanup in the
main loop when the flag is detected.
^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v2] testpmd: cleanup cleanly from signal
2022-10-14 17:23 ` [RFC 2/2] testpmd: cleanup cleanly from signal Stephen Hemminger
2022-11-06 10:50 ` Andrew Rybchenko
@ 2022-11-08 18:53 ` Stephen Hemminger
2022-11-08 20:24 ` [PATCH v3] " Stephen Hemminger
` (5 subsequent siblings)
7 siblings, 0 replies; 48+ messages in thread
From: Stephen Hemminger @ 2022-11-08 18:53 UTC (permalink / raw)
To: dev; +Cc: phil.yang, Stephen Hemminger
Do clean shutdown of testpmd when a signal is received.
Instead of having testpmd commit suicide when a signal
is received, do a clean shutdown. This fixes problem
where a signal could be received in the middle of a PMD
and then the signal handler would call PMD's close routine
which could cause a deadlock.
Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
v2 - use sigaction() instead of poll() to handle interrupted read
app/test-pmd/testpmd.c | 58 ++++++++++++++++++++++--------------------
1 file changed, 30 insertions(+), 28 deletions(-)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index cf5942d0c422..29b17d7d6d82 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -15,6 +15,7 @@
#include <sys/types.h>
#include <errno.h>
#include <stdbool.h>
+#include <poll.h>
#include <sys/queue.h>
#include <sys/stat.h>
@@ -4251,26 +4252,11 @@ print_stats(void)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
- signum);
-#ifdef RTE_LIB_PDUMP
- /* uninitialize packet capture framework */
- rte_pdump_uninit();
-#endif
-#ifdef RTE_LIB_LATENCYSTATS
- if (latencystats_enabled != 0)
- rte_latencystats_uninit();
-#endif
- force_quit();
- /* Set flag to indicate the force termination. */
- f_quit = 1;
- /* exit with the expected status */
-#ifndef RTE_EXEC_ENV_WINDOWS
- signal(signum, SIG_DFL);
- kill(getpid(), signum);
-#endif
- }
+ fprintf(stderr, "\nSignal %d %s received, preparing to exit...\n",
+ signum, strsignal(signum));
+
+ /* Set flag to indicate the force termination. */
+ f_quit = 1;
}
int
@@ -4280,9 +4266,14 @@ main(int argc, char** argv)
portid_t port_id;
uint16_t count;
int ret;
+ struct sigaction sa = {
+ .sa_handler = signal_handler,
+ .sa_flags = 0,
+ };
- signal(SIGINT, signal_handler);
- signal(SIGTERM, signal_handler);
+ /* Want read() to be interrupted not restarted */
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
testpmd_logtype = rte_log_register("testpmd");
if (testpmd_logtype < 0)
@@ -4476,15 +4467,26 @@ main(int argc, char** argv)
prev_time = cur_time;
rte_delay_us_sleep(US_PER_S);
}
+ } else {
+ printf("Press enter to exit\n");
+ rc = read(0, &c, 1);
+ if (rc < 0 && errno != EINTR)
+ fprintf(stderr, "Read stdin failed: %s\n",
+ strerror(errno));
}
-
- printf("Press enter to exit\n");
- rc = read(0, &c, 1);
- pmd_test_exit();
- if (rc < 0)
- return 1;
+ stop_packet_forwarding();
+ force_quit();
}
+#ifdef RTE_LIB_PDUMP
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
+#endif
+#ifdef RTE_LIB_LATENCYSTATS
+ if (latencystats_enabled != 0)
+ rte_latencystats_uninit();
+#endif
+
ret = rte_eal_cleanup();
if (ret != 0)
rte_exit(EXIT_FAILURE,
--
2.35.1
^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3] testpmd: cleanup cleanly from signal
2022-10-14 17:23 ` [RFC 2/2] testpmd: cleanup cleanly from signal Stephen Hemminger
2022-11-06 10:50 ` Andrew Rybchenko
2022-11-08 18:53 ` [PATCH v2] " Stephen Hemminger
@ 2022-11-08 20:24 ` Stephen Hemminger
2022-11-09 4:10 ` [PATCH v4] " Stephen Hemminger
` (4 subsequent siblings)
7 siblings, 0 replies; 48+ messages in thread
From: Stephen Hemminger @ 2022-11-08 20:24 UTC (permalink / raw)
To: dev; +Cc: phil.yang, Stephen Hemminger
Do clean shutdown of testpmd when a signal is received.
Instead of having testpmd commit suicide when a signal
is received, do a clean shutdown. This fixes problem
where a signal could be received in the middle of a PMD
and then the signal handler would call PMD's close routine
which could cause a deadlock.
Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
v3 - drop unnecessary poll.h that causes windows build failure
app/test-pmd/testpmd.c | 57 +++++++++++++++++++++---------------------
1 file changed, 29 insertions(+), 28 deletions(-)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index cf5942d0c422..341788f5bc84 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -4251,26 +4251,11 @@ print_stats(void)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
- signum);
-#ifdef RTE_LIB_PDUMP
- /* uninitialize packet capture framework */
- rte_pdump_uninit();
-#endif
-#ifdef RTE_LIB_LATENCYSTATS
- if (latencystats_enabled != 0)
- rte_latencystats_uninit();
-#endif
- force_quit();
- /* Set flag to indicate the force termination. */
- f_quit = 1;
- /* exit with the expected status */
-#ifndef RTE_EXEC_ENV_WINDOWS
- signal(signum, SIG_DFL);
- kill(getpid(), signum);
-#endif
- }
+ fprintf(stderr, "\nSignal %d %s received, preparing to exit...\n",
+ signum, strsignal(signum));
+
+ /* Set flag to indicate the force termination. */
+ f_quit = 1;
}
int
@@ -4280,9 +4265,14 @@ main(int argc, char** argv)
portid_t port_id;
uint16_t count;
int ret;
+ struct sigaction sa = {
+ .sa_handler = signal_handler,
+ .sa_flags = 0,
+ };
- signal(SIGINT, signal_handler);
- signal(SIGTERM, signal_handler);
+ /* Want read() to be interrupted not restarted */
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
testpmd_logtype = rte_log_register("testpmd");
if (testpmd_logtype < 0)
@@ -4476,15 +4466,26 @@ main(int argc, char** argv)
prev_time = cur_time;
rte_delay_us_sleep(US_PER_S);
}
+ } else {
+ printf("Press enter to exit\n");
+ rc = read(0, &c, 1);
+ if (rc < 0 && errno != EINTR)
+ fprintf(stderr, "Read stdin failed: %s\n",
+ strerror(errno));
}
-
- printf("Press enter to exit\n");
- rc = read(0, &c, 1);
- pmd_test_exit();
- if (rc < 0)
- return 1;
+ stop_packet_forwarding();
+ force_quit();
}
+#ifdef RTE_LIB_PDUMP
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
+#endif
+#ifdef RTE_LIB_LATENCYSTATS
+ if (latencystats_enabled != 0)
+ rte_latencystats_uninit();
+#endif
+
ret = rte_eal_cleanup();
if (ret != 0)
rte_exit(EXIT_FAILURE,
--
2.35.1
^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v4] testpmd: cleanup cleanly from signal
2022-10-14 17:23 ` [RFC 2/2] testpmd: cleanup cleanly from signal Stephen Hemminger
` (2 preceding siblings ...)
2022-11-08 20:24 ` [PATCH v3] " Stephen Hemminger
@ 2022-11-09 4:10 ` Stephen Hemminger
2022-11-09 21:46 ` Mattias Rönnblom
2022-11-09 17:29 ` [PATCH v5] " Stephen Hemminger
` (3 subsequent siblings)
7 siblings, 1 reply; 48+ messages in thread
From: Stephen Hemminger @ 2022-11-09 4:10 UTC (permalink / raw)
To: dev; +Cc: phil.yang, Stephen Hemminger
Do a clean shutdown of testpmd when a signal is received;
instead of having testpmd kill itself.
This fixes problem where a signal could be received
in the middle of a PMD and then the signal handler would call
PMD's close routine which could cause a deadlock.
Added benefit is it gets rid of Windows specific code.
Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
v4 - use select() because that is available on Windows; and other
functions poll() and sigaction() are not.
app/test-pmd/testpmd.c | 63 +++++++++++++++++++++++-------------------
1 file changed, 34 insertions(+), 29 deletions(-)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index cf5942d0c422..274e96cac2d4 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -12,6 +12,7 @@
#ifndef RTE_EXEC_ENV_WINDOWS
#include <sys/mman.h>
#endif
+#include <sys/select.h>
#include <sys/types.h>
#include <errno.h>
#include <stdbool.h>
@@ -4251,26 +4252,11 @@ print_stats(void)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
- signum);
-#ifdef RTE_LIB_PDUMP
- /* uninitialize packet capture framework */
- rte_pdump_uninit();
-#endif
-#ifdef RTE_LIB_LATENCYSTATS
- if (latencystats_enabled != 0)
- rte_latencystats_uninit();
-#endif
- force_quit();
- /* Set flag to indicate the force termination. */
- f_quit = 1;
- /* exit with the expected status */
-#ifndef RTE_EXEC_ENV_WINDOWS
- signal(signum, SIG_DFL);
- kill(getpid(), signum);
-#endif
- }
+ fprintf(stderr, "\nSignal %d %s received, preparing to exit...\n",
+ signum, strsignal(signum));
+
+ /* Set flag to indicate the force termination. */
+ f_quit = 1;
}
int
@@ -4449,9 +4435,6 @@ main(int argc, char** argv)
} else
#endif
{
- char c;
- int rc;
-
f_quit = 0;
printf("No commandline core given, start packet forwarding\n");
@@ -4476,15 +4459,37 @@ main(int argc, char** argv)
prev_time = cur_time;
rte_delay_us_sleep(US_PER_S);
}
- }
+ } else {
+ char c;
+ fd_set fds;
- printf("Press enter to exit\n");
- rc = read(0, &c, 1);
- pmd_test_exit();
- if (rc < 0)
- return 1;
+ printf("Press enter to exit\n");
+
+ FD_ZERO(&fds);
+ FD_SET(0, &fds);
+
+ if (select(1, &fds, NULL, NULL, NULL) <= 0) {
+ fprintf(stderr, "Select failed: %s\n",
+ strerror(errno));
+ } else if (read(0, &c, 1) <= 0) {
+ fprintf(stderr,
+ "Read stdin failed: %s\n",
+ strerror(errno));
+ }
+ }
+ stop_packet_forwarding();
+ force_quit();
}
+#ifdef RTE_LIB_PDUMP
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
+#endif
+#ifdef RTE_LIB_LATENCYSTATS
+ if (latencystats_enabled != 0)
+ rte_latencystats_uninit();
+#endif
+
ret = rte_eal_cleanup();
if (ret != 0)
rte_exit(EXIT_FAILURE,
--
2.35.1
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v4] testpmd: cleanup cleanly from signal
2022-11-09 4:10 ` [PATCH v4] " Stephen Hemminger
@ 2022-11-09 21:46 ` Mattias Rönnblom
2022-11-09 22:53 ` Stephen Hemminger
0 siblings, 1 reply; 48+ messages in thread
From: Mattias Rönnblom @ 2022-11-09 21:46 UTC (permalink / raw)
To: Stephen Hemminger, dev; +Cc: phil.yang
On 2022-11-09 05:10, Stephen Hemminger wrote:
> Do a clean shutdown of testpmd when a signal is received;
> instead of having testpmd kill itself.
> This fixes problem where a signal could be received
> in the middle of a PMD and then the signal handler would call
> PMD's close routine which could cause a deadlock.
>
> Added benefit is it gets rid of Windows specific code.
>
> Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> v4 - use select() because that is available on Windows; and other
> functions poll() and sigaction() are not.
>
> app/test-pmd/testpmd.c | 63 +++++++++++++++++++++++-------------------
> 1 file changed, 34 insertions(+), 29 deletions(-)
>
> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
> index cf5942d0c422..274e96cac2d4 100644
> --- a/app/test-pmd/testpmd.c
> +++ b/app/test-pmd/testpmd.c
> @@ -12,6 +12,7 @@
> #ifndef RTE_EXEC_ENV_WINDOWS
> #include <sys/mman.h>
> #endif
> +#include <sys/select.h>
> #include <sys/types.h>
> #include <errno.h>
> #include <stdbool.h>
> @@ -4251,26 +4252,11 @@ print_stats(void)
> static void
> signal_handler(int signum)
> {
> - if (signum == SIGINT || signum == SIGTERM) {
> - fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
> - signum);
> -#ifdef RTE_LIB_PDUMP
> - /* uninitialize packet capture framework */
> - rte_pdump_uninit();
> -#endif
> -#ifdef RTE_LIB_LATENCYSTATS
> - if (latencystats_enabled != 0)
> - rte_latencystats_uninit();
> -#endif
> - force_quit();
> - /* Set flag to indicate the force termination. */
> - f_quit = 1;
> - /* exit with the expected status */
> -#ifndef RTE_EXEC_ENV_WINDOWS
> - signal(signum, SIG_DFL);
> - kill(getpid(), signum);
> -#endif
> - }
> + fprintf(stderr, "\nSignal %d %s received, preparing to exit...\n",
> + signum, strsignal(signum));
fprintf() is not async signal safe, and neither is strsignal().
This is not a regression introduced by this patch, but I thought it
might be worth fixing.
> +
> + /* Set flag to indicate the force termination. */
> + f_quit = 1;
> }
>
> int
> @@ -4449,9 +4435,6 @@ main(int argc, char** argv)
> } else
> #endif
> {
> - char c;
> - int rc;
> -
> f_quit = 0;
>
> printf("No commandline core given, start packet forwarding\n");
> @@ -4476,15 +4459,37 @@ main(int argc, char** argv)
> prev_time = cur_time;
> rte_delay_us_sleep(US_PER_S);
> }
> - }
> + } else {
> + char c;
> + fd_set fds;
>
> - printf("Press enter to exit\n");
> - rc = read(0, &c, 1);
> - pmd_test_exit();
> - if (rc < 0)
> - return 1;
> + printf("Press enter to exit\n");
> +
> + FD_ZERO(&fds);
> + FD_SET(0, &fds);
> +
> + if (select(1, &fds, NULL, NULL, NULL) <= 0) {
> + fprintf(stderr, "Select failed: %s\n",
> + strerror(errno));
Why is select() needed? Wouldn't a blocking read suffice? Or getchar().
> + } else if (read(0, &c, 1) <= 0) {
> + fprintf(stderr,
> + "Read stdin failed: %s\n",
> + strerror(errno));
> + }
> + }
> + stop_packet_forwarding();
> + force_quit();
> }
>
> +#ifdef RTE_LIB_PDUMP
> + /* uninitialize packet capture framework */
> + rte_pdump_uninit();
> +#endif
> +#ifdef RTE_LIB_LATENCYSTATS
> + if (latencystats_enabled != 0)
> + rte_latencystats_uninit();
> +#endif
> +
> ret = rte_eal_cleanup();
> if (ret != 0)
> rte_exit(EXIT_FAILURE,
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v4] testpmd: cleanup cleanly from signal
2022-11-09 21:46 ` Mattias Rönnblom
@ 2022-11-09 22:53 ` Stephen Hemminger
2022-11-10 7:50 ` Mattias Rönnblom
0 siblings, 1 reply; 48+ messages in thread
From: Stephen Hemminger @ 2022-11-09 22:53 UTC (permalink / raw)
To: Mattias Rönnblom; +Cc: dev, phil.yang
On Wed, 9 Nov 2022 22:46:55 +0100
Mattias Rönnblom <hofors@lysator.liu.se> wrote:
> On 2022-11-09 05:10, Stephen Hemminger wrote:
> > Do a clean shutdown of testpmd when a signal is received;
> > instead of having testpmd kill itself.
> > This fixes problem where a signal could be received
> > in the middle of a PMD and then the signal handler would call
> > PMD's close routine which could cause a deadlock.
> >
> > Added benefit is it gets rid of Windows specific code.
> >
> > Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> > ---
> > v4 - use select() because that is available on Windows; and other
> > functions poll() and sigaction() are not.
> >
> > app/test-pmd/testpmd.c | 63 +++++++++++++++++++++++-------------------
> > 1 file changed, 34 insertions(+), 29 deletions(-)
> >
> > diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
> > index cf5942d0c422..274e96cac2d4 100644
> > --- a/app/test-pmd/testpmd.c
> > +++ b/app/test-pmd/testpmd.c
> > @@ -12,6 +12,7 @@
> > #ifndef RTE_EXEC_ENV_WINDOWS
> > #include <sys/mman.h>
> > #endif
> > +#include <sys/select.h>
> > #include <sys/types.h>
> > #include <errno.h>
> > #include <stdbool.h>
> > @@ -4251,26 +4252,11 @@ print_stats(void)
> > static void
> > signal_handler(int signum)
> > {
> > - if (signum == SIGINT || signum == SIGTERM) {
> > - fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
> > - signum);
> > -#ifdef RTE_LIB_PDUMP
> > - /* uninitialize packet capture framework */
> > - rte_pdump_uninit();
> > -#endif
> > -#ifdef RTE_LIB_LATENCYSTATS
> > - if (latencystats_enabled != 0)
> > - rte_latencystats_uninit();
> > -#endif
> > - force_quit();
> > - /* Set flag to indicate the force termination. */
> > - f_quit = 1;
> > - /* exit with the expected status */
> > -#ifndef RTE_EXEC_ENV_WINDOWS
> > - signal(signum, SIG_DFL);
> > - kill(getpid(), signum);
> > -#endif
> > - }
> > + fprintf(stderr, "\nSignal %d %s received, preparing to exit...\n",
> > + signum, strsignal(signum));
>
> fprintf() is not async signal safe, and neither is strsignal().
>
> This is not a regression introduced by this patch, but I thought it
> might be worth fixing.
>
> > +
> > + /* Set flag to indicate the force termination. */
> > + f_quit = 1;
> > }
> >
> > int
> > @@ -4449,9 +4435,6 @@ main(int argc, char** argv)
> > } else
> > #endif
> > {
> > - char c;
> > - int rc;
> > -
> > f_quit = 0;
> >
> > printf("No commandline core given, start packet forwarding\n");
> > @@ -4476,15 +4459,37 @@ main(int argc, char** argv)
> > prev_time = cur_time;
> > rte_delay_us_sleep(US_PER_S);
> > }
> > - }
> > + } else {
> > + char c;
> > + fd_set fds;
> >
> > - printf("Press enter to exit\n");
> > - rc = read(0, &c, 1);
> > - pmd_test_exit();
> > - if (rc < 0)
> > - return 1;
> > + printf("Press enter to exit\n");
> > +
> > + FD_ZERO(&fds);
> > + FD_SET(0, &fds);
> > +
> > + if (select(1, &fds, NULL, NULL, NULL) <= 0) {
> > + fprintf(stderr, "Select failed: %s\n",
> > + strerror(errno));
>
> Why is select() needed? Wouldn't a blocking read suffice? Or getchar().
On Linux, signal set SA_RESTART so a simple read is not interrupted.
One option was to use sigaction() which allows controlling flags, but that
won't work on Windows. Using select() works on both.
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v4] testpmd: cleanup cleanly from signal
2022-11-09 22:53 ` Stephen Hemminger
@ 2022-11-10 7:50 ` Mattias Rönnblom
2022-11-10 16:14 ` Stephen Hemminger
0 siblings, 1 reply; 48+ messages in thread
From: Mattias Rönnblom @ 2022-11-10 7:50 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev, phil.yang
On 2022-11-09 23:53, Stephen Hemminger wrote:
> On Wed, 9 Nov 2022 22:46:55 +0100
> Mattias Rönnblom <hofors@lysator.liu.se> wrote:
>
>> On 2022-11-09 05:10, Stephen Hemminger wrote:
>>> Do a clean shutdown of testpmd when a signal is received;
>>> instead of having testpmd kill itself.
>>> This fixes problem where a signal could be received
>>> in the middle of a PMD and then the signal handler would call
>>> PMD's close routine which could cause a deadlock.
>>>
>>> Added benefit is it gets rid of Windows specific code.
>>>
>>> Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
>>> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
>>> ---
>>> v4 - use select() because that is available on Windows; and other
>>> functions poll() and sigaction() are not.
>>>
>>> app/test-pmd/testpmd.c | 63 +++++++++++++++++++++++-------------------
>>> 1 file changed, 34 insertions(+), 29 deletions(-)
>>>
>>> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
>>> index cf5942d0c422..274e96cac2d4 100644
>>> --- a/app/test-pmd/testpmd.c
>>> +++ b/app/test-pmd/testpmd.c
>>> @@ -12,6 +12,7 @@
>>> #ifndef RTE_EXEC_ENV_WINDOWS
>>> #include <sys/mman.h>
>>> #endif
>>> +#include <sys/select.h>
>>> #include <sys/types.h>
>>> #include <errno.h>
>>> #include <stdbool.h>
>>> @@ -4251,26 +4252,11 @@ print_stats(void)
>>> static void
>>> signal_handler(int signum)
>>> {
>>> - if (signum == SIGINT || signum == SIGTERM) {
>>> - fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
>>> - signum);
>>> -#ifdef RTE_LIB_PDUMP
>>> - /* uninitialize packet capture framework */
>>> - rte_pdump_uninit();
>>> -#endif
>>> -#ifdef RTE_LIB_LATENCYSTATS
>>> - if (latencystats_enabled != 0)
>>> - rte_latencystats_uninit();
>>> -#endif
>>> - force_quit();
>>> - /* Set flag to indicate the force termination. */
>>> - f_quit = 1;
>>> - /* exit with the expected status */
>>> -#ifndef RTE_EXEC_ENV_WINDOWS
>>> - signal(signum, SIG_DFL);
>>> - kill(getpid(), signum);
>>> -#endif
>>> - }
>>> + fprintf(stderr, "\nSignal %d %s received, preparing to exit...\n",
>>> + signum, strsignal(signum));
>>
>> fprintf() is not async signal safe, and neither is strsignal().
>>
>> This is not a regression introduced by this patch, but I thought it
>> might be worth fixing.
>>
>>> +
>>> + /* Set flag to indicate the force termination. */
>>> + f_quit = 1;
>>> }
>>>
>>> int
>>> @@ -4449,9 +4435,6 @@ main(int argc, char** argv)
>>> } else
>>> #endif
>>> {
>>> - char c;
>>> - int rc;
>>> -
>>> f_quit = 0;
>>>
>>> printf("No commandline core given, start packet forwarding\n");
>>> @@ -4476,15 +4459,37 @@ main(int argc, char** argv)
>>> prev_time = cur_time;
>>> rte_delay_us_sleep(US_PER_S);
>>> }
>>> - }
>>> + } else {
>>> + char c;
>>> + fd_set fds;
>>>
>>> - printf("Press enter to exit\n");
>>> - rc = read(0, &c, 1);
>>> - pmd_test_exit();
>>> - if (rc < 0)
>>> - return 1;
>>> + printf("Press enter to exit\n");
>>> +
>>> + FD_ZERO(&fds);
>>> + FD_SET(0, &fds);
>>> +
>>> + if (select(1, &fds, NULL, NULL, NULL) <= 0) {
>>> + fprintf(stderr, "Select failed: %s\n",
>>> + strerror(errno));
>>
>> Why is select() needed? Wouldn't a blocking read suffice? Or getchar().
>
> On Linux, signal set SA_RESTART so a simple read is not interrupted.
> One option was to use sigaction() which allows controlling flags, but that
> won't work on Windows. Using select() works on both.
>
OK, so select() is used because a signal might interrupt read() on Windows?
while (read(0, &c, 1) == -1 && errno == EINTR)
;
Would that work?
(select() won't return 0 since you don't have a timeout.)
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v4] testpmd: cleanup cleanly from signal
2022-11-10 7:50 ` Mattias Rönnblom
@ 2022-11-10 16:14 ` Stephen Hemminger
2022-11-10 22:06 ` Mattias Rönnblom
0 siblings, 1 reply; 48+ messages in thread
From: Stephen Hemminger @ 2022-11-10 16:14 UTC (permalink / raw)
To: Mattias Rönnblom; +Cc: dev, phil.yang
On Thu, 10 Nov 2022 08:50:40 +0100
Mattias Rönnblom <hofors@lysator.liu.se> wrote:
> >>
> >> Why is select() needed? Wouldn't a blocking read suffice? Or getchar().
> >
> > On Linux, signal set SA_RESTART so a simple read is not interrupted.
> > One option was to use sigaction() which allows controlling flags, but that
> > won't work on Windows. Using select() works on both.
> >
>
> OK, so select() is used because a signal might interrupt read() on Windows?
>
> while (read(0, &c, 1) == -1 && errno == EINTR)
> ;
>
> Would that work?
Try it. On Linux the read never gets interrupted.
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v4] testpmd: cleanup cleanly from signal
2022-11-10 16:14 ` Stephen Hemminger
@ 2022-11-10 22:06 ` Mattias Rönnblom
0 siblings, 0 replies; 48+ messages in thread
From: Mattias Rönnblom @ 2022-11-10 22:06 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev, phil.yang
On 2022-11-10 17:14, Stephen Hemminger wrote:
> On Thu, 10 Nov 2022 08:50:40 +0100
> Mattias Rönnblom <hofors@lysator.liu.se> wrote:
>
>>>>
>>>> Why is select() needed? Wouldn't a blocking read suffice? Or getchar().
>>>
>>> On Linux, signal set SA_RESTART so a simple read is not interrupted.
>>> One option was to use sigaction() which allows controlling flags, but that
>>> won't work on Windows. Using select() works on both.
>>>
>>
>> OK, so select() is used because a signal might interrupt read() on Windows?
>>
>> while (read(0, &c, 1) == -1 && errno == EINTR)
>> ;
>>
>> Would that work?
>
> Try it. On Linux the read never gets interrupted.
I had no doubts about that, but I misunderstood the code and thought
that was the required behavior.
^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v5] testpmd: cleanup cleanly from signal
2022-10-14 17:23 ` [RFC 2/2] testpmd: cleanup cleanly from signal Stephen Hemminger
` (3 preceding siblings ...)
2022-11-09 4:10 ` [PATCH v4] " Stephen Hemminger
@ 2022-11-09 17:29 ` Stephen Hemminger
2022-11-10 7:14 ` Andrew Rybchenko
2022-11-10 16:53 ` [PATCH v6] " Stephen Hemminger
` (2 subsequent siblings)
7 siblings, 1 reply; 48+ messages in thread
From: Stephen Hemminger @ 2022-11-09 17:29 UTC (permalink / raw)
To: dev; +Cc: phil.yang, Stephen Hemminger
Do a clean shutdown of testpmd when a signal is received;
instead of having testpmd kill itself.
This fixes problem where a signal could be received
in the middle of a PMD and then the signal handler would call
PMD's close routine which could cause a deadlock.
Added benefit is it gets rid of Windows specific code.
Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
v5 - fix build on Windows.
Windows has select() function but the prototype is in winsock.h
not sys/select.h
app/test-pmd/testpmd.c | 63 +++++++++++++++++++++++-------------------
1 file changed, 34 insertions(+), 29 deletions(-)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index cf5942d0c422..be8fa7f0a0b1 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -11,6 +11,7 @@
#include <fcntl.h>
#ifndef RTE_EXEC_ENV_WINDOWS
#include <sys/mman.h>
+#include <sys/select.h>
#endif
#include <sys/types.h>
#include <errno.h>
@@ -4251,26 +4252,11 @@ print_stats(void)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
- signum);
-#ifdef RTE_LIB_PDUMP
- /* uninitialize packet capture framework */
- rte_pdump_uninit();
-#endif
-#ifdef RTE_LIB_LATENCYSTATS
- if (latencystats_enabled != 0)
- rte_latencystats_uninit();
-#endif
- force_quit();
- /* Set flag to indicate the force termination. */
- f_quit = 1;
- /* exit with the expected status */
-#ifndef RTE_EXEC_ENV_WINDOWS
- signal(signum, SIG_DFL);
- kill(getpid(), signum);
-#endif
- }
+ fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
+ signum);
+
+ /* Set flag to indicate the force termination. */
+ f_quit = 1;
}
int
@@ -4449,9 +4435,6 @@ main(int argc, char** argv)
} else
#endif
{
- char c;
- int rc;
-
f_quit = 0;
printf("No commandline core given, start packet forwarding\n");
@@ -4476,15 +4459,37 @@ main(int argc, char** argv)
prev_time = cur_time;
rte_delay_us_sleep(US_PER_S);
}
- }
+ } else {
+ char c;
+ fd_set fds;
- printf("Press enter to exit\n");
- rc = read(0, &c, 1);
- pmd_test_exit();
- if (rc < 0)
- return 1;
+ printf("Press enter to exit\n");
+
+ FD_ZERO(&fds);
+ FD_SET(0, &fds);
+
+ if (select(1, &fds, NULL, NULL, NULL) <= 0) {
+ fprintf(stderr, "Select failed: %s\n",
+ strerror(errno));
+ } else if (read(0, &c, 1) <= 0) {
+ fprintf(stderr,
+ "Read stdin failed: %s\n",
+ strerror(errno));
+ }
+ }
+ stop_packet_forwarding();
+ force_quit();
}
+#ifdef RTE_LIB_PDUMP
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
+#endif
+#ifdef RTE_LIB_LATENCYSTATS
+ if (latencystats_enabled != 0)
+ rte_latencystats_uninit();
+#endif
+
ret = rte_eal_cleanup();
if (ret != 0)
rte_exit(EXIT_FAILURE,
--
2.35.1
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v5] testpmd: cleanup cleanly from signal
2022-11-09 17:29 ` [PATCH v5] " Stephen Hemminger
@ 2022-11-10 7:14 ` Andrew Rybchenko
2022-11-10 16:13 ` Stephen Hemminger
0 siblings, 1 reply; 48+ messages in thread
From: Andrew Rybchenko @ 2022-11-10 7:14 UTC (permalink / raw)
To: Stephen Hemminger, dev; +Cc: phil.yang
On 11/9/22 20:29, Stephen Hemminger wrote:
> Do a clean shutdown of testpmd when a signal is received;
> instead of having testpmd kill itself.
> This fixes problem where a signal could be received
> in the middle of a PMD and then the signal handler would call
> PMD's close routine which could cause a deadlock.
>
> Added benefit is it gets rid of Windows specific code.
>
> Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
Cc to stable?
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
with one nit below:
Reviewed-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
[snip]
> @@ -4476,15 +4459,37 @@ main(int argc, char** argv)
> prev_time = cur_time;
> rte_delay_us_sleep(US_PER_S);
> }
> - }
> + } else {
> + char c;
> + fd_set fds;
>
> - printf("Press enter to exit\n");
> - rc = read(0, &c, 1);
> - pmd_test_exit();
> - if (rc < 0)
> - return 1;
> + printf("Press enter to exit\n");
> +
> + FD_ZERO(&fds);
> + FD_SET(0, &fds);
> +
> + if (select(1, &fds, NULL, NULL, NULL) <= 0) {
> + fprintf(stderr, "Select failed: %s\n",
> + strerror(errno));
> + } else if (read(0, &c, 1) <= 0) {
> + fprintf(stderr,
> + "Read stdin failed: %s\n",
> + strerror(errno));
> + }
> + }
> + stop_packet_forwarding();
force_quit() calls stop_packet_forwarding() if test_done is 0.
So, there is no difference in test_done == 0 case.
If test_done is not zero, stop_packet_forwarding() just logs
"Packet forwarding not started" and does nothing. So, the
difference is only in error message. Is it intentional?
> + force_quit();
> }
>
> +#ifdef RTE_LIB_PDUMP
> + /* uninitialize packet capture framework */
> + rte_pdump_uninit();
> +#endif
> +#ifdef RTE_LIB_LATENCYSTATS
> + if (latencystats_enabled != 0)
> + rte_latencystats_uninit();
> +#endif
> +
> ret = rte_eal_cleanup();
> if (ret != 0)
> rte_exit(EXIT_FAILURE,
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v5] testpmd: cleanup cleanly from signal
2022-11-10 7:14 ` Andrew Rybchenko
@ 2022-11-10 16:13 ` Stephen Hemminger
0 siblings, 0 replies; 48+ messages in thread
From: Stephen Hemminger @ 2022-11-10 16:13 UTC (permalink / raw)
To: Andrew Rybchenko; +Cc: dev, phil.yang
> > + stop_packet_forwarding();
>
> force_quit() calls stop_packet_forwarding() if test_done is 0.
> So, there is no difference in test_done == 0 case.
> If test_done is not zero, stop_packet_forwarding() just logs
> "Packet forwarding not started" and does nothing. So, the
> difference is only in error message. Is it intentional?
>
> > + force_quit();
> > }
Will fix in new version, it was a logic error.
^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v6] testpmd: cleanup cleanly from signal
2022-10-14 17:23 ` [RFC 2/2] testpmd: cleanup cleanly from signal Stephen Hemminger
` (4 preceding siblings ...)
2022-11-09 17:29 ` [PATCH v5] " Stephen Hemminger
@ 2022-11-10 16:53 ` Stephen Hemminger
2022-11-11 8:05 ` Andrew Rybchenko
2022-11-11 16:51 ` [PATCH v7] " Stephen Hemminger
2022-11-12 17:28 ` [PATCH v8] " Stephen Hemminger
7 siblings, 1 reply; 48+ messages in thread
From: Stephen Hemminger @ 2022-11-10 16:53 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Aman Singh, Yuying Zhang, Phil Yang, Jianbo Liu
Do a clean shutdown of testpmd when a signal is received;
instead of having testpmd kill itself.
This fixes the problem where a signal could be received
in the middle of a PMD and then the signal handler would call
PMD's close routine leading to locking problems.
An added benefit is it gets rid of some Windows specific code.
Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
v5 - drop unnecessary print in signal handler.
don't cleanup twice
don't print message when select() is interrupted.
app/test-pmd/testpmd.c | 72 ++++++++++++++++++++----------------------
1 file changed, 35 insertions(+), 37 deletions(-)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index cf5942d0c422..62d87f758ac8 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -11,6 +11,7 @@
#include <fcntl.h>
#ifndef RTE_EXEC_ENV_WINDOWS
#include <sys/mman.h>
+#include <sys/select.h>
#endif
#include <sys/types.h>
#include <errno.h>
@@ -4224,13 +4225,6 @@ init_port(void)
memset(txring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
}
-static void
-force_quit(void)
-{
- pmd_test_exit();
- prompt_exit();
-}
-
static void
print_stats(void)
{
@@ -4249,28 +4243,9 @@ print_stats(void)
}
static void
-signal_handler(int signum)
+signal_handler(int signum __rte_unused)
{
- if (signum == SIGINT || signum == SIGTERM) {
- fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
- signum);
-#ifdef RTE_LIB_PDUMP
- /* uninitialize packet capture framework */
- rte_pdump_uninit();
-#endif
-#ifdef RTE_LIB_LATENCYSTATS
- if (latencystats_enabled != 0)
- rte_latencystats_uninit();
-#endif
- force_quit();
- /* Set flag to indicate the force termination. */
- f_quit = 1;
- /* exit with the expected status */
-#ifndef RTE_EXEC_ENV_WINDOWS
- signal(signum, SIG_DFL);
- kill(getpid(), signum);
-#endif
- }
+ f_quit = 1;
}
int
@@ -4449,9 +4424,6 @@ main(int argc, char** argv)
} else
#endif
{
- char c;
- int rc;
-
f_quit = 0;
printf("No commandline core given, start packet forwarding\n");
@@ -4476,15 +4448,41 @@ main(int argc, char** argv)
prev_time = cur_time;
rte_delay_us_sleep(US_PER_S);
}
- }
+ } else {
+ char c;
+ fd_set fds;
+ int rc;
- printf("Press enter to exit\n");
- rc = read(0, &c, 1);
- pmd_test_exit();
- if (rc < 0)
- return 1;
+ printf("Press enter to exit\n");
+
+ FD_ZERO(&fds);
+ FD_SET(0, &fds);
+
+ rc = select(1, &fds, NULL, NULL, NULL);
+ if (rc < 0 && errno != EINTR) {
+ fprintf(stderr, "Select failed: %s\n",
+ strerror(errno));
+ return 1;
+ }
+ if (rc > 0)
+ rc = read(0, &c, 1);
+
+ pmd_test_exit();
+ if (rc < 0)
+ return 1;
+ prompt_exit();
+ }
}
+#ifdef RTE_LIB_PDUMP
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
+#endif
+#ifdef RTE_LIB_LATENCYSTATS
+ if (latencystats_enabled != 0)
+ rte_latencystats_uninit();
+#endif
+
ret = rte_eal_cleanup();
if (ret != 0)
rte_exit(EXIT_FAILURE,
--
2.35.1
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v6] testpmd: cleanup cleanly from signal
2022-11-10 16:53 ` [PATCH v6] " Stephen Hemminger
@ 2022-11-11 8:05 ` Andrew Rybchenko
2022-11-11 16:49 ` Stephen Hemminger
0 siblings, 1 reply; 48+ messages in thread
From: Andrew Rybchenko @ 2022-11-11 8:05 UTC (permalink / raw)
To: Stephen Hemminger, dev; +Cc: Aman Singh, Yuying Zhang, Phil Yang, Jianbo Liu
On 11/10/22 19:53, Stephen Hemminger wrote:
> Do a clean shutdown of testpmd when a signal is received;
> instead of having testpmd kill itself.
> This fixes the problem where a signal could be received
> in the middle of a PMD and then the signal handler would call
> PMD's close routine leading to locking problems.
>
> An added benefit is it gets rid of some Windows specific code.
>
> Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> v5 - drop unnecessary print in signal handler.
> don't cleanup twice
> don't print message when select() is interrupted.
>
> app/test-pmd/testpmd.c | 72 ++++++++++++++++++++----------------------
> 1 file changed, 35 insertions(+), 37 deletions(-)
>
> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
> index cf5942d0c422..62d87f758ac8 100644
> --- a/app/test-pmd/testpmd.c
> +++ b/app/test-pmd/testpmd.c
> @@ -11,6 +11,7 @@
> #include <fcntl.h>
> #ifndef RTE_EXEC_ENV_WINDOWS
> #include <sys/mman.h>
> +#include <sys/select.h>
> #endif
> #include <sys/types.h>
> #include <errno.h>
> @@ -4224,13 +4225,6 @@ init_port(void)
> memset(txring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
> }
>
> -static void
> -force_quit(void)
> -{
> - pmd_test_exit();
> - prompt_exit();
> -}
> -
> static void
> print_stats(void)
> {
> @@ -4249,28 +4243,9 @@ print_stats(void)
> }
>
> static void
> -signal_handler(int signum)
> +signal_handler(int signum __rte_unused)
> {
> - if (signum == SIGINT || signum == SIGTERM) {
> - fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
> - signum);
> -#ifdef RTE_LIB_PDUMP
> - /* uninitialize packet capture framework */
> - rte_pdump_uninit();
> -#endif
> -#ifdef RTE_LIB_LATENCYSTATS
> - if (latencystats_enabled != 0)
> - rte_latencystats_uninit();
> -#endif
> - force_quit();
> - /* Set flag to indicate the force termination. */
> - f_quit = 1;
> - /* exit with the expected status */
> -#ifndef RTE_EXEC_ENV_WINDOWS
> - signal(signum, SIG_DFL);
> - kill(getpid(), signum);
> -#endif
> - }
> + f_quit = 1;
> }
>
> int
> @@ -4449,9 +4424,6 @@ main(int argc, char** argv)
> } else
> #endif
> {
> - char c;
> - int rc;
> -
> f_quit = 0;
>
> printf("No commandline core given, start packet forwarding\n");
> @@ -4476,15 +4448,41 @@ main(int argc, char** argv)
> prev_time = cur_time;
> rte_delay_us_sleep(US_PER_S);
> }
> - }
> + } else {
> + char c;
> + fd_set fds;
> + int rc;
>
> - printf("Press enter to exit\n");
> - rc = read(0, &c, 1);
> - pmd_test_exit();
> - if (rc < 0)
> - return 1;
> + printf("Press enter to exit\n");
> +
> + FD_ZERO(&fds);
> + FD_SET(0, &fds);
> +
> + rc = select(1, &fds, NULL, NULL, NULL);
> + if (rc < 0 && errno != EINTR) {
> + fprintf(stderr, "Select failed: %s\n",
> + strerror(errno));
> + return 1;
> + }
> + if (rc > 0)
> + rc = read(0, &c, 1);
> +
> + pmd_test_exit();
It looks wrong to skip pmd_test_exit() in periodic stats
case (if body above). Earlier it happened in signal handler.
IMHO, pmd_test_exit() should be done just before pdump
uninit below (outside if/else bodies (and removed from
interactive == 1 branch above).
> + if (rc < 0)
> + return 1;
It took some time for me to understand what's happening here.
Finally I came to conclusion that it just preserve previous
behaviour to return with failure code immediately if read
fails. Except addition of pmd_test_exit() above.
I think it is a wrong behaviour to skip all cleanup which
is done below, but I agree that it is a separate issue to
fix.
> + prompt_exit();
prompt_exit() is registered as atexit() callback and if I'm not
mistakes will be called anyway.
> + }
> }
>
> +#ifdef RTE_LIB_PDUMP
> + /* uninitialize packet capture framework */
> + rte_pdump_uninit();
> +#endif
> +#ifdef RTE_LIB_LATENCYSTATS
> + if (latencystats_enabled != 0)
> + rte_latencystats_uninit();
> +#endif
> +
> ret = rte_eal_cleanup();
> if (ret != 0)
> rte_exit(EXIT_FAILURE,
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v6] testpmd: cleanup cleanly from signal
2022-11-11 8:05 ` Andrew Rybchenko
@ 2022-11-11 16:49 ` Stephen Hemminger
0 siblings, 0 replies; 48+ messages in thread
From: Stephen Hemminger @ 2022-11-11 16:49 UTC (permalink / raw)
To: Andrew Rybchenko; +Cc: dev, Aman Singh, Yuying Zhang, Phil Yang, Jianbo Liu
On Fri, 11 Nov 2022 11:05:24 +0300
Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru> wrote:
> It looks wrong to skip pmd_test_exit() in periodic stats
> case (if body above). Earlier it happened in signal handler.
> IMHO, pmd_test_exit() should be done just before pdump
> uninit below (outside if/else bodies (and removed from
> interactive == 1 branch above).
>
> > + if (rc < 0)
> > + return 1;
>
> It took some time for me to understand what's happening here.
> Finally I came to conclusion that it just preserve previous
> behaviour to return with failure code immediately if read
> fails. Except addition of pmd_test_exit() above.
> I think it is a wrong behaviour to skip all cleanup which
> is done below, but I agree that it is a separate issue to
> fix.
>
> > + prompt_exit();
>
> prompt_exit() is registered as atexit() callback and if I'm not
> mistakes will be called anyway.
Good catch.
Trying to unwind the intentions of earlier code here.
Next version should be cleaner.
^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v7] testpmd: cleanup cleanly from signal
2022-10-14 17:23 ` [RFC 2/2] testpmd: cleanup cleanly from signal Stephen Hemminger
` (5 preceding siblings ...)
2022-11-10 16:53 ` [PATCH v6] " Stephen Hemminger
@ 2022-11-11 16:51 ` Stephen Hemminger
2022-11-12 17:28 ` [PATCH v8] " Stephen Hemminger
7 siblings, 0 replies; 48+ messages in thread
From: Stephen Hemminger @ 2022-11-11 16:51 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Aman Singh, Yuying Zhang, Jianbo Liu, Phil Yang
Do a clean shutdown of testpmd when a signal is received;
instead of having testpmd kill itself.
This fixes the problem where a signal could be received
in the middle of a PMD and then the signal handler would call
PMD's close routine leading to locking problems.
An added benefit is it gets rid of some Windows specific code.
Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
v5 - fix windows build
v6 - drop unneeded prprint in signal handler
v7 - cleanup logic around exiting, use rte_exit() for read/select errors
app/test-pmd/testpmd.c | 67 +++++++++++++++++++-----------------------
1 file changed, 31 insertions(+), 36 deletions(-)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index cf5942d0c422..c012f9edbc99 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -11,6 +11,7 @@
#include <fcntl.h>
#ifndef RTE_EXEC_ENV_WINDOWS
#include <sys/mman.h>
+#include <sys/select.h>
#endif
#include <sys/types.h>
#include <errno.h>
@@ -4224,13 +4225,6 @@ init_port(void)
memset(txring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
}
-static void
-force_quit(void)
-{
- pmd_test_exit();
- prompt_exit();
-}
-
static void
print_stats(void)
{
@@ -4249,28 +4243,9 @@ print_stats(void)
}
static void
-signal_handler(int signum)
+signal_handler(int signum __rte_unused)
{
- if (signum == SIGINT || signum == SIGTERM) {
- fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
- signum);
-#ifdef RTE_LIB_PDUMP
- /* uninitialize packet capture framework */
- rte_pdump_uninit();
-#endif
-#ifdef RTE_LIB_LATENCYSTATS
- if (latencystats_enabled != 0)
- rte_latencystats_uninit();
-#endif
- force_quit();
- /* Set flag to indicate the force termination. */
- f_quit = 1;
- /* exit with the expected status */
-#ifndef RTE_EXEC_ENV_WINDOWS
- signal(signum, SIG_DFL);
- kill(getpid(), signum);
-#endif
- }
+ f_quit = 1;
}
int
@@ -4449,9 +4424,6 @@ main(int argc, char** argv)
} else
#endif
{
- char c;
- int rc;
-
f_quit = 0;
printf("No commandline core given, start packet forwarding\n");
@@ -4476,15 +4448,38 @@ main(int argc, char** argv)
prev_time = cur_time;
rte_delay_us_sleep(US_PER_S);
}
- }
+ } else {
+ char c;
+ fd_set fds;
+
+ printf("Press enter to exit\n");
+
+ FD_ZERO(&fds);
+ FD_SET(STDIN_FILENO, &fds);
- printf("Press enter to exit\n");
- rc = read(0, &c, 1);
+ ret = select(1, &fds, NULL, NULL, NULL);
+ if (ret < 0 && errno != EINTR)
+ rte_exit(EXIT_FAILURE,
+ "Select failed: %s\n",
+ strerror(errno));
+
+ if (ret == 1 && read(STDIN_FILENO, &c, 1) < 0)
+ rte_exit(EXIT_FAILURE,
+ "Read failed: %s\n",
+ strerror(errno));
+ }
pmd_test_exit();
- if (rc < 0)
- return 1;
}
+#ifdef RTE_LIB_PDUMP
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
+#endif
+#ifdef RTE_LIB_LATENCYSTATS
+ if (latencystats_enabled != 0)
+ rte_latencystats_uninit();
+#endif
+
ret = rte_eal_cleanup();
if (ret != 0)
rte_exit(EXIT_FAILURE,
--
2.35.1
^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v8] testpmd: cleanup cleanly from signal
2022-10-14 17:23 ` [RFC 2/2] testpmd: cleanup cleanly from signal Stephen Hemminger
` (6 preceding siblings ...)
2022-11-11 16:51 ` [PATCH v7] " Stephen Hemminger
@ 2022-11-12 17:28 ` Stephen Hemminger
2023-01-19 15:53 ` Ferruh Yigit
2023-01-25 18:32 ` [PATCH v9] " Stephen Hemminger
7 siblings, 2 replies; 48+ messages in thread
From: Stephen Hemminger @ 2022-11-12 17:28 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Aman Singh, Yuying Zhang, Phil Yang, Jianbo Liu
Do a clean shutdown of testpmd when a signal is received;
instead of having testpmd kill itself.
This fixes the problem where a signal could be received
in the middle of a PMD and then the signal handler would call
PMD's close routine leading to locking problems.
An added benefit is it gets rid of some Windows specific code.
Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
v8 - fix build on Windows (again)
Windows doesn't have FILENO_STDIN
app/test-pmd/testpmd.c | 67 +++++++++++++++++++-----------------------
1 file changed, 31 insertions(+), 36 deletions(-)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index aa7ea29f15ba..b4fb6a2bcbcf 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -11,6 +11,7 @@
#include <fcntl.h>
#ifndef RTE_EXEC_ENV_WINDOWS
#include <sys/mman.h>
+#include <sys/select.h>
#endif
#include <sys/types.h>
#include <errno.h>
@@ -4224,13 +4225,6 @@ init_port(void)
memset(txring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
}
-static void
-force_quit(void)
-{
- pmd_test_exit();
- prompt_exit();
-}
-
static void
print_stats(void)
{
@@ -4249,28 +4243,9 @@ print_stats(void)
}
static void
-signal_handler(int signum)
+signal_handler(int signum __rte_unused)
{
- if (signum == SIGINT || signum == SIGTERM) {
- fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
- signum);
-#ifdef RTE_LIB_PDUMP
- /* uninitialize packet capture framework */
- rte_pdump_uninit();
-#endif
-#ifdef RTE_LIB_LATENCYSTATS
- if (latencystats_enabled != 0)
- rte_latencystats_uninit();
-#endif
- force_quit();
- /* Set flag to indicate the force termination. */
- f_quit = 1;
- /* exit with the expected status */
-#ifndef RTE_EXEC_ENV_WINDOWS
- signal(signum, SIG_DFL);
- kill(getpid(), signum);
-#endif
- }
+ f_quit = 1;
}
int
@@ -4449,9 +4424,6 @@ main(int argc, char** argv)
} else
#endif
{
- char c;
- int rc;
-
f_quit = 0;
printf("No commandline core given, start packet forwarding\n");
@@ -4476,15 +4448,38 @@ main(int argc, char** argv)
prev_time = cur_time;
rte_delay_us_sleep(US_PER_S);
}
- }
+ } else {
+ char c;
+ fd_set fds;
+
+ printf("Press enter to exit\n");
+
+ FD_ZERO(&fds);
+ FD_SET(0, &fds);
- printf("Press enter to exit\n");
- rc = read(0, &c, 1);
+ ret = select(1, &fds, NULL, NULL, NULL);
+ if (ret < 0 && errno != EINTR)
+ rte_exit(EXIT_FAILURE,
+ "Select failed: %s\n",
+ strerror(errno));
+
+ if (ret == 1 && read(0, &c, 1) < 0)
+ rte_exit(EXIT_FAILURE,
+ "Read failed: %s\n",
+ strerror(errno));
+ }
pmd_test_exit();
- if (rc < 0)
- return 1;
}
+#ifdef RTE_LIB_PDUMP
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
+#endif
+#ifdef RTE_LIB_LATENCYSTATS
+ if (latencystats_enabled != 0)
+ rte_latencystats_uninit();
+#endif
+
ret = rte_eal_cleanup();
if (ret != 0)
rte_exit(EXIT_FAILURE,
--
2.35.1
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v8] testpmd: cleanup cleanly from signal
2022-11-12 17:28 ` [PATCH v8] " Stephen Hemminger
@ 2023-01-19 15:53 ` Ferruh Yigit
2023-01-25 18:32 ` [PATCH v9] " Stephen Hemminger
1 sibling, 0 replies; 48+ messages in thread
From: Ferruh Yigit @ 2023-01-19 15:53 UTC (permalink / raw)
To: Stephen Hemminger, dev; +Cc: Aman Singh, Yuying Zhang, Phil Yang, Jianbo Liu
On 11/12/2022 5:28 PM, Stephen Hemminger wrote:
> Do a clean shutdown of testpmd when a signal is received;
> instead of having testpmd kill itself.
> This fixes the problem where a signal could be received
> in the middle of a PMD and then the signal handler would call
> PMD's close routine leading to locking problems.
>
> An added benefit is it gets rid of some Windows specific code.
>
> Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> v8 - fix build on Windows (again)
> Windows doesn't have FILENO_STDIN
>
> app/test-pmd/testpmd.c | 67 +++++++++++++++++++-----------------------
> 1 file changed, 31 insertions(+), 36 deletions(-)
>
> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
> index aa7ea29f15ba..b4fb6a2bcbcf 100644
> --- a/app/test-pmd/testpmd.c
> +++ b/app/test-pmd/testpmd.c
> @@ -11,6 +11,7 @@
> #include <fcntl.h>
> #ifndef RTE_EXEC_ENV_WINDOWS
> #include <sys/mman.h>
> +#include <sys/select.h>
> #endif
> #include <sys/types.h>
> #include <errno.h>
> @@ -4224,13 +4225,6 @@ init_port(void)
> memset(txring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
> }
>
> -static void
> -force_quit(void)
> -{
> - pmd_test_exit();
> - prompt_exit();
> -}
> -
> static void
> print_stats(void)
> {
> @@ -4249,28 +4243,9 @@ print_stats(void)
> }
>
> static void
> -signal_handler(int signum)
> +signal_handler(int signum __rte_unused)
> {
> - if (signum == SIGINT || signum == SIGTERM) {
> - fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
> - signum);
> -#ifdef RTE_LIB_PDUMP
> - /* uninitialize packet capture framework */
> - rte_pdump_uninit();
> -#endif
> -#ifdef RTE_LIB_LATENCYSTATS
> - if (latencystats_enabled != 0)
> - rte_latencystats_uninit();
> -#endif
> - force_quit();
> - /* Set flag to indicate the force termination. */
> - f_quit = 1;
> - /* exit with the expected status */
> -#ifndef RTE_EXEC_ENV_WINDOWS
> - signal(signum, SIG_DFL);
> - kill(getpid(), signum);
> -#endif
> - }
> + f_quit = 1;
> }
Signal handler used for interactive mode too, that is why
'force_quit();' is still needed in signal handler.
Perhaps different signal handlers can be set for interactive and
non-interactive modes.
>
> int
> @@ -4449,9 +4424,6 @@ main(int argc, char** argv)
> } else
> #endif
> {
> - char c;
> - int rc;
> -
> f_quit = 0;
>
> printf("No commandline core given, start packet forwarding\n");
> @@ -4476,15 +4448,38 @@ main(int argc, char** argv)
> prev_time = cur_time;
> rte_delay_us_sleep(US_PER_S);
> }
> - }
> + } else {
> + char c;
> + fd_set fds;
> +
> + printf("Press enter to exit\n");
> +
> + FD_ZERO(&fds);
> + FD_SET(0, &fds);
>
> - printf("Press enter to exit\n");
> - rc = read(0, &c, 1);
> + ret = select(1, &fds, NULL, NULL, NULL);
> + if (ret < 0 && errno != EINTR)
> + rte_exit(EXIT_FAILURE,
> + "Select failed: %s\n",
> + strerror(errno));
> +
> + if (ret == 1 && read(0, &c, 1) < 0)
> + rte_exit(EXIT_FAILURE,
> + "Read failed: %s\n",
> + strerror(errno));
> + }
> pmd_test_exit();
> - if (rc < 0)
> - return 1;
> }
>
> +#ifdef RTE_LIB_PDUMP
> + /* uninitialize packet capture framework */
> + rte_pdump_uninit();
> +#endif
> +#ifdef RTE_LIB_LATENCYSTATS
> + if (latencystats_enabled != 0)
> + rte_latencystats_uninit();
> +#endif
+1 to move these functions here, but signal handler for the interactive
mode also needs these functions.
> +
> ret = rte_eal_cleanup();
> if (ret != 0)
> rte_exit(EXIT_FAILURE,
^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v9] testpmd: cleanup cleanly from signal
2022-11-12 17:28 ` [PATCH v8] " Stephen Hemminger
2023-01-19 15:53 ` Ferruh Yigit
@ 2023-01-25 18:32 ` Stephen Hemminger
2023-01-30 18:48 ` Ferruh Yigit
1 sibling, 1 reply; 48+ messages in thread
From: Stephen Hemminger @ 2023-01-25 18:32 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Aman Singh, Yuying Zhang, Phil Yang, Jianbo Liu
Do a clean shutdown of testpmd when a signal is received; instead of
having testpmd kill itself. This fixes the problem where a signal could
be received in the middle of a PMD and then the signal handler would
call PMD's close routine leading to locking problems.
An added benefit is it gets rid of some Windows specific code.
Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
v9 - also handle the interactive case.
use cmdine_poll() rather than signals and atexit
app/test-pmd/cmdline.c | 28 +++++----------
app/test-pmd/testpmd.c | 77 ++++++++++++++++++++----------------------
app/test-pmd/testpmd.h | 1 +
3 files changed, 46 insertions(+), 60 deletions(-)
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index b32dc8bfd445..fbe9ad694dee 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -65,7 +65,6 @@
#include "cmdline_tm.h"
#include "bpf_cmd.h"
-static struct cmdline *testpmd_cl;
static cmdline_parse_ctx_t *main_ctx;
static TAILQ_HEAD(, testpmd_driver_commands) driver_commands_head =
TAILQ_HEAD_INITIALIZER(driver_commands_head);
@@ -12921,28 +12920,19 @@ cmdline_read_from_file(const char *filename)
void
prompt(void)
{
- int ret;
+ struct cmdline *cl;
- testpmd_cl = cmdline_stdin_new(main_ctx, "testpmd> ");
- if (testpmd_cl == NULL)
+ cl = cmdline_stdin_new(main_ctx, "testpmd> ");
+ if (cl == NULL)
return;
- ret = atexit(prompt_exit);
- if (ret != 0)
- fprintf(stderr, "Cannot set exit function for cmdline\n");
-
- cmdline_interact(testpmd_cl);
- if (ret != 0)
- cmdline_stdin_exit(testpmd_cl);
-}
-
-void
-prompt_exit(void)
-{
- if (testpmd_cl != NULL) {
- cmdline_quit(testpmd_cl);
- cmdline_stdin_exit(testpmd_cl);
+ while (f_quit == 0 && cl_quit == 0) {
+ if (cmdline_poll(cl) < 0)
+ break;
}
+
+ cmdline_quit(cl);
+ cmdline_stdin_exit(cl);
}
void
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 134d79a55547..d01b6105b7de 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -11,6 +11,7 @@
#include <fcntl.h>
#ifndef RTE_EXEC_ENV_WINDOWS
#include <sys/mman.h>
+#include <sys/select.h>
#endif
#include <sys/types.h>
#include <errno.h>
@@ -231,7 +232,7 @@ unsigned int xstats_display_num; /**< Size of extended statistics to show */
* In container, it cannot terminate the process which running with 'stats-period'
* option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
*/
-static volatile uint8_t f_quit;
+volatile uint8_t f_quit;
uint8_t cl_quit; /* Quit testpmd from cmdline. */
/*
@@ -4315,13 +4316,6 @@ init_port(void)
memset(txring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
}
-static void
-force_quit(void)
-{
- pmd_test_exit();
- prompt_exit();
-}
-
static void
print_stats(void)
{
@@ -4340,28 +4334,9 @@ print_stats(void)
}
static void
-signal_handler(int signum)
+signal_handler(int signum __rte_unused)
{
- if (signum == SIGINT || signum == SIGTERM) {
- fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
- signum);
-#ifdef RTE_LIB_PDUMP
- /* uninitialize packet capture framework */
- rte_pdump_uninit();
-#endif
-#ifdef RTE_LIB_LATENCYSTATS
- if (latencystats_enabled != 0)
- rte_latencystats_uninit();
-#endif
- force_quit();
- /* Set flag to indicate the force termination. */
- f_quit = 1;
- /* exit with the expected status */
-#ifndef RTE_EXEC_ENV_WINDOWS
- signal(signum, SIG_DFL);
- kill(getpid(), signum);
-#endif
- }
+ f_quit = 1;
}
int
@@ -4536,15 +4511,9 @@ main(int argc, char** argv)
start_packet_forwarding(0);
}
prompt();
- pmd_test_exit();
} else
#endif
{
- char c;
- int rc;
-
- f_quit = 0;
-
printf("No commandline core given, start packet forwarding\n");
start_packet_forwarding(tx_first);
if (stats_period != 0) {
@@ -4567,15 +4536,41 @@ main(int argc, char** argv)
prev_time = cur_time;
rte_delay_us_sleep(US_PER_S);
}
- }
+ } else {
+ char c;
+ fd_set fds;
+
+ printf("Press enter to exit\n");
- printf("Press enter to exit\n");
- rc = read(0, &c, 1);
- pmd_test_exit();
- if (rc < 0)
- return 1;
+ FD_ZERO(&fds);
+ FD_SET(0, &fds);
+
+ /* wait for signal or enter */
+ ret = select(1, &fds, NULL, NULL, NULL);
+ if (ret < 0 && errno != EINTR)
+ rte_exit(EXIT_FAILURE,
+ "Select failed: %s\n",
+ strerror(errno));
+
+ /* if got enter then consume it */
+ if (ret == 1 && read(0, &c, 1) < 0)
+ rte_exit(EXIT_FAILURE,
+ "Read failed: %s\n",
+ strerror(errno));
+ }
}
+ pmd_test_exit();
+
+#ifdef RTE_LIB_PDUMP
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
+#endif
+#ifdef RTE_LIB_LATENCYSTATS
+ if (latencystats_enabled != 0)
+ rte_latencystats_uninit();
+#endif
+
ret = rte_eal_cleanup();
if (ret != 0)
rte_exit(EXIT_FAILURE,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 7d24d25970d2..022210a7a964 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -34,6 +34,7 @@
#define RTE_PORT_HANDLING (uint16_t)3
extern uint8_t cl_quit;
+extern volatile uint8_t f_quit;
/*
* It is used to allocate the memory for hash key.
--
2.39.0
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v9] testpmd: cleanup cleanly from signal
2023-01-25 18:32 ` [PATCH v9] " Stephen Hemminger
@ 2023-01-30 18:48 ` Ferruh Yigit
2023-01-30 20:11 ` Stephen Hemminger
0 siblings, 1 reply; 48+ messages in thread
From: Ferruh Yigit @ 2023-01-30 18:48 UTC (permalink / raw)
To: Stephen Hemminger, dev, Olivier Matz, Thomas Monjalon
Cc: Aman Singh, Yuying Zhang, Phil Yang, Jianbo Liu
On 1/25/2023 6:32 PM, Stephen Hemminger wrote:
> Do a clean shutdown of testpmd when a signal is received; instead of
> having testpmd kill itself. This fixes the problem where a signal could
> be received in the middle of a PMD and then the signal handler would
> call PMD's close routine leading to locking problems.
>
> An added benefit is it gets rid of some Windows specific code.
>
> Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Patch looks good to me, but './devtools/test-null.sh' hangs with change.
It is possible the fix by updating './devtools/test-null.sh', but my
concern is if this behavior change hit more consumers other than this
internal tool, and I am for keeping previous behavior.
'./devtools/test-null.sh' sends 'stop' command to testpmd but that seems
not really what makes testpmd quit, because following change still works
with original testpmd code:
-(sleep 1 && echo stop) |
+(sleep 1 && echo help) |
Somehow testpmd gets Ctrl-D or equivalent with above command.
And it seems because of 'cmdline_interact()' and 'cmdline_poll()'
difference behavior changes with above command.
It is possible to add something like 'cmdline_interact_one()' (non loop
version of 'cmdline_interact()'), but not really sure that is correct
way to fix the issue.
> ---
> v9 - also handle the interactive case.
> use cmdine_poll() rather than signals and atexit
>
> app/test-pmd/cmdline.c | 28 +++++----------
> app/test-pmd/testpmd.c | 77 ++++++++++++++++++++----------------------
> app/test-pmd/testpmd.h | 1 +
> 3 files changed, 46 insertions(+), 60 deletions(-)
>
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
> index b32dc8bfd445..fbe9ad694dee 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -65,7 +65,6 @@
> #include "cmdline_tm.h"
> #include "bpf_cmd.h"
>
> -static struct cmdline *testpmd_cl;
> static cmdline_parse_ctx_t *main_ctx;
> static TAILQ_HEAD(, testpmd_driver_commands) driver_commands_head =
> TAILQ_HEAD_INITIALIZER(driver_commands_head);
> @@ -12921,28 +12920,19 @@ cmdline_read_from_file(const char *filename)
> void
> prompt(void)
> {
> - int ret;
> + struct cmdline *cl;
>
> - testpmd_cl = cmdline_stdin_new(main_ctx, "testpmd> ");
> - if (testpmd_cl == NULL)
> + cl = cmdline_stdin_new(main_ctx, "testpmd> ");
> + if (cl == NULL)
> return;
>
> - ret = atexit(prompt_exit);
> - if (ret != 0)
> - fprintf(stderr, "Cannot set exit function for cmdline\n");
> -
> - cmdline_interact(testpmd_cl);
> - if (ret != 0)
> - cmdline_stdin_exit(testpmd_cl);
> -}
> -
> -void
> -prompt_exit(void)
> -{
> - if (testpmd_cl != NULL) {
> - cmdline_quit(testpmd_cl);
> - cmdline_stdin_exit(testpmd_cl);
> + while (f_quit == 0 && cl_quit == 0) {
> + if (cmdline_poll(cl) < 0)
> + break;
> }
> +
> + cmdline_quit(cl);
> + cmdline_stdin_exit(cl);
> }
>
> void
> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
> index 134d79a55547..d01b6105b7de 100644
> --- a/app/test-pmd/testpmd.c
> +++ b/app/test-pmd/testpmd.c
> @@ -11,6 +11,7 @@
> #include <fcntl.h>
> #ifndef RTE_EXEC_ENV_WINDOWS
> #include <sys/mman.h>
> +#include <sys/select.h>
> #endif
> #include <sys/types.h>
> #include <errno.h>
> @@ -231,7 +232,7 @@ unsigned int xstats_display_num; /**< Size of extended statistics to show */
> * In container, it cannot terminate the process which running with 'stats-period'
> * option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
> */
> -static volatile uint8_t f_quit;
> +volatile uint8_t f_quit;
> uint8_t cl_quit; /* Quit testpmd from cmdline. */
>
> /*
> @@ -4315,13 +4316,6 @@ init_port(void)
> memset(txring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
> }
>
> -static void
> -force_quit(void)
> -{
> - pmd_test_exit();
> - prompt_exit();
> -}
> -
> static void
> print_stats(void)
> {
> @@ -4340,28 +4334,9 @@ print_stats(void)
> }
>
> static void
> -signal_handler(int signum)
> +signal_handler(int signum __rte_unused)
> {
> - if (signum == SIGINT || signum == SIGTERM) {
> - fprintf(stderr, "\nSignal %d received, preparing to exit...\n",
> - signum);
> -#ifdef RTE_LIB_PDUMP
> - /* uninitialize packet capture framework */
> - rte_pdump_uninit();
> -#endif
> -#ifdef RTE_LIB_LATENCYSTATS
> - if (latencystats_enabled != 0)
> - rte_latencystats_uninit();
> -#endif
> - force_quit();
> - /* Set flag to indicate the force termination. */
> - f_quit = 1;
> - /* exit with the expected status */
> -#ifndef RTE_EXEC_ENV_WINDOWS
> - signal(signum, SIG_DFL);
> - kill(getpid(), signum);
> -#endif
> - }
> + f_quit = 1;
> }
>
> int
> @@ -4536,15 +4511,9 @@ main(int argc, char** argv)
> start_packet_forwarding(0);
> }
> prompt();
> - pmd_test_exit();
> } else
> #endif
> {
> - char c;
> - int rc;
> -
> - f_quit = 0;
> -
> printf("No commandline core given, start packet forwarding\n");
> start_packet_forwarding(tx_first);
> if (stats_period != 0) {
> @@ -4567,15 +4536,41 @@ main(int argc, char** argv)
> prev_time = cur_time;
> rte_delay_us_sleep(US_PER_S);
> }
> - }
> + } else {
> + char c;
> + fd_set fds;
> +
> + printf("Press enter to exit\n");
>
> - printf("Press enter to exit\n");
> - rc = read(0, &c, 1);
> - pmd_test_exit();
> - if (rc < 0)
> - return 1;
> + FD_ZERO(&fds);
> + FD_SET(0, &fds);
> +
> + /* wait for signal or enter */
> + ret = select(1, &fds, NULL, NULL, NULL);
> + if (ret < 0 && errno != EINTR)
> + rte_exit(EXIT_FAILURE,
> + "Select failed: %s\n",
> + strerror(errno));
> +
> + /* if got enter then consume it */
> + if (ret == 1 && read(0, &c, 1) < 0)
> + rte_exit(EXIT_FAILURE,
> + "Read failed: %s\n",
> + strerror(errno));
> + }
> }
>
> + pmd_test_exit();
> +
> +#ifdef RTE_LIB_PDUMP
> + /* uninitialize packet capture framework */
> + rte_pdump_uninit();
> +#endif
> +#ifdef RTE_LIB_LATENCYSTATS
> + if (latencystats_enabled != 0)
> + rte_latencystats_uninit();
> +#endif
> +
> ret = rte_eal_cleanup();
> if (ret != 0)
> rte_exit(EXIT_FAILURE,
> diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
> index 7d24d25970d2..022210a7a964 100644
> --- a/app/test-pmd/testpmd.h
> +++ b/app/test-pmd/testpmd.h
> @@ -34,6 +34,7 @@
> #define RTE_PORT_HANDLING (uint16_t)3
>
> extern uint8_t cl_quit;
> +extern volatile uint8_t f_quit;
>
> /*
> * It is used to allocate the memory for hash key.
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v9] testpmd: cleanup cleanly from signal
2023-01-30 18:48 ` Ferruh Yigit
@ 2023-01-30 20:11 ` Stephen Hemminger
0 siblings, 0 replies; 48+ messages in thread
From: Stephen Hemminger @ 2023-01-30 20:11 UTC (permalink / raw)
To: Ferruh Yigit
Cc: dev, Olivier Matz, Thomas Monjalon, Aman Singh, Yuying Zhang,
Phil Yang, Jianbo Liu
On Mon, 30 Jan 2023 18:48:25 +0000
Ferruh Yigit <ferruh.yigit@amd.com> wrote:
> On 1/25/2023 6:32 PM, Stephen Hemminger wrote:
> > Do a clean shutdown of testpmd when a signal is received; instead of
> > having testpmd kill itself. This fixes the problem where a signal could
> > be received in the middle of a PMD and then the signal handler would
> > call PMD's close routine leading to locking problems.
> >
> > An added benefit is it gets rid of some Windows specific code.
> >
> > Fixes: d9a191a00e81 ("app/testpmd: fix quitting in container")
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
>
> Patch looks good to me, but './devtools/test-null.sh' hangs with change.
>
> It is possible the fix by updating './devtools/test-null.sh', but my
> concern is if this behavior change hit more consumers other than this
> internal tool, and I am for keeping previous behavior.
>
> './devtools/test-null.sh' sends 'stop' command to testpmd but that seems
> not really what makes testpmd quit, because following change still works
> with original testpmd code:
> -(sleep 1 && echo stop) |
> +(sleep 1 && echo help) |
> Somehow testpmd gets Ctrl-D or equivalent with above command.
>
> And it seems because of 'cmdline_interact()' and 'cmdline_poll()'
> difference behavior changes with above command.
>
> It is possible to add something like 'cmdline_interact_one()' (non loop
> version of 'cmdline_interact()'), but not really sure that is correct
> way to fix the issue.
>
Thanks for the review.
Fixed the end-of-file handling in v10 of the patch.
The cmdline_poll() function doesn't handle EOF correctly.
The function cmdline_poll() documentation is problematic since it
references that the return value is an enum, but the enum is actually
private and not exported by the library!
^ permalink raw reply [flat|nested] 48+ messages in thread