1 /* Global test failure counter.
2 Copyright (C) 2016-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19 #include <support/check.h>
20 #include <support/support.h>
21 #include <support/test-driver.h>
22
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/mman.h>
27 #include <unistd.h>
28
29 /* This structure keeps track of test failures. The counter is
30 incremented on each failure. The failed member is set to true if a
31 failure is detected, so that even if the counter wraps around to
32 zero, the failure of a test can be detected.
33
34 The init constructor function below puts *state on a shared
35 annonymous mapping, so that failure reports from subprocesses
36 propagate to the parent process. */
37 struct test_failures
38 {
39 unsigned int counter;
40 unsigned int failed;
41 };
42 static struct test_failures *state;
43
44 static __attribute__ ((constructor)) void
init(void)45 init (void)
46 {
47 void *ptr = mmap (NULL, sizeof (*state), PROT_READ | PROT_WRITE,
48 MAP_ANONYMOUS | MAP_SHARED, -1, 0);
49 if (ptr == MAP_FAILED)
50 {
51 printf ("error: could not map %zu bytes: %m\n", sizeof (*state));
52 exit (1);
53 }
54 /* Zero-initialization of the struct is sufficient. */
55 state = ptr;
56 }
57
58 void
support_record_failure(void)59 support_record_failure (void)
60 {
61 if (state == NULL)
62 {
63 write_message
64 ("error: support_record_failure called without initialization\n");
65 _exit (1);
66 }
67 /* Relaxed MO is sufficient because we are only interested in the
68 values themselves, in isolation. */
69 __atomic_store_n (&state->failed, 1, __ATOMIC_RELEASE);
70 __atomic_add_fetch (&state->counter, 1, __ATOMIC_RELEASE);
71 }
72
73 int
support_report_failure(int status)74 support_report_failure (int status)
75 {
76 if (state == NULL)
77 {
78 write_message
79 ("error: support_report_failure called without initialization\n");
80 return 1;
81 }
82
83 /* Relaxed MO is sufficient because acquire test result reporting
84 assumes that exiting from the main thread happens before the
85 error reporting via support_record_failure, which requires some
86 form of external synchronization. */
87 bool failed = __atomic_load_n (&state->failed, __ATOMIC_RELAXED);
88 if (failed)
89 printf ("error: %u test failures\n",
90 __atomic_load_n (&state->counter, __ATOMIC_RELAXED));
91
92 if ((status == 0 || status == EXIT_UNSUPPORTED) && failed)
93 /* If we have a recorded failure, it overrides a non-failure
94 report from the test function. */
95 status = 1;
96 return status;
97 }
98
99 void
support_record_failure_reset(void)100 support_record_failure_reset (void)
101 {
102 /* Only used for testing the test framework, with external
103 synchronization, but use release MO for consistency. */
104 __atomic_store_n (&state->failed, 0, __ATOMIC_RELAXED);
105 __atomic_add_fetch (&state->counter, 0, __ATOMIC_RELAXED);
106 }
107
108 int
support_record_failure_is_failed(void)109 support_record_failure_is_failed (void)
110 {
111 /* Relaxed MO is sufficient because we need (blocking) external
112 synchronization for reliable test error reporting anyway. */
113 return __atomic_load_n (&state->failed, __ATOMIC_RELAXED);
114 }
115