summaryrefslogtreecommitdiff
path: root/cpp/src/IceUtil/RWRecMutex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IceUtil/RWRecMutex.cpp')
-rw-r--r--cpp/src/IceUtil/RWRecMutex.cpp165
1 files changed, 165 insertions, 0 deletions
diff --git a/cpp/src/IceUtil/RWRecMutex.cpp b/cpp/src/IceUtil/RWRecMutex.cpp
new file mode 100644
index 00000000000..0137ca79668
--- /dev/null
+++ b/cpp/src/IceUtil/RWRecMutex.cpp
@@ -0,0 +1,165 @@
+// **********************************************************************
+//
+// Copyright (c) 2001
+// IONA Technologies, Inc.
+// Waltham, MA, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+#include <IceUtil/RWRecMutex.h>
+#include <IceUtil/Exception.h>
+
+#include <assert.h>
+
+IceUtil::RWRecMutex::RWRecMutex() :
+ _count(0),
+ _waitingWriters(0)
+{
+}
+
+IceUtil::RWRecMutex::~RWRecMutex()
+{
+}
+
+void
+IceUtil::RWRecMutex::readLock()
+{
+ Mutex::Lock lock(_mutex);
+
+ //
+ // Wait while a writer holds the lock or while writers are waiting
+ // to get the lock.
+ //
+ while (_count < 0 || _waitingWriters != 0)
+ {
+ _readers.wait(lock);
+ }
+ _count++;
+}
+
+void
+IceUtil::RWRecMutex::tryReadLock()
+{
+ Mutex::Lock lock(_mutex);
+
+ //
+ // Would block if a writer holds the lock or if writers are
+ // waiting to get the lock.
+ //
+ if (_count < 0 || _waitingWriters != 0)
+ {
+ throw LockedException(__FILE__, __LINE__);
+ }
+ _count++;
+}
+
+void
+IceUtil::RWRecMutex::writeLock()
+{
+ Mutex::Lock lock(_mutex);
+
+ //
+ // Wait for the lock to become available and increment the number
+ // of waiting writers.
+ //
+ while (_count != 0)
+ {
+ _waitingWriters++;
+ try
+ {
+ _writers.wait(lock);
+ }
+ catch(...)
+ {
+ --_waitingWriters;
+ throw;
+ }
+ _waitingWriters--;
+ }
+
+ //
+ // Got the lock, indicate it's held by a writer.
+ //
+ _count = -1;
+}
+
+void
+IceUtil::RWRecMutex::tryWriteLock()
+{
+ Mutex::Lock lock(_mutex);
+
+ //
+ // If there are readers or other writers then the call would block.
+ //
+ if (_count != 0)
+ {
+ throw LockedException(__FILE__, __LINE__);
+ }
+
+ //
+ // Got the lock, indicate it's held by a writer.
+ //
+ _count = -1;
+}
+
+void
+IceUtil::RWRecMutex::unlock()
+{
+ bool ww;
+ bool wr;
+ {
+ Mutex::Lock lock(_mutex);
+
+ assert(_count != 0);
+
+ //
+ // If _count < 0, the calling thread is a writer that holds the
+ // lock, so release the lock. Otherwise, _count is guaranteed to
+ // be > 0, so the calling thread is a reader releasing the lock.
+ //
+ if (_count < 0)
+ {
+ //
+ // Writer called unlock
+ //
+ _count = 0;
+ }
+ else
+ {
+ //
+ // Reader called unlock
+ //
+ --_count;
+ }
+
+ //
+ // Writers are waiting (ww) if _waitingWriters > 0. In that
+ // case, it's OK to let another writer into the region once there
+ // are no more readers (_count == 0). Otherwise, no writers are
+ // waiting but readers may be waiting (wr).
+ //
+ ww = (_waitingWriters != 0 && _count == 0);
+ wr = (_waitingWriters == 0);
+ }
+
+ //
+ // Wake up a waiting writer if there is one. If not, wake up all
+ // readers (just in case -- there may be none).
+ //
+ if (ww)
+ {
+ //
+ // Wake writer
+ //
+ _writers.signal();
+ }
+ else if (wr)
+ {
+ //
+ // Wake readers
+ //
+ _readers.broadcast();
+ }
+}