diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/threads/test/TestSharedSection.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/threads/test/TestSharedSection.cpp')
-rw-r--r-- | xbmc/threads/test/TestSharedSection.cpp | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/xbmc/threads/test/TestSharedSection.cpp b/xbmc/threads/test/TestSharedSection.cpp new file mode 100644 index 0000000..fc2ca08 --- /dev/null +++ b/xbmc/threads/test/TestSharedSection.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "threads/Event.h" +#include "threads/IRunnable.h" +#include "threads/SharedSection.h" +#include "threads/test/TestHelpers.h" + +#include <mutex> +#include <shared_mutex> +#include <stdio.h> + +using namespace std::chrono_literals; + +//============================================================================= +// Helper classes +//============================================================================= + +template<class L> +class locker : public IRunnable +{ + CSharedSection& sec; + CEvent* wait; + + std::atomic<long>* mutex; +public: + volatile bool haslock; + volatile bool obtainedlock; + + inline locker(CSharedSection& o, std::atomic<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() override + { + AtomicGuard g(mutex); + L lock(sec); + haslock = true; + obtainedlock = true; + if (wait) + wait->Wait(); + haslock = false; + } +}; + +TEST(TestCritSection, General) +{ + CCriticalSection sec; + + std::unique_lock<CCriticalSection> l1(sec); + std::unique_lock<CCriticalSection> l2(sec); +} + +TEST(TestSharedSection, General) +{ + CSharedSection sec; + + std::shared_lock<CSharedSection> l1(sec); + std::shared_lock<CSharedSection> l2(sec); +} + +TEST(TestSharedSection, GetSharedLockWhileTryingExclusiveLock) +{ + std::atomic<long> mutex(0L); + CEvent event; + + CSharedSection sec; + + std::shared_lock<CSharedSection> l1(sec); // get a shared lock + + locker<std::unique_lock<CSharedSection>> l2(sec, &mutex); + thread waitThread1(l2); // try to get an exclusive lock + + EXPECT_TRUE(waitForThread(mutex, 1, 10000ms)); + std::this_thread::sleep_for(10ms); // 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<std::shared_lock<CSharedSection>> l3(sec, &mutex, &event); + thread waitThread3(l3); // try to get a shared lock + EXPECT_TRUE(waitForThread(mutex, 2, 10000ms)); + std::this_thread::sleep_for(10ms); + EXPECT_TRUE(l3.haslock); + + event.Set(); + EXPECT_TRUE(waitThread3.timed_join(10000ms)); + + // 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.unlock(); // the last shared lock leaves. + + EXPECT_TRUE(waitThread1.timed_join(10000ms)); + + 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; + std::atomic<long> mutex(0L); + + locker<std::shared_lock<CSharedSection>> l1(sec, &mutex, &event); + + { + std::shared_lock<CSharedSection> lock(sec); + thread waitThread1(l1); + + EXPECT_TRUE(waitForWaiters(event, 1, 10000ms)); + EXPECT_TRUE(l1.haslock); + + event.Set(); + + EXPECT_TRUE(waitThread1.timed_join(10000ms)); + } + + locker<std::shared_lock<CSharedSection>> l2(sec, &mutex, &event); + { + std::unique_lock<CSharedSection> lock(sec); // get exclusive lock + thread waitThread2(l2); // thread should block + + EXPECT_TRUE(waitForThread(mutex, 1, 10000ms)); + std::this_thread::sleep_for(10ms); + + EXPECT_TRUE(!l2.haslock); + + lock.unlock(); + + EXPECT_TRUE(waitForWaiters(event, 1, 10000ms)); + std::this_thread::sleep_for(10ms); + EXPECT_TRUE(l2.haslock); + + event.Set(); + + EXPECT_TRUE(waitThread2.timed_join(10000ms)); + } +} + +TEST(TestMultipleSharedSection, General) +{ + CSharedSection sec; + + CEvent event; + std::atomic<long> mutex(0L); + + locker<std::shared_lock<CSharedSection>> l1(sec, &mutex, &event); + + { + std::shared_lock<CSharedSection> lock(sec); + thread waitThread1(l1); + + EXPECT_TRUE(waitForThread(mutex, 1, 10000ms)); + std::this_thread::sleep_for(10ms); + + EXPECT_TRUE(l1.haslock); + + event.Set(); + + EXPECT_TRUE(waitThread1.timed_join(10000ms)); + } + + locker<std::shared_lock<CSharedSection>> l2(sec, &mutex, &event); + locker<std::shared_lock<CSharedSection>> l3(sec, &mutex, &event); + locker<std::shared_lock<CSharedSection>> l4(sec, &mutex, &event); + locker<std::shared_lock<CSharedSection>> l5(sec, &mutex, &event); + { + std::unique_lock<CSharedSection> lock(sec); + thread waitThread1(l2); + thread waitThread2(l3); + thread waitThread3(l4); + thread waitThread4(l5); + + EXPECT_TRUE(waitForThread(mutex, 4, 10000ms)); + std::this_thread::sleep_for(10ms); + + EXPECT_TRUE(!l2.haslock); + EXPECT_TRUE(!l3.haslock); + EXPECT_TRUE(!l4.haslock); + EXPECT_TRUE(!l5.haslock); + + lock.unlock(); + + EXPECT_TRUE(waitForWaiters(event, 4, 10000ms)); + + EXPECT_TRUE(l2.haslock); + EXPECT_TRUE(l3.haslock); + EXPECT_TRUE(l4.haslock); + EXPECT_TRUE(l5.haslock); + + event.Set(); + + EXPECT_TRUE(waitThread1.timed_join(10000ms)); + EXPECT_TRUE(waitThread2.timed_join(10000ms)); + EXPECT_TRUE(waitThread3.timed_join(10000ms)); + EXPECT_TRUE(waitThread4.timed_join(10000ms)); + } +} + |