summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/mutex.cpp
diff options
context:
space:
mode:
authorGravatar Tony Wasserka2015-01-30 15:00:17 +0100
committerGravatar Tony Wasserka2015-01-30 15:00:17 +0100
commit28702cbfeb1fe21109f8b1efa189785594319b78 (patch)
tree64e4b1ec43b7699fe1a6ab1be1c688b6d63c0d75 /src/core/hle/kernel/mutex.cpp
parentMerge pull request #412 from purpasmart96/svc_table_cleanup (diff)
parentKernel: Mark all appropriate kernel objects as "final" (diff)
downloadyuzu-28702cbfeb1fe21109f8b1efa189785594319b78.tar.gz
yuzu-28702cbfeb1fe21109f8b1efa189785594319b78.tar.xz
yuzu-28702cbfeb1fe21109f8b1efa189785594319b78.zip
Merge pull request #503 from yuriks/kernel-lifetime4
Kernel Lifetime Reform Pt. 4
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
-rw-r--r--src/core/hle/kernel/mutex.cpp143
1 files changed, 44 insertions, 99 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index cd05a1397..acf484659 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -13,59 +13,30 @@
13 13
14namespace Kernel { 14namespace Kernel {
15 15
16class Mutex : public WaitObject {
17public:
18 std::string GetTypeName() const override { return "Mutex"; }
19 std::string GetName() const override { return name; }
20
21 static const HandleType HANDLE_TYPE = HandleType::Mutex;
22 HandleType GetHandleType() const override { return HANDLE_TYPE; }
23
24 bool initial_locked; ///< Initial lock state when mutex was created
25 bool locked; ///< Current locked state
26 std::string name; ///< Name of mutex (optional)
27 SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex
28
29 bool ShouldWait() override;
30 void Acquire() override;
31};
32
33////////////////////////////////////////////////////////////////////////////////////////////////////
34
35typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; 16typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap;
36static MutexMap g_mutex_held_locks; 17static MutexMap g_mutex_held_locks;
37 18
38/** 19/**
39 * Acquires the specified mutex for the specified thread
40 * @param mutex Mutex that is to be acquired
41 * @param thread Thread that will acquire the mutex
42 */
43void MutexAcquireLock(Mutex* mutex, Thread* thread) {
44 g_mutex_held_locks.insert(std::make_pair(thread, mutex));
45 mutex->holding_thread = thread;
46}
47
48/**
49 * Resumes a thread waiting for the specified mutex 20 * Resumes a thread waiting for the specified mutex
50 * @param mutex The mutex that some thread is waiting on 21 * @param mutex The mutex that some thread is waiting on
51 */ 22 */
52void ResumeWaitingThread(Mutex* mutex) { 23static void ResumeWaitingThread(Mutex* mutex) {
24 // Reset mutex lock thread handle, nothing is waiting
25 mutex->locked = false;
26 mutex->holding_thread = nullptr;
27
53 // Find the next waiting thread for the mutex... 28 // Find the next waiting thread for the mutex...
54 auto next_thread = mutex->WakeupNextThread(); 29 auto next_thread = mutex->WakeupNextThread();
55 if (next_thread != nullptr) { 30 if (next_thread != nullptr) {
56 MutexAcquireLock(mutex, next_thread); 31 mutex->Acquire(next_thread);
57 } else {
58 // Reset mutex lock thread handle, nothing is waiting
59 mutex->locked = false;
60 mutex->holding_thread = nullptr;
61 } 32 }
62} 33}
63 34
64void ReleaseThreadMutexes(Thread* thread) { 35void ReleaseThreadMutexes(Thread* thread) {
65 auto locked = g_mutex_held_locks.equal_range(thread); 36 auto locked_range = g_mutex_held_locks.equal_range(thread);
66 37
67 // Release every mutex that the thread holds, and resume execution on the waiting threads 38 // Release every mutex that the thread holds, and resume execution on the waiting threads
68 for (auto iter = locked.first; iter != locked.second; ++iter) { 39 for (auto iter = locked_range.first; iter != locked_range.second; ++iter) {
69 ResumeWaitingThread(iter->second.get()); 40 ResumeWaitingThread(iter->second.get());
70 } 41 }
71 42
@@ -73,72 +44,21 @@ void ReleaseThreadMutexes(Thread* thread) {
73 g_mutex_held_locks.erase(thread); 44 g_mutex_held_locks.erase(thread);
74} 45}
75 46
76bool ReleaseMutex(Mutex* mutex) { 47ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) {
77 if (mutex->locked) { 48 SharedPtr<Mutex> mutex(new Mutex);
78 auto locked = g_mutex_held_locks.equal_range(mutex->holding_thread); 49 // TOOD(yuriks): Don't create Handle (see Thread::Create())
79 50 CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(mutex));
80 for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
81 if (iter->second == mutex) {
82 g_mutex_held_locks.erase(iter);
83 break;
84 }
85 }
86
87 ResumeWaitingThread(mutex);
88 }
89 return true;
90}
91 51
92/** 52 mutex->initial_locked = initial_locked;
93 * Releases a mutex 53 mutex->locked = false;
94 * @param handle Handle to mutex to release 54 mutex->name = std::move(name);
95 */
96ResultCode ReleaseMutex(Handle handle) {
97 Mutex* mutex = Kernel::g_handle_table.Get<Mutex>(handle).get();
98 if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel);
99
100 if (!ReleaseMutex(mutex)) {
101 // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure
102 // what error condition this is supposed to be signaling.
103 return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel,
104 ErrorSummary::NothingHappened, ErrorLevel::Temporary);
105 }
106 return RESULT_SUCCESS;
107}
108
109/**
110 * Creates a mutex
111 * @param handle Reference to handle for the newly created mutex
112 * @param initial_locked Specifies if the mutex should be locked initially
113 * @param name Optional name of mutex
114 * @return Pointer to new Mutex object
115 */
116Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) {
117 Mutex* mutex = new Mutex;
118 // TODO(yuriks): Fix error reporting
119 handle = Kernel::g_handle_table.Create(mutex).ValueOr(INVALID_HANDLE);
120
121 mutex->locked = mutex->initial_locked = initial_locked;
122 mutex->name = name;
123 mutex->holding_thread = nullptr; 55 mutex->holding_thread = nullptr;
124 56
125 // Acquire mutex with current thread if initialized as locked... 57 // Acquire mutex with current thread if initialized as locked...
126 if (mutex->locked) 58 if (initial_locked)
127 MutexAcquireLock(mutex, GetCurrentThread()); 59 mutex->Acquire();
128
129 return mutex;
130}
131 60
132/** 61 return MakeResult<SharedPtr<Mutex>>(mutex);
133 * Creates a mutex
134 * @param initial_locked Specifies if the mutex should be locked initially
135 * @param name Optional name of mutex
136 * @return Handle to newly created object
137 */
138Handle CreateMutex(bool initial_locked, const std::string& name) {
139 Handle handle;
140 Mutex* mutex = CreateMutex(handle, initial_locked, name);
141 return handle;
142} 62}
143 63
144bool Mutex::ShouldWait() { 64bool Mutex::ShouldWait() {
@@ -146,9 +66,34 @@ bool Mutex::ShouldWait() {
146} 66}
147 67
148void Mutex::Acquire() { 68void Mutex::Acquire() {
69 Acquire(GetCurrentThread());
70}
71
72void Mutex::Acquire(Thread* thread) {
149 _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); 73 _assert_msg_(Kernel, !ShouldWait(), "object unavailable!");
74 if (locked)
75 return;
76
150 locked = true; 77 locked = true;
151 MutexAcquireLock(this, GetCurrentThread()); 78
79 g_mutex_held_locks.insert(std::make_pair(thread, this));
80 holding_thread = thread;
81}
82
83void Mutex::Release() {
84 if (!locked)
85 return;
86
87 auto locked_range = g_mutex_held_locks.equal_range(holding_thread);
88
89 for (MutexMap::iterator iter = locked_range.first; iter != locked_range.second; ++iter) {
90 if (iter->second == this) {
91 g_mutex_held_locks.erase(iter);
92 break;
93 }
94 }
95
96 ResumeWaitingThread(this);
152} 97}
153 98
154} // namespace 99} // namespace