(root)/
glibc-2.38/
sysdeps/
pthread/
tst-mutex5.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 <errno.h>
      19  #include <pthread.h>
      20  #include <stdio.h>
      21  #include <time.h>
      22  #include <unistd.h>
      23  #include <sys/time.h>
      24  #include <stdint.h>
      25  #include <config.h>
      26  #include <support/check.h>
      27  #include <support/timespec.h>
      28  #include <support/xthread.h>
      29  
      30  #ifdef ENABLE_PP
      31  #include "tst-tpp.h"
      32  #endif
      33  
      34  #ifndef TYPE
      35  # define TYPE PTHREAD_MUTEX_NORMAL
      36  #endif
      37  
      38  /* A bogus clock value that tells run_test to use
      39     pthread_mutex_timedlock rather than pthread_mutex_clocklock.  */
      40  #define CLOCK_USE_TIMEDLOCK (-1)
      41  
      42  static int
      43  do_test_clock (clockid_t clockid, const char *fnname, int tmo_result)
      44  {
      45    pthread_mutex_t m;
      46    pthread_mutexattr_t a;
      47    const clockid_t clockid_for_get =
      48      (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
      49  
      50    TEST_COMPARE (pthread_mutexattr_init (&a), 0);
      51    TEST_COMPARE (pthread_mutexattr_settype (&a, TYPE), 0);
      52  
      53  #if defined ENABLE_PI
      54    TEST_COMPARE (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT), 0);
      55  #elif defined ENABLE_PP
      56    TEST_COMPARE (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_PROTECT), 0);
      57    TEST_COMPARE (pthread_mutexattr_setprioceiling (&a, 6), 0);
      58  #endif
      59  
      60    int err = pthread_mutex_init (&m, &a);
      61    if (err != 0)
      62      {
      63  #ifdef ENABLE_PI
      64        if (err == ENOTSUP)
      65          FAIL_UNSUPPORTED ("PI mutexes unsupported");
      66  #endif
      67        FAIL_EXIT1 ("mutex_init failed");
      68      }
      69  
      70    TEST_COMPARE (pthread_mutexattr_destroy (&a), 0);
      71    TEST_COMPARE (pthread_mutex_lock (&m), 0);
      72    if (pthread_mutex_trylock (&m) == 0)
      73      FAIL_EXIT1 ("mutex_trylock succeeded");
      74  
      75    /* Wait 2 seconds.  */
      76    struct timespec ts_timeout = timespec_add (xclock_now (clockid_for_get),
      77                                               make_timespec (2, 0));
      78  
      79    if (clockid == CLOCK_USE_TIMEDLOCK)
      80      TEST_COMPARE (pthread_mutex_timedlock (&m, &ts_timeout), tmo_result);
      81    else
      82      TEST_COMPARE (pthread_mutex_clocklock (&m, clockid, &ts_timeout),
      83  		  tmo_result);
      84    if (tmo_result == ETIMEDOUT)
      85      TEST_TIMESPEC_BEFORE_NOW (ts_timeout, clockid_for_get);
      86  
      87    /* The following makes the ts value invalid.  */
      88    ts_timeout.tv_nsec += 1000000000;
      89  
      90    if (clockid == CLOCK_USE_TIMEDLOCK)
      91      TEST_COMPARE (pthread_mutex_timedlock (&m, &ts_timeout), EINVAL);
      92    else
      93      TEST_COMPARE (pthread_mutex_clocklock (&m, clockid, &ts_timeout), EINVAL);
      94    TEST_COMPARE (pthread_mutex_unlock (&m), 0);
      95  
      96    const struct timespec ts_start = xclock_now (CLOCK_REALTIME);
      97  
      98    /* Wait 2 seconds.  */
      99    ts_timeout = timespec_add (ts_start, make_timespec (2, 0));
     100  
     101    if (clockid == CLOCK_USE_TIMEDLOCK)
     102      TEST_COMPARE (pthread_mutex_timedlock (&m, &ts_timeout), 0);
     103    else
     104      TEST_COMPARE (pthread_mutex_clocklock (&m, clockid, &ts_timeout), 0);
     105  
     106    const struct timespec ts_end = xclock_now (clockid_for_get);
     107  
     108    /* Check that timedlock didn't delay.  We use a limit of 0.1 secs.  */
     109    TEST_TIMESPEC_BEFORE (ts_end,
     110                          timespec_add (ts_start, make_timespec (0, 100000000)));
     111  
     112    TEST_COMPARE (pthread_mutex_unlock (&m), 0);
     113    TEST_COMPARE (pthread_mutex_destroy (&m), 0);
     114  
     115    return 0;
     116  }
     117  
     118  static int do_test (void)
     119  {
     120  #ifdef ENABLE_PP
     121    init_tpp_test ();
     122  #endif
     123  
     124    int monotonic_result =
     125  #ifdef ENABLE_PI
     126      support_mutex_pi_monotonic () ? ETIMEDOUT : EINVAL;
     127  #else
     128      ETIMEDOUT;
     129  #endif
     130  
     131    do_test_clock (CLOCK_USE_TIMEDLOCK, "timedlock", ETIMEDOUT);
     132    do_test_clock (CLOCK_REALTIME, "clocklock(realtime)", ETIMEDOUT);
     133    do_test_clock (CLOCK_MONOTONIC, "clocklock(monotonic)", monotonic_result);
     134    return 0;
     135  }
     136  
     137  #include <support/test-driver.c>