diff options
Diffstat (limited to 'src/threads/test/TestSharedSection.cpp')
-rw-r--r-- | src/threads/test/TestSharedSection.cpp | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/src/threads/test/TestSharedSection.cpp b/src/threads/test/TestSharedSection.cpp new file mode 100644 index 0000000000..13b1e2c1c8 --- /dev/null +++ b/src/threads/test/TestSharedSection.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "threads/SharedSection.h" +#include "threads/SingleLock.h" +#include "threads/Event.h" +#include "threads/Atomics.h" +#include "threads/test/TestHelpers.h" + +#include <stdio.h> + +//============================================================================= +// Helper classes +//============================================================================= + +template<class L> +class locker : public IRunnable +{ + CSharedSection& sec; + CEvent* wait; + + volatile long* mutex; +public: + volatile bool haslock; + volatile bool obtainedlock; + + inline locker(CSharedSection& o, volatile long* mutex_ = NULL, CEvent* wait_ = NULL) : + sec(o), wait(wait_), mutex(mutex_), haslock(false), obtainedlock(false) {} + + inline locker(CSharedSection& o, CEvent* wait_ = NULL) : + sec(o), wait(wait_), mutex(NULL), haslock(false), obtainedlock(false) {} + + void Run() + { + AtomicGuard g(mutex); + L lock(sec); + haslock = true; + obtainedlock = true; + if (wait) + wait->Wait(); + haslock = false; + } +}; + +TEST(TestCritSection, General) +{ + CCriticalSection sec; + + CSingleLock l1(sec); + CSingleLock l2(sec); +} + +TEST(TestSharedSection, General) +{ + CSharedSection sec; + + CSharedLock l1(sec); + CSharedLock l2(sec); +} + +TEST(TestSharedSection, GetSharedLockWhileTryingExclusiveLock) +{ + volatile long mutex = 0; + CEvent event; + + CSharedSection sec; + + CSharedLock l1(sec); // get a shared lock + + locker<CExclusiveLock> l2(sec,&mutex); + thread waitThread1(l2); // try to get an exclusive lock + + EXPECT_TRUE(waitForThread(mutex,1,10000)); + SleepMillis(10); // still need to give it a chance to move ahead + + EXPECT_TRUE(!l2.haslock); // this thread is waiting ... + EXPECT_TRUE(!l2.obtainedlock); // this thread is waiting ... + + // now try and get a SharedLock + locker<CSharedLock> l3(sec,&mutex,&event); + thread waitThread3(l3); // try to get a shared lock + EXPECT_TRUE(waitForThread(mutex,2,10000)); + SleepMillis(10); + EXPECT_TRUE(l3.haslock); + + event.Set(); + EXPECT_TRUE(waitThread3.timed_join(MILLIS(10000))); + + // l3 should have released. + EXPECT_TRUE(!l3.haslock); + + // but the exclusive lock should still not have happened + EXPECT_TRUE(!l2.haslock); // this thread is waiting ... + EXPECT_TRUE(!l2.obtainedlock); // this thread is waiting ... + + // let it go + l1.Leave(); // the last shared lock leaves. + + EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000))); + + EXPECT_TRUE(l2.obtainedlock); // the exclusive lock was captured + EXPECT_TRUE(!l2.haslock); // ... but it doesn't have it anymore +} + +TEST(TestSharedSection, TwoCase) +{ + CSharedSection sec; + + CEvent event; + volatile long mutex = 0; + + locker<CSharedLock> l1(sec,&mutex,&event); + + { + CSharedLock lock(sec); + thread waitThread1(l1); + + EXPECT_TRUE(waitForWaiters(event,1,10000)); + EXPECT_TRUE(l1.haslock); + + event.Set(); + + EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000))); + } + + locker<CSharedLock> l2(sec,&mutex,&event); + { + CExclusiveLock lock(sec); // get exclusive lock + thread waitThread2(l2); // thread should block + + EXPECT_TRUE(waitForThread(mutex,1,10000)); + SleepMillis(10); + + EXPECT_TRUE(!l2.haslock); + + lock.Leave(); + + EXPECT_TRUE(waitForWaiters(event,1,10000)); + SleepMillis(10); + EXPECT_TRUE(l2.haslock); + + event.Set(); + + EXPECT_TRUE(waitThread2.timed_join(MILLIS(10000))); + } +} + +TEST(TestMultipleSharedSection, General) +{ + CSharedSection sec; + + CEvent event; + volatile long mutex = 0; + + locker<CSharedLock> l1(sec,&mutex, &event); + + { + CSharedLock lock(sec); + thread waitThread1(l1); + + EXPECT_TRUE(waitForThread(mutex,1,10000)); + SleepMillis(10); + + EXPECT_TRUE(l1.haslock); + + event.Set(); + + EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000))); + } + + locker<CSharedLock> l2(sec,&mutex,&event); + locker<CSharedLock> l3(sec,&mutex,&event); + locker<CSharedLock> l4(sec,&mutex,&event); + locker<CSharedLock> l5(sec,&mutex,&event); + { + CExclusiveLock lock(sec); + thread waitThread1(l2); + thread waitThread2(l3); + thread waitThread3(l4); + thread waitThread4(l5); + + EXPECT_TRUE(waitForThread(mutex,4,10000)); + SleepMillis(10); + + EXPECT_TRUE(!l2.haslock); + EXPECT_TRUE(!l3.haslock); + EXPECT_TRUE(!l4.haslock); + EXPECT_TRUE(!l5.haslock); + + lock.Leave(); + + EXPECT_TRUE(waitForWaiters(event,4,10000)); + + EXPECT_TRUE(l2.haslock); + EXPECT_TRUE(l3.haslock); + EXPECT_TRUE(l4.haslock); + EXPECT_TRUE(l5.haslock); + + event.Set(); + + EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000))); + EXPECT_TRUE(waitThread2.timed_join(MILLIS(10000))); + EXPECT_TRUE(waitThread3.timed_join(MILLIS(10000))); + EXPECT_TRUE(waitThread4.timed_join(MILLIS(10000))); + } +} + |