(root)/
glibc-2.38/
support/
support_record_failure.c
       1  /* Global test failure counter.
       2     Copyright (C) 2016-2023 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     anonymous 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
      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
      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
      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
     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
     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  }