diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index f020438fb5..a37b992ec1 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -417,8 +417,7 @@ void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { } ASSERT(is_locked); - if (static_cast(old_flags & static_cast(ThreadSchedMasks::LowMask)) == - ThreadSchedStatus::Runnable) { + if (old_flags == static_cast(ThreadSchedStatus::Runnable)) { // In this case the thread was running, now it's pausing/exitting if (thread->processor_id >= 0) { Unschedule(thread->current_priority, static_cast(thread->processor_id), thread); @@ -430,7 +429,7 @@ void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { Unsuggest(thread->current_priority, core, thread); } } - } else if (thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable) { + } else if (thread->scheduling_state == static_cast(ThreadSchedStatus::Runnable)) { // The thread is now set to running from being stopped if (thread->processor_id >= 0) { Schedule(thread->current_priority, static_cast(thread->processor_id), thread); @@ -448,7 +447,7 @@ void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { } void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priority) { - if (thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { + if (thread->scheduling_state != static_cast(ThreadSchedStatus::Runnable)) { return; } ASSERT(is_locked); @@ -486,7 +485,7 @@ void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priorit void GlobalScheduler::AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinity_mask, s32 old_core) { - if (thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable || + if (thread->scheduling_state != static_cast(ThreadSchedStatus::Runnable) || thread->current_priority >= THREADPRIO_COUNT) { return; } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 718462b2b1..da2f90a1d1 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1012,7 +1012,6 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size /// Sets the thread activity static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); - UNIMPLEMENTED(); if (activity > static_cast(ThreadActivity::Paused)) { return ERR_INVALID_ENUM_VALUE; } @@ -1039,9 +1038,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act return ERR_BUSY; } - thread->SetActivity(static_cast(activity)); - - return RESULT_SUCCESS; + return thread->SetActivity(static_cast(activity)); } /// Gets the thread context diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index e8962a0d8f..b99e3b7a55 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -113,20 +113,11 @@ void Thread::ResumeFromWait() { return; } - if (activity == ThreadActivity::Paused) { - SetStatus(ThreadStatus::Paused); - return; - } - SetStatus(ThreadStatus::Ready); } void Thread::OnWakeUp() { SchedulerLock lock(kernel); - if (activity == ThreadActivity::Paused) { - SetStatus(ThreadStatus::Paused); - return; - } SetStatus(ThreadStatus::Ready); } @@ -143,7 +134,7 @@ void Thread::CancelWait() { is_sync_cancelled = true; return; } - //TODO(Blinkhawk): Implement cancel of server session + // TODO(Blinkhawk): Implement cancel of server session is_sync_cancelled = false; SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); SetStatus(ThreadStatus::Ready); @@ -407,19 +398,31 @@ bool Thread::InvokeHLECallback(std::shared_ptr thread) { return hle_callback(std::move(thread)); } -void Thread::SetActivity(ThreadActivity value) { - activity = value; +ResultCode Thread::SetActivity(ThreadActivity value) { + SchedulerLock lock(kernel); + + auto sched_status = GetSchedulingStatus(); + + if (sched_status != ThreadSchedStatus::Runnable && sched_status != ThreadSchedStatus::Paused) { + return ERR_INVALID_STATE; + } + + if (IsPendingTermination()) { + return RESULT_SUCCESS; + } if (value == ThreadActivity::Paused) { - // Set status if not waiting - if (status == ThreadStatus::Ready || status == ThreadStatus::Running) { - SetStatus(ThreadStatus::Paused); - kernel.PrepareReschedule(processor_id); + if (pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag) != 0) { + return ERR_INVALID_STATE; } - } else if (status == ThreadStatus::Paused) { - // Ready to reschedule - ResumeFromWait(); + AddSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); + } else { + if (pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag) == 0) { + return ERR_INVALID_STATE; + } + RemoveSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); } + return RESULT_SUCCESS; } ResultCode Thread::Sleep(s64 nanoseconds) { @@ -460,11 +463,27 @@ ResultCode Thread::YieldAndWaitForLoadBalancing() { return RESULT_SUCCESS; } +void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { + const u32 old_state = scheduling_state; + pausing_state |= static_cast(flag); + const u32 base_scheduling = static_cast(GetSchedulingStatus()); + scheduling_state = base_scheduling | pausing_state; + kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); +} + +void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { + const u32 old_state = scheduling_state; + pausing_state &= ~static_cast(flag); + const u32 base_scheduling = static_cast(GetSchedulingStatus()); + scheduling_state = base_scheduling | pausing_state; + kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); +} + void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { - const u32 old_flags = scheduling_state; + const u32 old_state = scheduling_state; scheduling_state = (scheduling_state & static_cast(ThreadSchedMasks::HighMask)) | static_cast(new_status); - kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_flags); + kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); } void Thread::SetCurrentPriority(u32 new_priority) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index d8a983200c..0a8f7bb654 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -497,11 +497,7 @@ public: return affinity_mask; } - ThreadActivity GetActivity() const { - return activity; - } - - void SetActivity(ThreadActivity value); + ResultCode SetActivity(ThreadActivity value); /// Sleeps this thread for the given amount of nanoseconds. ResultCode Sleep(s64 nanoseconds); @@ -564,11 +560,22 @@ public: is_waiting_on_sync = is_waiting; } + bool IsPendingTermination() const { + return will_be_terminated || GetSchedulingStatus() == ThreadSchedStatus::Exited; + } + + bool IsPaused() const { + return pausing_state != 0; + } + private: friend class GlobalScheduler; friend class Scheduler; void SetSchedulingStatus(ThreadSchedStatus new_status); + void AddSchedulingFlag(ThreadSchedFlags flag); + void RemoveSchedulingFlag(ThreadSchedFlags flag); + void SetCurrentPriority(u32 new_priority); void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); @@ -650,18 +657,17 @@ private: u32 ideal_core{0xFFFFFFFF}; u64 affinity_mask{0x1}; - ThreadActivity activity = ThreadActivity::Normal; - s32 ideal_core_override = -1; u64 affinity_mask_override = 0x1; u32 affinity_override_count = 0; u32 scheduling_state = 0; + u32 pausing_state = 0; bool is_running = false; bool is_waiting_on_sync = false; bool is_sync_cancelled = false; - bool will_be_terminated{}; + bool will_be_terminated = false; std::string name; };