1/* Global test failure counter.
2 Copyright (C) 2016-2017 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 <http://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. */
37struct test_failures
38{
39 unsigned int counter;
40 unsigned int failed;
41};
42static struct test_failures *state;
43
44static __attribute__ ((constructor)) void
45init (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
58void
59support_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
73int
74support_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
99void
100support_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