(root)/
glibc-2.38/
nptl/
tst-rwlock-pwn.c
       1  /* Test rwlock with PREFER_WRITER_NONRECURSIVE_NP (bug 23861).
       2     Copyright (C) 2018-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  #include <stdio.h>
      20  #include <stdlib.h>
      21  #include <unistd.h>
      22  #include <pthread.h>
      23  #include <support/xthread.h>
      24  
      25  /* We choose 10 iterations because this happens to be able to trigger the
      26     stall on contemporary hardware.  */
      27  #define LOOPS 10
      28  /* We need 3 threads to trigger bug 23861.  One thread as a writer, and
      29     two reader threads.  The test verifies that the second-to-last reader
      30     is able to notify the *last* reader that it should be done waiting.
      31     If the second-to-last reader fails to notify the last reader or does
      32     so incorrectly then the last reader may stall indefinitely.  */
      33  #define NTHREADS 3
      34  
      35  _Atomic int do_exit;
      36  pthread_rwlockattr_t mylock_attr;
      37  pthread_rwlock_t mylock;
      38  
      39  void *
      40  run_loop (void *a)
      41  {
      42    while (!do_exit)
      43      {
      44        if (random () & 1)
      45  	{
      46  	  xpthread_rwlock_wrlock (&mylock);
      47  	  xpthread_rwlock_unlock (&mylock);
      48  	}
      49        else
      50  	{
      51  	  xpthread_rwlock_rdlock (&mylock);
      52  	  xpthread_rwlock_unlock (&mylock);
      53  	}
      54      }
      55    return NULL;
      56  }
      57  
      58  int
      59  do_test (void)
      60  {
      61    xpthread_rwlockattr_init (&mylock_attr);
      62    xpthread_rwlockattr_setkind_np (&mylock_attr,
      63  				  PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
      64    xpthread_rwlock_init (&mylock, &mylock_attr);
      65  
      66    for (int n = 0; n < LOOPS; n++)
      67      {
      68        pthread_t tids[NTHREADS];
      69        do_exit = 0;
      70        for (int i = 0; i < NTHREADS; i++)
      71  	tids[i] = xpthread_create (NULL, run_loop, NULL);
      72        /* Let the threads run for some time.  */
      73        sleep (1);
      74        printf ("Exiting...");
      75        fflush (stdout);
      76        do_exit = 1;
      77        for (int i = 0; i < NTHREADS; i++)
      78  	xpthread_join (tids[i]);
      79        printf ("done.\n");
      80      }
      81    pthread_rwlock_destroy (&mylock);
      82    pthread_rwlockattr_destroy (&mylock_attr);
      83    return 0;
      84  }
      85  
      86  #define TIMEOUT (DEFAULT_TIMEOUT + 3 * LOOPS)
      87  #include <support/test-driver.c>