(root)/
glibc-2.38/
sysdeps/
pthread/
tst-once4.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 <time.h>
      22  #include <unistd.h>
      23  
      24  
      25  static pthread_once_t once = PTHREAD_ONCE_INIT;
      26  
      27  static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
      28  static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
      29  
      30  static pthread_barrier_t bar;
      31  
      32  static int global;
      33  static int cl_called;
      34  
      35  static void
      36  once_handler1 (void)
      37  {
      38    if (pthread_mutex_lock (&mut) != 0)
      39      {
      40        puts ("once_handler1: mutex_lock failed");
      41        exit (1);
      42      }
      43  
      44    int r = pthread_barrier_wait (&bar);
      45    if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
      46      {
      47        puts ("once_handler1: barrier_wait failed");
      48        exit (1);
      49      }
      50  
      51    pthread_cond_wait (&cond, &mut);
      52  
      53    /* We should never get here.  */
      54  }
      55  
      56  
      57  static void
      58  once_handler2 (void)
      59  {
      60    global = 1;
      61  }
      62  
      63  
      64  static void
      65  cl (void *arg)
      66  {
      67    ++cl_called;
      68  }
      69  
      70  
      71  static void *
      72  tf1 (void *arg)
      73  {
      74    pthread_cleanup_push (cl, NULL);
      75  
      76    pthread_once (&once, once_handler1);
      77  
      78    pthread_cleanup_pop (0);
      79  
      80    /* We should never get here.  */
      81    puts ("pthread_once in tf returned");
      82    exit (1);
      83  }
      84  
      85  
      86  static void *
      87  tf2 (void *arg)
      88  {
      89    pthread_cleanup_push (cl, NULL);
      90  
      91    int r = pthread_barrier_wait (&bar);
      92    if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
      93      {
      94        puts ("once_handler2: barrier_wait failed");
      95        exit (1);
      96      }
      97  
      98    pthread_cleanup_pop (0);
      99  
     100    pthread_once (&once, once_handler2);
     101  
     102    return NULL;
     103  }
     104  
     105  
     106  static int
     107  do_test (void)
     108  {
     109    pthread_t th[2];
     110  
     111    if (pthread_barrier_init (&bar, NULL, 2) != 0)
     112      {
     113        puts ("barrier_init failed");
     114        return 1;
     115      }
     116  
     117    if (pthread_create (&th[0], NULL, tf1, NULL) != 0)
     118      {
     119        puts ("first create failed");
     120        return 1;
     121      }
     122  
     123    int r = pthread_barrier_wait (&bar);
     124    if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
     125      {
     126        puts ("first barrier_wait failed");
     127        return 1;
     128      }
     129  
     130    if (pthread_mutex_lock (&mut) != 0)
     131      {
     132        puts ("mutex_lock failed");
     133        return 1;
     134      }
     135    /* We unlock the mutex so that we catch the case where the pthread_cond_wait
     136       call incorrectly resumes and tries to get the mutex.  */
     137    if (pthread_mutex_unlock (&mut) != 0)
     138      {
     139        puts ("mutex_unlock failed");
     140        return 1;
     141      }
     142  
     143    if (pthread_create (&th[1], NULL, tf2, NULL) != 0)
     144      {
     145        puts ("second create failed");
     146        return 1;
     147      }
     148  
     149    r = pthread_barrier_wait (&bar);
     150    if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
     151      {
     152        puts ("second barrier_wait failed");
     153        return 1;
     154      }
     155  
     156    /* Give the second thread a chance to reach the pthread_once call.  */
     157    sleep (2);
     158  
     159    /* Cancel the thread.  */
     160    if (pthread_cancel (th[0]) != 0)
     161      {
     162        puts ("cancel failed");
     163        return 1;
     164      }
     165  
     166    void *result;
     167    pthread_join (th[0], &result);
     168    if (result != PTHREAD_CANCELED)
     169      {
     170        puts ("first join didn't return PTHREAD_CANCELED");
     171        return 1;
     172      }
     173  
     174    puts ("joined first thread");
     175  
     176    pthread_join (th[1], &result);
     177    if (result != NULL)
     178      {
     179        puts ("second join didn't return PTHREAD_CANCELED");
     180        return 1;
     181      }
     182  
     183    if (global != 1)
     184      {
     185        puts ("global still 0");
     186        return 1;
     187      }
     188  
     189    if (cl_called != 1)
     190      {
     191        printf ("cl_called = %d\n", cl_called);
     192        return 1;
     193      }
     194  
     195    return 0;
     196  }
     197  
     198  #define TEST_FUNCTION do_test ()
     199  #include "../test-skeleton.c"