diff options
| author | 2015-01-21 21:09:47 -0500 | |
|---|---|---|
| committer | 2015-01-21 21:09:47 -0500 | |
| commit | 24a63662ba6c7816001bba399e85d8c131a89489 (patch) | |
| tree | a9959e69723b4f19550834171c962ec06c9e34b7 /src/core/hle/kernel/mutex.cpp | |
| parent | Merge pull request #491 from archshift/hidspvr (diff) | |
| parent | WaitSynchronization: Added a result code for invalid result, fixed bug. (diff) | |
| download | yuzu-24a63662ba6c7816001bba399e85d8c131a89489.tar.gz yuzu-24a63662ba6c7816001bba399e85d8c131a89489.tar.xz yuzu-24a63662ba6c7816001bba399e85d8c131a89489.zip | |
Merge pull request #495 from bunnei/fix-waitsynch
Fix WaitSynchronization
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 112 |
1 files changed, 39 insertions, 73 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 853a5dd74..cd05a1397 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | class Mutex : public Object { | 16 | class Mutex : public WaitObject { |
| 17 | public: | 17 | public: |
| 18 | std::string GetTypeName() const override { return "Mutex"; } | 18 | std::string GetTypeName() const override { return "Mutex"; } |
| 19 | std::string GetName() const override { return name; } | 19 | std::string GetName() const override { return name; } |
| @@ -23,39 +23,26 @@ public: | |||
| 23 | 23 | ||
| 24 | bool initial_locked; ///< Initial lock state when mutex was created | 24 | bool initial_locked; ///< Initial lock state when mutex was created |
| 25 | bool locked; ///< Current locked state | 25 | bool locked; ///< Current locked state |
| 26 | Handle lock_thread; ///< Handle to thread that currently has mutex | ||
| 27 | std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex | ||
| 28 | std::string name; ///< Name of mutex (optional) | 26 | std::string name; ///< Name of mutex (optional) |
| 27 | SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex | ||
| 29 | 28 | ||
| 30 | ResultVal<bool> WaitSynchronization() override; | 29 | bool ShouldWait() override; |
| 30 | void Acquire() override; | ||
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 33 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 34 | 34 | ||
| 35 | typedef std::multimap<Handle, Handle> MutexMap; | 35 | typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; |
| 36 | static MutexMap g_mutex_held_locks; | 36 | static MutexMap g_mutex_held_locks; |
| 37 | 37 | ||
| 38 | /** | 38 | /** |
| 39 | * Acquires the specified mutex for the specified thread | 39 | * Acquires the specified mutex for the specified thread |
| 40 | * @param mutex Mutex that is to be acquired | 40 | * @param mutex Mutex that is to be acquired |
| 41 | * @param thread Thread that will acquired | 41 | * @param thread Thread that will acquire the mutex |
| 42 | */ | 42 | */ |
| 43 | void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandle()) { | 43 | void MutexAcquireLock(Mutex* mutex, Thread* thread) { |
| 44 | g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); | 44 | g_mutex_held_locks.insert(std::make_pair(thread, mutex)); |
| 45 | mutex->lock_thread = thread; | 45 | mutex->holding_thread = thread; |
| 46 | } | ||
| 47 | |||
| 48 | bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) { | ||
| 49 | MutexAcquireLock(mutex, thread_handle); | ||
| 50 | |||
| 51 | Thread* thread = Kernel::g_handle_table.Get<Thread>(thread_handle).get(); | ||
| 52 | if (thread == nullptr) { | ||
| 53 | LOG_ERROR(Kernel, "Called with invalid handle: %08X", thread_handle); | ||
| 54 | return false; | ||
| 55 | } | ||
| 56 | |||
| 57 | thread->ResumeFromWait(); | ||
| 58 | return true; | ||
| 59 | } | 46 | } |
| 60 | 47 | ||
| 61 | /** | 48 | /** |
| @@ -64,56 +51,41 @@ bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) { | |||
| 64 | */ | 51 | */ |
| 65 | void ResumeWaitingThread(Mutex* mutex) { | 52 | void ResumeWaitingThread(Mutex* mutex) { |
| 66 | // Find the next waiting thread for the mutex... | 53 | // Find the next waiting thread for the mutex... |
| 67 | if (mutex->waiting_threads.empty()) { | 54 | auto next_thread = mutex->WakeupNextThread(); |
| 55 | if (next_thread != nullptr) { | ||
| 56 | MutexAcquireLock(mutex, next_thread); | ||
| 57 | } else { | ||
| 68 | // Reset mutex lock thread handle, nothing is waiting | 58 | // Reset mutex lock thread handle, nothing is waiting |
| 69 | mutex->locked = false; | 59 | mutex->locked = false; |
| 70 | mutex->lock_thread = -1; | 60 | mutex->holding_thread = nullptr; |
| 71 | } | ||
| 72 | else { | ||
| 73 | // Resume the next waiting thread and re-lock the mutex | ||
| 74 | std::vector<Handle>::iterator iter = mutex->waiting_threads.begin(); | ||
| 75 | ReleaseMutexForThread(mutex, *iter); | ||
| 76 | mutex->waiting_threads.erase(iter); | ||
| 77 | } | 61 | } |
| 78 | } | 62 | } |
| 79 | 63 | ||
| 80 | void MutexEraseLock(Mutex* mutex) { | 64 | void ReleaseThreadMutexes(Thread* thread) { |
| 81 | Handle handle = mutex->GetHandle(); | ||
| 82 | auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread); | ||
| 83 | for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { | ||
| 84 | if (iter->second == handle) { | ||
| 85 | g_mutex_held_locks.erase(iter); | ||
| 86 | break; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | mutex->lock_thread = -1; | ||
| 90 | } | ||
| 91 | |||
| 92 | void ReleaseThreadMutexes(Handle thread) { | ||
| 93 | auto locked = g_mutex_held_locks.equal_range(thread); | 65 | auto locked = g_mutex_held_locks.equal_range(thread); |
| 94 | 66 | ||
| 95 | // Release every mutex that the thread holds, and resume execution on the waiting threads | 67 | // Release every mutex that the thread holds, and resume execution on the waiting threads |
| 96 | for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { | 68 | for (auto iter = locked.first; iter != locked.second; ++iter) { |
| 97 | Mutex* mutex = g_handle_table.Get<Mutex>(iter->second).get(); | 69 | ResumeWaitingThread(iter->second.get()); |
| 98 | ResumeWaitingThread(mutex); | ||
| 99 | } | 70 | } |
| 100 | 71 | ||
| 101 | // Erase all the locks that this thread holds | 72 | // Erase all the locks that this thread holds |
| 102 | g_mutex_held_locks.erase(thread); | 73 | g_mutex_held_locks.erase(thread); |
| 103 | } | 74 | } |
| 104 | 75 | ||
| 105 | bool LockMutex(Mutex* mutex) { | 76 | bool ReleaseMutex(Mutex* mutex) { |
| 106 | // Mutex alread locked? | ||
| 107 | if (mutex->locked) { | 77 | if (mutex->locked) { |
| 108 | return false; | 78 | auto locked = g_mutex_held_locks.equal_range(mutex->holding_thread); |
| 109 | } | ||
| 110 | MutexAcquireLock(mutex); | ||
| 111 | return true; | ||
| 112 | } | ||
| 113 | 79 | ||
| 114 | bool ReleaseMutex(Mutex* mutex) { | 80 | for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { |
| 115 | MutexEraseLock(mutex); | 81 | if (iter->second == mutex) { |
| 116 | ResumeWaitingThread(mutex); | 82 | g_mutex_held_locks.erase(iter); |
| 83 | break; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | ResumeWaitingThread(mutex); | ||
| 88 | } | ||
| 117 | return true; | 89 | return true; |
| 118 | } | 90 | } |
| 119 | 91 | ||
| @@ -148,15 +120,12 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) | |||
| 148 | 120 | ||
| 149 | mutex->locked = mutex->initial_locked = initial_locked; | 121 | mutex->locked = mutex->initial_locked = initial_locked; |
| 150 | mutex->name = name; | 122 | mutex->name = name; |
| 123 | mutex->holding_thread = nullptr; | ||
| 151 | 124 | ||
| 152 | // Acquire mutex with current thread if initialized as locked... | 125 | // Acquire mutex with current thread if initialized as locked... |
| 153 | if (mutex->locked) { | 126 | if (mutex->locked) |
| 154 | MutexAcquireLock(mutex); | 127 | MutexAcquireLock(mutex, GetCurrentThread()); |
| 155 | 128 | ||
| 156 | // Otherwise, reset lock thread handle | ||
| 157 | } else { | ||
| 158 | mutex->lock_thread = -1; | ||
| 159 | } | ||
| 160 | return mutex; | 129 | return mutex; |
| 161 | } | 130 | } |
| 162 | 131 | ||
| @@ -172,17 +141,14 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { | |||
| 172 | return handle; | 141 | return handle; |
| 173 | } | 142 | } |
| 174 | 143 | ||
| 175 | ResultVal<bool> Mutex::WaitSynchronization() { | 144 | bool Mutex::ShouldWait() { |
| 176 | bool wait = locked; | 145 | return locked && holding_thread != GetCurrentThread(); |
| 177 | if (locked) { | 146 | } |
| 178 | waiting_threads.push_back(GetCurrentThread()->GetHandle()); | ||
| 179 | Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); | ||
| 180 | } else { | ||
| 181 | // Lock the mutex when the first thread accesses it | ||
| 182 | locked = true; | ||
| 183 | MutexAcquireLock(this); | ||
| 184 | } | ||
| 185 | 147 | ||
| 186 | return MakeResult<bool>(wait); | 148 | void Mutex::Acquire() { |
| 149 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||
| 150 | locked = true; | ||
| 151 | MutexAcquireLock(this, GetCurrentThread()); | ||
| 187 | } | 152 | } |
| 153 | |||
| 188 | } // namespace | 154 | } // namespace |