diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/function_wrappers.h | 17 | ||||
| -rw-r--r-- | src/core/hle/kernel/event.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 22 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 9 | ||||
| -rw-r--r-- | src/core/hle/kernel/semaphore.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 76 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 14 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 26 |
9 files changed, 68 insertions, 113 deletions
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 23c86a72d..5949cb470 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h | |||
| @@ -9,11 +9,15 @@ | |||
| 9 | #include "core/arm/arm_interface.h" | 9 | #include "core/arm/arm_interface.h" |
| 10 | #include "core/memory.h" | 10 | #include "core/memory.h" |
| 11 | #include "core/hle/hle.h" | 11 | #include "core/hle/hle.h" |
| 12 | #include "core/hle/result.h" | ||
| 12 | 13 | ||
| 13 | namespace HLE { | 14 | namespace HLE { |
| 14 | 15 | ||
| 15 | #define PARAM(n) Core::g_app_core->GetReg(n) | 16 | #define PARAM(n) Core::g_app_core->GetReg(n) |
| 16 | 17 | ||
| 18 | /// An invalid result code that is meant to be overwritten when a thread resumes from waiting | ||
| 19 | static const ResultCode RESULT_INVALID(0xDEADC0DE); | ||
| 20 | |||
| 17 | /** | 21 | /** |
| 18 | * HLE a function return from the current ARM11 userland process | 22 | * HLE a function return from the current ARM11 userland process |
| 19 | * @param res Result to return | 23 | * @param res Result to return |
| @@ -57,8 +61,11 @@ template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() { | |||
| 57 | s32 param_1 = 0; | 61 | s32 param_1 = 0; |
| 58 | s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), | 62 | s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), |
| 59 | (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))).raw; | 63 | (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))).raw; |
| 60 | Core::g_app_core->SetReg(1, (u32)param_1); | 64 | |
| 61 | FuncReturn(retval); | 65 | if (retval != RESULT_INVALID.raw) { |
| 66 | Core::g_app_core->SetReg(1, (u32)param_1); | ||
| 67 | FuncReturn(retval); | ||
| 68 | } | ||
| 62 | } | 69 | } |
| 63 | 70 | ||
| 64 | template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() { | 71 | template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() { |
| @@ -73,7 +80,11 @@ template<ResultCode func(u32*)> void Wrap(){ | |||
| 73 | } | 80 | } |
| 74 | 81 | ||
| 75 | template<ResultCode func(u32, s64)> void Wrap() { | 82 | template<ResultCode func(u32, s64)> void Wrap() { |
| 76 | FuncReturn(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw); | 83 | s32 retval = func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw; |
| 84 | |||
| 85 | if (retval != RESULT_INVALID.raw) { | ||
| 86 | FuncReturn(retval); | ||
| 87 | } | ||
| 77 | } | 88 | } |
| 78 | 89 | ||
| 79 | template<ResultCode func(void*, void*, u32)> void Wrap(){ | 90 | template<ResultCode func(void*, void*, u32)> void Wrap(){ |
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index e45deb1c6..f338f3266 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp | |||
| @@ -41,10 +41,7 @@ void Event::Acquire() { | |||
| 41 | 41 | ||
| 42 | void Event::Signal() { | 42 | void Event::Signal() { |
| 43 | signaled = true; | 43 | signaled = true; |
| 44 | |||
| 45 | WakeupAllWaitingThreads(); | 44 | WakeupAllWaitingThreads(); |
| 46 | |||
| 47 | HLE::Reschedule(__func__); | ||
| 48 | } | 45 | } |
| 49 | 46 | ||
| 50 | void Event::Clear() { | 47 | void Event::Clear() { |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 726e4d2ff..20e11da16 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -32,27 +32,13 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { | |||
| 32 | waiting_threads.erase(itr); | 32 | waiting_threads.erase(itr); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | SharedPtr<Thread> WaitObject::WakeupNextThread() { | ||
| 36 | if (waiting_threads.empty()) | ||
| 37 | return nullptr; | ||
| 38 | |||
| 39 | auto next_thread = std::move(waiting_threads.front()); | ||
| 40 | waiting_threads.erase(waiting_threads.begin()); | ||
| 41 | |||
| 42 | next_thread->ReleaseWaitObject(this); | ||
| 43 | |||
| 44 | return next_thread; | ||
| 45 | } | ||
| 46 | |||
| 47 | void WaitObject::WakeupAllWaitingThreads() { | 35 | void WaitObject::WakeupAllWaitingThreads() { |
| 48 | auto waiting_threads_copy = waiting_threads; | 36 | for (auto thread : waiting_threads) |
| 37 | thread->ResumeFromWait(); | ||
| 49 | 38 | ||
| 50 | // We use a copy because ReleaseWaitObject will remove the thread from this object's | 39 | waiting_threads.clear(); |
| 51 | // waiting_threads list | ||
| 52 | for (auto thread : waiting_threads_copy) | ||
| 53 | thread->ReleaseWaitObject(this); | ||
| 54 | 40 | ||
| 55 | ASSERT_MSG(waiting_threads.empty(), "failed to awaken all waiting threads!"); | 41 | HLE::Reschedule(__func__); |
| 56 | } | 42 | } |
| 57 | 43 | ||
| 58 | HandleTable::HandleTable() { | 44 | HandleTable::HandleTable() { |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index a5a0f4800..64595f758 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -140,12 +140,6 @@ public: | |||
| 140 | */ | 140 | */ |
| 141 | void RemoveWaitingThread(Thread* thread); | 141 | void RemoveWaitingThread(Thread* thread); |
| 142 | 142 | ||
| 143 | /** | ||
| 144 | * Wake up the next thread waiting on this object | ||
| 145 | * @return Pointer to the thread that was resumed, nullptr if no threads are waiting | ||
| 146 | */ | ||
| 147 | SharedPtr<Thread> WakeupNextThread(); | ||
| 148 | |||
| 149 | /// Wake up all threads waiting on this object | 143 | /// Wake up all threads waiting on this object |
| 150 | void WakeupAllWaitingThreads(); | 144 | void WakeupAllWaitingThreads(); |
| 151 | 145 | ||
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 6aa73df86..edb97d324 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -23,12 +23,7 @@ static void ResumeWaitingThread(Mutex* mutex) { | |||
| 23 | // Reset mutex lock thread handle, nothing is waiting | 23 | // Reset mutex lock thread handle, nothing is waiting |
| 24 | mutex->lock_count = 0; | 24 | mutex->lock_count = 0; |
| 25 | mutex->holding_thread = nullptr; | 25 | mutex->holding_thread = nullptr; |
| 26 | 26 | mutex->WakeupAllWaitingThreads(); | |
| 27 | // Find the next waiting thread for the mutex... | ||
| 28 | auto next_thread = mutex->WakeupNextThread(); | ||
| 29 | if (next_thread != nullptr) { | ||
| 30 | mutex->Acquire(next_thread); | ||
| 31 | } | ||
| 32 | } | 27 | } |
| 33 | 28 | ||
| 34 | void ReleaseThreadMutexes(Thread* thread) { | 29 | void ReleaseThreadMutexes(Thread* thread) { |
| @@ -94,8 +89,6 @@ void Mutex::Release() { | |||
| 94 | ResumeWaitingThread(this); | 89 | ResumeWaitingThread(this); |
| 95 | } | 90 | } |
| 96 | } | 91 | } |
| 97 | |||
| 98 | HLE::Reschedule(__func__); | ||
| 99 | } | 92 | } |
| 100 | 93 | ||
| 101 | } // namespace | 94 | } // namespace |
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 96d61ed3a..4b359ed07 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp | |||
| @@ -48,13 +48,7 @@ ResultVal<s32> Semaphore::Release(s32 release_count) { | |||
| 48 | s32 previous_count = available_count; | 48 | s32 previous_count = available_count; |
| 49 | available_count += release_count; | 49 | available_count += release_count; |
| 50 | 50 | ||
| 51 | // Notify some of the threads that the semaphore has been released | 51 | WakeupAllWaitingThreads(); |
| 52 | // stop once the semaphore is full again or there are no more waiting threads | ||
| 53 | while (!ShouldWait() && WakeupNextThread() != nullptr) { | ||
| 54 | Acquire(); | ||
| 55 | } | ||
| 56 | |||
| 57 | HLE::Reschedule(__func__); | ||
| 58 | 52 | ||
| 59 | return MakeResult<s32>(previous_count); | 53 | return MakeResult<s32>(previous_count); |
| 60 | } | 54 | } |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 22c795ad4..4729a7fe0 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include "common/thread_queue_list.h" | 13 | #include "common/thread_queue_list.h" |
| 14 | 14 | ||
| 15 | #include "core/arm/arm_interface.h" | 15 | #include "core/arm/arm_interface.h" |
| 16 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 16 | #include "core/core.h" | 17 | #include "core/core.h" |
| 17 | #include "core/core_timing.h" | 18 | #include "core/core_timing.h" |
| 18 | #include "core/hle/hle.h" | 19 | #include "core/hle/hle.h" |
| @@ -193,8 +194,22 @@ static void SwitchContext(Thread* new_thread) { | |||
| 193 | if (new_thread) { | 194 | if (new_thread) { |
| 194 | DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running."); | 195 | DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running."); |
| 195 | 196 | ||
| 197 | // Cancel any outstanding wakeup events for this thread | ||
| 198 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); | ||
| 199 | |||
| 196 | current_thread = new_thread; | 200 | current_thread = new_thread; |
| 197 | 201 | ||
| 202 | // If the thread was waited by a svcWaitSynch call, step back PC by one instruction to rerun | ||
| 203 | // the SVC when the thread wakes up. This is necessary to ensure that the thread can acquire | ||
| 204 | // the requested wait object(s) before continuing. | ||
| 205 | if (new_thread->waitsynch_waited) { | ||
| 206 | // CPSR flag indicates CPU mode | ||
| 207 | bool thumb_mode = (new_thread->context.cpsr & TBIT) != 0; | ||
| 208 | |||
| 209 | // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM | ||
| 210 | new_thread->context.pc -= thumb_mode ? 2 : 4; | ||
| 211 | } | ||
| 212 | |||
| 198 | ready_queue.remove(new_thread->current_priority, new_thread); | 213 | ready_queue.remove(new_thread->current_priority, new_thread); |
| 199 | new_thread->status = THREADSTATUS_RUNNING; | 214 | new_thread->status = THREADSTATUS_RUNNING; |
| 200 | 215 | ||
| @@ -243,6 +258,7 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa | |||
| 243 | thread->wait_set_output = wait_set_output; | 258 | thread->wait_set_output = wait_set_output; |
| 244 | thread->wait_all = wait_all; | 259 | thread->wait_all = wait_all; |
| 245 | thread->wait_objects = std::move(wait_objects); | 260 | thread->wait_objects = std::move(wait_objects); |
| 261 | thread->waitsynch_waited = true; | ||
| 246 | thread->status = THREADSTATUS_WAIT_SYNCH; | 262 | thread->status = THREADSTATUS_WAIT_SYNCH; |
| 247 | } | 263 | } |
| 248 | 264 | ||
| @@ -268,6 +284,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | |||
| 268 | return; | 284 | return; |
| 269 | } | 285 | } |
| 270 | 286 | ||
| 287 | thread->waitsynch_waited = false; | ||
| 288 | |||
| 271 | if (thread->status == THREADSTATUS_WAIT_SYNCH) { | 289 | if (thread->status == THREADSTATUS_WAIT_SYNCH) { |
| 272 | thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, | 290 | thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, |
| 273 | ErrorSummary::StatusChanged, ErrorLevel::Info)); | 291 | ErrorSummary::StatusChanged, ErrorLevel::Info)); |
| @@ -288,63 +306,20 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { | |||
| 288 | CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle); | 306 | CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle); |
| 289 | } | 307 | } |
| 290 | 308 | ||
| 291 | void Thread::ReleaseWaitObject(WaitObject* wait_object) { | ||
| 292 | if (status != THREADSTATUS_WAIT_SYNCH || wait_objects.empty()) { | ||
| 293 | LOG_CRITICAL(Kernel, "thread is not waiting on any objects!"); | ||
| 294 | return; | ||
| 295 | } | ||
| 296 | |||
| 297 | // Remove this thread from the waiting object's thread list | ||
| 298 | wait_object->RemoveWaitingThread(this); | ||
| 299 | |||
| 300 | unsigned index = 0; | ||
| 301 | bool wait_all_failed = false; // Will be set to true if any object is unavailable | ||
| 302 | |||
| 303 | // Iterate through all waiting objects to check availability... | ||
| 304 | for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { | ||
| 305 | if ((*itr)->ShouldWait()) | ||
| 306 | wait_all_failed = true; | ||
| 307 | |||
| 308 | // The output should be the last index of wait_object | ||
| 309 | if (*itr == wait_object) | ||
| 310 | index = itr - wait_objects.begin(); | ||
| 311 | } | ||
| 312 | |||
| 313 | // If we are waiting on all objects... | ||
| 314 | if (wait_all) { | ||
| 315 | // Resume the thread only if all are available... | ||
| 316 | if (!wait_all_failed) { | ||
| 317 | SetWaitSynchronizationResult(RESULT_SUCCESS); | ||
| 318 | SetWaitSynchronizationOutput(-1); | ||
| 319 | |||
| 320 | ResumeFromWait(); | ||
| 321 | } | ||
| 322 | } else { | ||
| 323 | // Otherwise, resume | ||
| 324 | SetWaitSynchronizationResult(RESULT_SUCCESS); | ||
| 325 | |||
| 326 | if (wait_set_output) | ||
| 327 | SetWaitSynchronizationOutput(index); | ||
| 328 | |||
| 329 | ResumeFromWait(); | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | void Thread::ResumeFromWait() { | 309 | void Thread::ResumeFromWait() { |
| 334 | // Cancel any outstanding wakeup events for this thread | ||
| 335 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); | ||
| 336 | |||
| 337 | switch (status) { | 310 | switch (status) { |
| 338 | case THREADSTATUS_WAIT_SYNCH: | 311 | case THREADSTATUS_WAIT_SYNCH: |
| 339 | // Remove this thread from all other WaitObjects | ||
| 340 | for (auto wait_object : wait_objects) | ||
| 341 | wait_object->RemoveWaitingThread(this); | ||
| 342 | break; | ||
| 343 | case THREADSTATUS_WAIT_ARB: | 312 | case THREADSTATUS_WAIT_ARB: |
| 344 | case THREADSTATUS_WAIT_SLEEP: | 313 | case THREADSTATUS_WAIT_SLEEP: |
| 345 | break; | 314 | break; |
| 346 | case THREADSTATUS_RUNNING: | 315 | |
| 347 | case THREADSTATUS_READY: | 316 | case THREADSTATUS_READY: |
| 317 | // If the thread is waiting on multiple wait objects, it might be awoken more than once | ||
| 318 | // before actually resuming. We can ignore subsequent wakeups if the thread status has | ||
| 319 | // already been set to THREADSTATUS_READY. | ||
| 320 | return; | ||
| 321 | |||
| 322 | case THREADSTATUS_RUNNING: | ||
| 348 | DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId()); | 323 | DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId()); |
| 349 | return; | 324 | return; |
| 350 | case THREADSTATUS_DEAD: | 325 | case THREADSTATUS_DEAD: |
| @@ -415,6 +390,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 415 | thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); | 390 | thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); |
| 416 | thread->owner_process = g_current_process; | 391 | thread->owner_process = g_current_process; |
| 417 | thread->tls_index = -1; | 392 | thread->tls_index = -1; |
| 393 | thread->waitsynch_waited = false; | ||
| 418 | 394 | ||
| 419 | // Find the next available TLS index, and mark it as used | 395 | // Find the next available TLS index, and mark it as used |
| 420 | auto& used_tls_slots = Kernel::g_current_process->used_tls_slots; | 396 | auto& used_tls_slots = Kernel::g_current_process->used_tls_slots; |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 2c65419c3..b8160bb2c 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -96,12 +96,6 @@ public: | |||
| 96 | u32 GetThreadId() const { return thread_id; } | 96 | u32 GetThreadId() const { return thread_id; } |
| 97 | 97 | ||
| 98 | /** | 98 | /** |
| 99 | * Release an acquired wait object | ||
| 100 | * @param wait_object WaitObject to release | ||
| 101 | */ | ||
| 102 | void ReleaseWaitObject(WaitObject* wait_object); | ||
| 103 | |||
| 104 | /** | ||
| 105 | * Resumes a thread from waiting | 99 | * Resumes a thread from waiting |
| 106 | */ | 100 | */ |
| 107 | void ResumeFromWait(); | 101 | void ResumeFromWait(); |
| @@ -152,6 +146,8 @@ public: | |||
| 152 | 146 | ||
| 153 | s32 tls_index; ///< Index of the Thread Local Storage of the thread | 147 | s32 tls_index; ///< Index of the Thread Local Storage of the thread |
| 154 | 148 | ||
| 149 | bool waitsynch_waited; ///< Set to true if the last svcWaitSynch call caused the thread to wait | ||
| 150 | |||
| 155 | /// Mutexes currently held by this thread, which will be released when it exits. | 151 | /// Mutexes currently held by this thread, which will be released when it exits. |
| 156 | boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; | 152 | boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; |
| 157 | 153 | ||
| @@ -163,12 +159,12 @@ public: | |||
| 163 | 159 | ||
| 164 | std::string name; | 160 | std::string name; |
| 165 | 161 | ||
| 162 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. | ||
| 163 | Handle callback_handle; | ||
| 164 | |||
| 166 | private: | 165 | private: |
| 167 | Thread(); | 166 | Thread(); |
| 168 | ~Thread() override; | 167 | ~Thread() override; |
| 169 | |||
| 170 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. | ||
| 171 | Handle callback_handle; | ||
| 172 | }; | 168 | }; |
| 173 | 169 | ||
| 174 | /** | 170 | /** |
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index d1555c753..6cde4fc87 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -40,9 +40,6 @@ const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel, | |||
| 40 | const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, | 40 | const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, |
| 41 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E | 41 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E |
| 42 | 42 | ||
| 43 | /// An invalid result code that is meant to be overwritten when a thread resumes from waiting | ||
| 44 | const ResultCode RESULT_INVALID(0xDEADC0DE); | ||
| 45 | |||
| 46 | enum ControlMemoryOperation { | 43 | enum ControlMemoryOperation { |
| 47 | MEMORY_OPERATION_HEAP = 0x00000003, | 44 | MEMORY_OPERATION_HEAP = 0x00000003, |
| 48 | MEMORY_OPERATION_GSP_HEAP = 0x00010003, | 45 | MEMORY_OPERATION_GSP_HEAP = 0x00010003, |
| @@ -143,6 +140,10 @@ static ResultCode CloseHandle(Handle handle) { | |||
| 143 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds | 140 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds |
| 144 | static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { | 141 | static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { |
| 145 | auto object = Kernel::g_handle_table.GetWaitObject(handle); | 142 | auto object = Kernel::g_handle_table.GetWaitObject(handle); |
| 143 | Kernel::Thread* thread = Kernel::GetCurrentThread(); | ||
| 144 | |||
| 145 | thread->waitsynch_waited = false; | ||
| 146 | |||
| 146 | if (object == nullptr) | 147 | if (object == nullptr) |
| 147 | return ERR_INVALID_HANDLE; | 148 | return ERR_INVALID_HANDLE; |
| 148 | 149 | ||
| @@ -154,14 +155,14 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 154 | // Check for next thread to schedule | 155 | // Check for next thread to schedule |
| 155 | if (object->ShouldWait()) { | 156 | if (object->ShouldWait()) { |
| 156 | 157 | ||
| 157 | object->AddWaitingThread(Kernel::GetCurrentThread()); | 158 | object->AddWaitingThread(thread); |
| 158 | Kernel::WaitCurrentThread_WaitSynchronization({ object }, false, false); | 159 | Kernel::WaitCurrentThread_WaitSynchronization({ object }, false, false); |
| 159 | 160 | ||
| 160 | // Create an event to wake the thread up after the specified nanosecond delay has passed | 161 | // Create an event to wake the thread up after the specified nanosecond delay has passed |
| 161 | Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); | 162 | thread->WakeAfterDelay(nano_seconds); |
| 162 | 163 | ||
| 163 | // NOTE: output of this SVC will be set later depending on how the thread resumes | 164 | // NOTE: output of this SVC will be set later depending on how the thread resumes |
| 164 | return RESULT_INVALID; | 165 | return HLE::RESULT_INVALID; |
| 165 | } | 166 | } |
| 166 | 167 | ||
| 167 | object->Acquire(); | 168 | object->Acquire(); |
| @@ -173,6 +174,9 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 173 | static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { | 174 | static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { |
| 174 | bool wait_thread = !wait_all; | 175 | bool wait_thread = !wait_all; |
| 175 | int handle_index = 0; | 176 | int handle_index = 0; |
| 177 | Kernel::Thread* thread = Kernel::GetCurrentThread(); | ||
| 178 | bool was_waiting = thread->waitsynch_waited; | ||
| 179 | thread->waitsynch_waited = false; | ||
| 176 | 180 | ||
| 177 | // Check if 'handles' is invalid | 181 | // Check if 'handles' is invalid |
| 178 | if (handles == nullptr) | 182 | if (handles == nullptr) |
| @@ -190,6 +194,9 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||
| 190 | // necessary | 194 | // necessary |
| 191 | if (handle_count != 0) { | 195 | if (handle_count != 0) { |
| 192 | bool selected = false; // True once an object has been selected | 196 | bool selected = false; // True once an object has been selected |
| 197 | |||
| 198 | Kernel::SharedPtr<Kernel::WaitObject> wait_object; | ||
| 199 | |||
| 193 | for (int i = 0; i < handle_count; ++i) { | 200 | for (int i = 0; i < handle_count; ++i) { |
| 194 | auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); | 201 | auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); |
| 195 | if (object == nullptr) | 202 | if (object == nullptr) |
| @@ -204,10 +211,11 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||
| 204 | wait_thread = true; | 211 | wait_thread = true; |
| 205 | } else { | 212 | } else { |
| 206 | // Do not wait on this object, check if this object should be selected... | 213 | // Do not wait on this object, check if this object should be selected... |
| 207 | if (!wait_all && !selected) { | 214 | if (!wait_all && (!selected || (wait_object == object && was_waiting))) { |
| 208 | // Do not wait the thread | 215 | // Do not wait the thread |
| 209 | wait_thread = false; | 216 | wait_thread = false; |
| 210 | handle_index = i; | 217 | handle_index = i; |
| 218 | wait_object = object; | ||
| 211 | selected = true; | 219 | selected = true; |
| 212 | } | 220 | } |
| 213 | } | 221 | } |
| @@ -241,7 +249,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||
| 241 | Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); | 249 | Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); |
| 242 | 250 | ||
| 243 | // NOTE: output of this SVC will be set later depending on how the thread resumes | 251 | // NOTE: output of this SVC will be set later depending on how the thread resumes |
| 244 | return RESULT_INVALID; | 252 | return HLE::RESULT_INVALID; |
| 245 | } | 253 | } |
| 246 | 254 | ||
| 247 | // Acquire objects if we did not wait... | 255 | // Acquire objects if we did not wait... |
| @@ -261,7 +269,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||
| 261 | 269 | ||
| 262 | // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does | 270 | // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does |
| 263 | // not seem to set it to any meaningful value. | 271 | // not seem to set it to any meaningful value. |
| 264 | *out = wait_all ? 0 : handle_index; | 272 | *out = handle_count != 0 ? (wait_all ? -1 : handle_index) : 0; |
| 265 | 273 | ||
| 266 | return RESULT_SUCCESS; | 274 | return RESULT_SUCCESS; |
| 267 | } | 275 | } |