fix(shader): lock recompiler shared mutexes once when created
winpthreads initializes a statically initialized rwlock on its first lock and fails a concurrent first lock with EINVAL, which std::shared_mutex ignores, so two threads can hold the lock at once. The source, binding plan and specialized module caches take their first locks from several threads, so their mutexes now take and release the lock in their constructor, as guest rwlocks do. The GuestWriteWatch mutex the technical debt entry also named is in the Linux-only watch, so it is not affected.
This commit is contained in:
parent
a11c8f7f70
commit
48dcaace78
|
|
@ -290,6 +290,14 @@ struct SourceEntry {
|
|||
|
||||
namespace {
|
||||
|
||||
class PrimedSharedMutex : public std::shared_mutex {
|
||||
public:
|
||||
PrimedSharedMutex() {
|
||||
lock();
|
||||
unlock();
|
||||
}
|
||||
};
|
||||
|
||||
struct ResourceProgram {
|
||||
explicit ResourceProgram(const RecompileRequest& request, ShaderPreparationContext* preparation = nullptr) : program(std::make_unique<IrProgram>(PrepareResourceProgram(request, preparation))), plan(std::make_shared<const IrResourcePlan>(ResourceMaterializer{}.ExtractPlan(*program))) {}
|
||||
|
||||
|
|
@ -318,7 +326,7 @@ bool FailureMemo() {
|
|||
}
|
||||
|
||||
std::shared_ptr<SourceEntry> getSource(const RecompileRequest& request, ShaderPreparationContext* preparation = nullptr) {
|
||||
static std::shared_mutex mutex;
|
||||
static PrimedSharedMutex mutex;
|
||||
// Entries whose code hashes alike share a bucket; the code comparison picks the right one.
|
||||
static std::unordered_map<std::vector<std::uint64_t>, std::vector<std::shared_ptr<SourceEntry>>, SourceKeyHash> sources;
|
||||
struct SourceKeyStorage {};
|
||||
|
|
@ -587,7 +595,7 @@ struct PreparedBindingPlan {
|
|||
std::once_flag ready;
|
||||
std::exception_ptr failure;
|
||||
DescriptorBindingPlan bindings;
|
||||
std::shared_mutex mutex;
|
||||
PrimedSharedMutex mutex;
|
||||
std::map<std::vector<std::uint32_t>, std::shared_ptr<PreparedModuleEntry>> modules;
|
||||
};
|
||||
|
||||
|
|
@ -618,7 +626,7 @@ std::shared_ptr<PreparedBindingPlan> preparedBindingPlan(const CompiledVariant&
|
|||
}
|
||||
key.push_back(exports.size());
|
||||
for (const auto mapping : exports) key.push_back(mapping);
|
||||
static std::shared_mutex mutex;
|
||||
static PrimedSharedMutex mutex;
|
||||
static std::map<std::vector<std::uint64_t>, std::shared_ptr<PreparedBindingPlan>> plans;
|
||||
std::shared_ptr<PreparedBindingPlan> plan;
|
||||
{
|
||||
|
|
@ -647,7 +655,7 @@ std::shared_ptr<const SpecializedModule> specializeModule(const CompiledShaderAr
|
|||
key.clear();
|
||||
key.push_back(artifact.variantId);
|
||||
for (const auto& constant : constants) key.push_back((static_cast<std::uint64_t>(constant.id) << 32u) | constant.value);
|
||||
static std::shared_mutex mutex;
|
||||
static PrimedSharedMutex mutex;
|
||||
static std::map<std::vector<std::uint64_t>, std::shared_ptr<SpecializedModuleEntry>> modules;
|
||||
std::shared_ptr<SpecializedModuleEntry> entry;
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
- libgcc_s_seh-1.dll
|
||||
- libstdc++-6.dll
|
||||
- libwinpthread-1.dll
|
||||
- winpthreads initializes a statically initialized rwlock on its first lock and fails a concurrent first lock with `EINVAL`, which `std::shared_mutex` and `std::shared_timed_mutex` ignore, so that lock does not exclude. Guest rwlocks ([Pthread.hpp](../../core/libs/prx/libkernel/Pthread/include/Pthread.hpp)) are locked once when created. The host `std::shared_mutex` objects in [Recompiler.cpp](../../core/shader/recompiler/Recompiler.cpp) and [GuestWriteWatch.cpp](../../core/libs/prx/libc/src/GuestWriteWatch.cpp) are not, and can still race on their first contended use.
|
||||
- winpthreads initializes a statically initialized rwlock on its first lock and fails a concurrent first lock with `EINVAL`, which `std::shared_mutex` and `std::shared_timed_mutex` ignore, so that lock does not exclude. Guest rwlocks ([Pthread.hpp](../../core/libs/prx/libkernel/Pthread/include/Pthread.hpp)) and the host `std::shared_mutex` objects in [Recompiler.cpp](../../core/shader/recompiler/Recompiler.cpp) are locked once when created. A new host `std::shared_mutex` used on Windows needs the same.
|
||||
|
||||
### Silent stubs
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue