1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2024 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // SimpleMutex_unittest:
7*8975f5c5SAndroid Build Coastguard Worker // Tests of the SimpleMutex class
8*8975f5c5SAndroid Build Coastguard Worker //
9*8975f5c5SAndroid Build Coastguard Worker
10*8975f5c5SAndroid Build Coastguard Worker #include <gtest/gtest.h>
11*8975f5c5SAndroid Build Coastguard Worker
12*8975f5c5SAndroid Build Coastguard Worker #include "common/SimpleMutex.h"
13*8975f5c5SAndroid Build Coastguard Worker
14*8975f5c5SAndroid Build Coastguard Worker namespace angle
15*8975f5c5SAndroid Build Coastguard Worker {
16*8975f5c5SAndroid Build Coastguard Worker namespace
17*8975f5c5SAndroid Build Coastguard Worker {
18*8975f5c5SAndroid Build Coastguard Worker template <typename TestMutex>
runBasicMutexTest()19*8975f5c5SAndroid Build Coastguard Worker bool runBasicMutexTest()
20*8975f5c5SAndroid Build Coastguard Worker {
21*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kThreadCount = 16;
22*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kIterationCount = 50'000;
23*8975f5c5SAndroid Build Coastguard Worker
24*8975f5c5SAndroid Build Coastguard Worker std::array<std::thread, kThreadCount> threads;
25*8975f5c5SAndroid Build Coastguard Worker
26*8975f5c5SAndroid Build Coastguard Worker std::mutex mutex;
27*8975f5c5SAndroid Build Coastguard Worker std::condition_variable condVar;
28*8975f5c5SAndroid Build Coastguard Worker size_t readyCount = 0;
29*8975f5c5SAndroid Build Coastguard Worker
30*8975f5c5SAndroid Build Coastguard Worker TestMutex testMutex;
31*8975f5c5SAndroid Build Coastguard Worker std::atomic<size_t> testVar;
32*8975f5c5SAndroid Build Coastguard Worker
33*8975f5c5SAndroid Build Coastguard Worker for (size_t i = 0; i < kThreadCount; ++i)
34*8975f5c5SAndroid Build Coastguard Worker {
35*8975f5c5SAndroid Build Coastguard Worker threads[i] = std::thread([&]() {
36*8975f5c5SAndroid Build Coastguard Worker // Wait for all threads to start, so the following loop is as simultaneously executed as
37*8975f5c5SAndroid Build Coastguard Worker // possible.
38*8975f5c5SAndroid Build Coastguard Worker {
39*8975f5c5SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lock(mutex);
40*8975f5c5SAndroid Build Coastguard Worker ++readyCount;
41*8975f5c5SAndroid Build Coastguard Worker if (readyCount < kThreadCount)
42*8975f5c5SAndroid Build Coastguard Worker {
43*8975f5c5SAndroid Build Coastguard Worker condVar.wait(lock, [&]() { return readyCount == kThreadCount; });
44*8975f5c5SAndroid Build Coastguard Worker }
45*8975f5c5SAndroid Build Coastguard Worker else
46*8975f5c5SAndroid Build Coastguard Worker {
47*8975f5c5SAndroid Build Coastguard Worker condVar.notify_all();
48*8975f5c5SAndroid Build Coastguard Worker }
49*8975f5c5SAndroid Build Coastguard Worker }
50*8975f5c5SAndroid Build Coastguard Worker for (size_t j = 0; j < kIterationCount; ++j)
51*8975f5c5SAndroid Build Coastguard Worker {
52*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<TestMutex> lock(testMutex);
53*8975f5c5SAndroid Build Coastguard Worker const int local = testVar.load(std::memory_order_relaxed);
54*8975f5c5SAndroid Build Coastguard Worker const int newValue = local + 1;
55*8975f5c5SAndroid Build Coastguard Worker testVar.store(newValue, std::memory_order_relaxed);
56*8975f5c5SAndroid Build Coastguard Worker }
57*8975f5c5SAndroid Build Coastguard Worker });
58*8975f5c5SAndroid Build Coastguard Worker }
59*8975f5c5SAndroid Build Coastguard Worker
60*8975f5c5SAndroid Build Coastguard Worker for (size_t i = 0; i < kThreadCount; ++i)
61*8975f5c5SAndroid Build Coastguard Worker {
62*8975f5c5SAndroid Build Coastguard Worker threads[i].join();
63*8975f5c5SAndroid Build Coastguard Worker }
64*8975f5c5SAndroid Build Coastguard Worker
65*8975f5c5SAndroid Build Coastguard Worker const bool passed = testVar.load() == kThreadCount * kIterationCount;
66*8975f5c5SAndroid Build Coastguard Worker return passed;
67*8975f5c5SAndroid Build Coastguard Worker }
68*8975f5c5SAndroid Build Coastguard Worker } // anonymous namespace
69*8975f5c5SAndroid Build Coastguard Worker
70*8975f5c5SAndroid Build Coastguard Worker // Tests basic usage of std::mutex.
TEST(MutexTest,BasicStdMutex)71*8975f5c5SAndroid Build Coastguard Worker TEST(MutexTest, BasicStdMutex)
72*8975f5c5SAndroid Build Coastguard Worker {
73*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(runBasicMutexTest<std::mutex>());
74*8975f5c5SAndroid Build Coastguard Worker }
75*8975f5c5SAndroid Build Coastguard Worker
76*8975f5c5SAndroid Build Coastguard Worker // Tests basic usage of angle::SimpleMutex.
TEST(MutexTest,BasicSimpleMutex)77*8975f5c5SAndroid Build Coastguard Worker TEST(MutexTest, BasicSimpleMutex)
78*8975f5c5SAndroid Build Coastguard Worker {
79*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(runBasicMutexTest<SimpleMutex>());
80*8975f5c5SAndroid Build Coastguard Worker }
81*8975f5c5SAndroid Build Coastguard Worker
82*8975f5c5SAndroid Build Coastguard Worker // Tests failure with NoOpMutex. Disabled because it can and will flake.
TEST(MutexTest,DISABLED_BasicNoOpMutex)83*8975f5c5SAndroid Build Coastguard Worker TEST(MutexTest, DISABLED_BasicNoOpMutex)
84*8975f5c5SAndroid Build Coastguard Worker {
85*8975f5c5SAndroid Build Coastguard Worker // Technically not _guaranteed_ to calculate the wrong value, but highly likely to do so.
86*8975f5c5SAndroid Build Coastguard Worker EXPECT_FALSE(runBasicMutexTest<NoOpMutex>());
87*8975f5c5SAndroid Build Coastguard Worker }
88*8975f5c5SAndroid Build Coastguard Worker } // namespace angle
89