(root)/
glibc-2.38/
nptl/
tst-rwlock9.c
       1  /* Test program for timedout read/write lock functions.
       2     Copyright (C) 2000-2023 Free Software Foundation, Inc.
       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 License as
       6     published by the Free Software Foundation; either version 2.1 of the
       7     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; see the file COPYING.LIB.  If
      16     not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <error.h>
      20  #include <pthread.h>
      21  #include <stdio.h>
      22  #include <stdlib.h>
      23  #include <time.h>
      24  #include <unistd.h>
      25  #include <sys/time.h>
      26  #include <support/check.h>
      27  #include <support/timespec.h>
      28  #include <support/xthread.h>
      29  
      30  
      31  #define NWRITERS 15
      32  #define WRITETRIES 10
      33  #define NREADERS 15
      34  #define READTRIES 15
      35  
      36  static const struct timespec timeout = { 0,1000000 };
      37  static const struct timespec delay = { 0, 1000000 };
      38  
      39  #ifndef KIND
      40  # define KIND PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
      41  #endif
      42  
      43  /* A bogus clock value that tells the tests to use pthread_rwlock_timedrdlock
      44     and pthread_rwlock_timedwrlock rather than pthread_rwlock_clockrdlock and
      45     pthread_rwlock_clockwrlock.  */
      46  #define CLOCK_USE_TIMEDLOCK (-1)
      47  
      48  static pthread_rwlock_t lock;
      49  
      50  struct thread_args
      51  {
      52    int nr;
      53    clockid_t clockid;
      54    const char *fnname;
      55  };
      56  
      57  static void *
      58  writer_thread (void *arg)
      59  {
      60    struct thread_args *args = arg;
      61    const int nr = args->nr;
      62    const clockid_t clockid = args->clockid;
      63    const clockid_t clockid_for_get =
      64      (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
      65    const char *fnname = args->fnname;
      66  
      67    struct timespec ts;
      68    int n;
      69  
      70    for (n = 0; n < WRITETRIES; ++n)
      71      {
      72        int e;
      73        do
      74  	{
      75  	  xclock_gettime (clockid_for_get, &ts);
      76  
      77            ts = timespec_add (ts, timeout);
      78            ts = timespec_add (ts, timeout);
      79  
      80  	  printf ("writer thread %d tries again\n", nr);
      81  
      82  	  e = (clockid == CLOCK_USE_TIMEDLOCK)
      83  	    ? pthread_rwlock_timedwrlock (&lock, &ts)
      84  	    : pthread_rwlock_clockwrlock (&lock, clockid, &ts);
      85  	  if (e != 0 && e != ETIMEDOUT)
      86              FAIL_EXIT1 ("%swrlock failed", fnname);
      87  	}
      88        while (e == ETIMEDOUT);
      89  
      90        printf ("writer thread %d succeeded\n", nr);
      91  
      92        nanosleep (&delay, NULL);
      93  
      94        if (pthread_rwlock_unlock (&lock) != 0)
      95          FAIL_EXIT1 ("unlock for writer failed");
      96  
      97        printf ("writer thread %d released\n", nr);
      98      }
      99  
     100    return NULL;
     101  }
     102  
     103  
     104  static void *
     105  reader_thread (void *arg)
     106  {
     107    struct thread_args *args = arg;
     108    const int nr = args->nr;
     109    const clockid_t clockid = args->clockid;
     110    const clockid_t clockid_for_get =
     111      (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
     112    const char *fnname = args->fnname;
     113  
     114    struct timespec ts;
     115    int n;
     116  
     117    for (n = 0; n < READTRIES; ++n)
     118      {
     119        int e;
     120        do
     121  	{
     122  	  xclock_gettime (clockid_for_get, &ts);
     123  
     124            ts = timespec_add (ts, timeout);
     125  
     126  	  printf ("reader thread %d tries again\n", nr);
     127  
     128  	  if (clockid == CLOCK_USE_TIMEDLOCK)
     129  	    e = pthread_rwlock_timedrdlock (&lock, &ts);
     130            else
     131  	    e = pthread_rwlock_clockrdlock (&lock, clockid, &ts);
     132  	  if (e != 0 && e != ETIMEDOUT)
     133              FAIL_EXIT1 ("%srdlock failed", fnname);
     134  	}
     135        while (e == ETIMEDOUT);
     136  
     137        printf ("reader thread %d succeeded\n", nr);
     138  
     139        nanosleep (&delay, NULL);
     140  
     141        if (pthread_rwlock_unlock (&lock) != 0)
     142          FAIL_EXIT1 ("unlock for reader failed");
     143  
     144        printf ("reader thread %d released\n", nr);
     145      }
     146  
     147    return NULL;
     148  }
     149  
     150  
     151  static int
     152  do_test_clock (clockid_t clockid, const char *fnname)
     153  {
     154    pthread_t thwr[NWRITERS];
     155    pthread_t thrd[NREADERS];
     156    int n;
     157    pthread_rwlockattr_t a;
     158  
     159    if (pthread_rwlockattr_init (&a) != 0)
     160      FAIL_EXIT1 ("rwlockattr_t failed");
     161  
     162    if (pthread_rwlockattr_setkind_np (&a, KIND) != 0)
     163      FAIL_EXIT1 ("rwlockattr_setkind failed");
     164  
     165    if (pthread_rwlock_init (&lock, &a) != 0)
     166      FAIL_EXIT1 ("rwlock_init failed");
     167  
     168    /* Make standard error the same as standard output.  */
     169    dup2 (1, 2);
     170  
     171    /* Make sure we see all message, even those on stdout.  */
     172    setvbuf (stdout, NULL, _IONBF, 0);
     173  
     174    struct thread_args wargs[NWRITERS];
     175    for (n = 0; n < NWRITERS; ++n) {
     176      wargs[n].nr = n;
     177      wargs[n].clockid = clockid;
     178      wargs[n].fnname = fnname;
     179      thwr[n] = xpthread_create (NULL, writer_thread, &wargs[n]);
     180    }
     181  
     182    struct thread_args rargs[NREADERS];
     183    for (n = 0; n < NREADERS; ++n) {
     184      rargs[n].nr = n;
     185      rargs[n].clockid = clockid;
     186      rargs[n].fnname = fnname;
     187      thrd[n] = xpthread_create (NULL, reader_thread, &rargs[n]);
     188    }
     189  
     190    /* Wait for all the threads.  */
     191    for (n = 0; n < NWRITERS; ++n)
     192      xpthread_join (thwr[n]);
     193    for (n = 0; n < NREADERS; ++n)
     194      xpthread_join (thrd[n]);
     195  
     196    return 0;
     197  }
     198  
     199  static int
     200  do_test (void)
     201  {
     202    do_test_clock (CLOCK_USE_TIMEDLOCK, "timed");
     203    do_test_clock (CLOCK_REALTIME, "clock(realtime)");
     204    do_test_clock (CLOCK_MONOTONIC, "clock(monotonic)");
     205  
     206    return 0;
     207  }
     208  
     209  #define TIMEOUT 30
     210  #include <support/test-driver.c>