Blame nptl/tst-rwlock-trywrlock-stall.c

Packit Bot bdf314
/* Bug 23844: Test for pthread_rwlock_trywrlock stalls.
Packit Bot bdf314
   Copyright (C) 2019 Free Software Foundation, Inc.
Packit Bot bdf314
   This file is part of the GNU C Library.
Packit Bot bdf314
Packit Bot bdf314
   The GNU C Library is free software; you can redistribute it and/or
Packit Bot bdf314
   modify it under the terms of the GNU Lesser General Public
Packit Bot bdf314
   License as published by the Free Software Foundation; either
Packit Bot bdf314
   version 2.1 of the License, or (at your option) any later version.
Packit Bot bdf314
Packit Bot bdf314
   The GNU C Library is distributed in the hope that it will be useful,
Packit Bot bdf314
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Bot bdf314
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Bot bdf314
   Lesser General Public License for more details.
Packit Bot bdf314
Packit Bot bdf314
   You should have received a copy of the GNU Lesser General Public
Packit Bot bdf314
   License along with the GNU C Library; if not, see
Packit Bot bdf314
   <http://www.gnu.org/licenses/>.  */
Packit Bot bdf314
Packit Bot bdf314
/* For a full analysis see comments in tst-rwlock-tryrdlock-stall.c.
Packit Bot bdf314
Packit Bot bdf314
   Summary for the pthread_rwlock_trywrlock() stall:
Packit Bot bdf314
Packit Bot bdf314
   The stall is caused by pthread_rwlock_trywrlock setting
Packit Bot bdf314
   __wrphase_futex futex to 1 and loosing the
Packit Bot bdf314
   PTHREAD_RWLOCK_FUTEX_USED bit.
Packit Bot bdf314
Packit Bot bdf314
   The fix for bug 23844 ensures that waiters on __wrphase_futex are
Packit Bot bdf314
   correctly woken.  Before the fix the test stalls as readers can
Packit Bot bdf314
   wait forever on  __wrphase_futex.  */
Packit Bot bdf314
Packit Bot bdf314
#include <stdio.h>
Packit Bot bdf314
#include <stdlib.h>
Packit Bot bdf314
#include <unistd.h>
Packit Bot bdf314
#include <pthread.h>
Packit Bot bdf314
#include <support/xthread.h>
Packit Bot bdf314
#include <errno.h>
Packit Bot bdf314
Packit Bot bdf314
/* We need only one lock to reproduce the issue. We will need multiple
Packit Bot bdf314
   threads to get the exact case where we have a read, try, and unlock
Packit Bot bdf314
   all interleaving to produce the case where the readers are waiting
Packit Bot bdf314
   and the try clears the PTHREAD_RWLOCK_FUTEX_USED bit and a
Packit Bot bdf314
   subsequent unlock fails to wake them.  */
Packit Bot bdf314
pthread_rwlock_t onelock;
Packit Bot bdf314
Packit Bot bdf314
/* The number of threads is arbitrary but empirically chosen to have
Packit Bot bdf314
   enough threads that we see the condition where waiting readers are
Packit Bot bdf314
   not woken by a successful unlock.  */
Packit Bot bdf314
#define NTHREADS 32
Packit Bot bdf314
Packit Bot bdf314
_Atomic int do_exit;
Packit Bot bdf314
Packit Bot bdf314
void *
Packit Bot bdf314
run_loop (void *arg)
Packit Bot bdf314
{
Packit Bot bdf314
  int i = 0, ret;
Packit Bot bdf314
  while (!do_exit)
Packit Bot bdf314
    {
Packit Bot bdf314
      /* Arbitrarily choose if we are the writer or reader.  Choose a
Packit Bot bdf314
	 high enough ratio of readers to writers to make it likely
Packit Bot bdf314
	 that readers block (and eventually are susceptable to
Packit Bot bdf314
	 stalling).
Packit Bot bdf314
Packit Bot bdf314
         If we are a writer, take the write lock, and then unlock.
Packit Bot bdf314
	 If we are a reader, try the lock, then lock, then unlock.  */
Packit Bot bdf314
      if ((i % 8) != 0)
Packit Bot bdf314
	{
Packit Bot bdf314
	  if ((ret = pthread_rwlock_trywrlock (&onelock)) != 0)
Packit Bot bdf314
	    {
Packit Bot bdf314
	      if (ret == EBUSY)
Packit Bot bdf314
		xpthread_rwlock_wrlock (&onelock);
Packit Bot bdf314
	      else
Packit Bot bdf314
		exit (EXIT_FAILURE);
Packit Bot bdf314
	    }
Packit Bot bdf314
	}
Packit Bot bdf314
      else
Packit Bot bdf314
	xpthread_rwlock_rdlock (&onelock);
Packit Bot bdf314
      /* Thread does some work and then unlocks.  */
Packit Bot bdf314
      xpthread_rwlock_unlock (&onelock);
Packit Bot bdf314
      i++;
Packit Bot bdf314
    }
Packit Bot bdf314
  return NULL;
Packit Bot bdf314
}
Packit Bot bdf314
Packit Bot bdf314
int
Packit Bot bdf314
do_test (void)
Packit Bot bdf314
{
Packit Bot bdf314
  int i;
Packit Bot bdf314
  pthread_t tids[NTHREADS];
Packit Bot bdf314
  xpthread_rwlock_init (&onelock, NULL);
Packit Bot bdf314
  for (i = 0; i < NTHREADS; i++)
Packit Bot bdf314
    tids[i] = xpthread_create (NULL, run_loop, NULL);
Packit Bot bdf314
  /* Run for some amount of time.  The pthread_rwlock_tryrwlock stall
Packit Bot bdf314
     is very easy to trigger and happens in seconds under the test
Packit Bot bdf314
     conditions.  */
Packit Bot bdf314
  sleep (10);
Packit Bot bdf314
  /* Then exit.  */
Packit Bot bdf314
  printf ("INFO: Exiting...\n");
Packit Bot bdf314
  do_exit = 1;
Packit Bot bdf314
  /* If any readers stalled then we will timeout waiting for them.  */
Packit Bot bdf314
  for (i = 0; i < NTHREADS; i++)
Packit Bot bdf314
    xpthread_join (tids[i]);
Packit Bot bdf314
  printf ("INFO: Done.\n");
Packit Bot bdf314
  xpthread_rwlock_destroy (&onelock);
Packit Bot bdf314
  printf ("PASS: No pthread_rwlock_tryrwlock stalls detected.\n");
Packit Bot bdf314
  return 0;
Packit Bot bdf314
}
Packit Bot bdf314
Packit Bot bdf314
#include <support/test-driver.c>