summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/mutex.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2018-01-01 14:02:26 -0500
committerGravatar bunnei2018-01-01 14:02:26 -0500
commitb9950cd4b0cf414ca97daa5f7578f4ca22b2669d (patch)
tree194c711f7f02e68e5137f3f7287dbd21ab834d5b /src/core/hle/kernel/mutex.cpp
parentkernel: Add ObjectAddressTable class. (diff)
downloadyuzu-b9950cd4b0cf414ca97daa5f7578f4ca22b2669d.tar.gz
yuzu-b9950cd4b0cf414ca97daa5f7578f4ca22b2669d.tar.xz
yuzu-b9950cd4b0cf414ca97daa5f7578f4ca22b2669d.zip
svc: Implement svcLockMutex.
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
-rw-r--r--src/core/hle/kernel/mutex.cpp81
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 @@
7#include <boost/range/algorithm_ext/erase.hpp> 7#include <boost/range/algorithm_ext/erase.hpp>
8#include "common/assert.h" 8#include "common/assert.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/kernel/handle_table.h"
10#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/mutex.h" 12#include "core/hle/kernel/mutex.h"
13#include "core/hle/kernel/object_address_table.h"
12#include "core/hle/kernel/thread.h" 14#include "core/hle/kernel/thread.h"
13 15
14namespace Kernel { 16namespace Kernel {
@@ -25,17 +27,25 @@ void ReleaseThreadMutexes(Thread* thread) {
25Mutex::Mutex() {} 27Mutex::Mutex() {}
26Mutex::~Mutex() {} 28Mutex::~Mutex() {}
27 29
28SharedPtr<Mutex> Mutex::Create(bool initial_locked, VAddr addr, std::string name) { 30SharedPtr<Mutex> Mutex::Create(SharedPtr<Kernel::Thread> holding_thread, VAddr guest_addr,
31 std::string name) {
29 SharedPtr<Mutex> mutex(new Mutex); 32 SharedPtr<Mutex> mutex(new Mutex);
30 33
31 mutex->lock_count = 0; 34 mutex->lock_count = 0;
32 mutex->addr = addr; 35 mutex->guest_addr = guest_addr;
33 mutex->name = std::move(name); 36 mutex->name = std::move(name);
34 mutex->holding_thread = nullptr; 37 mutex->holding_thread = nullptr;
35 38
36 // Acquire mutex with current thread if initialized as locked 39 // If mutex was initialized with a holding thread, acquire it by the holding thread
37 if (initial_locked) 40 if (holding_thread) {
38 mutex->Acquire(GetCurrentThread()); 41 mutex->Acquire(holding_thread.get());
42 }
43
44 // Mutexes are referenced by guest address, so track this in the kernel
45 g_object_address_table.Insert(guest_addr, mutex);
46
47 // Verify that the created mutex matches the guest state for the mutex
48 mutex->VerifyGuestState();
39 49
40 return mutex; 50 return mutex;
41} 51}
@@ -53,38 +63,60 @@ void Mutex::Acquire(Thread* thread) {
53 thread->held_mutexes.insert(this); 63 thread->held_mutexes.insert(this);
54 holding_thread = thread; 64 holding_thread = thread;
55 thread->UpdatePriority(); 65 thread->UpdatePriority();
66 UpdateGuestState();
56 Core::System::GetInstance().PrepareReschedule(); 67 Core::System::GetInstance().PrepareReschedule();
57 } 68 }
58 69
59 lock_count++; 70 lock_count++;
60} 71}
61 72
62void Mutex::Release() { 73ResultCode Mutex::Release(Thread* thread) {
63 // Only release if the mutex is held 74 // We can only release the mutex if it's held by the calling thread.
64 if (lock_count > 0) { 75 if (thread != holding_thread) {
65 lock_count--; 76 if (holding_thread) {
66 77 LOG_ERROR(
67 // Yield to the next thread only if we've fully released the mutex 78 Kernel,
68 if (lock_count == 0) { 79 "Tried to release a mutex (owned by thread id %u) from a different thread id %u",
69 holding_thread->held_mutexes.erase(this); 80 holding_thread->thread_id, thread->thread_id);
70 holding_thread->UpdatePriority();
71 holding_thread = nullptr;
72 WakeupAllWaitingThreads();
73 Core::System::GetInstance().PrepareReschedule();
74 } 81 }
82 // TODO(bunnei): Use correct error code
83 return ResultCode(-1);
84 }
85
86 // Note: It should not be possible for the situation where the mutex has a holding thread with a
87 // zero lock count to occur. The real kernel still checks for this, so we do too.
88 if (lock_count <= 0) {
89 // TODO(bunnei): Use correct error code
90 return ResultCode(-1);
91 }
92
93 lock_count--;
94
95 // Yield to the next thread only if we've fully released the mutex
96 if (lock_count == 0) {
97 holding_thread->held_mutexes.erase(this);
98 holding_thread->UpdatePriority();
99 holding_thread = nullptr;
100 WakeupAllWaitingThreads();
101 UpdateGuestState();
102 Core::System::GetInstance().PrepareReschedule();
75 } 103 }
104
105 return RESULT_SUCCESS;
76} 106}
77 107
78void Mutex::AddWaitingThread(SharedPtr<Thread> thread) { 108void Mutex::AddWaitingThread(SharedPtr<Thread> thread) {
79 WaitObject::AddWaitingThread(thread); 109 WaitObject::AddWaitingThread(thread);
80 thread->pending_mutexes.insert(this); 110 thread->pending_mutexes.insert(this);
81 UpdatePriority(); 111 UpdatePriority();
112 UpdateGuestState();
82} 113}
83 114
84void Mutex::RemoveWaitingThread(Thread* thread) { 115void Mutex::RemoveWaitingThread(Thread* thread) {
85 WaitObject::RemoveWaitingThread(thread); 116 WaitObject::RemoveWaitingThread(thread);
86 thread->pending_mutexes.erase(this); 117 thread->pending_mutexes.erase(this);
87 UpdatePriority(); 118 UpdatePriority();
119 UpdateGuestState();
88} 120}
89 121
90void Mutex::UpdatePriority() { 122void Mutex::UpdatePriority() {
@@ -103,4 +135,17 @@ void Mutex::UpdatePriority() {
103 } 135 }
104} 136}
105 137
106} // namespace 138void Mutex::UpdateGuestState() {
139 GuestState guest_state{Memory::Read32(guest_addr)};
140 guest_state.has_waiters.Assign(!GetWaitingThreads().empty());
141 guest_state.holding_thread_handle.Assign(holding_thread ? holding_thread->guest_handle : 0);
142 Memory::Write32(guest_addr, guest_state.raw);
143}
144
145void Mutex::VerifyGuestState() {
146 GuestState guest_state{Memory::Read32(guest_addr)};
147 ASSERT(guest_state.has_waiters == !GetWaitingThreads().empty());
148 ASSERT(guest_state.holding_thread_handle == holding_thread->guest_handle);
149}
150
151} // namespace Kernel