diff options
Diffstat (limited to 'src/core/hle/kernel')
-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 |
9 files changed, 139 insertions, 56 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 // Wait current thread (acquire the arbiter)... case ArbitrationType::WaitIfLessThan: if ((s32)Memory::Read32(address) <= value) { - Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); + Kernel::WaitCurrentThread_ArbitrateAddress(object, address); HLE::Reschedule(__func__); } break; case ArbitrationType::WaitIfLessThanWithTimeout: if ((s32)Memory::Read32(address) <= value) { - Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); + Kernel::WaitCurrentThread_ArbitrateAddress(object, address); Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); HLE::Reschedule(__func__); } @@ -68,7 +68,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 s32 memory_value = Memory::Read32(address) - 1; Memory::Write32(address, memory_value); if (memory_value <= value) { - Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); + Kernel::WaitCurrentThread_ArbitrateAddress(object, address); HLE::Reschedule(__func__); } break; @@ -78,7 +78,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 s32 memory_value = Memory::Read32(address) - 1; Memory::Write32(address, memory_value); if (memory_value <= value) { - Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); + Kernel::WaitCurrentThread_ArbitrateAddress(object, address); Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); HLE::Reschedule(__func__); } 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: bool signaled; ///< Whether the event has already been signaled std::string name; ///< Name of event (optional) - ResultVal<bool> WaitSynchronization() override { + ResultVal<bool> WaitSynchronization(unsigned index) override { bool wait = !signaled; if (wait) { AddWaitingThread(GetCurrentThread()); - Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); + Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_EVENT, this, index); } return MakeResult<bool>(wait); } 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) { waiting_threads.erase(itr); } -Thread* WaitObject::ResumeNextThread() { +Thread* WaitObject::ReleaseNextThread() { if (waiting_threads.empty()) return nullptr; auto next_thread = waiting_threads.front(); - next_thread->ResumeFromWait(); + next_thread->ReleaseFromWait(this); waiting_threads.erase(waiting_threads.begin()); 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: /** * Wait for kernel object to synchronize. + * @param index Index of wait object (only applies to WaitSynchronizationN) * @return True if the current thread should wait as a result of the wait */ - virtual ResultVal<bool> WaitSynchronization() { + virtual ResultVal<bool> WaitSynchronization(unsigned index=0) { LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); return UnimplementedFunction(ErrorModule::Kernel); } @@ -111,10 +112,10 @@ public: void RemoveWaitingThread(Thread* thead); /** - * Resumes (and removes) the next thread waiting on this object + * Releases (and removes) the next thread waiting on this object * @return Pointer to the thread that was resumed, nullptr if no threads are waiting */ - Thread* ResumeNextThread(); + Thread* ReleaseNextThread(); /// Releases all threads waiting on this object 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: Handle lock_thread; ///< Handle to thread that currently has mutex std::string name; ///< Name of mutex (optional) - ResultVal<bool> WaitSynchronization() override; + ResultVal<bool> WaitSynchronization(unsigned index) override; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -50,7 +50,7 @@ void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandl */ void ResumeWaitingThread(Mutex* mutex) { // Find the next waiting thread for the mutex... - auto next_thread = mutex->ResumeNextThread(); + auto next_thread = mutex->ReleaseNextThread(); if (next_thread != nullptr) { MutexAcquireLock(mutex, next_thread->GetHandle()); } else { @@ -155,11 +155,11 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { return handle; } -ResultVal<bool> Mutex::WaitSynchronization() { +ResultVal<bool> Mutex::WaitSynchronization(unsigned index) { bool wait = locked; if (locked) { AddWaitingThread(GetCurrentThread()); - Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); + Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_MUTEX, this, index); } else { // Lock the mutex when the first thread accesses it 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: return available_count > 0; } - ResultVal<bool> WaitSynchronization() override { + ResultVal<bool> WaitSynchronization(unsigned index) override { bool wait = !IsAvailable(); if (wait) { - Kernel::WaitCurrentThread(WAITTYPE_SEMA, this); + Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_SEMA, this, index); AddWaitingThread(GetCurrentThread()); } else { --available_count; @@ -82,7 +82,7 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { // Notify some of the threads that the semaphore has been released // stop once the semaphore is full again or there are no more waiting threads - while (semaphore->IsAvailable() && semaphore->ResumeNextThread() != nullptr) { + while (semaphore->IsAvailable() && semaphore->ReleaseNextThread() != nullptr) { --semaphore->available_count; } 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 @@ namespace Kernel { -ResultVal<bool> Thread::WaitSynchronization() { +ResultVal<bool> Thread::WaitSynchronization(unsigned index) { const bool wait = status != THREADSTATUS_DORMANT; if (wait) { AddWaitingThread(GetCurrentThread()); - WaitCurrentThread(WAITTYPE_THREADEND, this); + WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this, index); } return MakeResult<bool>(wait); @@ -92,11 +92,11 @@ static bool CheckWaitType(const Thread* thread, WaitType type) { /// Check if a thread is blocking on a specified wait type with a specified handle static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { - auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); - if (itr == thread->wait_objects.end()) { - return false; + for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { + if (itr->first == wait_object) + return CheckWaitType(thread, type); } - return CheckWaitType(thread, type); + return false; } /// 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) { ChangeReadyState(this, false); status = THREADSTATUS_DORMANT; - ResumeAllWaitingThreads(); + ReleaseAllWaitingThreads(); // Stopped threads are never waiting. wait_type = WAITTYPE_NONE; @@ -135,7 +135,7 @@ static void ChangeThreadState(Thread* t, ThreadStatus new_status) { } /// Arbitrate the highest priority thread that is waiting -Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) { +Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address) { Thread* highest_priority_thread = nullptr; s32 priority = THREADPRIO_LOWEST; @@ -155,19 +155,19 @@ Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) { // If a thread was arbitrated, resume it if (nullptr != highest_priority_thread) { - highest_priority_thread->ResumeFromWait(); + highest_priority_thread->ReleaseFromWait(arbiter); } return highest_priority_thread; } /// Arbitrate all threads currently waiting -void ArbitrateAllThreads(Object* arbiter, u32 address) { +void ArbitrateAllThreads(WaitObject* arbiter, u32 address) { // Iterate through threads, find highest priority thread that is waiting to be arbitrated... for (auto& thread : thread_list) { if (CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address)) - thread->ResumeFromWait(); + thread->ReleaseFromWait(arbiter); } } @@ -220,19 +220,32 @@ static Thread* NextThread() { return next; } -void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object) { +void WaitCurrentThread(WaitType wait_type) { + Thread* thread = GetCurrentThread(); + thread->wait_type = wait_type; + ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); +} + +void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_object, unsigned index) { Thread* thread = GetCurrentThread(); thread->wait_type = wait_type; - auto res = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); - if (res == thread->wait_objects.end()) { - thread->wait_objects.push_back(wait_object); + bool insert_wait_object = true; + for (auto itr = thread->wait_objects.begin(); itr < thread->wait_objects.end(); ++itr) { + if (itr->first == wait_object) { + insert_wait_object = false; + break; + } } + + if (insert_wait_object) + thread->wait_objects.push_back(std::pair<SharedPtr<WaitObject>, unsigned>(wait_object, index)); + ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } -void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address) { - WaitCurrentThread(wait_type, wait_object); +void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address) { + WaitCurrentThread_WaitSynchronization(WaitType::WAITTYPE_ARB, wait_object, 0); GetCurrentThread()->wait_address = wait_address; } @@ -248,6 +261,9 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) { return; } + thread->SetReturnValue(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, + ErrorSummary::StatusChanged, ErrorLevel::Info), -1); + thread->ResumeFromWait(); } @@ -262,7 +278,40 @@ void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) { CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); } -/// Resumes a thread from waiting by marking it as "ready" +void Thread::ReleaseFromWait(WaitObject* wait_object) { + if (wait_objects.empty()) { + LOG_CRITICAL(Kernel, "thread is not waiting on any objects!"); + return; + } + + // Remove this thread from the wait_object + wait_object->RemoveWaitingThread(this); + + // Find the waiting object + auto itr = wait_objects.begin(); + for (; itr != wait_objects.end(); ++itr) { + if (wait_object == itr->first) + break; + } + unsigned index = itr->second; + + // Remove the wait_object from this thread + if (itr != wait_objects.end()) + wait_objects.erase(itr); + + // If wait_all=false, resume the thread on a release wait_object from wait + if (!wait_all) { + SetReturnValue(RESULT_SUCCESS, index); + ResumeFromWait(); + } else { + // Otherwise, wait_all=true, only resume the thread if all wait_object's have been released + if (wait_objects.empty()) { + SetReturnValue(RESULT_SUCCESS, -1); + ResumeFromWait(); + } + } +} + void Thread::ResumeFromWait() { // Cancel any outstanding wakeup events CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle()); @@ -271,11 +320,12 @@ void Thread::ResumeFromWait() { // Remove this thread from all other WaitObjects for (auto wait_object : wait_objects) - wait_object->RemoveWaitingThread(this); + wait_object.first->RemoveWaitingThread(this); wait_objects.clear(); wait_type = WAITTYPE_NONE; + wait_all = false; if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { ChangeReadyState(this, true); } @@ -342,6 +392,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, thread->initial_priority = thread->current_priority = priority; thread->processor_id = processor_id; thread->wait_type = WAITTYPE_NONE; + thread->wait_all = false; thread->wait_objects.clear(); thread->wait_address = 0; thread->name = std::move(name); @@ -432,6 +483,11 @@ void Reschedule() { } } +void Thread::SetReturnValue(ResultCode return_val, s32 out_val) { + context.cpu_registers[0] = return_val.raw; + context.cpu_registers[1] = out_val; +} + //////////////////////////////////////////////////////////////////////////////////////////////////// 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: inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } inline bool IsIdle() const { return idle; } - ResultVal<bool> WaitSynchronization() override; + ResultVal<bool> WaitSynchronization(unsigned index) override; s32 GetPriority() const { return current_priority; } void SetPriority(s32 priority); @@ -78,9 +78,29 @@ public: u32 GetThreadId() const { return thread_id; } void Stop(const char* reason); - /// Resumes a thread from waiting by marking it as "ready". + + /** + * Release an object from the thread's wait list + * @param wait_object WaitObject to release from the thread's wait list + */ + void ReleaseFromWait(WaitObject* wait_object); + + /// Resumes a thread from waiting by marking it as "ready" void ResumeFromWait(); + /** + * Sets the waiting mode of the thread + * @param wait_all If true, wait for all objects, otherwise just wait for the first one + */ + void SetWaitAll(bool wait_all) { this->wait_all = wait_all; } + + /** + * Sets the output values after the thread awakens from WaitSynchronization + * @param return_val Value returned + * @param out_val Value to set to the output parameter + */ + void SetReturnValue(ResultCode return_val, s32 out_val); + Core::ThreadContext context; u32 thread_id; @@ -96,7 +116,7 @@ public: s32 processor_id; WaitType wait_type; - std::vector<SharedPtr<WaitObject>> wait_objects; + std::vector<std::pair<SharedPtr<WaitObject>, unsigned>> wait_objects; VAddr wait_address; std::string name; @@ -105,6 +125,8 @@ public: bool idle = false; private: + bool wait_all = false; + Thread() = default; }; @@ -115,37 +137,41 @@ SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size); void Reschedule(); /// Arbitrate the highest priority thread that is waiting -Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address); +Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address); /// Arbitrate all threads currently waiting... -void ArbitrateAllThreads(Object* arbiter, u32 address); +void ArbitrateAllThreads(WaitObject* arbiter, u32 address); /// Gets the current thread Thread* GetCurrentThread(); /** - * Puts the current thread in the wait state for the given type + * Waits the current thread for the given type * @param wait_type Type of wait - * @param wait_object Kernel object that we are waiting on, defaults to current thread */ -void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object = GetCurrentThread()); +void WaitCurrentThread(WaitType wait_type); /** - * Schedules an event to wake up the specified thread after the specified delay. - * @param thread The thread to wake after the delay. - * @param nanoseconds The time this thread will be allowed to sleep for. + * Waits the current thread from a WaitSynchronization call + * @param wait_type Type of wait + * @param wait_object Kernel object that we are waiting on + * @param index Index of calling object (for WaitSynchronizationN only) */ -void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); +void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_object, unsigned index=0); /** - * Puts the current thread in the wait state for the given type - * @param wait_type Type of wait + * Waits the current thread from an ArbitrateAddress call * @param wait_object Kernel object that we are waiting on * @param wait_address Arbitration address used to resume from wait */ -void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address); - +void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address); +/** + * Schedules an event to wake up the specified thread after the specified delay. + * @param handle The thread handle. + * @param nanoseconds The time this thread will be allowed to sleep for. + */ +void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); /** * 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: u64 initial_delay; ///< The delay until the timer fires for the first time u64 interval_delay; ///< The delay until the timer fires after the first time - ResultVal<bool> WaitSynchronization() override { + ResultVal<bool> WaitSynchronization(unsigned index) override { bool wait = !signaled; if (wait) { AddWaitingThread(GetCurrentThread()); - Kernel::WaitCurrentThread(WAITTYPE_TIMER, this); + Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_TIMER, this, index); } return MakeResult<bool>(wait); } @@ -91,7 +91,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { timer->signaled = true; // Resume all waiting threads - timer->ResumeAllWaitingThreads(); + timer->ReleaseAllWaitingThreads(); if (timer->reset_type == RESETTYPE_ONESHOT) timer->signaled = false; |