diff options
author | yuzubot <yuzu@yuzu-emu.org> | 2019-11-26 13:01:20 +0000 |
---|---|---|
committer | yuzubot <yuzu@yuzu-emu.org> | 2019-11-26 13:01:20 +0000 |
commit | 70f3f49a530f1c296ca25dfc76055b23a4e564a0 (patch) | |
tree | 10e5baaa7f89a4b01920d887d816df47c60269c9 /src | |
parent | 71fb3ff3cd3bca9b97f2f778c52b89aea9bea00d (diff) |
"Merge Tagged PR 2365"
Diffstat (limited to 'src')
-rw-r--r-- | src/core/hle/kernel/mutex.cpp | 39 | ||||
-rw-r--r-- | src/core/hle/kernel/mutex.h | 2 | ||||
-rw-r--r-- | src/core/hle/kernel/svc.cpp | 8 |
3 files changed, 33 insertions, 16 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 8493d0f785..8223f3c9f9 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" @@ -23,7 +24,7 @@ namespace Kernel { /// Returns the number of threads that are waiting for a mutex, and the highest priority one among /// those. static std::pair<std::shared_ptr<Thread>, u32> GetHighestPriorityMutexWaitingThread( - const std::shared_ptr<Thread>& current_thread, VAddr mutex_addr) { + Thread* current_thread, VAddr mutex_addr) { std::shared_ptr<Thread> highest_priority_thread; u32 num_waiters = 0; @@ -45,16 +46,15 @@ static std::pair<std::shared_ptr<Thread>, u32> GetHighestPriorityMutexWaitingThr } /// Update the mutex owner field of all threads waiting on the mutex to point to the new owner. -static void TransferMutexOwnership(VAddr mutex_addr, std::shared_ptr<Thread> current_thread, - std::shared_ptr<Thread> new_owner) { +static void TransferMutexOwnership(VAddr mutex_addr, Thread* current_thread, Thread* new_owner) { const auto threads = current_thread->GetMutexWaitingThreads(); for (const auto& thread : threads) { if (thread->GetMutexWaitAddress() != mutex_addr) continue; - ASSERT(thread->GetLockOwner() == current_thread.get()); + ASSERT(thread->GetLockOwner() == current_thread); current_thread->RemoveMutexWaiter(thread); - if (new_owner != thread) + if (new_owner != thread.get()) new_owner->AddMutexWaiter(thread); } } @@ -79,7 +79,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 +90,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<Thread>(addr_value & Mutex::MutexOwnerMask); + } + } + } + // Wait until the mutex is released current_thread->SetMutexWaitAddress(address); current_thread->SetWaitHandle(requesting_thread_handle); @@ -105,15 +119,13 @@ 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<Thread> current_thread = - SharedFrom(system.CurrentScheduler().GetCurrentThread()); - auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(current_thread, address); + auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(holding_thread, address); // There are no more threads waiting for the mutex, release it completely. if (thread == nullptr) { @@ -122,7 +134,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, holding_thread, thread.get()); u32 mutex_value = thread->GetWaitHandle(); @@ -143,7 +155,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 b904de2e82..8cd990d9e6 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 9928b3a26d..8f8f39494e 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> thread = handle_table.Get<Thread>(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); |