xref: /aosp_15_r20/external/angle/src/libANGLE/GlobalMutex_unittest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2023 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // GlobalMutex_unittest:
7 //   Tests of the Scoped<*>GlobalMutexLock classes
8 //
9 
10 #include <gtest/gtest.h>
11 
12 #include "libANGLE/GlobalMutex.h"
13 
14 namespace
15 {
16 template <class ScopedGlobalLockT, class... Args>
runBasicGlobalMutexTest(bool expectToPass,Args &&...args)17 void runBasicGlobalMutexTest(bool expectToPass, Args &&...args)
18 {
19     constexpr size_t kThreadCount    = 16;
20     constexpr size_t kIterationCount = 50'000;
21 
22     std::array<std::thread, kThreadCount> threads;
23 
24     std::mutex mutex;
25     std::condition_variable condVar;
26     size_t readyCount = 0;
27 
28     std::atomic<size_t> testVar;
29 
30     for (size_t i = 0; i < kThreadCount; ++i)
31     {
32         threads[i] = std::thread([&]() {
33             {
34                 std::unique_lock<std::mutex> lock(mutex);
35                 ++readyCount;
36                 if (readyCount < kThreadCount)
37                 {
38                     condVar.wait(lock, [&]() { return readyCount == kThreadCount; });
39                 }
40                 else
41                 {
42                     condVar.notify_all();
43                 }
44             }
45             for (size_t j = 0; j < kIterationCount; ++j)
46             {
47                 ScopedGlobalLockT lock(std::forward<Args>(args)...);
48                 const int local    = testVar.load(std::memory_order_relaxed);
49                 const int newValue = local + 1;
50                 testVar.store(newValue, std::memory_order_relaxed);
51             }
52         });
53     }
54 
55     for (size_t i = 0; i < kThreadCount; ++i)
56     {
57         threads[i].join();
58     }
59 
60     if (expectToPass)
61     {
62         EXPECT_EQ(testVar.load(), kThreadCount * kIterationCount);
63     }
64     else
65     {
66         EXPECT_LE(testVar.load(), kThreadCount * kIterationCount);
67     }
68 }
69 
70 // Tests basic usage of ScopedGlobalEGLMutexLock.
TEST(GlobalMutexTest,ScopedGlobalEGLMutexLock)71 TEST(GlobalMutexTest, ScopedGlobalEGLMutexLock)
72 {
73     runBasicGlobalMutexTest<egl::ScopedGlobalEGLMutexLock>(true);
74 }
75 
76 // Tests basic usage of ScopedOptionalGlobalMutexLock (Enabled).
TEST(GlobalMutexTest,ScopedOptionalGlobalMutexLockEnabled)77 TEST(GlobalMutexTest, ScopedOptionalGlobalMutexLockEnabled)
78 {
79     runBasicGlobalMutexTest<egl::ScopedOptionalGlobalMutexLock>(true, true);
80 }
81 
82 // Tests basic usage of ScopedOptionalGlobalMutexLock (Disabled).
TEST(GlobalMutexTest,ScopedOptionalGlobalMutexLockDisabled)83 TEST(GlobalMutexTest, ScopedOptionalGlobalMutexLockDisabled)
84 {
85     runBasicGlobalMutexTest<egl::ScopedOptionalGlobalMutexLock>(false, false);
86 }
87 
88 #if defined(ANGLE_ENABLE_GLOBAL_MUTEX_RECURSION)
89 // Tests that ScopedGlobalEGLMutexLock can be recursively locked.
TEST(GlobalMutexTest,RecursiveScopedGlobalEGLMutexLock)90 TEST(GlobalMutexTest, RecursiveScopedGlobalEGLMutexLock)
91 {
92     egl::ScopedGlobalEGLMutexLock lock;
93     egl::ScopedGlobalEGLMutexLock lock2;
94 }
95 
96 // Tests that ScopedOptionalGlobalMutexLock can be recursively locked.
TEST(GlobalMutexTest,RecursiveScopedOptionalGlobalMutexLock)97 TEST(GlobalMutexTest, RecursiveScopedOptionalGlobalMutexLock)
98 {
99     egl::ScopedOptionalGlobalMutexLock lock(true);
100     egl::ScopedOptionalGlobalMutexLock lock2(true);
101 }
102 #endif
103 
104 }  // anonymous namespace
105