(root)/
glibc-2.38/
sysdeps/
pthread/
tst-cancel18.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 <stdio.h>
      21  #include <stdlib.h>
      22  #include <time.h>
      23  #include <unistd.h>
      24  
      25  
      26  static pthread_barrier_t b;
      27  
      28  
      29  /* Cleanup handling test.  */
      30  static int cl_called;
      31  
      32  static void
      33  cl (void *arg)
      34  {
      35    ++cl_called;
      36  }
      37  
      38  
      39  static void *
      40  tf (void *arg)
      41  {
      42    int r = pthread_barrier_wait (&b);
      43    if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
      44      {
      45        puts ("barrier_wait failed");
      46        exit (1);
      47      }
      48  
      49    pthread_cleanup_push (cl, NULL);
      50  
      51    struct timespec ts = { .tv_sec = arg == NULL ? 10000000 : 0, .tv_nsec = 0 };
      52    TEMP_FAILURE_RETRY (clock_nanosleep (CLOCK_REALTIME, 0, &ts, &ts));
      53  
      54    pthread_cleanup_pop (0);
      55  
      56    puts ("clock_nanosleep returned");
      57  
      58    exit (1);
      59  }
      60  
      61  
      62  static int
      63  do_test (void)
      64  {
      65    if (pthread_barrier_init (&b, NULL, 2) != 0)
      66      {
      67        puts ("barrier_init failed");
      68        return 1;
      69      }
      70  
      71    pthread_t th;
      72    if (pthread_create (&th, NULL, tf, NULL) != 0)
      73      {
      74        puts ("1st create failed");
      75        return 1;
      76      }
      77  
      78    int r = pthread_barrier_wait (&b);
      79    if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
      80      {
      81        puts ("barrier_wait failed");
      82        exit (1);
      83      }
      84  
      85    struct timespec  ts = { .tv_sec = 0, .tv_nsec = 100000000 };
      86    while (nanosleep (&ts, &ts) != 0)
      87      continue;
      88  
      89    puts ("going to cancel in-time");
      90    if (pthread_cancel (th) != 0)
      91      {
      92        puts ("1st cancel failed");
      93        return 1;
      94      }
      95  
      96    void *status;
      97    if (pthread_join (th, &status) != 0)
      98      {
      99        puts ("1st join failed");
     100        return 1;
     101      }
     102    if (status != PTHREAD_CANCELED)
     103      {
     104        puts ("1st thread not canceled");
     105        return 1;
     106      }
     107  
     108    if (cl_called == 0)
     109      {
     110        puts ("cleanup handler not called");
     111        return 1;
     112      }
     113    if (cl_called > 1)
     114      {
     115        puts ("cleanup handler called more than once");
     116        return 1;
     117      }
     118  
     119    puts ("in-time cancellation succeeded");
     120  
     121  
     122    cl_called = 0;
     123  
     124    if (pthread_create (&th, NULL, tf, NULL) != 0)
     125      {
     126        puts ("2nd create failed");
     127        return 1;
     128      }
     129  
     130    puts ("going to cancel early");
     131    if (pthread_cancel (th) != 0)
     132      {
     133        puts ("2nd cancel failed");
     134        return 1;
     135      }
     136  
     137    r = pthread_barrier_wait (&b);
     138    if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
     139      {
     140        puts ("barrier_wait failed");
     141        exit (1);
     142      }
     143  
     144    if (pthread_join (th, &status) != 0)
     145      {
     146        puts ("2nd join failed");
     147        return 1;
     148      }
     149    if (status != PTHREAD_CANCELED)
     150      {
     151        puts ("2nd thread not canceled");
     152        return 1;
     153      }
     154  
     155    if (cl_called == 0)
     156      {
     157        printf ("cleanup handler not called\n");
     158        return 1;
     159      }
     160    if (cl_called > 1)
     161      {
     162        printf ("cleanup handler called more than once\n");
     163        return 1;
     164      }
     165  
     166    puts ("early cancellation succeeded");
     167  
     168    return 0;
     169  }
     170  
     171  #define TEST_FUNCTION do_test ()
     172  #include "../test-skeleton.c"