(root)/
glibc-2.38/
nptl/
tst-rwlock7.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 <stdlib.h>
      21  #include <stdio.h>
      22  #include <string.h>
      23  #include <sys/time.h>
      24  #include <support/check.h>
      25  #include <support/timespec.h>
      26  #include <support/xthread.h>
      27  #include <support/xtime.h>
      28  
      29  
      30  /* A bogus clock value that tells run_test to use pthread_rwlock_timedrdlock
      31     and pthread_rwlock_timedwrlock rather than pthread_rwlock_clockrdlock and
      32     pthread_rwlock_clockwrlock.  */
      33  #define CLOCK_USE_TIMEDLOCK (-1)
      34  
      35  static int kind[] =
      36    {
      37      PTHREAD_RWLOCK_PREFER_READER_NP,
      38      PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,
      39      PTHREAD_RWLOCK_PREFER_WRITER_NP,
      40    };
      41  
      42  struct thread_args
      43  {
      44    pthread_rwlock_t *rwlock;
      45    clockid_t clockid;
      46    const char *fnname;
      47  };
      48  
      49  static void *
      50  tf (void *arg)
      51  {
      52    struct thread_args *args = arg;
      53    pthread_rwlock_t *r = args->rwlock;
      54    const clockid_t clockid = args->clockid;
      55    const clockid_t clockid_for_get =
      56      (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
      57    const char *fnname = args->fnname;
      58  
      59    /* Timeout: 0.3 secs.  */
      60    struct timespec ts_start;
      61    xclock_gettime (clockid_for_get, &ts_start);
      62    const struct timespec ts_timeout = timespec_add (ts_start,
      63                                                     make_timespec (0, 300000000));
      64  
      65    if (clockid == CLOCK_USE_TIMEDLOCK)
      66      TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_timeout), ETIMEDOUT);
      67    else
      68      TEST_COMPARE (pthread_rwlock_clockwrlock (r, clockid, &ts_timeout),
      69                    ETIMEDOUT);
      70    printf ("child: %swrlock failed with ETIMEDOUT", fnname);
      71  
      72    TEST_TIMESPEC_NOW_OR_AFTER (clockid_for_get, ts_timeout);
      73  
      74    struct timespec ts_invalid;
      75    xclock_gettime (clockid_for_get, &ts_invalid);
      76    ts_invalid.tv_sec += 10;
      77    /* Note that the following operation makes ts invalid.  */
      78    ts_invalid.tv_nsec += 1000000000;
      79  
      80    if (clockid == CLOCK_USE_TIMEDLOCK)
      81      TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_invalid), EINVAL);
      82    else
      83      TEST_COMPARE (pthread_rwlock_clockwrlock (r, clockid, &ts_invalid), EINVAL);
      84  
      85    printf ("child: %swrlock failed with EINVAL", fnname);
      86  
      87    return NULL;
      88  }
      89  
      90  
      91  static int
      92  do_test_clock (clockid_t clockid, const char *fnname)
      93  {
      94    const clockid_t clockid_for_get =
      95      (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
      96    size_t cnt;
      97    for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt)
      98      {
      99        pthread_rwlock_t r;
     100        pthread_rwlockattr_t a;
     101  
     102        if (pthread_rwlockattr_init (&a) != 0)
     103          FAIL_EXIT1 ("round %zu: rwlockattr_t failed\n", cnt);
     104  
     105        if (pthread_rwlockattr_setkind_np (&a, kind[cnt]) != 0)
     106          FAIL_EXIT1 ("round %zu: rwlockattr_setkind failed\n", cnt);
     107  
     108        if (pthread_rwlock_init (&r, &a) != 0)
     109          FAIL_EXIT1 ("round %zu: rwlock_init failed\n", cnt);
     110  
     111        if (pthread_rwlockattr_destroy (&a) != 0)
     112          FAIL_EXIT1 ("round %zu: rwlockattr_destroy failed\n", cnt);
     113  
     114        struct timespec ts;
     115        xclock_gettime (clockid_for_get, &ts);
     116  
     117        ++ts.tv_sec;
     118  
     119        /* Get a read lock.  */
     120        if (clockid == CLOCK_USE_TIMEDLOCK) {
     121          if (pthread_rwlock_timedrdlock (&r, &ts) != 0)
     122            FAIL_EXIT1 ("round %zu: rwlock_timedrdlock failed\n", cnt);
     123        } else {
     124          if (pthread_rwlock_clockrdlock (&r, clockid, &ts) != 0)
     125            FAIL_EXIT1 ("round %zu: rwlock_%srdlock failed\n", cnt, fnname);
     126        }
     127  
     128        printf ("%zu: got %srdlock\n", cnt, fnname);
     129  
     130        struct thread_args args;
     131        args.rwlock = &r;
     132        args.clockid = clockid;
     133        args.fnname = fnname;
     134        pthread_t th = xpthread_create (NULL, tf, &args);
     135        void *status = xpthread_join (th);
     136        if (status != NULL)
     137          FAIL_EXIT1 ("failure in round %zu\n", cnt);
     138  
     139        if (pthread_rwlock_destroy (&r) != 0)
     140          FAIL_EXIT1 ("round %zu: rwlock_destroy failed\n", cnt);
     141      }
     142  
     143    return 0;
     144  }
     145  
     146  static int
     147  do_test (void)
     148  {
     149    do_test_clock (CLOCK_USE_TIMEDLOCK, "timed");
     150    do_test_clock (CLOCK_MONOTONIC, "clock(monotonic)");
     151    do_test_clock (CLOCK_REALTIME, "clock(realtime)");
     152  
     153    return 0;
     154  }
     155  
     156  #include <support/test-driver.c>