summaryrefslogtreecommitdiff
path: root/cpp/test/IceUtil/thread/RWRecMutexTest.cpp
diff options
context:
space:
mode:
authorMatthew Newhook <matthew@zeroc.com>2002-04-18 17:30:42 +0000
committerMatthew Newhook <matthew@zeroc.com>2002-04-18 17:30:42 +0000
commita44de0d2616828e72e49532b4bd771a233683f84 (patch)
treec297bc1133ec1473c081b23d62eb76adbc4a4872 /cpp/test/IceUtil/thread/RWRecMutexTest.cpp
parentfix (diff)
downloadice-a44de0d2616828e72e49532b4bd771a233683f84.tar.bz2
ice-a44de0d2616828e72e49532b4bd771a233683f84.tar.xz
ice-a44de0d2616828e72e49532b4bd771a233683f84.zip
Added support for recursive write mutexes. Added read/write mutex upgrade.
Diffstat (limited to 'cpp/test/IceUtil/thread/RWRecMutexTest.cpp')
-rw-r--r--cpp/test/IceUtil/thread/RWRecMutexTest.cpp270
1 files changed, 265 insertions, 5 deletions
diff --git a/cpp/test/IceUtil/thread/RWRecMutexTest.cpp b/cpp/test/IceUtil/thread/RWRecMutexTest.cpp
index e36d0036a06..c6704341549 100644
--- a/cpp/test/IceUtil/thread/RWRecMutexTest.cpp
+++ b/cpp/test/IceUtil/thread/RWRecMutexTest.cpp
@@ -59,7 +59,8 @@ public:
{
}
- virtual void run()
+ virtual void
+ run()
{
try
{
@@ -78,6 +79,168 @@ public:
}
};
+class RWRecMutexReadTestThread2 : public RWRecMutexTestThread
+{
+public:
+
+ RWRecMutexReadTestThread2(RWRecMutex& m) :
+ RWRecMutexTestThread(m)
+ {
+ }
+
+ virtual void
+ run()
+ {
+ try
+ {
+ RWRecMutex::TryRLock lock(_mutex);
+ test(false);
+ }
+ catch(const LockedException&)
+ {
+ // Expected
+ }
+
+ _trylock = true;
+ _trylockCond.signal();
+
+ RWRecMutex::RLock lock(_mutex);
+ }
+};
+
+class RWRecMutexUpgradeReadThread : public Thread
+{
+public:
+
+ RWRecMutexUpgradeReadThread(RWRecMutex& m) :
+ _mutex(m),
+ _unlock(false),
+ _lock(false)
+ {
+ }
+ virtual void
+ run()
+ {
+ RWRecMutex::RLock lock(_mutex);
+
+ signalLock();
+ waitUnlock();
+ }
+
+ void
+ waitUnlock()
+ {
+ Mutex::Lock lock(_unlockMutex);
+ while (!_unlock)
+ {
+ _unlockCond.wait(lock);
+ }
+ }
+
+ void
+ signalUnlock()
+ {
+ Mutex::Lock lock(_unlockMutex);
+ _unlock = true;
+ _unlockCond.signal();
+ }
+
+ void
+ signalLock()
+ {
+ Mutex::Lock lock(_lockMutex);
+ _lock = true;
+ _lockCond.signal();
+ }
+
+ void
+ waitLock()
+ {
+ Mutex::Lock lock(_lockMutex);
+ while (!_lock)
+ {
+ _lockCond.wait(lock);
+ }
+ }
+
+private:
+
+ RWRecMutex& _mutex;
+
+ //
+ // Use native Condition variable here, not Monitor.
+ //
+ Cond _unlockCond;
+ Mutex _unlockMutex;
+ bool _unlock;
+
+ Cond _lockCond;
+ Mutex _lockMutex;
+ bool _lock;
+};
+typedef Handle<RWRecMutexUpgradeReadThread> RWRecMutexUpgradeReadThreadPtr;
+
+class RWRecMutexUpgradeTestThread : public Thread
+{
+public:
+
+ RWRecMutexUpgradeTestThread(RWRecMutex& m) :
+ _mutex(m),
+ _lock(false),
+ _upgradeAcquired(false)
+ {
+ }
+
+ virtual void
+ run()
+ {
+ RWRecMutex::RLock lock(_mutex);
+
+ signalLock();
+ lock.upgrade();
+
+ _upgradeAcquired = true;
+ }
+
+ void
+ signalLock()
+ {
+ Mutex::Lock lock(_lockMutex);
+ _lock = true;
+ _lockCond.signal();
+ }
+
+ void
+ waitLock()
+ {
+ Mutex::Lock lock(_lockMutex);
+ while (!_lock)
+ {
+ _lockCond.wait(lock);
+ }
+ }
+
+ bool
+ upgradeAcquired() const
+ {
+ return _upgradeAcquired;
+ }
+
+private:
+
+ RWRecMutex& _mutex;
+
+ //
+ // Use native Condition variable here, not Monitor.
+ //
+ Cond _lockCond;
+ Mutex _lockMutex;
+ bool _lock;
+
+ bool _upgradeAcquired;
+};
+typedef Handle<RWRecMutexUpgradeTestThread> RWRecMutexUpgradeTestThreadPtr;
+
class RWRecMutexWriteTestThread : public RWRecMutexTestThread
{
public:
@@ -87,7 +250,8 @@ public:
{
}
- virtual void run()
+ virtual void
+ run()
{
try
{
@@ -105,7 +269,6 @@ public:
RWRecMutex::WLock lock(_mutex);
}
};
-
typedef Handle<RWRecMutexTestThread> RWRecMutexTestThreadPtr;
RWRecMutexTest::RWRecMutexTest() :
@@ -162,11 +325,11 @@ RWRecMutexTest::run()
try
{
RWRecMutex::TryWLock wlock(mutex);
- test(false);
+ // Expected
}
catch(const LockedException&)
{
- // Expected
+ test(false);
}
}
@@ -238,4 +401,101 @@ RWRecMutexTest::run()
// acquire the mutex and then terminate.
//
control.join();
+
+ // TEST: Lock upgrading.
+ {
+ RWRecMutex::RLock rlock(mutex);
+
+ //
+ // Mutex now holds a write lock.
+ //
+ mutex.upgrade();
+
+ // Start thread that tries to acquire write lock
+ t = new RWRecMutexReadTestThread2(mutex);
+ control = t->start();
+
+ // TEST: Wait until the trylock has been tested. The thread is
+ // now waiting on a read lock.
+ t->waitTrylock();
+
+ // It's necessary for a small sleep here to ensure that the
+ // thread is actually waiting on a read lock.
+ ThreadControl::sleep(1000);
+ }
+
+ //
+ // TEST: Once the mutex has been released, the thread should
+ // acquire the mutex and then terminate.
+ //
+ control.join();
+
+ // TEST: Lock upgrading. This time a reader thread is started
+ // first.
+ {
+ RWRecMutexUpgradeReadThreadPtr t = new RWRecMutexUpgradeReadThread(mutex);
+ control = t->start();
+
+ // Wait for the thread to acquire the read lock.
+ t->waitLock();
+
+ // Spawn a thread to try acquiring the lock
+ RWRecMutexUpgradeTestThreadPtr t2 = new RWRecMutexUpgradeTestThread(mutex);
+ ThreadControl control2 = t2->start();
+ t2->waitLock();
+
+ //
+ // Small sleep to find out whether the thread actually
+ // terminates (which means that the write lock upgrade was
+ // mistakenly acquired).
+ //
+ ThreadControl::sleep(1000);
+
+ test(!t2->upgradeAcquired());
+
+ //
+ // A read lock at this point should fail.
+ //
+ try
+ {
+ RWRecMutex::TryRLock rlock2(mutex);
+ test(false);
+ }
+ catch(const LockedException&)
+ {
+ // Expected
+ }
+
+ //
+ // As should a write lock.
+ //
+ try
+ {
+ RWRecMutex::TryWLock rlock2(mutex);
+ test(false);
+ }
+ catch(const LockedException&)
+ {
+ // Expected
+ }
+
+ //
+ // Once the read lock is released then the upgrade should
+ // succeed & the thread should terminate.
+ //
+ t->signalUnlock();
+
+ control2.join();
+ control.join();
+
+ //
+ // Now both a read & write lock should be available.
+ //
+ {
+ RWRecMutex::WLock rlock2(mutex);
+ }
+ {
+ RWRecMutex::RLock rlock2(mutex);
+ }
+ }
}