(root)/
glibc-2.38/
sysdeps/
pthread/
tst-cancel21.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 <errno.h>
      19  #include <pthread.h>
      20  #include <signal.h>
      21  #include <stdio.h>
      22  #include <stdlib.h>
      23  #include <sys/wait.h>
      24  #include <unistd.h>
      25  
      26  
      27  static int fd[4];
      28  static pthread_barrier_t b;
      29  volatile int in_sh_body;
      30  unsigned long cleanups;
      31  
      32  static void
      33  cl (void *arg)
      34  {
      35    cleanups = (cleanups << 4) | (long) arg;
      36  }
      37  
      38  
      39  static void __attribute__((noinline))
      40  sh_body (void)
      41  {
      42    char c;
      43  
      44    pthread_cleanup_push (cl, (void *) 1L);
      45  
      46    in_sh_body = 1;
      47    if (read (fd[2], &c, 1) == 1)
      48      {
      49        puts ("read succeeded");
      50        exit (1);
      51      }
      52  
      53    pthread_cleanup_pop (0);
      54  }
      55  
      56  
      57  static void
      58  sh (int sig)
      59  {
      60    pthread_cleanup_push (cl, (void *) 2L);
      61    sh_body ();
      62    in_sh_body = 0;
      63  
      64    pthread_cleanup_pop (0);
      65  }
      66  
      67  
      68  static void __attribute__((noinline))
      69  tf_body (void)
      70  {
      71    char c;
      72  
      73    pthread_cleanup_push (cl, (void *) 3L);
      74  
      75    int r = pthread_barrier_wait (&b);
      76    if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
      77      {
      78        puts ("child thread: barrier_wait failed");
      79        exit (1);
      80      }
      81  
      82    if (read (fd[0], &c, 1) == 1)
      83      {
      84        puts ("read succeeded");
      85        exit (1);
      86      }
      87  
      88    pthread_cleanup_pop (0);
      89  }
      90  
      91  
      92  static void *
      93  tf (void *arg)
      94  {
      95    pthread_t th = (pthread_t) arg;
      96  
      97    int r = pthread_barrier_wait (&b);
      98    if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
      99      {
     100        puts ("parent thread: barrier_wait failed");
     101        exit (1);
     102      }
     103  
     104    sleep (1);
     105  
     106    r = pthread_kill (th, SIGHUP);
     107    if (r)
     108      {
     109        errno = r;
     110        printf ("pthread_kill failed %m\n");
     111        exit (1);
     112      }
     113  
     114    while (in_sh_body == 0)
     115      sleep (1);
     116  
     117    if (pthread_cancel (th) != 0)
     118      {
     119        puts ("cancel failed");
     120        exit (1);
     121      }
     122  
     123    void *ret;
     124    if (pthread_join (th, &ret) != 0)
     125      {
     126        puts ("join failed");
     127        exit (1);
     128      }
     129  
     130    if (ret != PTHREAD_CANCELED)
     131      {
     132        puts ("result is wrong");
     133        exit (1);
     134      }
     135  
     136    if (cleanups != 0x1234L)
     137      {
     138        printf ("called cleanups %lx\n", cleanups);
     139        exit (1);
     140      }
     141  
     142    if (pthread_barrier_destroy (&b))
     143      {
     144        puts ("barrier destroy failed");
     145        exit (1);
     146      }
     147  
     148    /* The pipe closing must be issued after the cancellation handling to avoid
     149       a race condition where the cancellation runs after both pipe ends are
     150       closed.  In this case the read syscall returns EOF and the cancellation
     151       must not act.  */
     152    close (fd[0]);
     153    close (fd[1]);
     154    close (fd[2]);
     155    close (fd[3]);
     156  
     157    exit (0);
     158  }
     159  
     160  
     161  static int
     162  do_one_test (void)
     163  {
     164    in_sh_body = 0;
     165  
     166    pid_t pid = fork ();
     167  
     168    if (pid == -1)
     169      {
     170        printf ("fork failed: %m\n");
     171        return 1;
     172      }
     173  
     174    if (pid)
     175      {
     176        int status;
     177        if (waitpid (pid, &status, 0) < 0)
     178  	{
     179  	  printf ("waitpid failed %m\n");
     180  	  return 1;
     181  	}
     182  
     183        return !WIFEXITED (status) || WEXITSTATUS (status);
     184      }
     185  
     186    if (pthread_barrier_init (&b, NULL, 2) != 0)
     187      {
     188        puts ("barrier_init failed");
     189        exit (1);
     190      }
     191  
     192    cleanups = 0;
     193    if (pipe (fd) != 0 || pipe (fd + 2) != 0)
     194      {
     195        puts ("pipe failed");
     196        exit (1);
     197      }
     198  
     199    pthread_t th;
     200    if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
     201      {
     202        puts ("create failed");
     203        exit (1);
     204      }
     205  
     206    pthread_cleanup_push (cl, (void *) 4L);
     207    tf_body ();
     208    pthread_cleanup_pop (0);
     209    exit (1);
     210  }
     211  
     212  
     213  static int
     214  do_test (void)
     215  {
     216    stack_t ss;
     217    ss.ss_sp = malloc (2 * SIGSTKSZ);
     218    if (ss.ss_sp == NULL)
     219      {
     220        puts ("failed to allocate alternate stack");
     221        return 1;
     222      }
     223    ss.ss_flags = 0;
     224    ss.ss_size = 2 * SIGSTKSZ;
     225    if (sigaltstack (&ss, NULL) < 0)
     226      {
     227        printf ("sigaltstack failed %m\n");
     228        return 1;
     229      }
     230  
     231    struct sigaction sa;
     232    sa.sa_handler = sh;
     233    sigemptyset (&sa.sa_mask);
     234    sa.sa_flags = 0;
     235  
     236    if (sigaction (SIGHUP, &sa, NULL) != 0)
     237      {
     238        puts ("sigaction failed");
     239        return 1;
     240      }
     241  
     242    puts ("sa_flags = 0 test");
     243    if (do_one_test ())
     244      return 1;
     245  
     246    sa.sa_handler = sh;
     247    sigemptyset (&sa.sa_mask);
     248    sa.sa_flags = SA_ONSTACK;
     249  
     250    if (sigaction (SIGHUP, &sa, NULL) != 0)
     251      {
     252        puts ("sigaction failed");
     253        return 1;
     254      }
     255  
     256    puts ("sa_flags = SA_ONSTACK test");
     257    if (do_one_test ())
     258      return 1;
     259  
     260  #ifdef SA_SIGINFO
     261    sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
     262    sigemptyset (&sa.sa_mask);
     263    sa.sa_flags = SA_SIGINFO;
     264  
     265    if (sigaction (SIGHUP, &sa, NULL) != 0)
     266      {
     267        puts ("sigaction failed");
     268        return 1;
     269      }
     270  
     271    puts ("sa_flags = SA_SIGINFO test");
     272    if (do_one_test ())
     273      return 1;
     274  
     275    sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
     276    sigemptyset (&sa.sa_mask);
     277    sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
     278  
     279    if (sigaction (SIGHUP, &sa, NULL) != 0)
     280      {
     281        puts ("sigaction failed");
     282        return 1;
     283      }
     284  
     285    puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test");
     286    if (do_one_test ())
     287      return 1;
     288  #endif
     289  
     290    return 0;
     291  }
     292  
     293  #define TIMEOUT 40
     294  #define TEST_FUNCTION do_test ()
     295  #include "../test-skeleton.c"