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