Hash :
49317d73
Author :
Date :
2024-05-10T16:11:59
Prepare resource map for being potentially thread-safe Resource maps are used for both shared and context-private resources. Context-private resource maps do not need any locking. Once glBind* and similar commands are made free of the share group lock, the resource map of the corresponding type must be made thread safe, especially for look up. This change adds the ability to the resource map to be either thread safe or not, based on the type of the resource it contains. Currently, only a test type (unsigned int) is thread safe (used in unit tests). This is achieved by a combination of the following: - For resource maps that need a lock, the flat part of the map has an initially reasonable size, but is _never_ reallocated. This makes access to that part of the map lockfree. - The hash-map that contains large ids is always protected by a mutex. Follow up changes will start enabling thread-safety for resources as their corresponding glBind command is made lockless. Bug: angleproject:8667 Change-Id: Ia4ffffee41f021d833d31f296bc883bf12f1135f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5527771 Reviewed-by: Geoff Lang <geofflang@chromium.org> Reviewed-by: Charlie Lao <cclao@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
//
// Copyright 2024 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.
//
// SimpleMutex_unittest:
// Tests of the SimpleMutex class
//
#include <gtest/gtest.h>
#include "common/SimpleMutex.h"
namespace angle
{
namespace
{
template <typename TestMutex>
bool runBasicMutexTest()
{
constexpr size_t kThreadCount = 16;
constexpr size_t kIterationCount = 50'000;
std::array<std::thread, kThreadCount> threads;
std::mutex mutex;
std::condition_variable condVar;
size_t readyCount = 0;
TestMutex testMutex;
std::atomic<size_t> testVar;
for (size_t i = 0; i < kThreadCount; ++i)
{
threads[i] = std::thread([&]() {
// Wait for all threads to start, so the following loop is as simultaneously executed as
// possible.
{
std::unique_lock<std::mutex> lock(mutex);
++readyCount;
if (readyCount < kThreadCount)
{
condVar.wait(lock, [&]() { return readyCount == kThreadCount; });
}
else
{
condVar.notify_all();
}
}
for (size_t j = 0; j < kIterationCount; ++j)
{
std::lock_guard<TestMutex> lock(testMutex);
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();
}
const bool passed = testVar.load() == kThreadCount * kIterationCount;
return passed;
}
} // anonymous namespace
// Tests basic usage of std::mutex.
TEST(MutexTest, BasicStdMutex)
{
EXPECT_TRUE(runBasicMutexTest<std::mutex>());
}
// Tests basic usage of angle::SimpleMutex.
TEST(MutexTest, BasicSimpleMutex)
{
EXPECT_TRUE(runBasicMutexTest<SimpleMutex>());
}
// Tests failure with NoOpMutex. Disabled because it can and will flake.
TEST(MutexTest, DISABLED_BasicNoOpMutex)
{
// Technically not _guaranteed_ to calculate the wrong value, but highly likely to do so.
EXPECT_FALSE(runBasicMutexTest<NoOpMutex>());
}
} // namespace angle