From c22bac6398ff1705992fc44b2c29775c84cff662 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 14 Jan 2015 19:22:50 -0500 Subject: Kernel: Added WaitObject and changed "waitable" objects inherit from it. --- src/core/hle/kernel/thread.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index bc86a7c59..845672702 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -25,10 +25,7 @@ namespace Kernel { ResultVal Thread::WaitSynchronization() { const bool wait = status != THREADSTATUS_DORMANT; if (wait) { - Thread* thread = GetCurrentThread(); - if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { - waiting_threads.push_back(thread); - } + AddWaitingThread(GetCurrentThread()); WaitCurrentThread(WAITTYPE_THREADEND, this); } @@ -110,11 +107,7 @@ void Thread::Stop(const char* reason) { ChangeReadyState(this, false); status = THREADSTATUS_DORMANT; - for (auto& waiting_thread : waiting_threads) { - if (CheckWaitType(waiting_thread.get(), WAITTYPE_THREADEND, this)) - waiting_thread->ResumeFromWait(); - } - waiting_threads.clear(); + ResumeAllWaitingThreads(); // Stopped threads are never waiting. wait_type = WAITTYPE_NONE; -- cgit v1.2.3 From 1f7a04f05a488b7d457d356f9bf2dda296cd6b92 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 14 Jan 2015 23:41:33 -0500 Subject: Thread: Keep track of multiple wait objects. --- src/core/hle/kernel/thread.cpp | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 845672702..00b72477e 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -65,7 +65,7 @@ static void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { t->current_priority = t->initial_priority; } t->wait_type = WAITTYPE_NONE; - t->wait_object = nullptr; + t->wait_objects.clear(); t->wait_address = 0; } @@ -92,7 +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) { - return CheckWaitType(thread, type) && wait_object == thread->wait_object; + auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); + if (itr == thread->wait_objects.end()) { + return false; + } + return CheckWaitType(thread, type); } /// Check if a thread is blocking on a specified wait type with a specified handle and address @@ -111,7 +115,7 @@ void Thread::Stop(const char* reason) { // Stopped threads are never waiting. wait_type = WAITTYPE_NONE; - wait_object = nullptr; + wait_objects.clear(); wait_address = 0; } @@ -216,14 +220,18 @@ static Thread* NextThread() { return next; } -void WaitCurrentThread(WaitType wait_type, Object* wait_object) { +void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object) { Thread* thread = GetCurrentThread(); thread->wait_type = wait_type; - thread->wait_object = wait_object; + + 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); + } ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } -void WaitCurrentThread(WaitType wait_type, Object* wait_object, VAddr wait_address) { +void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address) { WaitCurrentThread(wait_type, wait_object); GetCurrentThread()->wait_address = wait_address; } @@ -260,7 +268,13 @@ void Thread::ResumeFromWait() { CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle()); status &= ~THREADSTATUS_WAIT; - wait_object = nullptr; + + // Remove this thread from all other WaitObjects + for (auto wait_object : wait_objects) + wait_object->RemoveWaitingThread(this); + + wait_objects.clear(); + wait_type = WAITTYPE_NONE; if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { ChangeReadyState(this, true); @@ -328,7 +342,7 @@ ResultVal> 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_object = nullptr; + thread->wait_objects.clear(); thread->wait_address = 0; thread->name = std::move(name); @@ -412,9 +426,8 @@ void Reschedule() { LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); for (auto& thread : thread_list) { - LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X", - thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, - (thread->wait_object ? thread->wait_object->GetHandle() : INVALID_HANDLE)); + LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X", + thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type); } } } -- cgit v1.2.3 From 7faf2d8e06e705d1866fa0d7848ff43541a4b172 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Jan 2015 02:03:44 -0500 Subject: WaitSynchronizationN: Implement return values --- src/core/hle/kernel/thread.cpp | 94 +++++++++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 19 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') 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 Thread::WaitSynchronization() { +ResultVal 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(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, 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> 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() { -- cgit v1.2.3 From aa01c57ae9d73e41b65d37860ca6fbb91caba33a Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Jan 2015 22:23:49 -0500 Subject: Kernel: Separate WaitSynchronization into Wait and Acquire methods. --- src/core/hle/kernel/thread.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 0c9ecc091..6b0bdebb5 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,7 +22,7 @@ namespace Kernel { -ResultVal Thread::WaitSynchronization(unsigned index) { +ResultVal Thread::Wait(unsigned index) { const bool wait = status != THREADSTATUS_DORMANT; if (wait) { AddWaitingThread(GetCurrentThread()); @@ -32,6 +32,10 @@ ResultVal Thread::WaitSynchronization(unsigned index) { return MakeResult(wait); } +ResultVal Thread::Acquire() { + return MakeResult(true); +} + // Lists all thread ids that aren't deleted/etc. static std::vector> thread_list; -- cgit v1.2.3 From 6643673f28b9273149fc945849a13ed832e9ef33 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 01:27:46 -0500 Subject: WaitSynchronizationN: Refactor to fix several bugs - Separate wait checking from waiting the current thread - Resume thread when wait_all=true only if all objects are available at once - Set output to correct wait object index when there are duplicate handles --- src/core/hle/kernel/thread.cpp | 61 +++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 33 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 6b0bdebb5..62b85f56a 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,11 +22,11 @@ namespace Kernel { -ResultVal Thread::Wait(unsigned index) { +ResultVal Thread::Wait(bool wait_thread) { const bool wait = status != THREADSTATUS_DORMANT; - if (wait) { + if (wait && wait_thread) { AddWaitingThread(GetCurrentThread()); - WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this, index); + WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this); } return MakeResult(wait); @@ -97,7 +97,7 @@ 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) { for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { - if (itr->first == wait_object) + if (*itr == wait_object) return CheckWaitType(thread, type); } return false; @@ -234,16 +234,7 @@ void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_ Thread* thread = GetCurrentThread(); thread->wait_type = wait_type; - 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, unsigned>(wait_object, index)); + thread->wait_objects.push_back(wait_object); ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } @@ -288,31 +279,35 @@ void Thread::ReleaseFromWait(WaitObject* wait_object) { return; } - // Remove this thread from the wait_object + // Remove this thread from the waiting object's thread list 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; + unsigned index = 0; + bool wait_all_failed = false; // Will be set to true if any object is unavailable - // Remove the wait_object from this thread - if (itr != wait_objects.end()) - wait_objects.erase(itr); + // Iterate through all waiting objects to check availability... + for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { + auto res = (*itr)->Wait(false); - // 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()) { + if (*res && res.Succeeded()) + wait_all_failed = true; + + // The output should be the last index of wait_object + if (*itr == wait_object) + index = itr - wait_objects.begin(); + } + + // If we are waiting on all objects... + if (wait_all) { + // Resume the thread only if all are available... + if (!wait_all_failed) { SetReturnValue(RESULT_SUCCESS, -1); ResumeFromWait(); } + } else { + // Otherwise, resume + SetReturnValue(RESULT_SUCCESS, index); + ResumeFromWait(); } } @@ -324,7 +319,7 @@ void Thread::ResumeFromWait() { // Remove this thread from all other WaitObjects for (auto wait_object : wait_objects) - wait_object.first->RemoveWaitingThread(this); + wait_object->RemoveWaitingThread(this); wait_objects.clear(); -- cgit v1.2.3 From e5a9f1c64483e01b7856c581ae5685d0c5ad88dc Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 13:25:51 -0500 Subject: Kernel: Get rid of WaitTypes and simplify lots of code, removing hacks. --- src/core/hle/kernel/thread.cpp | 65 ++++++++++++------------------------------ 1 file changed, 19 insertions(+), 46 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 62b85f56a..601e0eb20 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,14 +22,8 @@ namespace Kernel { -ResultVal Thread::Wait(bool wait_thread) { - const bool wait = status != THREADSTATUS_DORMANT; - if (wait && wait_thread) { - AddWaitingThread(GetCurrentThread()); - WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this); - } - - return MakeResult(wait); +ResultVal Thread::Wait() { + return MakeResult(status != THREADSTATUS_DORMANT); } ResultVal Thread::Acquire() { @@ -68,7 +62,7 @@ static void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { if (t->current_priority < lowest_priority) { t->current_priority = t->initial_priority; } - t->wait_type = WAITTYPE_NONE; + t->wait_objects.clear(); t->wait_address = 0; } @@ -89,23 +83,18 @@ static void ChangeReadyState(Thread* t, bool ready) { } } -/// Check if a thread is blocking on a specified wait type -static bool CheckWaitType(const Thread* thread, WaitType type) { - return (type == thread->wait_type) && (thread->IsWaiting()); -} - -/// 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) { +/// Check if a thread is blocking on a the specified object +static bool CheckWaitType(const Thread* thread, Object* wait_object) { for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { if (*itr == wait_object) - return CheckWaitType(thread, type); + return (thread->IsWaiting()); } return false; } -/// Check if a thread is blocking on a specified wait type with a specified handle and address -static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object, VAddr wait_address) { - return CheckWaitType(thread, type, wait_object) && (wait_address == thread->wait_address); +/// Check if a thread is blocking on a the specified object and an address +static bool CheckWaitType(const Thread* thread, Object* wait_object, VAddr wait_address) { + return CheckWaitType(thread, wait_object) && (wait_address == thread->wait_address); } /// Stops the current thread @@ -118,7 +107,6 @@ void Thread::Stop(const char* reason) { ReleaseAllWaitingThreads(); // Stopped threads are never waiting. - wait_type = WAITTYPE_NONE; wait_objects.clear(); wait_address = 0; } @@ -130,12 +118,6 @@ static void ChangeThreadState(Thread* t, ThreadStatus new_status) { } ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0); t->status = new_status; - - if (new_status == THREADSTATUS_WAIT) { - if (t->wait_type == WAITTYPE_NONE) { - LOG_ERROR(Kernel, "Waittype none not allowed"); - } - } } /// Arbitrate the highest priority thread that is waiting @@ -145,7 +127,7 @@ Thread* ArbitrateHighestPriorityThread(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)) + if (!CheckWaitType(thread.get(), arbiter, address)) continue; if (thread == nullptr) @@ -170,7 +152,7 @@ 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)) + if (CheckWaitType(thread.get(), arbiter, address)) thread->ReleaseFromWait(arbiter); } } @@ -178,9 +160,6 @@ void ArbitrateAllThreads(WaitObject* arbiter, u32 address) { /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) static void CallThread(Thread* t) { // Stop waiting - if (t->wait_type != WAITTYPE_NONE) { - t->wait_type = WAITTYPE_NONE; - } ChangeThreadState(t, THREADSTATUS_READY); } @@ -201,7 +180,6 @@ static void SwitchContext(Thread* t) { current_thread = t; ChangeReadyState(t, false); t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; - t->wait_type = WAITTYPE_NONE; Core::g_app_core->LoadContext(t->context); } else { current_thread = nullptr; @@ -224,23 +202,20 @@ static Thread* NextThread() { return next; } -void WaitCurrentThread(WaitType wait_type) { +void WaitCurrentThread() { 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) { +void WaitCurrentThread_WaitSynchronization(WaitObject* wait_object, bool wait_all) { Thread* thread = GetCurrentThread(); - thread->wait_type = wait_type; - + thread->wait_all = wait_all; thread->wait_objects.push_back(wait_object); - ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address) { - WaitCurrentThread_WaitSynchronization(WaitType::WAITTYPE_ARB, wait_object, 0); + WaitCurrentThread_WaitSynchronization(wait_object); GetCurrentThread()->wait_address = wait_address; } @@ -287,7 +262,7 @@ void Thread::ReleaseFromWait(WaitObject* wait_object) { // Iterate through all waiting objects to check availability... for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { - auto res = (*itr)->Wait(false); + auto res = (*itr)->Wait(); if (*res && res.Succeeded()) wait_all_failed = true; @@ -322,9 +297,8 @@ void Thread::ResumeFromWait() { wait_object->RemoveWaitingThread(this); wait_objects.clear(); - - wait_type = WAITTYPE_NONE; wait_all = false; + if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { ChangeReadyState(this, true); } @@ -390,7 +364,6 @@ ResultVal> Thread::Create(std::string name, VAddr entry_point, thread->stack_size = stack_size; 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; @@ -476,8 +449,8 @@ void Reschedule() { LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); for (auto& thread : thread_list) { - LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X", - thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type); + LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X", thread->GetHandle(), + thread->current_priority, thread->status); } } } -- cgit v1.2.3 From 254e4ebd58a31e8462b70799f95f096d0d0038f2 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 13:56:40 -0500 Subject: AddressArbiter: Changed to Kernel::Object, big cleanup, removed code that made no sense. --- src/core/hle/kernel/thread.cpp | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 601e0eb20..16865ccc4 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -83,8 +83,8 @@ static void ChangeReadyState(Thread* t, bool ready) { } } -/// Check if a thread is blocking on a the specified object -static bool CheckWaitType(const Thread* thread, Object* wait_object) { +/// Check if a thread is waiting on a the specified wait object +static bool CheckWait_WaitObject(const Thread* thread, WaitObject* wait_object) { for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { if (*itr == wait_object) return (thread->IsWaiting()); @@ -92,9 +92,9 @@ static bool CheckWaitType(const Thread* thread, Object* wait_object) { return false; } -/// Check if a thread is blocking on a the specified object and an address -static bool CheckWaitType(const Thread* thread, Object* wait_object, VAddr wait_address) { - return CheckWaitType(thread, wait_object) && (wait_address == thread->wait_address); +/// Check if the specified thread is waiting on the specified address to be arbitrated +static bool CheckWait_AddressArbiter(const Thread* thread, VAddr wait_address) { + return thread->IsWaiting() && thread->wait_objects.empty() && wait_address == thread->wait_address; } /// Stops the current thread @@ -121,17 +121,17 @@ static void ChangeThreadState(Thread* t, ThreadStatus new_status) { } /// Arbitrate the highest priority thread that is waiting -Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address) { +Thread* ArbitrateHighestPriorityThread(u32 address) { Thread* highest_priority_thread = nullptr; s32 priority = THREADPRIO_LOWEST; // Iterate through threads, find highest priority thread that is waiting to be arbitrated... for (auto& thread : thread_list) { - if (!CheckWaitType(thread.get(), arbiter, address)) + if (!CheckWait_AddressArbiter(thread.get(), address)) continue; if (thread == nullptr) - continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. + continue; if(thread->current_priority <= priority) { highest_priority_thread = thread.get(); @@ -141,19 +141,19 @@ Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address) { // If a thread was arbitrated, resume it if (nullptr != highest_priority_thread) { - highest_priority_thread->ReleaseFromWait(arbiter); + highest_priority_thread->ResumeFromWait(); } return highest_priority_thread; } /// Arbitrate all threads currently waiting -void ArbitrateAllThreads(WaitObject* arbiter, u32 address) { +void ArbitrateAllThreads(u32 address) { // Iterate through threads, find highest priority thread that is waiting to be arbitrated... for (auto& thread : thread_list) { - if (CheckWaitType(thread.get(), arbiter, address)) - thread->ReleaseFromWait(arbiter); + if (CheckWait_AddressArbiter(thread.get(), address)) + thread->ResumeFromWait(); } } @@ -202,21 +202,28 @@ static Thread* NextThread() { return next; } -void WaitCurrentThread() { +void WaitCurrentThread_Sleep() { Thread* thread = GetCurrentThread(); + thread->wait_all = false; + thread->wait_address = 0; + thread->wait_objects.clear(); ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } void WaitCurrentThread_WaitSynchronization(WaitObject* wait_object, bool wait_all) { Thread* thread = GetCurrentThread(); thread->wait_all = wait_all; + thread->wait_address = 0; thread->wait_objects.push_back(wait_object); ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } -void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address) { - WaitCurrentThread_WaitSynchronization(wait_object); - GetCurrentThread()->wait_address = wait_address; +void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { + Thread* thread = GetCurrentThread(); + thread->wait_all = false; + thread->wait_address = wait_address; + thread->wait_objects.clear(); + ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } /// Event type for the thread wake up event @@ -248,7 +255,7 @@ void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) { CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); } -void Thread::ReleaseFromWait(WaitObject* wait_object) { +void Thread::ReleaseWaitObject(WaitObject* wait_object) { if (wait_objects.empty()) { LOG_CRITICAL(Kernel, "thread is not waiting on any objects!"); return; @@ -298,6 +305,7 @@ void Thread::ResumeFromWait() { wait_objects.clear(); wait_all = false; + wait_address = 0; if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { ChangeReadyState(this, true); -- cgit v1.2.3 From 9412996c8f86f5da5a9052f7533b05e9780c4eb0 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 14:33:11 -0500 Subject: Kernel: Moved Wait and Acquire to WaitObject, added way to retrieve a WaitObject safely. --- src/core/hle/kernel/thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 16865ccc4..271828ea7 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -210,7 +210,7 @@ void WaitCurrentThread_Sleep() { ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } -void WaitCurrentThread_WaitSynchronization(WaitObject* wait_object, bool wait_all) { +void WaitCurrentThread_WaitSynchronization(SharedPtr wait_object, bool wait_all) { Thread* thread = GetCurrentThread(); thread->wait_all = wait_all; thread->wait_address = 0; -- cgit v1.2.3 From c68eb1569549ae49ae25c6c29cec2e10d8329f2d Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 17:41:12 -0500 Subject: WaitObject: Renamed "Wait" to "ShouldWait", made "ShouldWait" and "Acquire" pure virtual. --- src/core/hle/kernel/thread.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 271828ea7..8a2cf8bf4 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,7 +22,7 @@ namespace Kernel { -ResultVal Thread::Wait() { +ResultVal Thread::ShouldWait() { return MakeResult(status != THREADSTATUS_DORMANT); } @@ -269,7 +269,7 @@ void Thread::ReleaseWaitObject(WaitObject* wait_object) { // Iterate through all waiting objects to check availability... for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { - auto res = (*itr)->Wait(); + auto res = (*itr)->ShouldWait(); if (*res && res.Succeeded()) wait_all_failed = true; -- cgit v1.2.3 From 15b6a4d9add6b260a2a1a84ab6228addced4f851 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 18:16:45 -0500 Subject: Kernel: Changed "ShouldWait" to return bool and "Acquire" to return void. --- src/core/hle/kernel/thread.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 8a2cf8bf4..7a7f430cf 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,12 +22,12 @@ namespace Kernel { -ResultVal Thread::ShouldWait() { - return MakeResult(status != THREADSTATUS_DORMANT); +bool Thread::ShouldWait() { + return status != THREADSTATUS_DORMANT; } -ResultVal Thread::Acquire() { - return MakeResult(true); +void Thread::Acquire() { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); } // Lists all thread ids that aren't deleted/etc. @@ -269,9 +269,7 @@ void Thread::ReleaseWaitObject(WaitObject* wait_object) { // Iterate through all waiting objects to check availability... for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { - auto res = (*itr)->ShouldWait(); - - if (*res && res.Succeeded()) + if ((*itr)->ShouldWait()) wait_all_failed = true; // The output should be the last index of wait_object -- cgit v1.2.3 From f09806aed24b2f7de7d969cbfdb3b9d18ab90c61 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 18:20:47 -0500 Subject: Kernel: Renamed some functions for clarity. - ReleaseNextThread->WakeupNextThread - ReleaseAllWaitingThreads->WakeupAllWaitingThreads. --- src/core/hle/kernel/thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 7a7f430cf..ab1126a36 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -104,7 +104,7 @@ void Thread::Stop(const char* reason) { ChangeReadyState(this, false); status = THREADSTATUS_DORMANT; - ReleaseAllWaitingThreads(); + WakeupAllWaitingThreads(); // Stopped threads are never waiting. wait_objects.clear(); -- cgit v1.2.3 From 2f3020a10247a0cb47848a6f8c19fbde50a7e0a6 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 18:33:23 -0500 Subject: Mutex: Cleanup and remove redundant code. --- src/core/hle/kernel/thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ab1126a36..3ca9603c2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -100,7 +100,7 @@ static bool CheckWait_AddressArbiter(const Thread* thread, VAddr wait_address) { /// Stops the current thread void Thread::Stop(const char* reason) { // Release all the mutexes that this thread holds - ReleaseThreadMutexes(GetHandle()); + ReleaseThreadMutexes(this); ChangeReadyState(this, false); status = THREADSTATUS_DORMANT; -- cgit v1.2.3 From 4255f25647dee3ae6098d14adbb3db0749935120 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 18:40:01 -0500 Subject: Thread: Use std::find in CheckWait_WaitObject. --- src/core/hle/kernel/thread.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 3ca9603c2..58523e145 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -85,10 +85,11 @@ static void ChangeReadyState(Thread* t, bool ready) { /// Check if a thread is waiting on a the specified wait object static bool CheckWait_WaitObject(const Thread* thread, WaitObject* wait_object) { - for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { - if (*itr == wait_object) - return (thread->IsWaiting()); - } + auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); + + if (itr != thread->wait_objects.end()) + return thread->IsWaiting(); + return false; } -- cgit v1.2.3 From 68ddaaa2f5726e3619accee77b488ec285f3a2d7 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 20:53:52 -0500 Subject: Thread: Fix WaitSynchronization1 to not set register 1 on thread wakeup. --- src/core/hle/kernel/thread.cpp | 43 +++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 58523e145..03b492c75 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -205,25 +205,24 @@ static Thread* NextThread() { void WaitCurrentThread_Sleep() { Thread* thread = GetCurrentThread(); - thread->wait_all = false; - thread->wait_address = 0; - thread->wait_objects.clear(); ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } -void WaitCurrentThread_WaitSynchronization(SharedPtr wait_object, bool wait_all) { +void WaitCurrentThread_WaitSynchronization(SharedPtr wait_object, bool wait_set_output, bool wait_all) { Thread* thread = GetCurrentThread(); + thread->wait_set_output = wait_set_output; thread->wait_all = wait_all; - thread->wait_address = 0; - thread->wait_objects.push_back(wait_object); + + // It's possible to call WaitSynchronizationN without any objects passed in... + if (wait_object != nullptr) + thread->wait_objects.push_back(wait_object); + ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { Thread* thread = GetCurrentThread(); - thread->wait_all = false; thread->wait_address = wait_address; - thread->wait_objects.clear(); ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } @@ -239,8 +238,11 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) { return; } - thread->SetReturnValue(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, - ErrorSummary::StatusChanged, ErrorLevel::Info), -1); + thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, + ErrorSummary::StatusChanged, ErrorLevel::Info)); + + if (thread->wait_set_output) + thread->SetWaitSynchronizationOutput(-1); thread->ResumeFromWait(); } @@ -282,12 +284,18 @@ void Thread::ReleaseWaitObject(WaitObject* wait_object) { if (wait_all) { // Resume the thread only if all are available... if (!wait_all_failed) { - SetReturnValue(RESULT_SUCCESS, -1); + SetWaitSynchronizationResult(RESULT_SUCCESS); + SetWaitSynchronizationOutput(-1); + ResumeFromWait(); } } else { // Otherwise, resume - SetReturnValue(RESULT_SUCCESS, index); + SetWaitSynchronizationResult(RESULT_SUCCESS); + + if (wait_set_output) + SetWaitSynchronizationOutput(index); + ResumeFromWait(); } } @@ -303,6 +311,7 @@ void Thread::ResumeFromWait() { wait_object->RemoveWaitingThread(this); wait_objects.clear(); + wait_set_output = false; wait_all = false; wait_address = 0; @@ -371,6 +380,7 @@ ResultVal> Thread::Create(std::string name, VAddr entry_point, thread->stack_size = stack_size; thread->initial_priority = thread->current_priority = priority; thread->processor_id = processor_id; + thread->wait_set_output = false; thread->wait_all = false; thread->wait_objects.clear(); thread->wait_address = 0; @@ -462,9 +472,12 @@ 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 Thread::SetWaitSynchronizationResult(ResultCode result) { + context.cpu_registers[0] = result.raw; +} + +void Thread::SetWaitSynchronizationOutput(s32 output) { + context.cpu_registers[1] = output; } //////////////////////////////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3