From 35c3c078e3c079c0a9192b411e20c71b122ff057 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 21 Dec 2020 22:36:53 -0800 Subject: core: hle: kernel: Update KSynchronizationObject. --- src/core/hle/kernel/thread.cpp | 66 ++++++++++++------------------------------ 1 file changed, 19 insertions(+), 47 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 a4f9e0d97..ac19e2997 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -34,26 +34,19 @@ namespace Kernel { -bool Thread::ShouldWait(const Thread* thread) const { - return status != ThreadStatus::Dead; -} - bool Thread::IsSignaled() const { - return status == ThreadStatus::Dead; + return signaled; } -void Thread::Acquire(Thread* thread) { - ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); -} - -Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {} +Thread::Thread(KernelCore& kernel) : KSynchronizationObject{kernel} {} Thread::~Thread() = default; void Thread::Stop() { { KScopedSchedulerLock lock(kernel); - SetStatus(ThreadStatus::Dead); - Signal(); + SetState(ThreadStatus::Dead); + signaled = true; + NotifyAvailable(); kernel.GlobalHandleTable().Close(global_handle); if (owner_process) { @@ -67,7 +60,7 @@ void Thread::Stop() { global_handle = 0; } -void Thread::ResumeFromWait() { +void Thread::Wakeup() { KScopedSchedulerLock lock(kernel); switch (status) { case ThreadStatus::Paused: @@ -82,9 +75,6 @@ void Thread::ResumeFromWait() { break; case ThreadStatus::Ready: - // The thread's wakeup callback must have already been cleared when the thread was first - // awoken. - ASSERT(hle_callback == nullptr); // If the thread is waiting on multiple wait objects, it might be awoken more than once // before actually resuming. We can ignore subsequent wakeups if the thread status has // already been set to ThreadStatus::Ready. @@ -96,30 +86,30 @@ void Thread::ResumeFromWait() { return; } - SetStatus(ThreadStatus::Ready); + SetState(ThreadStatus::Ready); } void Thread::OnWakeUp() { KScopedSchedulerLock lock(kernel); - SetStatus(ThreadStatus::Ready); + SetState(ThreadStatus::Ready); } ResultCode Thread::Start() { KScopedSchedulerLock lock(kernel); - SetStatus(ThreadStatus::Ready); + SetState(ThreadStatus::Ready); return RESULT_SUCCESS; } void Thread::CancelWait() { KScopedSchedulerLock lock(kernel); - if (GetSchedulingStatus() != ThreadSchedStatus::Paused || !is_waiting_on_sync) { + if (GetState() != ThreadSchedStatus::Paused || !is_cancellable) { is_sync_cancelled = true; return; } // TODO(Blinkhawk): Implement cancel of server session is_sync_cancelled = false; SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); - SetStatus(ThreadStatus::Ready); + SetState(ThreadStatus::Ready); } static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, @@ -194,7 +184,6 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy thread->processor_id = processor_id; thread->ideal_core = processor_id; thread->affinity_mask.SetAffinity(processor_id, true); - thread->wait_objects = nullptr; thread->mutex_wait_address = 0; thread->condvar_wait_address = 0; thread->wait_handle = 0; @@ -202,6 +191,7 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); thread->owner_process = owner_process; thread->type = type_flags; + thread->signaled = false; if ((type_flags & THREADTYPE_IDLE) == 0) { auto& scheduler = kernel.GlobalSchedulerContext(); scheduler.AddThread(thread); @@ -234,24 +224,18 @@ void Thread::SetPriority(u32 priority) { UpdatePriority(); } -void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode result) { +void Thread::SetSynchronizationResults(KSynchronizationObject* object, ResultCode result) { signaling_object = object; signaling_result = result; } -s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr object) const { - ASSERT_MSG(!wait_objects->empty(), "Thread is not waiting for anything"); - const auto match = std::find(wait_objects->rbegin(), wait_objects->rend(), object); - return static_cast(std::distance(match, wait_objects->rend()) - 1); -} - VAddr Thread::GetCommandBufferAddress() const { // Offset from the start of TLS at which the IPC command buffer begins. constexpr u64 command_header_offset = 0x80; return GetTLSAddress() + command_header_offset; } -void Thread::SetStatus(ThreadStatus new_status) { +void Thread::SetState(ThreadStatus new_status) { if (new_status == status) { return; } @@ -351,28 +335,16 @@ void Thread::UpdatePriority() { lock_owner->UpdatePriority(); } -bool Thread::AllSynchronizationObjectsReady() const { - return std::none_of(wait_objects->begin(), wait_objects->end(), - [this](const std::shared_ptr& object) { - return object->ShouldWait(this); - }); -} - -bool Thread::InvokeHLECallback(std::shared_ptr thread) { - ASSERT(hle_callback); - return hle_callback(std::move(thread)); -} - ResultCode Thread::SetActivity(ThreadActivity value) { KScopedSchedulerLock lock(kernel); - auto sched_status = GetSchedulingStatus(); + auto sched_status = GetState(); if (sched_status != ThreadSchedStatus::Runnable && sched_status != ThreadSchedStatus::Paused) { return ERR_INVALID_STATE; } - if (IsPendingTermination()) { + if (IsTerminationRequested()) { return RESULT_SUCCESS; } @@ -394,7 +366,7 @@ ResultCode Thread::Sleep(s64 nanoseconds) { Handle event_handle{}; { KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); - SetStatus(ThreadStatus::WaitSleep); + SetState(ThreadStatus::WaitSleep); } if (event_handle != InvalidHandle) { @@ -407,7 +379,7 @@ ResultCode Thread::Sleep(s64 nanoseconds) { void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { const u32 old_state = scheduling_state; pausing_state |= static_cast(flag); - const u32 base_scheduling = static_cast(GetSchedulingStatus()); + const u32 base_scheduling = static_cast(GetState()); scheduling_state = base_scheduling | pausing_state; KScheduler::OnThreadStateChanged(kernel, this, old_state); } @@ -415,7 +387,7 @@ void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { const u32 old_state = scheduling_state; pausing_state &= ~static_cast(flag); - const u32 base_scheduling = static_cast(GetSchedulingStatus()); + const u32 base_scheduling = static_cast(GetState()); scheduling_state = base_scheduling | pausing_state; KScheduler::OnThreadStateChanged(kernel, this, old_state); } -- cgit v1.2.3 From c3c43e32fcf198444acb493483e03fcb193156df Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 28 Dec 2020 13:16:43 -0800 Subject: hle: kernel: thread: Replace ThreadStatus/ThreadSchedStatus with a single ThreadState. - This is how the real kernel works, and is more accurate and simpler. --- src/core/hle/kernel/thread.cpp | 81 ++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 51 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 ac19e2997..33a4e1fa3 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -44,7 +44,7 @@ Thread::~Thread() = default; void Thread::Stop() { { KScopedSchedulerLock lock(kernel); - SetState(ThreadStatus::Dead); + SetState(ThreadState::Terminated); signaled = true; NotifyAvailable(); kernel.GlobalHandleTable().Close(global_handle); @@ -62,54 +62,43 @@ void Thread::Stop() { void Thread::Wakeup() { KScopedSchedulerLock lock(kernel); - switch (status) { - case ThreadStatus::Paused: - case ThreadStatus::WaitSynch: - case ThreadStatus::WaitHLEEvent: - case ThreadStatus::WaitSleep: - case ThreadStatus::WaitIPC: - case ThreadStatus::WaitMutex: - case ThreadStatus::WaitCondVar: - case ThreadStatus::WaitArb: - case ThreadStatus::Dormant: - break; - - case ThreadStatus::Ready: + switch (thread_state) { + case ThreadState::Runnable: // If the thread is waiting on multiple wait objects, it might be awoken more than once // before actually resuming. We can ignore subsequent wakeups if the thread status has // already been set to ThreadStatus::Ready. return; - case ThreadStatus::Dead: + case ThreadState::Terminated: // This should never happen, as threads must complete before being stopped. DEBUG_ASSERT_MSG(false, "Thread with object id {} cannot be resumed because it's DEAD.", GetObjectId()); return; } - SetState(ThreadStatus::Ready); + SetState(ThreadState::Runnable); } void Thread::OnWakeUp() { KScopedSchedulerLock lock(kernel); - SetState(ThreadStatus::Ready); + SetState(ThreadState::Runnable); } ResultCode Thread::Start() { KScopedSchedulerLock lock(kernel); - SetState(ThreadStatus::Ready); + SetState(ThreadState::Runnable); return RESULT_SUCCESS; } void Thread::CancelWait() { KScopedSchedulerLock lock(kernel); - if (GetState() != ThreadSchedStatus::Paused || !is_cancellable) { + if (GetState() != ThreadState::Waiting || !is_cancellable) { is_sync_cancelled = true; return; } // TODO(Blinkhawk): Implement cancel of server session is_sync_cancelled = false; SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); - SetState(ThreadStatus::Ready); + SetState(ThreadState::Runnable); } static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, @@ -173,7 +162,7 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy std::shared_ptr thread = std::make_shared(kernel); thread->thread_id = kernel.CreateNewThreadID(); - thread->status = ThreadStatus::Dormant; + thread->thread_state = ThreadState::Initialized; thread->entry_point = entry_point; thread->stack_top = stack_top; thread->disable_count = 1; @@ -235,27 +224,18 @@ VAddr Thread::GetCommandBufferAddress() const { return GetTLSAddress() + command_header_offset; } -void Thread::SetState(ThreadStatus new_status) { - if (new_status == status) { +void Thread::SetState(ThreadState new_status) { + if (new_status == thread_state) { return; } - switch (new_status) { - case ThreadStatus::Ready: - SetSchedulingStatus(ThreadSchedStatus::Runnable); - break; - case ThreadStatus::Dormant: - SetSchedulingStatus(ThreadSchedStatus::None); - break; - case ThreadStatus::Dead: - SetSchedulingStatus(ThreadSchedStatus::Exited); - break; - default: - SetSchedulingStatus(ThreadSchedStatus::Paused); - break; + if (new_status != ThreadState::Waiting) { + SetWaitingCondVar(false); } - status = new_status; + SetSchedulingStatus(new_status); + + thread_state = new_status; } void Thread::AddMutexWaiter(std::shared_ptr thread) { @@ -312,13 +292,13 @@ void Thread::UpdatePriority() { return; } - if (GetStatus() == ThreadStatus::WaitCondVar) { + if (GetState() == ThreadState::Waiting && is_waiting_on_condvar) { owner_process->RemoveConditionVariableThread(SharedFrom(this)); } SetCurrentPriority(new_priority); - if (GetStatus() == ThreadStatus::WaitCondVar) { + if (GetState() == ThreadState::Waiting && is_waiting_on_condvar) { owner_process->InsertConditionVariableThread(SharedFrom(this)); } @@ -340,7 +320,7 @@ ResultCode Thread::SetActivity(ThreadActivity value) { auto sched_status = GetState(); - if (sched_status != ThreadSchedStatus::Runnable && sched_status != ThreadSchedStatus::Paused) { + if (sched_status != ThreadState::Runnable && sched_status != ThreadState::Waiting) { return ERR_INVALID_STATE; } @@ -366,7 +346,7 @@ ResultCode Thread::Sleep(s64 nanoseconds) { Handle event_handle{}; { KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); - SetState(ThreadStatus::WaitSleep); + SetState(ThreadState::Waiting); } if (event_handle != InvalidHandle) { @@ -377,25 +357,24 @@ ResultCode Thread::Sleep(s64 nanoseconds) { } void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { - const u32 old_state = scheduling_state; + const auto old_state = GetRawState(); pausing_state |= static_cast(flag); - const u32 base_scheduling = static_cast(GetState()); - scheduling_state = base_scheduling | pausing_state; + const auto base_scheduling = GetState(); + thread_state = base_scheduling | static_cast(pausing_state); KScheduler::OnThreadStateChanged(kernel, this, old_state); } void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { - const u32 old_state = scheduling_state; + const auto old_state = GetRawState(); pausing_state &= ~static_cast(flag); - const u32 base_scheduling = static_cast(GetState()); - scheduling_state = base_scheduling | pausing_state; + const auto base_scheduling = GetState(); + thread_state = base_scheduling | static_cast(pausing_state); KScheduler::OnThreadStateChanged(kernel, this, old_state); } -void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { - const u32 old_state = scheduling_state; - scheduling_state = (scheduling_state & static_cast(ThreadSchedMasks::HighMask)) | - static_cast(new_status); +void Thread::SetSchedulingStatus(ThreadState new_status) { + const auto old_state = GetRawState(); + thread_state = (thread_state & ThreadState::HighMask) | new_status; KScheduler::OnThreadStateChanged(kernel, this, old_state); } -- cgit v1.2.3 From 912dd501465ffaabd149cc3532839e346982b337 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 30 Dec 2020 01:14:02 -0800 Subject: core: hle: Integrate new KConditionVariable and KAddressArbiter implementations. --- src/core/hle/kernel/thread.cpp | 227 +++++++++++++++++++++++------------------ 1 file changed, 127 insertions(+), 100 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 33a4e1fa3..eda56c31c 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -17,9 +17,11 @@ #include "core/hardware_properties.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/k_condition_variable.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/memory/memory_layout.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/thread.h" @@ -61,24 +63,6 @@ void Thread::Stop() { } void Thread::Wakeup() { - KScopedSchedulerLock lock(kernel); - switch (thread_state) { - case ThreadState::Runnable: - // If the thread is waiting on multiple wait objects, it might be awoken more than once - // before actually resuming. We can ignore subsequent wakeups if the thread status has - // already been set to ThreadStatus::Ready. - return; - case ThreadState::Terminated: - // This should never happen, as threads must complete before being stopped. - DEBUG_ASSERT_MSG(false, "Thread with object id {} cannot be resumed because it's DEAD.", - GetObjectId()); - return; - } - - SetState(ThreadState::Runnable); -} - -void Thread::OnWakeUp() { KScopedSchedulerLock lock(kernel); SetState(ThreadState::Runnable); } @@ -167,15 +151,14 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy thread->stack_top = stack_top; thread->disable_count = 1; thread->tpidr_el0 = 0; - thread->nominal_priority = thread->current_priority = priority; + thread->current_priority = priority; + thread->base_priority = priority; + thread->lock_owner = nullptr; thread->schedule_count = -1; thread->last_scheduled_tick = 0; thread->processor_id = processor_id; thread->ideal_core = processor_id; thread->affinity_mask.SetAffinity(processor_id, true); - thread->mutex_wait_address = 0; - thread->condvar_wait_address = 0; - thread->wait_handle = 0; thread->name = std::move(name); thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); thread->owner_process = owner_process; @@ -205,12 +188,17 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy return MakeResult>(std::move(thread)); } -void Thread::SetPriority(u32 priority) { - KScopedSchedulerLock lock(kernel); +void Thread::SetBasePriority(u32 priority) { ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, "Invalid priority value."); - nominal_priority = priority; - UpdatePriority(); + + KScopedSchedulerLock lock(kernel); + + // Change our base priority. + base_priority = priority; + + // Perform a priority restoration. + RestorePriority(kernel, this); } void Thread::SetSynchronizationResults(KSynchronizationObject* object, ResultCode result) { @@ -224,95 +212,146 @@ VAddr Thread::GetCommandBufferAddress() const { return GetTLSAddress() + command_header_offset; } -void Thread::SetState(ThreadState new_status) { - if (new_status == thread_state) { - return; +void Thread::SetState(ThreadState state) { + KScopedSchedulerLock sl(kernel); + + SetMutexWaitAddressForDebugging(0); + const ThreadState old_state = thread_state; + thread_state = + static_cast((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask)); + if (thread_state != old_state) { + KScheduler::OnThreadStateChanged(kernel, this, old_state); } +} + +void Thread::AddWaiterImpl(Thread* thread) { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); - if (new_status != ThreadState::Waiting) { - SetWaitingCondVar(false); + // Find the right spot to insert the waiter. + auto it = waiter_list.begin(); + while (it != waiter_list.end()) { + if (it->GetPriority() > thread->GetPriority()) { + break; + } + it++; } - SetSchedulingStatus(new_status); + // Keep track of how many kernel waiters we have. + if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { + ASSERT((num_kernel_waiters++) >= 0); + } - thread_state = new_status; + // Insert the waiter. + waiter_list.insert(it, *thread); + thread->SetLockOwner(this); } -void Thread::AddMutexWaiter(std::shared_ptr thread) { - if (thread->lock_owner.get() == 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. - const auto iter = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); - ASSERT(iter != wait_mutex_threads.end()); - return; +void Thread::RemoveWaiterImpl(Thread* thread) { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + + // Keep track of how many kernel waiters we have. + if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { + ASSERT((num_kernel_waiters--) > 0); } - // A thread can't wait on two different mutexes at the same time. - ASSERT(thread->lock_owner == nullptr); + // Remove the waiter. + waiter_list.erase(waiter_list.iterator_to(*thread)); + thread->SetLockOwner(nullptr); +} - // Ensure that the thread is not already in the list of mutex waiters - const auto iter = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); - ASSERT(iter == wait_mutex_threads.end()); +void Thread::RestorePriority(KernelCore& kernel, Thread* thread) { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); - // 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 = SharedFrom(this); + while (true) { + // We want to inherit priority where possible. + s32 new_priority = thread->GetBasePriority(); + if (thread->HasWaiters()) { + new_priority = std::min(new_priority, thread->waiter_list.front().GetPriority()); + } - UpdatePriority(); -} + // If the priority we would inherit is not different from ours, don't do anything. + if (new_priority == thread->GetPriority()) { + return; + } -void Thread::RemoveMutexWaiter(std::shared_ptr thread) { - ASSERT(thread->lock_owner.get() == this); + // Ensure we don't violate condition variable red black tree invariants. + if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { + BeforeUpdatePriority(kernel, cv_tree, thread); + } - // Ensure that the thread is in the list of mutex waiters - const auto iter = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); - ASSERT(iter != wait_mutex_threads.end()); + // Change the priority. + const s32 old_priority = thread->GetPriority(); + thread->SetPriority(new_priority); - wait_mutex_threads.erase(iter); + // Restore the condition variable, if relevant. + if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { + AfterUpdatePriority(kernel, cv_tree, thread); + } - thread->lock_owner = nullptr; - UpdatePriority(); -} + // Update the scheduler. + KScheduler::OnThreadPriorityChanged(kernel, thread, old_priority); -void Thread::UpdatePriority() { - // 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; - if (!wait_mutex_threads.empty()) { - if (wait_mutex_threads.front()->current_priority < new_priority) { - new_priority = wait_mutex_threads.front()->current_priority; + // Keep the lock owner up to date. + Thread* lock_owner = thread->GetLockOwner(); + if (lock_owner == nullptr) { + return; } - } - if (new_priority == current_priority) { - return; + // Update the thread in the lock owner's sorted list, and continue inheriting. + lock_owner->RemoveWaiterImpl(thread); + lock_owner->AddWaiterImpl(thread); + thread = lock_owner; } +} - if (GetState() == ThreadState::Waiting && is_waiting_on_condvar) { - owner_process->RemoveConditionVariableThread(SharedFrom(this)); - } +void Thread::AddWaiter(Thread* thread) { + AddWaiterImpl(thread); + RestorePriority(kernel, this); +} - SetCurrentPriority(new_priority); +void Thread::RemoveWaiter(Thread* thread) { + RemoveWaiterImpl(thread); + RestorePriority(kernel, this); +} - if (GetState() == ThreadState::Waiting && is_waiting_on_condvar) { - owner_process->InsertConditionVariableThread(SharedFrom(this)); - } +Thread* Thread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); - if (!lock_owner) { - return; + s32 num_waiters{}; + Thread* next_lock_owner{}; + auto it = waiter_list.begin(); + while (it != waiter_list.end()) { + if (it->GetAddressKey() == key) { + Thread* thread = std::addressof(*it); + + // Keep track of how many kernel waiters we have. + if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { + ASSERT((num_kernel_waiters--) > 0); + } + it = waiter_list.erase(it); + + // Update the next lock owner. + if (next_lock_owner == nullptr) { + next_lock_owner = thread; + next_lock_owner->SetLockOwner(nullptr); + } else { + next_lock_owner->AddWaiterImpl(thread); + } + num_waiters++; + } else { + it++; + } } - // Ensure that the thread is within the correct location in the waiting list. - auto old_owner = lock_owner; - lock_owner->RemoveMutexWaiter(SharedFrom(this)); - old_owner->AddMutexWaiter(SharedFrom(this)); + // Do priority updates, if we have a next owner. + if (next_lock_owner) { + RestorePriority(kernel, this); + RestorePriority(kernel, next_lock_owner); + } - // Recursively update the priority of the thread that depends on the priority of this one. - lock_owner->UpdatePriority(); + // Return output. + *out_num_waiters = num_waiters; + return next_lock_owner; } ResultCode Thread::SetActivity(ThreadActivity value) { @@ -372,18 +411,6 @@ void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { KScheduler::OnThreadStateChanged(kernel, this, old_state); } -void Thread::SetSchedulingStatus(ThreadState new_status) { - const auto old_state = GetRawState(); - thread_state = (thread_state & ThreadState::HighMask) | new_status; - KScheduler::OnThreadStateChanged(kernel, this, old_state); -} - -void Thread::SetCurrentPriority(u32 new_priority) { - const u32 old_priority = std::exchange(current_priority, new_priority); - KScheduler::OnThreadPriorityChanged(kernel, this, kernel.CurrentScheduler()->GetCurrentThread(), - old_priority); -} - ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { KScopedSchedulerLock lock(kernel); const auto HighestSetCore = [](u64 mask, u32 max_cores) { -- cgit v1.2.3 From 03dfc8d8e74910d447b755e00848a623ec65cd93 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 10 Jan 2021 14:29:02 -0800 Subject: hle: kernel: thread: Preserve thread wait reason for debugging only. - This is decoupled from core functionality and used for debugging only. --- 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 eda56c31c..d97323255 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -215,7 +215,10 @@ VAddr Thread::GetCommandBufferAddress() const { void Thread::SetState(ThreadState state) { KScopedSchedulerLock sl(kernel); - SetMutexWaitAddressForDebugging(0); + // Clear debugging state + SetMutexWaitAddressForDebugging({}); + SetWaitReasonForDebugging({}); + const ThreadState old_state = thread_state; thread_state = static_cast((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask)); @@ -386,6 +389,7 @@ ResultCode Thread::Sleep(s64 nanoseconds) { { KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); SetState(ThreadState::Waiting); + SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); } if (event_handle != InvalidHandle) { -- cgit v1.2.3