(root)/
glibc-2.38/
nptl/
tst-cleanup4.c
       1  /* Copyright (C) 2003-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <pthread.h>
      19  #include <shlib-compat.h>
      20  #include <stdio.h>
      21  #include <stdlib.h>
      22  #include <unistd.h>
      23  
      24  #include <support/xunistd.h>
      25  
      26  /* LinuxThreads pthread_cleanup_{push,pop} helpers.  */
      27  extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
      28                                     void (*__routine) (void *),
      29                                     void *__arg);
      30  compat_symbol_reference (libpthread, _pthread_cleanup_push,
      31                           _pthread_cleanup_push, GLIBC_2_0);
      32  extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
      33                                    int __execute);
      34  compat_symbol_reference (libpthread, _pthread_cleanup_pop,
      35                           _pthread_cleanup_pop, GLIBC_2_0);
      36  
      37  static int fds[2];
      38  static pthread_barrier_t b2;
      39  static int global;
      40  
      41  /* Defined in tst-cleanup4aux.c, never compiled with -fexceptions.  */
      42  extern void fn5 (void);
      43  extern void fn7 (void);
      44  extern void fn9 (void);
      45  
      46  void
      47  clh (void *arg)
      48  {
      49    int val = (long int) arg;
      50  
      51    printf ("clh (%d)\n", val);
      52  
      53    global *= val;
      54    global += val;
      55  }
      56  
      57  
      58  static __attribute__((noinline)) void
      59  fn_read (void)
      60  {
      61    int r = pthread_barrier_wait (&b2);
      62    if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
      63      {
      64        printf ("%s: barrier_wait failed\n", __FUNCTION__);
      65        exit (1);
      66      }
      67  
      68    char c;
      69    xread (fds[0], &c, 1);
      70  }
      71  
      72  
      73  __attribute__((noinline)) void
      74  fn0 (void)
      75  {
      76    pthread_cleanup_push (clh, (void *) 1l);
      77  
      78    fn_read ();
      79  
      80    pthread_cleanup_pop (1);
      81  }
      82  
      83  
      84  __attribute__((noinline)) void
      85  fn1 (void)
      86  {
      87    /* This is the old LinuxThreads pthread_cleanup_{push,pop}.  */
      88    struct _pthread_cleanup_buffer b;
      89    _pthread_cleanup_push (&b, clh, (void *) 2l);
      90  
      91    fn0 ();
      92  
      93    _pthread_cleanup_pop (&b, 1);
      94  }
      95  
      96  
      97  static __attribute__((noinline)) void
      98  fn2 (void)
      99  {
     100    pthread_cleanup_push (clh, (void *) 3l);
     101  
     102    fn1 ();
     103  
     104    pthread_cleanup_pop (1);
     105  }
     106  
     107  
     108  static void *
     109  tf (void *a)
     110  {
     111    switch ((long) a)
     112      {
     113      case 0:
     114        fn2 ();
     115        break;
     116      case 1:
     117        fn5 ();
     118        break;
     119      case 2:
     120        fn7 ();
     121        break;
     122      case 3:
     123        fn9 ();
     124        break;
     125      }
     126  
     127    return NULL;
     128  }
     129  
     130  
     131  int
     132  do_test (void)
     133  {
     134    int result = 0;
     135  
     136    if (pipe (fds) != 0)
     137      {
     138        puts ("pipe failed");
     139        exit (1);
     140      }
     141  
     142    if (pthread_barrier_init (&b2, NULL, 2) != 0)
     143      {
     144        puts ("b2 init failed");
     145        exit (1);
     146      }
     147  
     148    const int expect[] =
     149      {
     150        15,	/* 1 2 3 */
     151        276,	/* 1 4 5 6 */
     152        120,	/* 1 7 8 */
     153        460	/* 1 2 9 10 */
     154      };
     155  
     156    long i;
     157    for (i = 0; i < 4; ++i)
     158      {
     159        global = 0;
     160  
     161        printf ("test %ld\n", i);
     162  
     163        pthread_t th;
     164        if (pthread_create (&th, NULL, tf, (void *) i) != 0)
     165  	{
     166  	  puts ("create failed");
     167  	  exit (1);
     168  	}
     169  
     170        int e = pthread_barrier_wait (&b2);
     171        if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
     172  	{
     173  	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
     174  	  exit (1);
     175  	}
     176  
     177        pthread_cancel (th);
     178  
     179        void *r;
     180        if ((e = pthread_join (th, &r)) != 0)
     181  	{
     182  	  printf ("join failed: %d\n", e);
     183  	  _exit (1);
     184  	}
     185  
     186        if (r != PTHREAD_CANCELED)
     187  	{
     188  	  puts ("thread not canceled");
     189  	  exit (1);
     190  	}
     191  
     192        if (global != expect[i])
     193  	{
     194  	  printf ("global = %d, expected %d\n", global, expect[i]);
     195  	  result = 1;
     196  	}
     197      }
     198  
     199    return result;
     200  }
     201  
     202  #define TEST_FUNCTION do_test ()
     203  #include "../test-skeleton.c"