From 827f9b0376971cf9eefd339a7c867e5687ddb09b Mon Sep 17 00:00:00 2001 From: yuzubot Date: Mon, 25 Nov 2019 13:01:29 +0000 Subject: [PATCH] "Merge Tagged PR 2365" --- src/core/hle/kernel/mutex.cpp | 31 ++++++++++++++++++++++++------- src/core/hle/kernel/mutex.h | 2 +- src/core/hle/kernel/svc.cpp | 8 +++++--- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 8493d0f78..abcc61075 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -7,6 +7,7 @@ #include "common/assert.h" #include "core/core.h" +#include "core/core_cpu.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -79,7 +80,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, // thread. ASSERT(requesting_thread == current_thread); - const u32 addr_value = Memory::Read32(address); + u32 addr_value = Memory::Read32(address); // If the mutex isn't being held, just return success. if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { @@ -90,6 +91,20 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, return ERR_INVALID_HANDLE; } + // This a workaround where an unknown bug writes the mutex value to give ownership to a cond var + // waiting thread. + if (holding_thread->GetStatus() == ThreadStatus::WaitCondVar) { + if (holding_thread->GetMutexWaitAddress() == address) { + Release(address, holding_thread.get()); + addr_value = Memory::Read32(address); + if (addr_value == 0) + return RESULT_SUCCESS; + else { + holding_thread = handle_table.Get(addr_value & Mutex::MutexOwnerMask); + } + } + } + // Wait until the mutex is released current_thread->SetMutexWaitAddress(address); current_thread->SetWaitHandle(requesting_thread_handle); @@ -105,15 +120,14 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, return RESULT_SUCCESS; } -ResultCode Mutex::Release(VAddr address) { +ResultCode Mutex::Release(VAddr address, Thread* holding_thread) { // The mutex address must be 4-byte aligned if ((address % sizeof(u32)) != 0) { return ERR_INVALID_ADDRESS; } - std::shared_ptr current_thread = - SharedFrom(system.CurrentScheduler().GetCurrentThread()); - auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(current_thread, address); + auto [thread, num_waiters] = + GetHighestPriorityMutexWaitingThread(SharedFrom(holding_thread), address); // There are no more threads waiting for the mutex, release it completely. if (thread == nullptr) { @@ -122,7 +136,7 @@ ResultCode Mutex::Release(VAddr address) { } // Transfer the ownership of the mutex from the previous owner to the new one. - TransferMutexOwnership(address, current_thread, thread); + TransferMutexOwnership(address, SharedFrom(holding_thread), thread); u32 mutex_value = thread->GetWaitHandle(); @@ -143,7 +157,10 @@ ResultCode Mutex::Release(VAddr address) { thread->SetWaitHandle(0); thread->SetWaitSynchronizationResult(RESULT_SUCCESS); - system.PrepareReschedule(); + if (thread->GetProcessorID() >= 0) + system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); + if (holding_thread->GetProcessorID() >= 0) + system.CpuCore(holding_thread->GetProcessorID()).PrepareReschedule(); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index b904de2e8..8cd990d9e 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -29,7 +29,7 @@ public: Handle requesting_thread_handle); /// Releases the mutex at the specified address. - ResultCode Release(VAddr address); + ResultCode Release(VAddr address, Thread* holding_thread); private: Core::System& system; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9928b3a26..8f8f39494 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -584,7 +584,8 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) { } auto* const current_process = system.Kernel().CurrentProcess(); - return current_process->GetMutex().Release(mutex_addr); + return current_process->GetMutex().Release(mutex_addr, + system.CurrentScheduler().GetCurrentThread()); } enum class BreakType : u32 { @@ -1621,12 +1622,13 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add std::shared_ptr thread = handle_table.Get(thread_handle); ASSERT(thread); - const auto release_result = current_process->GetMutex().Release(mutex_addr); + Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); + + const auto release_result = current_process->GetMutex().Release(mutex_addr, current_thread); if (release_result.IsError()) { return release_result; } - Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); current_thread->SetCondVarWaitAddress(condition_variable_addr); current_thread->SetMutexWaitAddress(mutex_addr); current_thread->SetWaitHandle(thread_handle);