(root)/
glibc-2.38/
sysdeps/
pthread/
tst-rwlock-trywrlock-stall.c
       1  /* Bug 23844: Test for pthread_rwlock_trywrlock stalls.
       2     Copyright (C) 2019-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  /* For a full analysis see comments in tst-rwlock-tryrdlock-stall.c.
      20  
      21     Summary for the pthread_rwlock_trywrlock() stall:
      22  
      23     The stall is caused by pthread_rwlock_trywrlock setting
      24     __wrphase_futex futex to 1 and losing the
      25     PTHREAD_RWLOCK_FUTEX_USED bit.
      26  
      27     The fix for bug 23844 ensures that waiters on __wrphase_futex are
      28     correctly woken.  Before the fix the test stalls as readers can
      29     wait forever on  __wrphase_futex.  */
      30  
      31  #include <stdio.h>
      32  #include <stdlib.h>
      33  #include <unistd.h>
      34  #include <pthread.h>
      35  #include <support/xthread.h>
      36  #include <errno.h>
      37  
      38  /* We need only one lock to reproduce the issue. We will need multiple
      39     threads to get the exact case where we have a read, try, and unlock
      40     all interleaving to produce the case where the readers are waiting
      41     and the try clears the PTHREAD_RWLOCK_FUTEX_USED bit and a
      42     subsequent unlock fails to wake them.  */
      43  pthread_rwlock_t onelock;
      44  
      45  /* The number of threads is arbitrary but empirically chosen to have
      46     enough threads that we see the condition where waiting readers are
      47     not woken by a successful unlock.  */
      48  #define NTHREADS 32
      49  
      50  _Atomic int do_exit;
      51  
      52  void *
      53  run_loop (void *arg)
      54  {
      55    int i = 0, ret;
      56    while (!do_exit)
      57      {
      58        /* Arbitrarily choose if we are the writer or reader.  Choose a
      59  	 high enough ratio of readers to writers to make it likely
      60  	 that readers block (and eventually are susceptable to
      61  	 stalling).
      62  
      63           If we are a writer, take the write lock, and then unlock.
      64  	 If we are a reader, try the lock, then lock, then unlock.  */
      65        if ((i % 8) != 0)
      66  	{
      67  	  if ((ret = pthread_rwlock_trywrlock (&onelock)) != 0)
      68  	    {
      69  	      if (ret == EBUSY)
      70  		xpthread_rwlock_wrlock (&onelock);
      71  	      else
      72  		exit (EXIT_FAILURE);
      73  	    }
      74  	}
      75        else
      76  	xpthread_rwlock_rdlock (&onelock);
      77        /* Thread does some work and then unlocks.  */
      78        xpthread_rwlock_unlock (&onelock);
      79        i++;
      80      }
      81    return NULL;
      82  }
      83  
      84  int
      85  do_test (void)
      86  {
      87    int i;
      88    pthread_t tids[NTHREADS];
      89    xpthread_rwlock_init (&onelock, NULL);
      90    for (i = 0; i < NTHREADS; i++)
      91      tids[i] = xpthread_create (NULL, run_loop, NULL);
      92    /* Run for some amount of time.  The pthread_rwlock_tryrwlock stall
      93       is very easy to trigger and happens in seconds under the test
      94       conditions.  */
      95    sleep (10);
      96    /* Then exit.  */
      97    printf ("INFO: Exiting...\n");
      98    do_exit = 1;
      99    /* If any readers stalled then we will timeout waiting for them.  */
     100    for (i = 0; i < NTHREADS; i++)
     101      xpthread_join (tids[i]);
     102    printf ("INFO: Done.\n");
     103    xpthread_rwlock_destroy (&onelock);
     104    printf ("PASS: No pthread_rwlock_tryrwlock stalls detected.\n");
     105    return 0;
     106  }
     107  
     108  #include <support/test-driver.c>