From 31f88f98c97f5645c045aaca7de76dafe3e63aec Mon Sep 17 00:00:00 2001 From: Philippe Canal <pcanal@fnal.gov> Date: Fri, 20 Oct 2017 13:47:47 -0500 Subject: [PATCH] RWLock: handle case of writer meeting a nested reader. Prior to this update if a thread requested the write lock when another thread had two or more nested read lock take, the code would dead-lock --- core/thread/inc/ROOT/TReentrantRWLock.hxx | 8 ++++++++ core/thread/src/TReentrantRWLock.cxx | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/core/thread/inc/ROOT/TReentrantRWLock.hxx b/core/thread/inc/ROOT/TReentrantRWLock.hxx index 6f6a3879a6c..a616b8d9669 100644 --- a/core/thread/inc/ROOT/TReentrantRWLock.hxx +++ b/core/thread/inc/ROOT/TReentrantRWLock.hxx @@ -50,6 +50,10 @@ struct UniqueLockRecurseCount { template <typename MutexT> void DecrementReadCount(local_t &local, MutexT &) { DecrementReadCount(local); } + void ResetReadCount(local_t &local, int newvalue) { + local->fReadersCount = newvalue; + } + bool IsNotCurrentWriter(local_t &local) { return !local->fIsWriter; } void SetIsWriter(local_t &local) @@ -97,6 +101,10 @@ struct RecurseCounts { DecrementReadCount(local); } + void ResetReadCount(local_t &local, int newvalue) { + fReadersCount[local] = newvalue; + } + bool IsNotCurrentWriter(local_t &local) { return fWriterThread != local; } void SetIsWriter(local_t &local) diff --git a/core/thread/src/TReentrantRWLock.cxx b/core/thread/src/TReentrantRWLock.cxx index f04ab29c84b..457fd87b130 100644 --- a/core/thread/src/TReentrantRWLock.cxx +++ b/core/thread/src/TReentrantRWLock.cxx @@ -35,6 +35,7 @@ thus preventing starvation. #include "ROOT/TSpinMutex.hxx" #include "TMutex.h" #include "TError.h" +#include <assert.h> using namespace ROOT; @@ -75,7 +76,21 @@ void TReentrantRWLock<MutexT, RecurseCountsT>::ReadLock() std::unique_lock<MutexT> lock(fMutex); // Wait for writers, if any - if (fWriter && fRecurseCounts.IsNotCurrentWriter(local)) fCond.wait(lock, [this] { return !fWriter; }); + if (fWriter && fRecurseCounts.IsNotCurrentWriter(local)) { + auto readerCount = fRecurseCounts.GetLocalReadersCount(local); + if (readerCount == 0) + fCond.wait(lock, [this] { return !fWriter; }); + // else + // There is a writer **but** we have outstanding readers + // locks, this must mean that the writer is actually + // waiting on this thread to release its read locks. + // This can be done in only two ways: + // * request the writer lock + // * release the reader lock + // Either way, this thread needs to proceed to + // be able to reach a point whether it does one + // of the two. + } fRecurseCounts.IncrementReadCount(local); -- GitLab