Skip to content

Commit a1f8270

Browse files
committed
lib/tst_test.c: Fix tst_brk() handling
This makes the tst_brk() handling cleaner and saner as instead of propagating the tst_brk() result in a return value an abort flag is introduced into the shared memory. Now: - All the processes but the library one that reports the results exit with 0 - tst_brk(TBROK, ...) increments result counters, sets the abort flag, exit current process and makes sure all process group processes are terminated - all other tst_brk() variants will just increments the counters and exits the current process (which is current iteration for .all_filesystems, .test_variants, etc.) This makes the tst_brk() behavior well defined so we can now even call tst_brk() with TFAIL and TPASS as well. And since TBROK is supposed to exit the test immediately (i.e. unrecoverable error) we are now properly doing so. The case that main test pid called TBROK was working correctly before this patch, since send the SIGKILL signal to the process group after we waited for the main test pid. All that was missing is a code that sends a signal to the main test pid in the case that TBROK was triggered by one of it's children and now we properly kill all test processes in that case as well. There is also special case where we call tst_brk() before the test library has been initialized (mostly done by the C shell helpers) in that case we have to exit with a proper return value, which is normally done by the test library process. Signed-off-by: Cyril Hrubis <[email protected]> Acked-by: Andrea Cervesato <[email protected]> Acked-by: Jan Stancek <[email protected]> Reviewed-by: Petr Vorel <[email protected]>
1 parent b070a56 commit a1f8270

File tree

11 files changed

+245
-57
lines changed

11 files changed

+245
-57
lines changed

doc/old/C-Test-API.asciidoc

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -245,13 +245,13 @@ The 'ttype' can be combined bitwise with 'TERRNO' or 'TTERRNO' to print
245245
void tst_brk(int ttype, char *arg_fmt, ...);
246246
-------------------------------------------------------------------------------
247247

248-
Printf-like function to report error and exit the test, it can be used with ttype:
248+
Printf-like function to report result and exits current test. If test uses
249+
'.all_filesystems', '.test_variants' etc. the 'tst_brk()' exits current test
250+
iteration e.g. currently running filesystem test or a test variant unless
251+
'ttype' is set to 'TBROK'.
249252

250-
|============================================================
251-
| 'TBROK' | Something has failed in test preparation phase.
252-
| 'TCONF' | Test is not appropriate for current configuration
253-
(syscall not implemented, unsupported arch, ...)
254-
|============================================================
253+
If 'ttype' is set to 'TBROK' all test processes are killed and the test exits
254+
immediately with an error.
255255

256256
The 'ttype' can be combined bitwise with 'TERRNO' or 'TTERRNO' to print
257257
'errno', 'TST_ERR' respectively.
@@ -647,15 +647,15 @@ IMPORTANT: You have to set the '.forks_child' flag in the test structure
647647
Results reported by 'tst_res()' are propagated to the parent test process via
648648
block of shared memory.
649649

650-
Calling 'tst_brk()' causes child process to exit with non-zero exit value.
651-
Which means that it's safe to use 'SAFE_*()' macros in the child processes as
652-
well.
650+
Calling 'tst_brk()' causes child process to set the test library abort flag and
651+
exits the test immediately. Which means that it's safe to use 'SAFE_*()' macros
652+
in the child processes as well.
653653

654654
Children that outlive the 'test()' function execution are waited for in the
655655
test library. Unclean child exit (killed by signal, non-zero exit value, etc.)
656-
will cause the main test process to exit with 'tst_brk()', which especially
657-
means that 'TBROK' propagated from a child process will cause the whole test
658-
to exit with 'TBROK'.
656+
will cause the main test process to exit with 'tst_brk()'. That means that all
657+
test child processes are supposed to exit with success unless they are
658+
explicitly waited for.
659659

660660
If a test needs a child that segfaults or does anything else that cause it to
661661
exit uncleanly all you need to do is to wait for such children from the

include/tst_common.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,6 @@
7979
#define TST_BUILD_BUG_ON(condition) \
8080
do { ((void)sizeof(char[1 - 2 * !!(condition)])); } while (0)
8181

82-
#define TST_BRK_SUPPORTS_ONLY_TCONF_TBROK(condition) \
83-
TST_BUILD_BUG_ON(condition)
84-
8582
#define TST_RES_SUPPORTS_TCONF_TDEBUG_TFAIL_TINFO_TPASS_TWARN(condition) \
8683
TST_BUILD_BUG_ON(condition)
8784

