diff options
author | bunnei <bunneidev@gmail.com> | 2018-01-01 20:02:26 +0100 |
---|---|---|
committer | bunnei <bunneidev@gmail.com> | 2018-01-01 20:02:26 +0100 |
commit | b9950cd4b0cf414ca97daa5f7578f4ca22b2669d (patch) | |
tree | 194c711f7f02e68e5137f3f7287dbd21ab834d5b /src/core/hle/kernel/mutex.cpp | |
parent | kernel: Add ObjectAddressTable class. (diff) | |
download | yuzu-b9950cd4b0cf414ca97daa5f7578f4ca22b2669d.tar yuzu-b9950cd4b0cf414ca97daa5f7578f4ca22b2669d.tar.gz yuzu-b9950cd4b0cf414ca97daa5f7578f4ca22b2669d.tar.bz2 yuzu-b9950cd4b0cf414ca97daa5f7578f4ca22b2669d.tar.lz yuzu-b9950cd4b0cf414ca97daa5f7578f4ca22b2669d.tar.xz yuzu-b9950cd4b0cf414ca97daa5f7578f4ca22b2669d.tar.zst yuzu-b9950cd4b0cf414ca97daa5f7578f4ca22b2669d.zip |
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
-rw-r--r-- | src/core/hle/kernel/mutex.cpp | 81 |
1 files changed, 63 insertions, 18 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 30dade552..1b7cda740 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -7,8 +7,10 @@ #include <boost/range/algorithm_ext/erase.hpp> #include "common/assert.h" #include "core/core.h" +#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/mutex.h" +#include "core/hle/kernel/object_address_table.h" #include "core/hle/kernel/thread.h" namespace Kernel { @@ -25,17 +27,25 @@ void ReleaseThreadMutexes(Thread* thread) { Mutex::Mutex() {} Mutex::~Mutex() {} -SharedPtr<Mutex> Mutex::Create(bool initial_locked, VAddr addr, std::string name) { +SharedPtr<Mutex> Mutex::Create(SharedPtr<Kernel::Thread> holding_thread, VAddr guest_addr, + std::string name) { SharedPtr<Mutex> mutex(new Mutex); mutex->lock_count = 0; - mutex->addr = addr; + mutex->guest_addr = guest_addr; mutex->name = std::move(name); mutex->holding_thread = nullptr; - // Acquire mutex with current thread if initialized as locked - if (initial_locked) - mutex->Acquire(GetCurrentThread()); + // If mutex was initialized with a holding thread, acquire it by the holding thread + if (holding_thread) { + mutex->Acquire(holding_thread.get()); + } + + // Mutexes are referenced by guest address, so track this in the kernel + g_object_address_table.Insert(guest_addr, mutex); + + // Verify that the created mutex matches the guest state for the mutex + mutex->VerifyGuestState(); return mutex; } @@ -53,38 +63,60 @@ void Mutex::Acquire(Thread* thread) { thread->held_mutexes.insert(this); holding_thread = thread; thread->UpdatePriority(); + UpdateGuestState(); Core::System::GetInstance().PrepareReschedule(); } lock_count++; } -void Mutex::Release() { - // Only release if the mutex is held - if (lock_count > 0) { - lock_count--; - - // Yield to the next thread only if we've fully released the mutex - if (lock_count == 0) { - holding_thread->held_mutexes.erase(this); - holding_thread->UpdatePriority(); - holding_thread = nullptr; - WakeupAllWaitingThreads(); - Core::System::GetInstance().PrepareReschedule(); +ResultCode Mutex::Release(Thread* thread) { + // We can only release the mutex if it's held by the calling thread. + if (thread != holding_thread) { + if (holding_thread) { + LOG_ERROR( + Kernel, + "Tried to release a mutex (owned by thread id %u) from a different thread id %u", + holding_thread->thread_id, thread->thread_id); } + // TODO(bunnei): Use correct error code + return ResultCode(-1); + } + + // Note: It should not be possible for the situation where the mutex has a holding thread with a + // zero lock count to occur. The real kernel still checks for this, so we do too. + if (lock_count <= 0) { + // TODO(bunnei): Use correct error code + return ResultCode(-1); + } + + lock_count--; + + // Yield to the next thread only if we've fully released the mutex + if (lock_count == 0) { + holding_thread->held_mutexes.erase(this); + holding_thread->UpdatePriority(); + holding_thread = nullptr; + WakeupAllWaitingThreads(); + UpdateGuestState(); + Core::System::GetInstance().PrepareReschedule(); } + + return RESULT_SUCCESS; } void Mutex::AddWaitingThread(SharedPtr<Thread> thread) { WaitObject::AddWaitingThread(thread); thread->pending_mutexes.insert(this); UpdatePriority(); + UpdateGuestState(); } void Mutex::RemoveWaitingThread(Thread* thread) { WaitObject::RemoveWaitingThread(thread); thread->pending_mutexes.erase(this); UpdatePriority(); + UpdateGuestState(); } void Mutex::UpdatePriority() { @@ -103,4 +135,17 @@ void Mutex::UpdatePriority() { } } -} // namespace +void Mutex::UpdateGuestState() { + GuestState guest_state{Memory::Read32(guest_addr)}; + guest_state.has_waiters.Assign(!GetWaitingThreads().empty()); + guest_state.holding_thread_handle.Assign(holding_thread ? holding_thread->guest_handle : 0); + Memory::Write32(guest_addr, guest_state.raw); +} + +void Mutex::VerifyGuestState() { + GuestState guest_state{Memory::Read32(guest_addr)}; + ASSERT(guest_state.has_waiters == !GetWaitingThreads().empty()); + ASSERT(guest_state.holding_thread_handle == holding_thread->guest_handle); +} + +} // namespace Kernel |