(root)/
glibc-2.38/
sysdeps/
pthread/
tst-join5.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  #include <support/check.h>
      26  #include <support/timespec.h>
      27  #include <support/xthread.h>
      28  #include <support/xtime.h>
      29  
      30  static void
      31  wait_code (void)
      32  {
      33    struct timespec ts = { .tv_sec = 0, .tv_nsec = 200000000 };
      34    while (nanosleep (&ts, &ts) < 0)
      35      ;
      36  }
      37  
      38  
      39  #ifdef WAIT_IN_CHILD
      40  static pthread_barrier_t b;
      41  #endif
      42  
      43  static int
      44  thread_join (pthread_t thread, void **retval)
      45  {
      46  #if defined USE_PTHREAD_TIMEDJOIN_NP
      47    const struct timespec ts = timespec_add (xclock_now (CLOCK_REALTIME),
      48                                             make_timespec (1000, 0));
      49    return pthread_timedjoin_np (thread, retval, &ts);
      50  #elif defined USE_PTHREAD_CLOCKJOIN_NP_REALTIME
      51    const struct timespec ts = timespec_add (xclock_now (CLOCK_REALTIME),
      52                                             make_timespec (1000, 0));
      53    return pthread_clockjoin_np (thread, retval, CLOCK_REALTIME, &ts);
      54  #elif defined USE_PTHREAD_CLOCKJOIN_NP_MONOTONIC
      55    const struct timespec ts = timespec_add (xclock_now (CLOCK_MONOTONIC),
      56                                             make_timespec (1000, 0));
      57    return pthread_clockjoin_np (thread, retval, CLOCK_MONOTONIC, &ts);
      58  #else
      59    return pthread_join (thread, retval);
      60  #endif
      61  }
      62  
      63  
      64  static void *
      65  tf1 (void *arg)
      66  {
      67  #ifdef WAIT_IN_CHILD
      68    xpthread_barrier_wait (&b);
      69  
      70    wait_code ();
      71  #endif
      72  
      73    thread_join ((pthread_t) arg, NULL);
      74  
      75    exit (42);
      76  }
      77  
      78  
      79  static void *
      80  tf2 (void *arg)
      81  {
      82  #ifdef WAIT_IN_CHILD
      83    xpthread_barrier_wait (&b);
      84  
      85    wait_code ();
      86  #endif
      87  
      88    thread_join ((pthread_t) arg, NULL);
      89  
      90    exit (43);
      91  }
      92  
      93  
      94  static int
      95  do_test (void)
      96  {
      97  #ifdef WAIT_IN_CHILD
      98    xpthread_barrier_init (&b, NULL, 2);
      99  #endif
     100  
     101    pthread_t th;
     102  
     103    int err = thread_join (pthread_self (), NULL);
     104    if (err == 0)
     105      {
     106        puts ("1st circular join succeeded");
     107        return 1;
     108      }
     109    if (err != EDEADLK)
     110      {
     111        printf ("1st circular join %d, not EDEADLK\n", err);
     112        return 1;
     113      }
     114  
     115    th = xpthread_create (NULL, tf1, (void *) pthread_self ());
     116  
     117  #ifndef WAIT_IN_CHILD
     118    wait_code ();
     119  #endif
     120  
     121    xpthread_cancel (th);
     122  
     123  #ifdef WAIT_IN_CHILD
     124    xpthread_barrier_wait (&b);
     125  #endif
     126  
     127    void *r;
     128    err = thread_join (th, &r);
     129    if (err != 0)
     130      {
     131        printf ("cannot join 1st thread: %d\n", err);
     132        return 1;
     133      }
     134    if (r != PTHREAD_CANCELED)
     135      {
     136        puts ("1st thread not canceled");
     137        return 1;
     138      }
     139  
     140    err = thread_join (pthread_self (), NULL);
     141    if (err == 0)
     142      {
     143        puts ("2nd circular join succeeded");
     144        return 1;
     145      }
     146    if (err != EDEADLK)
     147      {
     148        printf ("2nd circular join %d, not EDEADLK\n", err);
     149        return 1;
     150      }
     151  
     152    th = xpthread_create (NULL, tf2, (void *) pthread_self ());
     153  
     154  #ifndef WAIT_IN_CHILD
     155    wait_code ();
     156  #endif
     157  
     158    xpthread_cancel (th);
     159  
     160  #ifdef WAIT_IN_CHILD
     161    xpthread_barrier_wait (&b);
     162  #endif
     163  
     164    if (thread_join (th, &r) != 0)
     165      {
     166        puts ("cannot join 2nd thread");
     167        return 1;
     168      }
     169    if (r != PTHREAD_CANCELED)
     170      {
     171        puts ("2nd thread not canceled");
     172        return 1;
     173      }
     174  
     175    err = thread_join (pthread_self (), NULL);
     176    if (err == 0)
     177      {
     178        puts ("3rd circular join succeeded");
     179        return 1;
     180      }
     181    if (err != EDEADLK)
     182      {
     183        printf ("3rd circular join %d, not EDEADLK\n", err);
     184        return 1;
     185      }
     186  
     187    return 0;
     188  }
     189  
     190  #include <support/test-driver.c>