(root)/
glibc-2.38/
sysdeps/
pthread/
tst-cancel16.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 <string.h>
      23  #include <unistd.h>
      24  #include <sys/mman.h>
      25  #include <sys/wait.h>
      26  
      27  
      28  static pthread_barrier_t b2;
      29  static int fd;
      30  static int called;
      31  
      32  
      33  static void
      34  cl (void *arg)
      35  {
      36    called = 1;
      37  }
      38  
      39  
      40  static void *
      41  tf (void *arg)
      42  {
      43    int r = pthread_barrier_wait (&b2);
      44    if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
      45      {
      46        puts ("child thread: barrier_wait failed");
      47        exit (1);
      48      }
      49  
      50    pthread_cleanup_push (cl, NULL);
      51  
      52    /* This call should never return.  */
      53    if (lockf (fd, F_LOCK, 0))
      54      {
      55        puts ("child thread: lockf failed");
      56        exit (1);
      57      }
      58  
      59    pthread_cleanup_pop (0);
      60  
      61    return NULL;
      62  }
      63  
      64  
      65  static int
      66  do_test (void)
      67  {
      68    char fname[] = "/tmp/cancel16XXXXXX";
      69    fd = mkstemp (fname);
      70    if (fd == -1)
      71      {
      72        puts ("mkstemp failed");
      73        return 1;
      74      }
      75    unlink (fname);
      76  
      77    char mem[sizeof (pthread_barrier_t)];
      78    memset (mem, '\0', sizeof (mem));
      79    if (TEMP_FAILURE_RETRY (pwrite (fd, mem, sizeof (mem), 0)) != sizeof (mem))
      80      {
      81        puts ("pwrite failed");
      82        return 1;
      83      }
      84  
      85    void *p = mmap (NULL, sizeof (mem), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
      86    if (p == MAP_FAILED)
      87      {
      88        puts ("mmap failed");
      89        return 1;
      90      }
      91    pthread_barrier_t *b = (pthread_barrier_t *) p;
      92  
      93    pthread_barrierattr_t ba;
      94    if (pthread_barrierattr_init (&ba) != 0)
      95      {
      96        puts ("barrierattr_init failed");
      97        return 1;
      98      }
      99    if (pthread_barrierattr_setpshared (&ba, 1) != 0)
     100      {
     101        puts ("barrierattr_setshared failed");
     102        return 1;
     103      }
     104  
     105    if (pthread_barrier_init (b, &ba, 2) != 0)
     106      {
     107        puts ("1st barrier_init failed");
     108        return 1;
     109      }
     110    if (pthread_barrierattr_destroy (&ba) != 0)
     111      {
     112        puts ("barrier_destroy failed");
     113        return 1;
     114      }
     115  
     116    pid_t pid = fork ();
     117    if (pid == 0)
     118      {
     119        /* Child.  Lock the file and wait.  */
     120        if (lockf (fd, F_LOCK, 0) != 0)
     121  	{
     122  	  puts ("child process: lockf failed");
     123  	  _exit (1);
     124  	}
     125  
     126        int r = pthread_barrier_wait (b);
     127        if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
     128  	{
     129  	  puts ("child process: 1st barrier_wait failed");
     130  	  _exit (1);
     131  	}
     132  
     133        /* Make sure the process dies.  */
     134        alarm (5);
     135  
     136        r = pthread_barrier_wait (b);
     137        if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
     138  	{
     139  	  puts ("child process: 2nd barrier_wait failed");
     140  	  _exit (1);
     141  	}
     142  
     143        _exit (0);
     144      }
     145    if (pid == -1)
     146      {
     147        puts ("fork failed");
     148        return 1;
     149      }
     150  
     151    int r = pthread_barrier_wait (b);
     152    if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
     153      {
     154        puts ("main: 1st barrier_wait failed");
     155        _exit (1);
     156      }
     157  
     158    if (pthread_barrier_init (&b2, NULL, 2) != 0)
     159      {
     160        puts ("2nd barrier_init failed");
     161        return 1;
     162      }
     163  
     164    pthread_t th;
     165    if (pthread_create (&th, NULL, tf, NULL) != 0)
     166      {
     167        puts ("create failed");
     168        return 1;
     169      }
     170  
     171    r = pthread_barrier_wait (&b2);
     172    if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
     173      {
     174        puts ("main: 2nd barrier_wait failed");
     175        return 1;
     176      }
     177  
     178    /* Delay.  */
     179    sleep (1);
     180  
     181    if (pthread_cancel (th) != 0)
     182      {
     183        puts ("cancel failed");
     184        return 1;
     185      }
     186  
     187    void *result;
     188    if (pthread_join (th, &result) != 0)
     189      {
     190        puts ("join failed");
     191        return 1;
     192      }
     193    if (result != PTHREAD_CANCELED)
     194      {
     195        puts ("thread not canceled");
     196        return 1;
     197      }
     198    if (called == 0)
     199      {
     200        puts ("cleanup handler not called");
     201        return 1;
     202      }
     203  
     204    r = pthread_barrier_wait (b);
     205    if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
     206      {
     207        puts ("main: 3rd barrier_wait failed");
     208        return 1;
     209      }
     210  
     211    int status;
     212    if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
     213      {
     214        puts ("waitpid failed");
     215        return 1;
     216      }
     217    if (WEXITSTATUS (status) != 0)
     218      {
     219        printf ("child process exits with %d\n", WEXITSTATUS (status));
     220        return 1;
     221      }
     222  
     223    if (lockf (fd, F_LOCK, 0) != 0)
     224      {
     225        puts ("main: lockf failed");
     226        return 1;
     227      }
     228  
     229    return 0;
     230  }
     231  
     232  #define TEST_FUNCTION do_test ()
     233  #include "../test-skeleton.c"