diff options
| author | 2015-01-17 02:03:44 -0500 | |
|---|---|---|
| committer | 2015-01-21 19:09:03 -0500 | |
| commit | 7faf2d8e06e705d1866fa0d7848ff43541a4b172 (patch) | |
| tree | 7cca6433c6b06a1299af1193df2cedac7ad522c5 /src | |
| parent | Event: Fixed some bugs and cleanup (Subv) (diff) | |
| download | yuzu-7faf2d8e06e705d1866fa0d7848ff43541a4b172.tar.gz yuzu-7faf2d8e06e705d1866fa0d7848ff43541a4b172.tar.xz yuzu-7faf2d8e06e705d1866fa0d7848ff43541a4b172.zip | |
WaitSynchronizationN: Implement return values
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/address_arbiter.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/event.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 7 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/semaphore.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 94 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 58 | ||||
| -rw-r--r-- | src/core/hle/kernel/timer.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 77 |
10 files changed, 189 insertions, 83 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index ff1472066..520601455 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -52,13 +52,13 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 | |||
| 52 | // Wait current thread (acquire the arbiter)... | 52 | // Wait current thread (acquire the arbiter)... |
| 53 | case ArbitrationType::WaitIfLessThan: | 53 | case ArbitrationType::WaitIfLessThan: |
| 54 | if ((s32)Memory::Read32(address) <= value) { | 54 | if ((s32)Memory::Read32(address) <= value) { |
| 55 | Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); | 55 | Kernel::WaitCurrentThread_ArbitrateAddress(object, address); |
| 56 | HLE::Reschedule(__func__); | 56 | HLE::Reschedule(__func__); |
| 57 | } | 57 | } |
| 58 | break; | 58 | break; |
| 59 | case ArbitrationType::WaitIfLessThanWithTimeout: | 59 | case ArbitrationType::WaitIfLessThanWithTimeout: |
| 60 | if ((s32)Memory::Read32(address) <= value) { | 60 | if ((s32)Memory::Read32(address) <= value) { |
| 61 | Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); | 61 | Kernel::WaitCurrentThread_ArbitrateAddress(object, address); |
| 62 | Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); | 62 | Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); |
| 63 | HLE::Reschedule(__func__); | 63 | HLE::Reschedule(__func__); |
| 64 | } | 64 | } |
| @@ -68,7 +68,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 | |||
| 68 | s32 memory_value = Memory::Read32(address) - 1; | 68 | s32 memory_value = Memory::Read32(address) - 1; |
| 69 | Memory::Write32(address, memory_value); | 69 | Memory::Write32(address, memory_value); |
| 70 | if (memory_value <= value) { | 70 | if (memory_value <= value) { |
| 71 | Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); | 71 | Kernel::WaitCurrentThread_ArbitrateAddress(object, address); |
| 72 | HLE::Reschedule(__func__); | 72 | HLE::Reschedule(__func__); |
| 73 | } | 73 | } |
| 74 | break; | 74 | break; |
| @@ -78,7 +78,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 | |||
| 78 | s32 memory_value = Memory::Read32(address) - 1; | 78 | s32 memory_value = Memory::Read32(address) - 1; |
| 79 | Memory::Write32(address, memory_value); | 79 | Memory::Write32(address, memory_value); |
| 80 | if (memory_value <= value) { | 80 | if (memory_value <= value) { |
| 81 | Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); | 81 | Kernel::WaitCurrentThread_ArbitrateAddress(object, address); |
| 82 | Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); | 82 | Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); |
| 83 | HLE::Reschedule(__func__); | 83 | HLE::Reschedule(__func__); |
| 84 | } | 84 | } |
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 540199e03..4173a980b 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp | |||
| @@ -28,11 +28,11 @@ public: | |||
| 28 | bool signaled; ///< Whether the event has already been signaled | 28 | bool signaled; ///< Whether the event has already been signaled |
| 29 | std::string name; ///< Name of event (optional) | 29 | std::string name; ///< Name of event (optional) |
| 30 | 30 | ||
| 31 | ResultVal<bool> WaitSynchronization() override { | 31 | ResultVal<bool> WaitSynchronization(unsigned index) override { |
| 32 | bool wait = !signaled; | 32 | bool wait = !signaled; |
| 33 | if (wait) { | 33 | if (wait) { |
| 34 | AddWaitingThread(GetCurrentThread()); | 34 | AddWaitingThread(GetCurrentThread()); |
| 35 | Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); | 35 | Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_EVENT, this, index); |
| 36 | } | 36 | } |
| 37 | return MakeResult<bool>(wait); | 37 | return MakeResult<bool>(wait); |
| 38 | } | 38 | } |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1dba85939..be3495412 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -30,13 +30,13 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { | |||
| 30 | waiting_threads.erase(itr); | 30 | waiting_threads.erase(itr); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | Thread* WaitObject::ResumeNextThread() { | 33 | Thread* WaitObject::ReleaseNextThread() { |
| 34 | if (waiting_threads.empty()) | 34 | if (waiting_threads.empty()) |
| 35 | return nullptr; | 35 | return nullptr; |
| 36 | 36 | ||
| 37 | auto next_thread = waiting_threads.front(); | 37 | auto next_thread = waiting_threads.front(); |
| 38 | 38 | ||
| 39 | next_thread->ResumeFromWait(); | 39 | next_thread->ReleaseFromWait(this); |
| 40 | waiting_threads.erase(waiting_threads.begin()); | 40 | waiting_threads.erase(waiting_threads.begin()); |
| 41 | 41 | ||
| 42 | return next_thread.get(); | 42 | return next_thread.get(); |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 53b3f9143..af4e2f443 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -66,9 +66,10 @@ public: | |||
| 66 | 66 | ||
| 67 | /** | 67 | /** |
| 68 | * Wait for kernel object to synchronize. | 68 | * Wait for kernel object to synchronize. |
| 69 | * @param index Index of wait object (only applies to WaitSynchronizationN) | ||
| 69 | * @return True if the current thread should wait as a result of the wait | 70 | * @return True if the current thread should wait as a result of the wait |
| 70 | */ | 71 | */ |
| 71 | virtual ResultVal<bool> WaitSynchronization() { | 72 | virtual ResultVal<bool> WaitSynchronization(unsigned index=0) { |
| 72 | LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); | 73 | LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); |
| 73 | return UnimplementedFunction(ErrorModule::Kernel); | 74 | return UnimplementedFunction(ErrorModule::Kernel); |
| 74 | } | 75 | } |
| @@ -111,10 +112,10 @@ public: | |||
| 111 | void RemoveWaitingThread(Thread* thead); | 112 | void RemoveWaitingThread(Thread* thead); |
| 112 | 113 | ||
| 113 | /** | 114 | /** |
| 114 | * Resumes (and removes) the next thread waiting on this object | 115 | * Releases (and removes) the next thread waiting on this object |
| 115 | * @return Pointer to the thread that was resumed, nullptr if no threads are waiting | 116 | * @return Pointer to the thread that was resumed, nullptr if no threads are waiting |
| 116 | */ | 117 | */ |
| 117 | Thread* ResumeNextThread(); | 118 | Thread* ReleaseNextThread(); |
| 118 | 119 | ||
| 119 | /// Releases all threads waiting on this object | 120 | /// Releases all threads waiting on this object |
| 120 | void ReleaseAllWaitingThreads(); | 121 | void ReleaseAllWaitingThreads(); |
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 35d829606..78063b8f1 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -26,7 +26,7 @@ public: | |||
| 26 | Handle lock_thread; ///< Handle to thread that currently has mutex | 26 | Handle lock_thread; ///< Handle to thread that currently has mutex |
| 27 | std::string name; ///< Name of mutex (optional) | 27 | std::string name; ///< Name of mutex (optional) |
| 28 | 28 | ||
| 29 | ResultVal<bool> WaitSynchronization() override; | 29 | ResultVal<bool> WaitSynchronization(unsigned index) override; |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 32 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -50,7 +50,7 @@ void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandl | |||
| 50 | */ | 50 | */ |
| 51 | void ResumeWaitingThread(Mutex* mutex) { | 51 | void ResumeWaitingThread(Mutex* mutex) { |
| 52 | // Find the next waiting thread for the mutex... | 52 | // Find the next waiting thread for the mutex... |
| 53 | auto next_thread = mutex->ResumeNextThread(); | 53 | auto next_thread = mutex->ReleaseNextThread(); |
| 54 | if (next_thread != nullptr) { | 54 | if (next_thread != nullptr) { |
| 55 | MutexAcquireLock(mutex, next_thread->GetHandle()); | 55 | MutexAcquireLock(mutex, next_thread->GetHandle()); |
| 56 | } else { | 56 | } else { |
| @@ -155,11 +155,11 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { | |||
| 155 | return handle; | 155 | return handle; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | ResultVal<bool> Mutex::WaitSynchronization() { | 158 | ResultVal<bool> Mutex::WaitSynchronization(unsigned index) { |
| 159 | bool wait = locked; | 159 | bool wait = locked; |
| 160 | if (locked) { | 160 | if (locked) { |
| 161 | AddWaitingThread(GetCurrentThread()); | 161 | AddWaitingThread(GetCurrentThread()); |
| 162 | Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); | 162 | Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_MUTEX, this, index); |
| 163 | } else { | 163 | } else { |
| 164 | // Lock the mutex when the first thread accesses it | 164 | // Lock the mutex when the first thread accesses it |
| 165 | locked = true; | 165 | locked = true; |
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index af2c465e4..288928441 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp | |||
| @@ -32,11 +32,11 @@ public: | |||
| 32 | return available_count > 0; | 32 | return available_count > 0; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | ResultVal<bool> WaitSynchronization() override { | 35 | ResultVal<bool> WaitSynchronization(unsigned index) override { |
| 36 | bool wait = !IsAvailable(); | 36 | bool wait = !IsAvailable(); |
| 37 | 37 | ||
| 38 | if (wait) { | 38 | if (wait) { |
| 39 | Kernel::WaitCurrentThread(WAITTYPE_SEMA, this); | 39 | Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_SEMA, this, index); |
| 40 | AddWaitingThread(GetCurrentThread()); | 40 | AddWaitingThread(GetCurrentThread()); |
| 41 | } else { | 41 | } else { |
| 42 | --available_count; | 42 | --available_count; |
| @@ -82,7 +82,7 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { | |||
| 82 | 82 | ||
| 83 | // Notify some of the threads that the semaphore has been released | 83 | // Notify some of the threads that the semaphore has been released |
| 84 | // stop once the semaphore is full again or there are no more waiting threads | 84 | // stop once the semaphore is full again or there are no more waiting threads |
| 85 | while (semaphore->IsAvailable() && semaphore->ResumeNextThread() != nullptr) { | 85 | while (semaphore->IsAvailable() && semaphore->ReleaseNextThread() != nullptr) { |
| 86 | --semaphore->available_count; | 86 | --semaphore->available_count; |
| 87 | } | 87 | } |
| 88 | 88 | ||
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 00b72477e..0c9ecc091 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -22,11 +22,11 @@ | |||
| 22 | 22 | ||
| 23 | namespace Kernel { | 23 | namespace Kernel { |
| 24 | 24 | ||
| 25 | ResultVal<bool> Thread::WaitSynchronization() { | 25 | ResultVal<bool> Thread::WaitSynchronization(unsigned index) { |
| 26 | const bool wait = status != THREADSTATUS_DORMANT; | 26 | const bool wait = status != THREADSTATUS_DORMANT; |
| 27 | if (wait) { | 27 | if (wait) { |
| 28 | AddWaitingThread(GetCurrentThread()); | 28 | AddWaitingThread(GetCurrentThread()); |
| 29 | WaitCurrentThread(WAITTYPE_THREADEND, this); | 29 | WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this, index); |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | return MakeResult<bool>(wait); | 32 | return MakeResult<bool>(wait); |
| @@ -92,11 +92,11 @@ static bool CheckWaitType(const Thread* thread, WaitType type) { | |||
| 92 | 92 | ||
| 93 | /// Check if a thread is blocking on a specified wait type with a specified handle | 93 | /// Check if a thread is blocking on a specified wait type with a specified handle |
| 94 | static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { | 94 | static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { |
| 95 | auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); | 95 | for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { |
| 96 | if (itr == thread->wait_objects.end()) { | 96 | if (itr->first == wait_object) |
| 97 | return false; | 97 | return CheckWaitType(thread, type); |
| 98 | } | 98 | } |
| 99 | return CheckWaitType(thread, type); | 99 | return false; |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | /// Check if a thread is blocking on a specified wait type with a specified handle and address | 102 | /// Check if a thread is blocking on a specified wait type with a specified handle and address |
| @@ -111,7 +111,7 @@ void Thread::Stop(const char* reason) { | |||
| 111 | 111 | ||
| 112 | ChangeReadyState(this, false); | 112 | ChangeReadyState(this, false); |
| 113 | status = THREADSTATUS_DORMANT; | 113 | status = THREADSTATUS_DORMANT; |
| 114 | ResumeAllWaitingThreads(); | 114 | ReleaseAllWaitingThreads(); |
| 115 | 115 | ||
| 116 | // Stopped threads are never waiting. | 116 | // Stopped threads are never waiting. |
| 117 | wait_type = WAITTYPE_NONE; | 117 | wait_type = WAITTYPE_NONE; |
| @@ -135,7 +135,7 @@ static void ChangeThreadState(Thread* t, ThreadStatus new_status) { | |||
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | /// Arbitrate the highest priority thread that is waiting | 137 | /// Arbitrate the highest priority thread that is waiting |
| 138 | Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) { | 138 | Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address) { |
| 139 | Thread* highest_priority_thread = nullptr; | 139 | Thread* highest_priority_thread = nullptr; |
| 140 | s32 priority = THREADPRIO_LOWEST; | 140 | s32 priority = THREADPRIO_LOWEST; |
| 141 | 141 | ||
| @@ -155,19 +155,19 @@ Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) { | |||
| 155 | 155 | ||
| 156 | // If a thread was arbitrated, resume it | 156 | // If a thread was arbitrated, resume it |
| 157 | if (nullptr != highest_priority_thread) { | 157 | if (nullptr != highest_priority_thread) { |
| 158 | highest_priority_thread->ResumeFromWait(); | 158 | highest_priority_thread->ReleaseFromWait(arbiter); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | return highest_priority_thread; | 161 | return highest_priority_thread; |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | /// Arbitrate all threads currently waiting | 164 | /// Arbitrate all threads currently waiting |
| 165 | void ArbitrateAllThreads(Object* arbiter, u32 address) { | 165 | void ArbitrateAllThreads(WaitObject* arbiter, u32 address) { |
| 166 | 166 | ||
| 167 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | 167 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... |
| 168 | for (auto& thread : thread_list) { | 168 | for (auto& thread : thread_list) { |
| 169 | if (CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address)) | 169 | if (CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address)) |
| 170 | thread->ResumeFromWait(); | 170 | thread->ReleaseFromWait(arbiter); |
| 171 | } | 171 | } |
| 172 | } | 172 | } |
| 173 | 173 | ||
| @@ -220,19 +220,32 @@ static Thread* NextThread() { | |||
| 220 | return next; | 220 | return next; |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object) { | 223 | void WaitCurrentThread(WaitType wait_type) { |
| 224 | Thread* thread = GetCurrentThread(); | ||
| 225 | thread->wait_type = wait_type; | ||
| 226 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); | ||
| 227 | } | ||
| 228 | |||
| 229 | void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_object, unsigned index) { | ||
| 224 | Thread* thread = GetCurrentThread(); | 230 | Thread* thread = GetCurrentThread(); |
| 225 | thread->wait_type = wait_type; | 231 | thread->wait_type = wait_type; |
| 226 | 232 | ||
| 227 | auto res = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); | 233 | bool insert_wait_object = true; |
| 228 | if (res == thread->wait_objects.end()) { | 234 | for (auto itr = thread->wait_objects.begin(); itr < thread->wait_objects.end(); ++itr) { |
| 229 | thread->wait_objects.push_back(wait_object); | 235 | if (itr->first == wait_object) { |
| 236 | insert_wait_object = false; | ||
| 237 | break; | ||
| 238 | } | ||
| 230 | } | 239 | } |
| 240 | |||
| 241 | if (insert_wait_object) | ||
| 242 | thread->wait_objects.push_back(std::pair<SharedPtr<WaitObject>, unsigned>(wait_object, index)); | ||
| 243 | |||
| 231 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); | 244 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); |
| 232 | } | 245 | } |
| 233 | 246 | ||
| 234 | void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address) { | 247 | void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address) { |
| 235 | WaitCurrentThread(wait_type, wait_object); | 248 | WaitCurrentThread_WaitSynchronization(WaitType::WAITTYPE_ARB, wait_object, 0); |
| 236 | GetCurrentThread()->wait_address = wait_address; | 249 | GetCurrentThread()->wait_address = wait_address; |
| 237 | } | 250 | } |
| 238 | 251 | ||
| @@ -248,6 +261,9 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) { | |||
| 248 | return; | 261 | return; |
| 249 | } | 262 | } |
| 250 | 263 | ||
| 264 | thread->SetReturnValue(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, | ||
| 265 | ErrorSummary::StatusChanged, ErrorLevel::Info), -1); | ||
| 266 | |||
| 251 | thread->ResumeFromWait(); | 267 | thread->ResumeFromWait(); |
| 252 | } | 268 | } |
| 253 | 269 | ||
| @@ -262,7 +278,40 @@ void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) { | |||
| 262 | CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); | 278 | CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); |
| 263 | } | 279 | } |
| 264 | 280 | ||
| 265 | /// Resumes a thread from waiting by marking it as "ready" | 281 | void Thread::ReleaseFromWait(WaitObject* wait_object) { |
| 282 | if (wait_objects.empty()) { | ||
| 283 | LOG_CRITICAL(Kernel, "thread is not waiting on any objects!"); | ||
| 284 | return; | ||
| 285 | } | ||
| 286 | |||
| 287 | // Remove this thread from the wait_object | ||
| 288 | wait_object->RemoveWaitingThread(this); | ||
| 289 | |||
| 290 | // Find the waiting object | ||
| 291 | auto itr = wait_objects.begin(); | ||
| 292 | for (; itr != wait_objects.end(); ++itr) { | ||
| 293 | if (wait_object == itr->first) | ||
| 294 | break; | ||
| 295 | } | ||
| 296 | unsigned index = itr->second; | ||
| 297 | |||
| 298 | // Remove the wait_object from this thread | ||
| 299 | if (itr != wait_objects.end()) | ||
| 300 | wait_objects.erase(itr); | ||
| 301 | |||
| 302 | // If wait_all=false, resume the thread on a release wait_object from wait | ||
| 303 | if (!wait_all) { | ||
| 304 | SetReturnValue(RESULT_SUCCESS, index); | ||
| 305 | ResumeFromWait(); | ||
| 306 | } else { | ||
| 307 | // Otherwise, wait_all=true, only resume the thread if all wait_object's have been released | ||
| 308 | if (wait_objects.empty()) { | ||
| 309 | SetReturnValue(RESULT_SUCCESS, -1); | ||
| 310 | ResumeFromWait(); | ||
| 311 | } | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 266 | void Thread::ResumeFromWait() { | 315 | void Thread::ResumeFromWait() { |
| 267 | // Cancel any outstanding wakeup events | 316 | // Cancel any outstanding wakeup events |
| 268 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle()); | 317 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle()); |
| @@ -271,11 +320,12 @@ void Thread::ResumeFromWait() { | |||
| 271 | 320 | ||
| 272 | // Remove this thread from all other WaitObjects | 321 | // Remove this thread from all other WaitObjects |
| 273 | for (auto wait_object : wait_objects) | 322 | for (auto wait_object : wait_objects) |
| 274 | wait_object->RemoveWaitingThread(this); | 323 | wait_object.first->RemoveWaitingThread(this); |
| 275 | 324 | ||
| 276 | wait_objects.clear(); | 325 | wait_objects.clear(); |
| 277 | 326 | ||
| 278 | wait_type = WAITTYPE_NONE; | 327 | wait_type = WAITTYPE_NONE; |
| 328 | wait_all = false; | ||
| 279 | if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { | 329 | if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { |
| 280 | ChangeReadyState(this, true); | 330 | ChangeReadyState(this, true); |
| 281 | } | 331 | } |
| @@ -342,6 +392,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 342 | thread->initial_priority = thread->current_priority = priority; | 392 | thread->initial_priority = thread->current_priority = priority; |
| 343 | thread->processor_id = processor_id; | 393 | thread->processor_id = processor_id; |
| 344 | thread->wait_type = WAITTYPE_NONE; | 394 | thread->wait_type = WAITTYPE_NONE; |
| 395 | thread->wait_all = false; | ||
| 345 | thread->wait_objects.clear(); | 396 | thread->wait_objects.clear(); |
| 346 | thread->wait_address = 0; | 397 | thread->wait_address = 0; |
| 347 | thread->name = std::move(name); | 398 | thread->name = std::move(name); |
| @@ -432,6 +483,11 @@ void Reschedule() { | |||
| 432 | } | 483 | } |
| 433 | } | 484 | } |
| 434 | 485 | ||
| 486 | void Thread::SetReturnValue(ResultCode return_val, s32 out_val) { | ||
| 487 | context.cpu_registers[0] = return_val.raw; | ||
| 488 | context.cpu_registers[1] = out_val; | ||
| 489 | } | ||
| 490 | |||
| 435 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 491 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 436 | 492 | ||
| 437 | void ThreadingInit() { | 493 | void ThreadingInit() { |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9ec96c18c..f3dc4eec0 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -70,7 +70,7 @@ public: | |||
| 70 | inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } | 70 | inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } |
| 71 | inline bool IsIdle() const { return idle; } | 71 | inline bool IsIdle() const { return idle; } |
| 72 | 72 | ||
| 73 | ResultVal<bool> WaitSynchronization() override; | 73 | ResultVal<bool> WaitSynchronization(unsigned index) override; |
| 74 | 74 | ||
| 75 | s32 GetPriority() const { return current_priority; } | 75 | s32 GetPriority() const { return current_priority; } |
| 76 | void SetPriority(s32 priority); | 76 | void SetPriority(s32 priority); |
| @@ -78,9 +78,29 @@ public: | |||
| 78 | u32 GetThreadId() const { return thread_id; } | 78 | u32 GetThreadId() const { return thread_id; } |
| 79 | 79 | ||
| 80 | void Stop(const char* reason); | 80 | void Stop(const char* reason); |
| 81 | /// Resumes a thread from waiting by marking it as "ready". | 81 | |
| 82 | /** | ||
| 83 | * Release an object from the thread's wait list | ||
| 84 | * @param wait_object WaitObject to release from the thread's wait list | ||
| 85 | */ | ||
| 86 | void ReleaseFromWait(WaitObject* wait_object); | ||
| 87 | |||
| 88 | /// Resumes a thread from waiting by marking it as "ready" | ||
| 82 | void ResumeFromWait(); | 89 | void ResumeFromWait(); |
| 83 | 90 | ||
| 91 | /** | ||
| 92 | * Sets the waiting mode of the thread | ||
| 93 | * @param wait_all If true, wait for all objects, otherwise just wait for the first one | ||
| 94 | */ | ||
| 95 | void SetWaitAll(bool wait_all) { this->wait_all = wait_all; } | ||
| 96 | |||
| 97 | /** | ||
| 98 | * Sets the output values after the thread awakens from WaitSynchronization | ||
| 99 | * @param return_val Value returned | ||
| 100 | * @param out_val Value to set to the output parameter | ||
| 101 | */ | ||
| 102 | void SetReturnValue(ResultCode return_val, s32 out_val); | ||
| 103 | |||
| 84 | Core::ThreadContext context; | 104 | Core::ThreadContext context; |
| 85 | 105 | ||
| 86 | u32 thread_id; | 106 | u32 thread_id; |
| @@ -96,7 +116,7 @@ public: | |||
| 96 | s32 processor_id; | 116 | s32 processor_id; |
| 97 | 117 | ||
| 98 | WaitType wait_type; | 118 | WaitType wait_type; |
| 99 | std::vector<SharedPtr<WaitObject>> wait_objects; | 119 | std::vector<std::pair<SharedPtr<WaitObject>, unsigned>> wait_objects; |
| 100 | VAddr wait_address; | 120 | VAddr wait_address; |
| 101 | 121 | ||
| 102 | std::string name; | 122 | std::string name; |
| @@ -105,6 +125,8 @@ public: | |||
| 105 | bool idle = false; | 125 | bool idle = false; |
| 106 | 126 | ||
| 107 | private: | 127 | private: |
| 128 | bool wait_all = false; | ||
| 129 | |||
| 108 | Thread() = default; | 130 | Thread() = default; |
| 109 | }; | 131 | }; |
| 110 | 132 | ||
| @@ -115,37 +137,41 @@ SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size); | |||
| 115 | void Reschedule(); | 137 | void Reschedule(); |
| 116 | 138 | ||
| 117 | /// Arbitrate the highest priority thread that is waiting | 139 | /// Arbitrate the highest priority thread that is waiting |
| 118 | Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address); | 140 | Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address); |
| 119 | 141 | ||
| 120 | /// Arbitrate all threads currently waiting... | 142 | /// Arbitrate all threads currently waiting... |
| 121 | void ArbitrateAllThreads(Object* arbiter, u32 address); | 143 | void ArbitrateAllThreads(WaitObject* arbiter, u32 address); |
| 122 | 144 | ||
| 123 | /// Gets the current thread | 145 | /// Gets the current thread |
| 124 | Thread* GetCurrentThread(); | 146 | Thread* GetCurrentThread(); |
| 125 | 147 | ||
| 126 | /** | 148 | /** |
| 127 | * Puts the current thread in the wait state for the given type | 149 | * Waits the current thread for the given type |
| 128 | * @param wait_type Type of wait | 150 | * @param wait_type Type of wait |
| 129 | * @param wait_object Kernel object that we are waiting on, defaults to current thread | ||
| 130 | */ | 151 | */ |
| 131 | void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object = GetCurrentThread()); | 152 | void WaitCurrentThread(WaitType wait_type); |
| 132 | 153 | ||
| 133 | /** | 154 | /** |
| 134 | * Schedules an event to wake up the specified thread after the specified delay. | 155 | * Waits the current thread from a WaitSynchronization call |
| 135 | * @param thread The thread to wake after the delay. | 156 | * @param wait_type Type of wait |
| 136 | * @param nanoseconds The time this thread will be allowed to sleep for. | 157 | * @param wait_object Kernel object that we are waiting on |
| 158 | * @param index Index of calling object (for WaitSynchronizationN only) | ||
| 137 | */ | 159 | */ |
| 138 | void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); | 160 | void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_object, unsigned index=0); |
| 139 | 161 | ||
| 140 | /** | 162 | /** |
| 141 | * Puts the current thread in the wait state for the given type | 163 | * Waits the current thread from an ArbitrateAddress call |
| 142 | * @param wait_type Type of wait | ||
| 143 | * @param wait_object Kernel object that we are waiting on | 164 | * @param wait_object Kernel object that we are waiting on |
| 144 | * @param wait_address Arbitration address used to resume from wait | 165 | * @param wait_address Arbitration address used to resume from wait |
| 145 | */ | 166 | */ |
| 146 | void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address); | 167 | void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address); |
| 147 | |||
| 148 | 168 | ||
| 169 | /** | ||
| 170 | * Schedules an event to wake up the specified thread after the specified delay. | ||
| 171 | * @param handle The thread handle. | ||
| 172 | * @param nanoseconds The time this thread will be allowed to sleep for. | ||
| 173 | */ | ||
| 174 | void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); | ||
| 149 | 175 | ||
| 150 | /** | 176 | /** |
| 151 | * Sets up the idle thread, this is a thread that is intended to never execute instructions, | 177 | * Sets up the idle thread, this is a thread that is intended to never execute instructions, |
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 2d4fa4c01..c97ae6c5c 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -29,11 +29,11 @@ public: | |||
| 29 | u64 initial_delay; ///< The delay until the timer fires for the first time | 29 | u64 initial_delay; ///< The delay until the timer fires for the first time |
| 30 | u64 interval_delay; ///< The delay until the timer fires after the first time | 30 | u64 interval_delay; ///< The delay until the timer fires after the first time |
| 31 | 31 | ||
| 32 | ResultVal<bool> WaitSynchronization() override { | 32 | ResultVal<bool> WaitSynchronization(unsigned index) override { |
| 33 | bool wait = !signaled; | 33 | bool wait = !signaled; |
| 34 | if (wait) { | 34 | if (wait) { |
| 35 | AddWaitingThread(GetCurrentThread()); | 35 | AddWaitingThread(GetCurrentThread()); |
| 36 | Kernel::WaitCurrentThread(WAITTYPE_TIMER, this); | 36 | Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_TIMER, this, index); |
| 37 | } | 37 | } |
| 38 | return MakeResult<bool>(wait); | 38 | return MakeResult<bool>(wait); |
| 39 | } | 39 | } |
| @@ -91,7 +91,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { | |||
| 91 | timer->signaled = true; | 91 | timer->signaled = true; |
| 92 | 92 | ||
| 93 | // Resume all waiting threads | 93 | // Resume all waiting threads |
| 94 | timer->ResumeAllWaitingThreads(); | 94 | timer->ReleaseAllWaitingThreads(); |
| 95 | 95 | ||
| 96 | if (timer->reset_type == RESETTYPE_ONESHOT) | 96 | if (timer->reset_type == RESETTYPE_ONESHOT) |
| 97 | timer->signaled = false; | 97 | timer->signaled = false; |
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index a487f757c..170ac87f3 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -133,6 +133,9 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 133 | if (wait.Succeeded() && *wait) { | 133 | if (wait.Succeeded() && *wait) { |
| 134 | // Create an event to wake the thread up after the specified nanosecond delay has passed | 134 | // Create an event to wake the thread up after the specified nanosecond delay has passed |
| 135 | Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); | 135 | Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); |
| 136 | |||
| 137 | Kernel::GetCurrentThread()->SetWaitAll(false); | ||
| 138 | |||
| 136 | HLE::Reschedule(__func__); | 139 | HLE::Reschedule(__func__); |
| 137 | } | 140 | } |
| 138 | 141 | ||
| @@ -140,44 +143,64 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 140 | } | 143 | } |
| 141 | 144 | ||
| 142 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 145 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds |
| 143 | static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, | 146 | static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { |
| 144 | s64 nano_seconds) { | 147 | bool wait_thread = false; |
| 145 | 148 | bool wait_all_succeeded = false; | |
| 146 | // TODO(bunnei): Do something with nano_seconds, currently ignoring this | 149 | int handle_index = 0; |
| 147 | bool unlock_all = true; | ||
| 148 | bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated | ||
| 149 | 150 | ||
| 150 | LOG_TRACE(Kernel_SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld", | 151 | while (handle_index < handle_count) { |
| 151 | handle_count, (wait_all ? "true" : "false"), nano_seconds); | 152 | SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handles[handle_index]); |
| 152 | |||
| 153 | // Iterate through each handle, synchronize kernel object | ||
| 154 | for (s32 i = 0; i < handle_count; i++) { | ||
| 155 | SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handles[i]); | ||
| 156 | if (object == nullptr) | 153 | if (object == nullptr) |
| 157 | return InvalidHandle(ErrorModule::Kernel).raw; | 154 | return InvalidHandle(ErrorModule::Kernel).raw; |
| 158 | 155 | ||
| 159 | LOG_TRACE(Kernel_SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], | 156 | ResultVal<bool> wait = object->WaitSynchronization(handle_index); |
| 160 | object->GetTypeName().c_str(), object->GetName().c_str()); | ||
| 161 | 157 | ||
| 162 | // TODO(yuriks): Verify how the real function behaves when an error happens here | 158 | wait_thread = (wait.Succeeded() && *wait); |
| 163 | ResultVal<bool> wait_result = object->WaitSynchronization(); | ||
| 164 | bool wait = wait_result.Succeeded() && *wait_result; | ||
| 165 | 159 | ||
| 166 | if (!wait && !wait_all) { | 160 | // If this object waited and we are waiting on all objects to synchronize |
| 167 | *out = i; | 161 | if (wait_thread && wait_all) { |
| 168 | return RESULT_SUCCESS.raw; | 162 | // Enforce later on that this thread does not continue |
| 169 | } else { | 163 | wait_all_succeeded = true; |
| 170 | unlock_all = false; | ||
| 171 | } | 164 | } |
| 165 | |||
| 166 | // If this object synchronized and we are not waiting on all objects to synchronize | ||
| 167 | if (!wait_thread && !wait_all) | ||
| 168 | // We're done, the thread will continue | ||
| 169 | break; | ||
| 170 | |||
| 171 | handle_index++; | ||
| 172 | } | ||
| 173 | |||
| 174 | // Change the thread state to waiting if blocking on all handles... | ||
| 175 | if (wait_thread || wait_all_succeeded) { | ||
| 176 | // Create an event to wake the thread up after the specified nanosecond delay has passed | ||
| 177 | Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); | ||
| 178 | Kernel::GetCurrentThread()->SetWaitAll(wait_all); | ||
| 179 | |||
| 180 | HLE::Reschedule(__func__); | ||
| 181 | |||
| 182 | // NOTE: output of this SVC will be set later depending on how the thread resumes | ||
| 183 | return RESULT_DUMMY.raw; | ||
| 172 | } | 184 | } |
| 173 | 185 | ||
| 174 | if (wait_all && unlock_all) { | 186 | // Acquire objects if we did not wait... |
| 175 | *out = handle_count; | 187 | for (int i = 0; i < handle_count; ++i) { |
| 176 | return RESULT_SUCCESS.raw; | 188 | auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); |
| 189 | |||
| 190 | // Acquire the object if it is not waiting... | ||
| 191 | if (!object->ShouldWait()) { | ||
| 192 | object->Acquire(); | ||
| 193 | |||
| 194 | // If this was the first non-waiting object and 'wait_all' is false, don't acquire | ||
| 195 | // any other objects | ||
| 196 | if (!wait_all) | ||
| 197 | break; | ||
| 198 | } | ||
| 177 | } | 199 | } |
| 178 | 200 | ||
| 179 | // Check for next thread to schedule | 201 | // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does |
| 180 | HLE::Reschedule(__func__); | 202 | // not seem to set it to any meaningful value. |
| 203 | *out = wait_all ? 0 : handle_index; | ||
| 181 | 204 | ||
| 182 | return RESULT_SUCCESS.raw; | 205 | return RESULT_SUCCESS.raw; |
| 183 | } | 206 | } |