diff options
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 93 |
1 files changed, 55 insertions, 38 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index eb54d6651..1b891f632 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -7,8 +7,6 @@ #include <optional> #include <vector> -#include <boost/range/algorithm_ext/erase.hpp> - #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" @@ -30,7 +28,7 @@ namespace Kernel { -bool Thread::ShouldWait(Thread* thread) const { +bool Thread::ShouldWait(const Thread* thread) const { return status != ThreadStatus::Dead; } @@ -64,21 +62,12 @@ void Thread::Stop() { } wait_objects.clear(); + owner_process->UnregisterThread(this); + // Mark the TLS slot in the thread's page as free. owner_process->FreeTLSSlot(tls_address); } -void WaitCurrentThread_Sleep() { - Thread* thread = GetCurrentThread(); - thread->SetStatus(ThreadStatus::WaitSleep); -} - -void ExitCurrentThread() { - Thread* thread = GetCurrentThread(); - thread->Stop(); - Core::System::GetInstance().CurrentScheduler().RemoveThread(thread); -} - void Thread::WakeAfterDelay(s64 nanoseconds) { // Don't schedule a wakeup if the thread wants to wait forever if (nanoseconds == -1) @@ -118,6 +107,7 @@ void Thread::ResumeFromWait() { case ThreadStatus::WaitSleep: case ThreadStatus::WaitIPC: case ThreadStatus::WaitMutex: + case ThreadStatus::WaitCondVar: case ThreadStatus::WaitArb: break; @@ -211,9 +201,11 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap(); thread->owner_process = &owner_process; thread->scheduler = &system.Scheduler(processor_id); - thread->scheduler->AddThread(thread, priority); + thread->scheduler->AddThread(thread); thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread); + thread->owner_process->RegisterThread(thread.get()); + // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used // to initialize the context ResetThreadContext(thread->context, stack_top, entry_point, arg); @@ -241,16 +233,16 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { context.cpu_registers[1] = output; } -s32 Thread::GetWaitObjectIndex(WaitObject* object) const { +s32 Thread::GetWaitObjectIndex(const WaitObject* object) const { ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything"); - auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); + const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1); } VAddr Thread::GetCommandBufferAddress() const { // Offset from the start of TLS at which the IPC command buffer begins. - static constexpr int CommandHeaderOffset = 0x80; - return GetTLSAddress() + CommandHeaderOffset; + constexpr u64 command_header_offset = 0x80; + return GetTLSAddress() + command_header_offset; } void Thread::SetStatus(ThreadStatus new_status) { @@ -269,8 +261,8 @@ void Thread::AddMutexWaiter(SharedPtr<Thread> thread) { if (thread->lock_owner == this) { // If the thread is already waiting for this thread to release the mutex, ensure that the // waiters list is consistent and return without doing anything. - auto itr = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); - ASSERT(itr != wait_mutex_threads.end()); + const auto iter = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); + ASSERT(iter != wait_mutex_threads.end()); return; } @@ -278,11 +270,16 @@ void Thread::AddMutexWaiter(SharedPtr<Thread> thread) { ASSERT(thread->lock_owner == nullptr); // Ensure that the thread is not already in the list of mutex waiters - auto itr = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); - ASSERT(itr == wait_mutex_threads.end()); - + const auto iter = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); + ASSERT(iter == wait_mutex_threads.end()); + + // Keep the list in an ordered fashion + const auto insertion_point = std::find_if( + wait_mutex_threads.begin(), wait_mutex_threads.end(), + [&thread](const auto& entry) { return entry->GetPriority() > thread->GetPriority(); }); + wait_mutex_threads.insert(insertion_point, thread); thread->lock_owner = this; - wait_mutex_threads.emplace_back(std::move(thread)); + UpdatePriority(); } @@ -290,32 +287,44 @@ void Thread::RemoveMutexWaiter(SharedPtr<Thread> thread) { ASSERT(thread->lock_owner == this); // Ensure that the thread is in the list of mutex waiters - auto itr = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); - ASSERT(itr != wait_mutex_threads.end()); + const auto iter = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); + ASSERT(iter != wait_mutex_threads.end()); + + wait_mutex_threads.erase(iter); - boost::remove_erase(wait_mutex_threads, thread); thread->lock_owner = nullptr; UpdatePriority(); } void Thread::UpdatePriority() { - // Find the highest priority among all the threads that are waiting for this thread's lock + // If any of the threads waiting on the mutex have a higher priority + // (taking into account priority inheritance), then this thread inherits + // that thread's priority. u32 new_priority = nominal_priority; - for (const auto& thread : wait_mutex_threads) { - if (thread->nominal_priority < new_priority) - new_priority = thread->nominal_priority; + if (!wait_mutex_threads.empty()) { + if (wait_mutex_threads.front()->current_priority < new_priority) { + new_priority = wait_mutex_threads.front()->current_priority; + } } - if (new_priority == current_priority) + if (new_priority == current_priority) { return; + } scheduler->SetThreadPriority(this, new_priority); - current_priority = new_priority; + if (!lock_owner) { + return; + } + + // Ensure that the thread is within the correct location in the waiting list. + auto old_owner = lock_owner; + lock_owner->RemoveMutexWaiter(this); + old_owner->AddMutexWaiter(this); + // Recursively update the priority of the thread that depends on the priority of this one. - if (lock_owner) - lock_owner->UpdatePriority(); + lock_owner->UpdatePriority(); } void Thread::ChangeCore(u32 core, u64 mask) { @@ -347,7 +356,7 @@ void Thread::ChangeScheduler() { if (*new_processor_id != processor_id) { // Remove thread from previous core's scheduler scheduler->RemoveThread(this); - next_scheduler.AddThread(this, current_priority); + next_scheduler.AddThread(this); } processor_id = *new_processor_id; @@ -362,7 +371,7 @@ void Thread::ChangeScheduler() { system.CpuCore(processor_id).PrepareReschedule(); } -bool Thread::AllWaitObjectsReady() { +bool Thread::AllWaitObjectsReady() const { return std::none_of( wait_objects.begin(), wait_objects.end(), [this](const SharedPtr<WaitObject>& object) { return object->ShouldWait(this); }); @@ -391,6 +400,14 @@ void Thread::SetActivity(ThreadActivity value) { } } +void Thread::Sleep(s64 nanoseconds) { + // Sleep current thread and check for next thread to schedule + SetStatus(ThreadStatus::WaitSleep); + + // Create an event to wake the thread up after the specified nanosecond delay has passed + WakeAfterDelay(nanoseconds); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// /** |
