From 3e75175d0242090902e4b383086e3f5ac6cf3f73 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Mon, 3 Dec 2018 12:25:27 -0500 Subject: svc: Implement SetThreadActivity (thread suspension) --- src/core/hle/kernel/errors.h | 2 +- src/core/hle/kernel/svc.cpp | 38 ++++++++++++++++++++++++++++++++++---- src/core/hle/kernel/thread.cpp | 24 +++++++++++++++++++++++- src/core/hle/kernel/thread.h | 14 ++++++++++++++ 4 files changed, 72 insertions(+), 6 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 8b58d701d..d8240ec6d 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -27,7 +27,7 @@ constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118}; constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119}; constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120}; constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121}; -constexpr ResultCode ERR_ALREADY_REGISTERED{ErrorModule::Kernel, 122}; +constexpr ResultCode ERR_BUSY{ErrorModule::Kernel, 122}; constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE{ErrorModule::Kernel, 123}; constexpr ResultCode ERR_INVALID_STATE{ErrorModule::Kernel, 125}; constexpr ResultCode ERR_RESOURCE_LIMIT_EXCEEDED{ErrorModule::Kernel, 132}; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 948989b31..72da3eb3d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -851,8 +851,35 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) } /// Sets the thread activity -static ResultCode SetThreadActivity(Handle handle, u32 unknown) { - LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, unknown=0x{:08X}", handle, unknown); +static ResultCode SetThreadActivity(Handle handle, u32 activity) { + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); + if (activity > static_cast(ThreadActivity::Paused)) { + return ERR_INVALID_ENUM_VALUE; + } + + const auto* current_process = Core::CurrentProcess(); + const SharedPtr thread = current_process->GetHandleTable().Get(handle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); + return ERR_INVALID_HANDLE; + } + + if (thread->GetOwnerProcess() != current_process) { + LOG_ERROR(Kernel_SVC, + "The current process does not own the current thread, thread_handle={:08X} " + "thread_pid={}, " + "current_process_pid={}", + handle, thread->GetOwnerProcess()->GetProcessID(), + current_process->GetProcessID()); + return ERR_INVALID_HANDLE; + } + + if (thread == GetCurrentThread()) { + LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); + return ERR_BUSY; + } + + thread->SetActivity(static_cast(activity)); return RESULT_SUCCESS; } @@ -879,7 +906,7 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { if (thread == GetCurrentThread()) { LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); - return ERR_ALREADY_REGISTERED; + return ERR_BUSY; } Core::ARM_Interface::ThreadContext ctx = thread->GetContext(); @@ -1157,7 +1184,10 @@ static ResultCode StartThread(Handle thread_handle) { ASSERT(thread->GetStatus() == ThreadStatus::Dormant); thread->ResumeFromWait(); - Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); + + if (thread->GetStatus() == ThreadStatus::Ready) { + Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); + } return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 4ffb76818..748c45dd7 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -50,7 +50,7 @@ void Thread::Stop() { // Clean up thread from ready queue // This is only needed when the thread is terminated forcefully (SVC TerminateProcess) - if (status == ThreadStatus::Ready) { + if (status == ThreadStatus::Ready || status == ThreadStatus::Paused) { scheduler->UnscheduleThread(this, current_priority); } @@ -140,6 +140,11 @@ void Thread::ResumeFromWait() { wakeup_callback = nullptr; + if (activity == ThreadActivity::Paused) { + status = ThreadStatus::Paused; + return; + } + status = ThreadStatus::Ready; ChangeScheduler(); @@ -388,6 +393,23 @@ bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, SharedPtr t return wakeup_callback(reason, std::move(thread), std::move(object), index); } +void Thread::SetActivity(ThreadActivity value) { + activity = value; + + if (value == ThreadActivity::Paused) { + // Set status if not waiting + if (status == ThreadStatus::Ready) { + status = ThreadStatus::Paused; + } else if (status == ThreadStatus::Running) { + status = ThreadStatus::Paused; + Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); + } + } else if (status == ThreadStatus::Paused) { + // Ready to reschedule + ResumeFromWait(); + } +} + //////////////////////////////////////////////////////////////////////////////////////////////////// /** diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index d384d50db..268bf845b 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -44,6 +44,7 @@ enum ThreadProcessorId : s32 { enum class ThreadStatus { Running, ///< Currently running Ready, ///< Ready to run + Paused, ///< Paused by SetThreadActivity or debug WaitHLEEvent, ///< Waiting for hle event to finish WaitSleep, ///< Waiting due to a SleepThread SVC WaitIPC, ///< Waiting for the reply from an IPC request @@ -60,6 +61,11 @@ enum class ThreadWakeupReason { Timeout // The thread was woken up due to a wait timeout. }; +enum class ThreadActivity : u32 { + Normal = 0, + Paused = 1, +}; + class Thread final : public WaitObject { public: using TLSMemory = std::vector; @@ -370,6 +376,12 @@ public: return affinity_mask; } + ThreadActivity GetActivity() const { + return activity; + } + + void SetActivity(ThreadActivity value); + private: explicit Thread(KernelCore& kernel); ~Thread() override; @@ -438,6 +450,8 @@ private: TLSMemoryPtr tls_memory = std::make_shared(); std::string name; + + ThreadActivity activity = ThreadActivity::Normal; }; /** -- cgit v1.2.3