about summary refs log tree commit diff
path: root/nptl/pthread_rwlock_timedwrlock.c
diff options
context:
space:
mode:
authorTorvald Riegel <triegel@redhat.com>2015-04-21 20:34:21 +0200
committerTorvald Riegel <triegel@redhat.com>2015-06-04 15:31:59 +0200
commit3c9c61febede148b79d8509e16588152d99b3774 (patch)
tree883d4c88b3ca19506e9449132bfe2c93b0798269 /nptl/pthread_rwlock_timedwrlock.c
parentda7f049cad943629f16cd6e533214955edfd511d (diff)
downloadglibc-3c9c61febede148b79d8509e16588152d99b3774.tar.gz
glibc-3c9c61febede148b79d8509e16588152d99b3774.tar.xz
glibc-3c9c61febede148b79d8509e16588152d99b3774.zip
Fix lost wake-up when pthread_rwlock_timedrwlock times out.
If we set up a rwlock to prefer writers (and disallow recursive rdlock
acquisitions), then readers will block for writers that are blocked to
acquire the lock (otherwise, readers could constantly enter and exit,
and the writer would never get the lock).  However, the existing
implementation did not wake such readers when the writer timed out.
This patch adds the missing wake-up.
There's no similar case for writers being blocked on readers.
Diffstat (limited to 'nptl/pthread_rwlock_timedwrlock.c')
-rw-r--r--nptl/pthread_rwlock_timedwrlock.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/nptl/pthread_rwlock_timedwrlock.c b/nptl/pthread_rwlock_timedwrlock.c
index 416f6e2bd5..a759fa997f 100644
--- a/nptl/pthread_rwlock_timedwrlock.c
+++ b/nptl/pthread_rwlock_timedwrlock.c
@@ -23,6 +23,7 @@
 #include <pthreadP.h>
 #include <sys/time.h>
 #include <kernel-features.h>
+#include <stdbool.h>
 
 
 /* Try to acquire write lock for RWLOCK or return after specfied time.	*/
@@ -32,6 +33,7 @@ pthread_rwlock_timedwrlock (rwlock, abstime)
      const struct timespec *abstime;
 {
   int result = 0;
+  bool wake_readers = false;
 
   /* Make sure we are alone.  */
   lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
@@ -136,6 +138,17 @@ pthread_rwlock_timedwrlock (rwlock, abstime)
       if (err == -ETIMEDOUT)
 	{
 	  result = ETIMEDOUT;
+	  /* If we prefer writers, it can have happened that readers blocked
+	     for us to acquire the lock first.  If we have timed out, we need
+	     to wake such readers if there are any, and if there is no writer
+	     currently (otherwise, the writer will take care of wake-up).  */
+	  if (!PTHREAD_RWLOCK_PREFER_READER_P (rwlock)
+	      && (rwlock->__data.__nr_readers_queued > 0)
+	      && (rwlock->__data.__writer == 0))
+	    {
+	      ++rwlock->__data.__readers_wakeup;
+	      wake_readers = true;
+	    }
 	  break;
 	}
     }
@@ -143,5 +156,10 @@ pthread_rwlock_timedwrlock (rwlock, abstime)
   /* We are done, free the lock.  */
   lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
 
+  /* Might be required after timeouts.  */
+  if (wake_readers)
+    lll_futex_wake (&rwlock->__data.__readers_wakeup, INT_MAX,
+	rwlock->__data.__shared);
+
   return result;
 }