// // Copyright 2023 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // GlobalMutex_unittest: // Tests of the Scoped<*>GlobalMutexLock classes // #include #include "libANGLE/GlobalMutex.h" namespace { template void runBasicGlobalMutexTest(bool expectToPass, Args &&...args) { constexpr size_t kThreadCount = 16; constexpr size_t kIterationCount = 50'000; std::array threads; std::mutex mutex; std::condition_variable condVar; size_t readyCount = 0; std::atomic testVar; for (size_t i = 0; i < kThreadCount; ++i) { threads[i] = std::thread([&]() { { std::unique_lock lock(mutex); ++readyCount; if (readyCount < kThreadCount) { condVar.wait(lock, [&]() { return readyCount == kThreadCount; }); } else { condVar.notify_all(); } } for (size_t j = 0; j < kIterationCount; ++j) { ScopedGlobalLockT lock(std::forward(args)...); const int local = testVar.load(std::memory_order_relaxed); const int newValue = local + 1; testVar.store(newValue, std::memory_order_relaxed); } }); } for (size_t i = 0; i < kThreadCount; ++i) { threads[i].join(); } if (expectToPass) { EXPECT_EQ(testVar.load(), kThreadCount * kIterationCount); } else { EXPECT_LE(testVar.load(), kThreadCount * kIterationCount); } } // Tests basic usage of ScopedGlobalEGLMutexLock. TEST(GlobalMutexTest, ScopedGlobalEGLMutexLock) { runBasicGlobalMutexTest(true); } // Tests basic usage of ScopedOptionalGlobalMutexLock (Enabled). TEST(GlobalMutexTest, ScopedOptionalGlobalMutexLockEnabled) { runBasicGlobalMutexTest(true, true); } // Tests basic usage of ScopedOptionalGlobalMutexLock (Disabled). TEST(GlobalMutexTest, ScopedOptionalGlobalMutexLockDisabled) { runBasicGlobalMutexTest(false, false); } #if defined(ANGLE_ENABLE_GLOBAL_MUTEX_RECURSION) // Tests that ScopedGlobalEGLMutexLock can be recursively locked. TEST(GlobalMutexTest, RecursiveScopedGlobalEGLMutexLock) { egl::ScopedGlobalEGLMutexLock lock; egl::ScopedGlobalEGLMutexLock lock2; } // Tests that ScopedOptionalGlobalMutexLock can be recursively locked. TEST(GlobalMutexTest, RecursiveScopedOptionalGlobalMutexLock) { egl::ScopedOptionalGlobalMutexLock lock(true); egl::ScopedOptionalGlobalMutexLock lock2(true); } #endif } // anonymous namespace