(root)/
glibc-2.38/
nptl/
tst-pthread-timedlock-lockloop.c
       1  /* Make sure pthread_mutex_timedlock doesn't return spurious error codes.
       2  
       3     Copyright (C) 2020-2023 Free Software Foundation, Inc.
       4     This file is part of the GNU C Library.
       5  
       6     The GNU C Library is free software; you can redistribute it and/or
       7     modify it under the terms of the GNU Lesser General Public
       8     License as published by the Free Software Foundation; either
       9     version 2.1 of the License, or (at your option) any later version.
      10  
      11     The GNU C Library is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14     Lesser General Public License for more details.
      15  
      16     You should have received a copy of the GNU Lesser General Public
      17     License along with the GNU C Library; if not, see
      18     <https://www.gnu.org/licenses/>.  */
      19  
      20  #include <errno.h>
      21  #include <pthread.h>
      22  #include <signal.h>
      23  #include <stdio.h>
      24  #include <stdlib.h>
      25  #include <support/check.h>
      26  #include <support/timespec.h>
      27  #include <support/xsignal.h>
      28  #include <support/xthread.h>
      29  #include <support/xtime.h>
      30  #include <time.h>
      31  #include <unistd.h>
      32  
      33  #define NANO_PER_SEC 1000000000LL
      34  #define TIMEOUT (NANO_PER_SEC / 1000LL)
      35  #define NUM_THREADS 50
      36  #define RETEST_TIMES 100
      37  
      38  static pthread_mutex_t mutex;
      39  static int runs;
      40  static clockid_t clockid;
      41  
      42  static void
      43  signal_handler (int sig_num)
      44  {
      45    TEST_COMPARE (sig_num, SIGUSR1);
      46  }
      47  
      48  /* Call pthread_mutex_timedlock()/pthread_mutex_unlock() repetitively, hoping
      49     that one of them returns EAGAIN or EINTR unexpectedly.  */
      50  static void *
      51  worker_timedlock (void *arg)
      52  {
      53    for (unsigned int run = 0; run < runs; run++)
      54      {
      55        struct timespec abs_time = timespec_add (xclock_now (CLOCK_REALTIME),
      56  					       make_timespec (0, 1000000));
      57  
      58        int ret = pthread_mutex_timedlock (&mutex, &abs_time);
      59  
      60        if (ret == 0)
      61  	xpthread_mutex_unlock (&mutex);
      62  
      63        TEST_VERIFY_EXIT (ret == 0 || ret == ETIMEDOUT);
      64      }
      65    return NULL;
      66  }
      67  
      68  static void *
      69  worker_clocklock (void *arg)
      70  {
      71    for (unsigned int run = 0; run < runs; run++)
      72      {
      73        struct timespec time =
      74  	timespec_add (xclock_now (clockid), make_timespec (0, 1000000));
      75  
      76        int ret = pthread_mutex_clocklock (&mutex, clockid, &time);
      77  
      78        if (ret == 0)
      79  	xpthread_mutex_unlock (&mutex);
      80  
      81        TEST_VERIFY_EXIT (ret == 0 || ret == ETIMEDOUT);
      82      }
      83    return NULL;
      84  }
      85  
      86  static int
      87  run_test_set (void *(*worker) (void *))
      88  {
      89    pthread_t workers[NUM_THREADS];
      90  
      91    /* Check if default pthread_mutex_{timed,clock}lock with valid arguments
      92       returns either 0 or ETIMEDOUT.  Since there is no easy way to force
      93       the error condition, the test creates multiple threads which in turn
      94       issues pthread_mutex_timedlock multiple times.  */
      95    runs = 100;
      96    for (int run = 0; run < RETEST_TIMES; run++)
      97      {
      98        for (int i = 0; i < NUM_THREADS; i++)
      99  	workers[i] = xpthread_create (NULL, worker, NULL);
     100        for (int i = 0; i < NUM_THREADS; i++)
     101  	xpthread_join (workers[i]);
     102      }
     103  
     104    /* The idea is similar to previous tests, but we check if
     105       pthread_mutex_{timed,clock}lock does not return EINTR.  */
     106    pthread_t thread;
     107    runs = 1;
     108    for (int i = 0; i < RETEST_TIMES * 1000; i++)
     109      {
     110        xpthread_mutex_lock (&mutex);
     111        thread = xpthread_create (NULL, worker, NULL);
     112        /* Sleep just a little bit to reach the lock on the worker thread.  */
     113        usleep (10);
     114        pthread_kill (thread, SIGUSR1);
     115        xpthread_mutex_unlock (&mutex);
     116        xpthread_join (thread);
     117      }
     118  
     119    return 0;
     120  }
     121  
     122  static int
     123  do_test (void)
     124  {
     125  
     126    xsignal (SIGUSR1, signal_handler);
     127  
     128    xpthread_mutex_init (&mutex, NULL);
     129  
     130    run_test_set (worker_timedlock);
     131    clockid = CLOCK_REALTIME;
     132    run_test_set (worker_clocklock);
     133    clockid = CLOCK_MONOTONIC;
     134    run_test_set (worker_clocklock);
     135    return 0;
     136  }
     137  
     138  #include <support/test-driver.c>