(root)/
coreutils-9.4/
gnulib-tests/
test-pthread-cond.c
       1  /* Test of condition variables in multithreaded situations.
       2     Copyright (C) 2008-2023 Free Software Foundation, Inc.
       3  
       4     This program is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation, either version 3 of the License, or
       7     (at your option) any later version.
       8  
       9     This program 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
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <config.h>
      18  
      19  #if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
      20  
      21  /* Which tests to perform.
      22     Uncomment some of these, to verify that all tests crash if no locking
      23     is enabled.  */
      24  #define DO_TEST_COND 1
      25  #define DO_TEST_TIMEDCOND 1
      26  
      27  /* Whether to help the scheduler through explicit sched_yield().
      28     Uncomment this to see if the operating system has a fair scheduler.  */
      29  #define EXPLICIT_YIELD 1
      30  
      31  /* Whether to print debugging messages.  */
      32  #define ENABLE_DEBUGGING 0
      33  
      34  #include <pthread.h>
      35  #include <stdio.h>
      36  #include <stdlib.h>
      37  #include <string.h>
      38  #include <sys/time.h>
      39  
      40  #if EXPLICIT_YIELD
      41  # include <sched.h>
      42  #endif
      43  
      44  #if HAVE_DECL_ALARM
      45  # include <signal.h>
      46  # include <unistd.h>
      47  #endif
      48  
      49  #include "macros.h"
      50  
      51  #if ENABLE_DEBUGGING
      52  # define dbgprintf printf
      53  #else
      54  # define dbgprintf if (0) printf
      55  #endif
      56  
      57  #if EXPLICIT_YIELD
      58  # define yield() sched_yield ()
      59  #else
      60  # define yield()
      61  #endif
      62  
      63  
      64  /*
      65   * Condition check
      66   */
      67  static int cond_value = 0;
      68  static pthread_cond_t condtest;
      69  static pthread_mutex_t lockcond;
      70  
      71  static void *
      72  pthread_cond_wait_routine (void *arg)
      73  {
      74    ASSERT (pthread_mutex_lock (&lockcond) == 0);
      75    while (!cond_value)
      76      {
      77        ASSERT (pthread_cond_wait (&condtest, &lockcond) == 0);
      78      }
      79    ASSERT (pthread_mutex_unlock (&lockcond) == 0);
      80  
      81    cond_value = 2;
      82  
      83    return NULL;
      84  }
      85  
      86  static void
      87  test_pthread_cond_wait ()
      88  {
      89    struct timespec remain;
      90    pthread_t thread;
      91    int ret;
      92  
      93    remain.tv_sec = 2;
      94    remain.tv_nsec = 0;
      95  
      96    cond_value = 0;
      97  
      98    ASSERT (pthread_create (&thread, NULL, pthread_cond_wait_routine, NULL) == 0);
      99    do
     100      {
     101        yield ();
     102        ret = nanosleep (&remain, &remain);
     103        ASSERT (ret >= -1);
     104      }
     105    while (ret == -1 && (remain.tv_sec != 0 || remain.tv_nsec != 0));
     106  
     107    /* signal condition */
     108    ASSERT (pthread_mutex_lock (&lockcond) == 0);
     109    cond_value = 1;
     110    ASSERT (pthread_cond_signal (&condtest) == 0);
     111    ASSERT (pthread_mutex_unlock (&lockcond) == 0);
     112  
     113    ASSERT (pthread_join (thread, NULL) == 0);
     114  
     115    if (cond_value != 2)
     116      abort ();
     117  }
     118  
     119  
     120  /*
     121   * Timed Condition check
     122   */
     123  static int cond_timeout;
     124  
     125  static void
     126  get_ts (struct timespec *ts)
     127  {
     128    struct timeval now;
     129  
     130    gettimeofday (&now, NULL);
     131  
     132    ts->tv_sec = now.tv_sec + 1;
     133    ts->tv_nsec = now.tv_usec * 1000;
     134  }
     135  
     136  static void *
     137  pthread_cond_timedwait_routine (void *arg)
     138  {
     139    int ret;
     140    struct timespec ts;
     141  
     142    ASSERT (pthread_mutex_lock (&lockcond) == 0);
     143    while (!cond_value)
     144      {
     145        get_ts (&ts);
     146        ret = pthread_cond_timedwait (&condtest, &lockcond, &ts);
     147        if (ret == ETIMEDOUT)
     148          cond_timeout = 1;
     149      }
     150    ASSERT (pthread_mutex_unlock (&lockcond) == 0);
     151  
     152    return NULL;
     153  }
     154  
     155  static void
     156  test_pthread_cond_timedwait (void)
     157  {
     158    struct timespec remain;
     159    pthread_t thread;
     160    int ret;
     161  
     162    remain.tv_sec = 2;
     163    remain.tv_nsec = 0;
     164  
     165    cond_value = cond_timeout = 0;
     166  
     167    ASSERT (pthread_create (&thread, NULL, pthread_cond_timedwait_routine, NULL)
     168            == 0);
     169    do
     170      {
     171        yield ();
     172        ret = nanosleep (&remain, &remain);
     173        ASSERT (ret >= -1);
     174      }
     175    while (ret == -1 && (remain.tv_sec != 0 || remain.tv_nsec != 0));
     176  
     177    /* signal condition */
     178    ASSERT (pthread_mutex_lock (&lockcond) == 0);
     179    cond_value = 1;
     180    ASSERT (pthread_cond_signal (&condtest) == 0);
     181    ASSERT (pthread_mutex_unlock (&lockcond) == 0);
     182  
     183    ASSERT (pthread_join (thread, NULL) == 0);
     184  
     185    if (!cond_timeout)
     186      abort ();
     187  }
     188  
     189  int
     190  main ()
     191  {
     192  #if HAVE_DECL_ALARM
     193    /* Declare failure if test takes too long, by using default abort
     194       caused by SIGALRM.  */
     195    int alarm_value = 600;
     196    signal (SIGALRM, SIG_DFL);
     197    alarm (alarm_value);
     198  #endif
     199  
     200    ASSERT (pthread_cond_init (&condtest, NULL) == 0);
     201  
     202    {
     203      pthread_mutexattr_t attr;
     204  
     205      ASSERT (pthread_mutexattr_init (&attr) == 0);
     206      ASSERT (pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL) == 0);
     207      ASSERT (pthread_mutex_init (&lockcond, &attr) == 0);
     208      ASSERT (pthread_mutexattr_destroy (&attr) == 0);
     209    }
     210  
     211  #if DO_TEST_COND
     212    printf ("Starting test_pthread_cond_wait ..."); fflush (stdout);
     213    test_pthread_cond_wait ();
     214    printf (" OK\n"); fflush (stdout);
     215  #endif
     216  #if DO_TEST_TIMEDCOND
     217    printf ("Starting test_pthread_cond_timedwait ..."); fflush (stdout);
     218    test_pthread_cond_timedwait ();
     219    printf (" OK\n"); fflush (stdout);
     220  #endif
     221  
     222    return 0;
     223  }
     224  
     225  #else
     226  
     227  /* No multithreading available.  */
     228  
     229  #include <stdio.h>
     230  
     231  int
     232  main ()
     233  {
     234    fputs ("Skipping test: multithreading not enabled\n", stderr);
     235    return 77;
     236  }
     237  
     238  #endif