diff options
| author | 2015-01-30 15:00:17 +0100 | |
|---|---|---|
| committer | 2015-01-30 15:00:17 +0100 | |
| commit | 28702cbfeb1fe21109f8b1efa189785594319b78 (patch) | |
| tree | 64e4b1ec43b7699fe1a6ab1be1c688b6d63c0d75 /src/core/hle/kernel/mutex.cpp | |
| parent | Merge pull request #412 from purpasmart96/svc_table_cleanup (diff) | |
| parent | Kernel: Mark all appropriate kernel objects as "final" (diff) | |
| download | yuzu-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.cpp | 143 |
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 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | class Mutex : public WaitObject { | ||
| 17 | public: | ||
| 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 | |||
| 35 | typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; | 16 | typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; |
| 36 | static MutexMap g_mutex_held_locks; | 17 | static 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 | */ | ||
| 43 | void 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 | */ |
| 52 | void ResumeWaitingThread(Mutex* mutex) { | 23 | static 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 | ||
| 64 | void ReleaseThreadMutexes(Thread* thread) { | 35 | void 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 | ||
| 76 | bool ReleaseMutex(Mutex* mutex) { | 47 | ResultVal<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 | */ | ||
| 96 | ResultCode 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 | */ | ||
| 116 | Mutex* 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 | */ | ||
| 138 | Handle 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 | ||
| 144 | bool Mutex::ShouldWait() { | 64 | bool Mutex::ShouldWait() { |
| @@ -146,9 +66,34 @@ bool Mutex::ShouldWait() { | |||
| 146 | } | 66 | } |
| 147 | 67 | ||
| 148 | void Mutex::Acquire() { | 68 | void Mutex::Acquire() { |
| 69 | Acquire(GetCurrentThread()); | ||
| 70 | } | ||
| 71 | |||
| 72 | void 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 | |||
| 83 | void 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 |