include/tst_test.h

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,28 +98,32 @@ void tst_brk_(const char *file, const int lineno, int ttype,
9898
__attribute__ ((format (printf, 4, 5)));
9999

100100
/**
101-
* tst_brk() - Reports a breakage and exits the test.
101+
* tst_brk() - Reports a breakage and exits the test or test process.
102102
*
103103
* @ttype: An &enum tst_res_flags.
104104
* @arg_fmt: A printf-like format.
105105
* @...: A printf-like parameters.
106106
*
107-
* Reports either TBROK or TCONF and exits the test immediately. When called
108-
* all children in the same process group as the main test library process are
109-
* killed. This function, unless in a test cleanup, calls _exit() and does not
110-
* return.
107+
* Reports a single result and exits immediately. The call behaves differently
108+
* based on the ttype parameter. For all ttype results but TBROK the call exits
109+
* the current test process, i.e. increments test result counters and calls
110+
* exit(0).
111+
*
112+
* The TBROK ttype is special that apart from exiting the current test process
113+
* it also tells to the test library to exit immediately. When TBROK is
114+
* triggered by any of the test processes the whole process group is killed so
115+
* that there are no processes left after the library process exits. This also
116+
* means that any subsequent test iterations are not executed, e.g. if a test
117+
* runs for all filesystems and tst_brk() with TBROK is called, the test exits
118+
* and does not attempt to continue a test iteration for the next filesystem.
111119
*
112120
* When test is in cleanup() function TBROK is converted into TWARN by the test
113121
* library and we attempt to carry on with a cleanup even when tst_brk() was
114122
* called. This makes it possible to use SAFE_FOO() macros in the test cleanup
115123
* without interrupting the cleanup process on a failure.
116124
*/
117-
#define tst_brk(ttype, arg_fmt, ...) \
118-
({ \
119-
TST_BRK_SUPPORTS_ONLY_TCONF_TBROK(!((ttype) & \
120-
(TBROK | TCONF | TFAIL))); \
121-
tst_brk_(__FILE__, __LINE__, (ttype), (arg_fmt), ##__VA_ARGS__);\
122-
})
125+
#define tst_brk(ttype, arg_fmt, ...) \
126+
tst_brk_(__FILE__, __LINE__, (ttype), (arg_fmt), ##__VA_ARGS__)
123127

124128
void tst_printf(const char *const fmt, ...)
125129
__attribute__((nonnull(1), format (printf, 1, 2)));

lib/newlib_tests/.gitignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,10 @@ test_runtime01
5858
test_runtime02
5959
test_children_cleanup
6060
tst_res_flags
61-
tst_safe_sscanf
61+
tst_safe_sscanf
62+
test_brk_child
63+
test_brk_fail
64+
test_brk_parent
65+
test_brk_pass
66+
test_brk_variant
67+
test_fail_variant

lib/newlib_tests/test_brk_child.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (c) 2025 Cyril Hrubis <[email protected]>
4+
*/
5+
6+
/*
7+
* Test that tst_brk(TFAIL, ...) exits only single test variant.
8+
*/
9+
#include "tst_test.h"
10+
11+
static void do_test(void)
12+
{
13+
int i;
14+
15+
for (i = 0; i < 10; i++) {
16+
if (!SAFE_FORK()) {
17+
tst_res(TINFO, "Suspending child %i", i);
18+
pause();
19+
}
20+
}
21+
22+
if (!SAFE_FORK())
23+
tst_brk(TBROK, "Child triggers TBROK");
24+
25+
pause();
26+
}
27+
28+
static struct tst_test test = {
29+
.test_all = do_test,
30+
.forks_child = 1,
31+
};

lib/newlib_tests/test_brk_fail.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (c) 2024 Cyril Hrubis <[email protected]>
4+
*/
5+
6+
/*
7+
* Test that tst_brk(TFAIL, ...) works properly.
8+
*/
9+
#include "tst_test.h"
10+
11+
static void do_test(void)
12+
{
13+
int pid = SAFE_FORK();
14+
15+
if (pid)
16+
return;
17+
18+
tst_brk(TFAIL, "Test child exiting...");
19+
tst_res(TWARN, "Test child stil alive!");
20+
}
21+
22+
static struct tst_test test = {
23+
.test_all = do_test,
24+
.forks_child = 1,
25+
};

lib/newlib_tests/test_brk_parent.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (c) 2025 Cyril Hrubis <[email protected]>
4+
*/
5+
6+
/*
7+
* Test that tst_brk(TFAIL, ...) exits only single test variant.
8+
*/
9+
#include "tst_test.h"
10+
11+
static void do_test(void)
12+
{
13+
int i;
14+
15+
for (i = 0; i < 10; i++) {
16+
if (!SAFE_FORK()) {
17+
tst_res(TINFO, "Suspending child %i", i);
18+
pause();
19+
}
20+
}
21+
22+
tst_brk(TBROK, "Parent triggers TBROK");
23+
}
24+
25+
static struct tst_test test = {
26+
.test_all = do_test,
27+
.forks_child = 1,
28+
};

lib/newlib_tests/test_brk_pass.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (c) 2024 Cyril Hrubis <[email protected]>
4+
*/
5+
6+
/*
7+
* Test that tst_brk(TPASS, ...) works properly.
8+
*/
9+
#include "tst_test.h"
10+
11+
static void do_test(void)
12+
{
13+
int pid = SAFE_FORK();
14+
15+
if (pid)
16+
return;
17+
18+
tst_brk(TPASS, "Test child exiting...");
19+
tst_res(TWARN, "Test child stil alive!");
20+
}
21+
22+
static struct tst_test test = {
23+
.test_all = do_test,
24+
.forks_child = 1,
25+
};

lib/newlib_tests/test_brk_variant.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (c) 2024 Cyril Hrubis <[email protected]>
4+
*/
5+
6+
/*
7+
* Test that tst_brk(TBROK, ...) exits the test immediately.
8+
*/
9+
#include "tst_test.h"
10+
11+
static void do_test(void)
12+
{
13+
tst_brk(TBROK, "Exitting the test during the first variant");
14+
}
15+
16+
static struct tst_test test = {
17+
.test_all = do_test,
18+
.test_variants = 10,
19+
};

lib/newlib_tests/test_fail_variant.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (c) 2024 Cyril Hrubis <[email protected]>
4+
*/
5+
6+
/*
7+
* Test that tst_brk(TFAIL, ...) exits only single test variant.
8+
*/
9+
#include "tst_test.h"
10+
11+
static void do_test(void)
12+
{
13+
tst_brk(TFAIL, "Failing a test variant");
14+
tst_res(TWARN, "Shouldn't be reached");
15+
}
16+
17+
static struct tst_test test = {
18+
.test_all = do_test,
19+
.test_variants = 10,
20+
};

0 commit comments

Comments
 (0)