lib/tst_test.c: Run test in child process
PATCH v2 1/1 lib/tst_test.c: Run test in child process
This commit moves the actuall test to a child process. The parent process now serves two purposes. It sets up an alarm timer that kills the test on a timeout and also does the library setup and cleanup which means that the test temporary directory is removed even if the test crashed in one of the functions exported in tst_test structure.
The timeout is defined per test run, which is either one execution of test_all() function or single loop over the test() function. The timeout is reset after each test run by the test library by sending SIGUSR1 to the parent.
The default timeout is set to 300 seconds and can be overriden by setting tst_test->timeout variable.
There is also LTP_TIMEOUT_MUL env variable that, if set to float > 1, is used to multiply the timeout before the start of a test. This is especially intended for slow machines where the default timeout may not be enough. In that case you can double all timeouts just by exporting LTP_TIMEOUT_MUL=2 before starting the testrun.
--- include/tst_test.h | 3 ++ lib/newlib_tests/.gitignore | 3 ++ lib/newlib_tests/test10.c | 33 +++++++++++++++ lib/newlib_tests/test11.c | 34 ++++++++++++++++ lib/newlib_tests/test12.c | 32 +++++++++++++++ lib/tst_test.c | 98 +++++++++++++++++++++++++++++++++++++++------ 6 files changed, 190 insertions(+), 13 deletions(-) create mode 100644 lib/newlib_tests/test10.c create mode 100644 lib/newlib_tests/test11.c create mode 100644 lib/newlib_tests/test12.c
include/tst_test.h +3 -0
@@ -84,6 +84,9 @@ struct tst_test { int needs_device:1; int needs_checkpoints:1; +/* override default timeout per test run */ +unsigned int timeout; +void (*setup)(void );void (*cleanup)(void );
lib/newlib_tests/.gitignore +3 -0
@@ -7,3 +7,6 @@ test06 test07 test08 test09 +test10 +test11 +test12
lib/newlib_tests/test10.c new file +33 -0
@@ -0,0 +1,33 @@ +/* +* Copyright (c) 2016 Linux Test Project +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +/* +* Test for watchdog timeout. +*/ + +#include "tst_test.h" + + +static void do_test (void ) +{ +sleep (2 ); +tst_res (TPASS ,"Not reached" ); +} + +static struct tst_test test = { + .tid ="test10" , + .test_all = do_test, + .timeout =1 , +};
lib/newlib_tests/test11.c new file +34 -0
@@ -0,0 +1,34 @@ +/* +* Copyright (c) 2016 Linux Test Project +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +/* +* Test for segfault. +*/ + +#include "tst_test.h" + +static void do_test (void ) +{ +volatile char *ptr =NULL ; + + *ptr =0 ; + +tst_res (TPASS ,"Not reached" ); +} + +static struct tst_test test = { + .tid ="test11" , + .test_all = do_test, +};
lib/newlib_tests/test12.c new file +32 -0
@@ -0,0 +1,32 @@ +/* +* Copyright (c) 2016 Linux Test Project +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +/* +* Test for timeout override. +*/ + +#include "tst_test.h" + +static void do_test (void ) +{ +sleep (1 ); +tst_res (TPASS ,"Passed!" ); +} + +static struct tst_test test = { + .tid ="test12" , + .timeout =2 , + .test_all = do_test, +};
lib/tst_test.c +85 -13
142 lines not on this page · raw message
Signature · 6 lines
2.7.3 -- Cyril Hrubis [email protected]
PATCH v2 1/1 lib/tst_test.c: Run test in child process
----- Original Message -----
Quoted 22 lines
From: "Cyril Hrubis" <[email protected]>
To: [email protected]
Sent: Tuesday, 7 June, 2016 1:58:07 PM
Subject: [LTP] [PATCH v2]lib/tst_test.c: Run test in child processThis commit moves the actuall test to a child process. The parent process now serves two purposes. It sets up an alarm timer that kills the test on a timeout
and also does the library setup and cleanup which means that the test temporary
directory is removed even if the test crashed in one of the functions exported
intst_teststructure.The timeout is defined per test run, which is either one execution of
test_all()function or single loop over thetest()function. The timeout is reset after each test run by the test library by sending SIGUSR1 to the parent.The default timeout is set to 300 seconds and can be overriden by setting
tst_test->timeoutvariable.
Quoted 6 lines
There is also
LTP_TIMEOUT_MULenv variable that, if set to float > 1, is used to multiply the timeout before the start of a test. This is especially intended
for slow machines where the default timeout may not be enough. In that case you can double all timeouts just by exporting LTP_TIMEOUT_MUL=2 before starting the testrun.
Looks good to me, ACK. Couple notes below.
<snip>
Quoted 18 lines
lib/tst_test.c +5
-1@@ -220,17 +220,19 @@ void tst_vres_(const char *file, const int lineno, int ttype,void tst_vbrk_ (const char *file,const int lineno,int ttype,const char *fmt,va_list va) __attribute__((noreturn)); -static void do_cleanup (void ); +static void do_test_cleanup (void ) +{ +if (tst_test->cleanup) + tst_test->cleanup (); +}void tst_vbrk_ (const char *file,const int lineno,int ttype,const char *fmt,va_list va)
lib/tst_test.c void tst_vres_(const char *file, const int lineno, int · line 237
Quoted 10 lines
lib/tst_test.c +2
-4{print_result (file, lineno, ttype, fmt, va); -if (getpid () == main_pid) { -do_cleanup (); -cleanup_ipc (); - } +if (getpid () == main_pid) +do_test_cleanup ();
Not directly related to this patch, but I noticed that we don't seem to cleanup_ipc if we hit TBROK outside of main test pid.
Quoted 70 lines
lib/tst_test.c +0
-0exit (TTYPE_RESULT (ttype));}
lib/tst_test.c +26
-8@@ -550,7 +552,10 @@ static void do_setup(int argc, char *argv[])if (tst_test->resource_files)copy_resources (); +} +static void do_test_setup (void ) +{ main_pid =getpid ();if (tst_test->setup)@@ -562,9 +567,6 @@ static void do_setup(int argc, char *argv[])static void do_cleanup (void ) { -if (tst_test->cleanup) - tst_test->cleanup (); -if (tst_test->needs_device && tdev.dev)tst_release_device (tdev.dev);@@ -619,16 +621,13 @@ static unsigned long long get_time_ms(void)return tv.tv_sec *1000 + tv.tv_usec /1000 ; } -void tst_run_tcases (int argc,char *argv[],struct tst_test *self) +static void testrun (void ) {unsigned int i =0 ;unsigned long long stop_time =0 ;int cont =1 ; - tst_test = self; -TCID = tst_test->tid; - -do_setup (argc, argv); +do_test_setup ();if (duration >0 ) stop_time =get_time_ms () + (unsigned long long )(duration *1000 );@@ -648,8 +647,81 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self) break;run_tests (); + +kill (getppid (),SIGUSR1 ); } +do_test_cleanup (); +exit (0 ); +} + +static pid_t test_pid; +static unsigned int timeout =300 ; + +static void alarm_handler(int sig LTP_ATTRIBUTE_UNUSED) +{ +kill (test_pid,SIGKILL ); +} + +static void heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED) +{ +alarm (timeout); +} + +void tst_run_tcases (int argc,char *argv[],struct tst_test *self) +{
lib/tst_test.c void tst_run_tcases(int argc, char *argv[], struct · line 683
Quoted 10 lines
lib/tst_test.c +10
-0+int status; +char *mul; + + tst_test = self; +TCID = tst_test->tid; + +do_setup (argc, argv); + +if (tst_test->timeout) + timeout = tst_test->timeout;
Can you think of a testcase where we would want to disable timeout?
Regards,
Jan
PATCH v2 1/1 lib/tst_test.c: Run test in child process
Hi!
Quoted 21 lines
Quoted 21 lines
lib/tst_test.c +5
-1@@ -220,17 +220,19 @@ void tst_vres_(const char *file, const int lineno, int ttype,void tst_vbrk_ (const char *file,const int lineno,int ttype,const char *fmt,va_list va) __attribute__((noreturn)); -static void do_cleanup (void ); +static void do_test_cleanup (void ) +{ +if (tst_test->cleanup) + tst_test->cleanup (); +}void tst_vbrk_ (const char *file,const int lineno,int ttype,const char *fmt,va_list va) {print_result (file, lineno, ttype, fmt, va);
Quoted 10 lines
lib/tst_test.c void tst_vres_(const char *file, const int lineno, int ttype, · line 236
Quoted 7 lines
lib/tst_test.c +2
-4-if (getpid () == main_pid) { -do_cleanup (); -cleanup_ipc (); - } +if (getpid () == main_pid) +do_test_cleanup ();Not directly related to this patch, but I noticed that we don't seem to
cleanup_ipcif we hit TBROK outside of main test pid.
The cleanup_ipc() is intended to be executed just before the main pid exits since it unlinks the shm file. If child TBROKs it's catched in the check_child_status() in the parent, tst_brk() is called which will call the cleanup_ipc().
I guess that we may close and unmap the shm even in the children but wouldn't that happen anyway as the process exits?
Quoted 6 lines
Quoted 6 lines
lib/tst_test.c +6
-0+void tst_run_tcases (int argc,char *argv[],struct tst_test *self) +{ +int status; +char *mul; + + tst_test = self;
Quoted 8 lines
lib/tst_test.c void tst_run_tcases(int argc, char *argv[], struct tst_test *self) · line 682
Quoted 6 lines
lib/tst_test.c +6
-0+TCID = tst_test->tid; + +do_setup (argc, argv); + +if (tst_test->timeout) + timeout = tst_test->timeout;Can you think of a testcase where we would want to disable timeout?
At the moment I do not remember a test that would need timeout to be turned off. And if we find that it's necessary we can always disable in case that tst_test->timeout < 0.
Signature · 2 lines
Cyril Hrubis [email protected]
PATCH v2 1/1 lib/tst_test.c: Run test in child process
----- Original Message -----
Quoted 40 lines
From: "Cyril Hrubis" <[email protected]>
To: "Jan Stancek" <[email protected]>
Cc: [email protected]
Sent: Wednesday, 8 June, 2016 2:30:56 PM
Subject: Re: [LTP] [PATCH v2]lib/tst_test.c: Run test in child processHi!
Quoted 22 lines
Quoted 22 lines
lib/tst_test.c +0
-0@@ -220,17 +220,19 @@ void tst_vres_(const char *file, const int lineno,int
ttype,
void tst_vbrk_(const char *file, const int lineno, int ttype,const char *fmt, va_list va) __attribute__((noreturn));lib/tst_test.c +5
-1-static void do_cleanup (void ); +static void do_test_cleanup (void ) +{ +if (tst_test->cleanup) + tst_test->cleanup (); +}void tst_vbrk_ (const char *file,const int lineno,int ttype,const char *fmt,va_list va) {print_result (file, lineno, ttype, fmt, va);Quoted 10 lines
lib/tst_test.c
Quoted 7 lines
lib/tst_test.c +2
-4-if (getpid () == main_pid) { -do_cleanup (); -cleanup_ipc (); - } +if (getpid () == main_pid) +do_test_cleanup ();Not directly related to this patch, but I noticed that we don't seem to
cleanup_ipcif we hit TBROK outside of main test pid.
Quoted 2 lines
The
cleanup_ipc()is intended to be executed just before the main pid exits since it unlinks the shm file.
So, if we fail a SAFE macro somewhere in lib/tst_test.c, I don't see we ever call cleanup_ipc().
tst_run_tcases
SAFE_WAITPID(test_pid, &status, 0);
tst_brkm
tst_brkm_
tst_brk_
tst_vbrk_
exit
Quoted 3 lines
If child TBROKs it's catched in the
check_child_status()in the parent,tst_brk()is called which will call thecleanup_ipc().
Not anymore. After this patch the only place that now calls cleanup_ipc() is do_exit().
What I'm thinking is something like this on top of your patch:
lib/tst_test.c +5 -1
@@ -40,7 +40,7 @@ struct tst_test *tst_test;static char tmpdir_created;static int iterations =1 ;static float duration =-1 ; -static pid_t main_pid; +static pid_t main_pid, lib_pid;struct results {int passed;
@@ -234,6 +234,9 @@ void tst_vbrk_(const char *file, const int lineno, int ttype,if (getpid () == main_pid)do_test_cleanup (); +if (getpid () == lib_pid) +do_exit (); +exit (TTYPE_RESULT (ttype)); }
@@ -673,6 +676,7 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self)int status;char *mul; + lib_pid =getpid (); tst_test = self;TCID = tst_test->tid;
Quoted 27 lines
I guess that we may close and unmap the shm even in the children but wouldn't that happen anyway as the process exits?
Quoted 6 lines
Quoted 6 lines
lib/tst_test.c +6
-0+void tst_run_tcases (int argc,char *argv[],struct tst_test *self) +{ +int status; +char *mul; + + tst_test = self;Quoted 8 lines
lib/tst_test.c
Quoted 6 lines
lib/tst_test.c +6
-0+TCID = tst_test->tid; + +do_setup (argc, argv); + +if (tst_test->timeout) + timeout = tst_test->timeout;Can you think of a testcase where we would want to disable timeout?
At the moment I do not remember a test that would need timeout to be turned off. And if we find that it's necessary we can always disable in case that
tst_test->timeout< 0.--
Cyril Hrubis
[email protected]
PATCH v2 1/1 lib/tst_test.c: Run test in child process
Hi!
Quoted 14 lines
Quoted 2 lines
The
cleanup_ipc()is intended to be executed just before the main pid exits since it unlinks the shm file.So, if we fail a SAFE macro somewhere in
lib/tst_test.c, I don't see we ever callcleanup_ipc().
tst_run_tcases
SAFE_WAITPID(test_pid, &status, 0);
tst_brkm
tst_brkm_
tst_brk_
tst_vbrk_
exit
Quoted 6 lines
Quoted 3 lines
If child TBROKs it's catched in the
check_child_status()in the parent,tst_brk()is called which will call thecleanup_ipc().Not anymore. After this patch the only place that now calls
cleanup_ipc()isdo_exit().
Ah, right, that is since what was previously main_pid has been split into the library process and main test process.
Indeed the cleanup_ipc() should be called from the library in the tst_vbrk_().
Quoted 26 lines
What I'm thinking is something like this on top of your patch:
lib/tst_test.c +4
-1@@ -40,7 +40,7 @@ struct tst_test *tst_test;static char tmpdir_created;static int iterations =1 ;static float duration =-1 ; -static pid_t main_pid; +static pid_t main_pid, lib_pid;struct results {int passed;@@ -234,6 +234,9 @@ void tst_vbrk_(const char *file, const int lineno, int ttype,if (getpid () == main_pid)do_test_cleanup (); +if (getpid () == lib_pid) +do_exit (); +exit (TTYPE_RESULT (ttype)); }
lib/tst_test.c void tst_run_tcases(int argc, char *argv[], struct tst_test *self) · line 681
Quoted 6 lines
lib/tst_test.c +1
-0@@ -673,6 +676,7 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self)int status;char *mul; + lib_pid =getpid (); tst_test = self;TCID = tst_test->tid;
Looks good to me, acked.
Signature · 2 lines
Cyril Hrubis [email protected]
PATCH v2 1/1 lib/tst_test.c: Run test in child process
----- Original Message -----
Quoted 33 lines
From: "Cyril Hrubis" <[email protected]>
To: "Jan Stancek" <[email protected]>
Cc: [email protected]
Sent: Wednesday, 8 June, 2016 3:15:15 PM
Subject: Re: [LTP] [PATCH v2]lib/tst_test.c: Run test in child processHi!
Quoted 14 lines
Quoted 2 lines
The
cleanup_ipc()is intended to be executed just before the main pid exits since it unlinks the shm file.So, if we fail a SAFE macro somewhere in
lib/tst_test.c, I don't see we ever callcleanup_ipc().
tst_run_tcases
SAFE_WAITPID(test_pid, &status, 0);
tst_brkm
tst_brkm_
tst_brk_
tst_vbrk_
exitQuoted 6 lines
Quoted 3 lines
If child TBROKs it's catched in the
check_child_status()in the parent,tst_brk()is called which will call thecleanup_ipc().Not anymore. After this patch the only place that now calls
cleanup_ipc()isdo_exit().Ah, right, that is since what was previously
main_pidhas been split into the library process and main test process.Indeed the
cleanup_ipc()should be called from the library in thetst_vbrk_().
...
Quoted 1 line
Looks good to me, acked.
Pushed.
Regards,
Jan
PATCH v2 1/1 lib/tst_test.c: Run test in child process
Hi!
Quoted 9 lines
Quoted 5 lines
Ah, right, that is since what was previously
main_pidhas been split into the library process and main test process.Indeed the
cleanup_ipc()should be called from the library in thetst_vbrk_()....
Quoted 1 line
Looks good to me, acked.
Pushed.
And looking at the code closely, this is not enough, since we have:
if (WIFEXITED(status) && WEXITSTATUS(status)) exit(WEXITSTATUS(status));
in the tst_run_tcases(). So we have to call cleanup_ipc() before the exit() here as well.
Also we do not count the TBROK in results structure, since the TBROK is propagated only by exit value so do_exit() will exit with 0 in case that we TBROK in the test library.
This is getting more complicated than I would like.
Minimal patch to fix this would be:
lib/tst_test.c +4 -2
@@ -237,7 +237,7 @@ void tst_vbrk_(const char *file, const int lineno, int ttype,do_test_cleanup ();if (getpid () == lib_pid) -do_exit (); +cleanup_ipc ();exit (TTYPE_RESULT (ttype)); }
@@ -718,8 +718,10 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self)do_cleanup (); -if (WIFEXITED (status) &&WEXITSTATUS (status)) +if (WIFEXITED (status) &&WEXITSTATUS (status)) {\ +cleanup_ipc ();exit (WEXITSTATUS (status)); + }if (WIFSIGNALED (status) &&WTERMSIG (status) ==SIGKILL ) { tst_res(TINFO, "If you are running on slow machine, "
Or we may change do_exit() to take parameter so that we can actually pass the TBROK to it, in a case that you want to print the statistics in this case as well...
Signature · 2 lines
Cyril Hrubis [email protected]
PATCH v2 1/1 lib/tst_test.c: Run test in child process
Hi!
And I guess that the best solution is to pass the exit value to do_exit(), that way we have only one function that calls the exit() in the code called by the test library process.
What about:
lib/tst_test.c +5 -7
@@ -64,7 +64,7 @@ char *const tst_ipc_envp[] = {ipc_path, NULL};static char shm_path[1024 ]; -static void do_exit (void ) __attribute__ ((noreturn)); +static void do_exit (int ret) __attribute__ ((noreturn));static void setup_ipc (void ) {
@@ -237,7 +237,7 @@ void tst_vbrk_(const char *file, const int lineno, int ttype,do_test_cleanup ();if (getpid () == lib_pid) -do_exit (); +do_exit (TTYPE_RESULT (ttype));exit (TTYPE_RESULT (ttype)); }
@@ -443,10 +443,8 @@ static void parse_opts(int argc, char *argv[]) } -static void do_exit (void ) +static void do_exit (int ret) { -int ret =0 ; -printf ("\nSummary:\n" );printf ("passed %d\n" , results->passed);printf ("failed %d\n" , results->failed);
@@ -719,7 +717,7 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self)do_cleanup ();if (WIFEXITED (status) &&WEXITSTATUS (status)) -exit (WEXITSTATUS (status)); +do_exit (WEXITSTATUS (status));if (WIFSIGNALED (status) &&WTERMSIG (status) ==SIGKILL ) { tst_res(TINFO, "If you are running on slow machine, "
@@ -730,5 +728,5 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self)if (WIFSIGNALED (status))tst_brk (TBROK ,"Test killed by %s!" ,tst_strsig (WTERMSIG (status))); -do_exit (); +do_exit (0 ); }
Signature · 2 lines
Cyril Hrubis [email protected]
PATCH v2 1/1 lib/tst_test.c: Run test in child process
----- Original Message -----
Quoted 10 lines
From: "Cyril Hrubis" <[email protected]>
To: "Jan Stancek" <[email protected]>
Cc: [email protected]
Sent: Wednesday, 8 June, 2016 4:06:35 PM
Subject: Re: [LTP] [PATCH v2]lib/tst_test.c: Run test in child processHi!
And I guess that the best solution is to pass the exit value todo_exit(), that way we have only one function that calls theexit()in the code called by the test library process.
I was thinking the same as your patch below, but plus these changes:
- remove call to do_cleanup in tst_run_tcases
- add call to cleanup_ipc in do_cleanup
- remove call to cleanup_ipc in do_exit
- add call to do_cleanup in do_exit
Quoted 62 lines
What about:
lib/tst_test.c +2
-2@@ -64,7 +64,7 @@ char *const tst_ipc_envp[] = {ipc_path, NULL};static char shm_path[1024 ]; -static void do_exit (void ) __attribute__ ((noreturn)); +static void do_exit (int ret) __attribute__ ((noreturn));static void setup_ipc (void ) {@@ -237,7 +237,7 @@ void tst_vbrk_(const char *file, const int lineno, int ttype,do_test_cleanup ();if (getpid () == lib_pid) -do_exit (); +do_exit (TTYPE_RESULT (ttype));exit (TTYPE_RESULT (ttype));}
lib/tst_test.c +2
-4@@ -443,10 +443,8 @@ static void parse_opts(int argc, char *argv[]) } -static void do_exit (void ) +static void do_exit (int ret) { -int ret =0 ; -printf ("\nSummary:\n" );printf ("passed %d\n" , results->passed);printf ("failed %d\n" , results->failed);@@ -719,7 +717,7 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self)do_cleanup ();if (WIFEXITED (status) &&WEXITSTATUS (status)) -exit (WEXITSTATUS (status)); +do_exit (WEXITSTATUS (status));if (WIFSIGNALED (status) &&WTERMSIG (status) ==SIGKILL ) {lib/tst_test.c +1
-1tst_res(TINFO, "If you are running on slow machine, "@@ -730,5 +728,5 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self)if (WIFSIGNALED (status))tst_brk (TBROK ,"Test killed by %s!" ,tst_strsig (WTERMSIG (status))); -do_exit (); +do_exit (0 );}
--
Cyril Hrubis
[email protected]
PATCH v2 1/1 lib/tst_test.c: Run test in child process
Hi!
Quoted 5 lines
I was thinking the same as your patch below, but plus these changes:
- remove call todo_cleanupintst_run_tcases
- add call tocleanup_ipcindo_cleanup
- remove call tocleanup_ipcindo_exit
- add call todo_cleanupindo_exit
So, the test library could exit only via do_exit() call and the whole cleanup would be done in do_exit() just before the call to exit(), right? Sounds good to me. Will you prepare a patch?
Signature · 2 lines
Cyril Hrubis [email protected]