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