(root)/
glibc-2.38/
stdlib/
test-cxa_atexit-race2.c
       1  /* Support file for atexit/exit, etc. race tests (BZ #27749).
       2     Copyright (C) 2021-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  /* The atexit/exit, at_quick_exit/quick_exit, __cxa_atexit/exit, etc.
      20     exhibited data race while calling destructors.
      21  
      22     This test registers destructors from the background thread, and checks that
      23     the same destructor is not called more than once.  */
      24  
      25  #include <stdatomic.h>
      26  #include <stdio.h>
      27  #include <stdlib.h>
      28  #include <support/check.h>
      29  #include <support/xthread.h>
      30  #include <support/xunistd.h>
      31  #include <sys/wait.h>
      32  #include <unistd.h>
      33  
      34  static atomic_int registered;
      35  static atomic_int todo = 100000;
      36  
      37  static void
      38  atexit_cb (void *arg)
      39  {
      40    atomic_fetch_sub (&registered, 1);
      41    static void *prev;
      42    if (arg == prev)
      43      FAIL_EXIT1 ("%s: %p\n", __func__, arg);
      44    prev = arg;
      45  
      46    while (atomic_load (&todo) > 0 && atomic_load (&registered) < 100)
      47      ;
      48  }
      49  
      50  int __cxa_atexit (void (*func) (void *), void *arg, void *d);
      51  
      52  static void *
      53  thread_func (void *arg)
      54  {
      55    void *cb_arg = NULL;
      56    while (atomic_load (&todo) > 0)
      57      {
      58        if (atomic_load (&registered) < 10000)
      59          {
      60            int n = 10;
      61            for (int i = 0; i < n; ++i)
      62              __cxa_atexit (&atexit_cb, ++cb_arg, 0);
      63            atomic_fetch_add (&registered, n);
      64            atomic_fetch_sub (&todo, n);
      65          }
      66      }
      67  
      68    return NULL;
      69  }
      70  
      71  _Noreturn static void
      72  test_and_exit (void)
      73  {
      74    pthread_attr_t attr;
      75  
      76    xpthread_attr_init (&attr);
      77    xpthread_attr_setdetachstate (&attr, 1);
      78  
      79    xpthread_create (&attr, thread_func, NULL);
      80    xpthread_attr_destroy (&attr);
      81  
      82    while (atomic_load (&registered) == 0)
      83      ;
      84    exit (0);
      85  }
      86  
      87  static int
      88  do_test (void)
      89  {
      90    for (int i = 0; i < 20; ++i)
      91      {
      92        for (int i = 0; i < 10; ++i)
      93          if (xfork () == 0)
      94            test_and_exit ();
      95  
      96        for (int i = 0; i < 10; ++i)
      97          {
      98            int status;
      99            xwaitpid (0, &status, 0);
     100            if (!WIFEXITED (status))
     101              FAIL_EXIT1 ("Failed iterations %d", i);
     102            TEST_COMPARE (WEXITSTATUS (status), 0);
     103          }
     104      }
     105  
     106    return 0;
     107  }
     108  
     109  #define TEST_FUNCTION do_test
     110  #include <support/test-driver.c>