aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoryuzubot <yuzu@yuzu-emu.org>2019-11-26 13:01:20 +0000
committeryuzubot <yuzu@yuzu-emu.org>2019-11-26 13:01:20 +0000
commit70f3f49a530f1c296ca25dfc76055b23a4e564a0 (patch)
tree10e5baaa7f89a4b01920d887d816df47c60269c9 /src
parent71fb3ff3cd3bca9b97f2f778c52b89aea9bea00d (diff)
"Merge Tagged PR 2365"
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/mutex.cpp39
-rw-r--r--src/core/hle/kernel/mutex.h2
-rw-r--r--src/core/hle/kernel/svc.cpp8
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);