(root)/
glibc-2.38/
sysdeps/
pthread/
tst-cancel8.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 <stdio.h>
      20  #include <stdlib.h>
      21  #include <unistd.h>
      22  
      23  
      24  static pthread_barrier_t bar;
      25  
      26  static int global;
      27  
      28  
      29  static void
      30  cleanup (void *arg)
      31  {
      32    global = 1;
      33  }
      34  
      35  
      36  static void *
      37  tf (void *arg)
      38  {
      39    /* Enable cancellation, but defer it.  */
      40    if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0)
      41      {
      42        puts ("setcancelstate failed");
      43        exit (1);
      44      }
      45    if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0)
      46      {
      47        puts ("setcanceltype failed");
      48        exit (1);
      49      }
      50  
      51    /* Add cleanup handler.  */
      52    pthread_cleanup_push (cleanup, NULL);
      53  
      54    /* Synchronize with the main thread.  */
      55    int r = pthread_barrier_wait (&bar);
      56    if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
      57      {
      58        puts ("tf: first barrier_wait failed");
      59        exit (1);
      60      }
      61  
      62    /* And again.  Once this is done the main thread should have canceled
      63       this thread.  */
      64    r = pthread_barrier_wait (&bar);
      65    if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
      66      {
      67        puts ("tf: second barrier_wait failed");
      68        exit (1);
      69      }
      70  
      71    /* Remove the cleanup handler without executing it.  */
      72    pthread_cleanup_pop (0);
      73  
      74    /* Now react on the cancellation.  */
      75    pthread_testcancel ();
      76  
      77    /* This call should never return.  */
      78    return NULL;
      79  }
      80  
      81  
      82  static int
      83  do_test (void)
      84  {
      85    if (pthread_barrier_init (&bar, NULL, 2) != 0)
      86      {
      87        puts ("barrier_init failed");
      88        exit (1);
      89      }
      90  
      91    pthread_t th;
      92    if (pthread_create (&th, NULL, tf, NULL) != 0)
      93      {
      94        puts ("pthread_create failed");
      95        return 1;
      96      }
      97  
      98    int r = pthread_barrier_wait (&bar);
      99    if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
     100      {
     101        puts ("first barrier_wait failed");
     102        exit (1);
     103      }
     104  
     105    if (pthread_cancel (th) != 0)
     106      {
     107        puts ("pthread_cancel failed");
     108        return 1;
     109      }
     110  
     111    r = pthread_barrier_wait (&bar);
     112    if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
     113      {
     114        puts ("second barrier_wait failed");
     115        exit (1);
     116      }
     117  
     118    void *result;
     119    if (pthread_join (th, &result) != 0)
     120      {
     121        puts ("pthread_join failed");
     122        return 1;
     123      }
     124  
     125    if (result != PTHREAD_CANCELED)
     126      {
     127        puts ("thread was not canceled");
     128        exit (1);
     129      }
     130  
     131    if (global != 0)
     132      {
     133        puts ("cancellation handler has been called");
     134        exit (1);
     135      }
     136  
     137    return 0;
     138  }
     139  
     140  #define TEST_FUNCTION do_test ()
     141  #include "../test-skeleton.c"