From 3e75175d0242090902e4b383086e3f5ac6cf3f73 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Mon, 3 Dec 2018 12:25:27 -0500 Subject: [PATCH 1/2] 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 ++++++++++++ src/yuzu/debugger/wait_tree.cpp | 4 ++++ 5 files changed, 76 insertions(+), 6 deletions(-) diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 8b58d701d6..d8240ec6d0 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 948989b318..72da3eb3dc 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 4ffb768183..748c45dd76 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 d384d50dbc..268bf845bb 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; }; /** diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 96c57fe976..293351c759 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -221,6 +221,9 @@ QString WaitTreeThread::GetText() const { case Kernel::ThreadStatus::Ready: status = tr("ready"); break; + case Kernel::ThreadStatus::Paused: + status = tr("paused"); + break; case Kernel::ThreadStatus::WaitHLEEvent: status = tr("waiting for HLE return"); break; @@ -261,6 +264,7 @@ QColor WaitTreeThread::GetColor() const { case Kernel::ThreadStatus::Running: return QColor(Qt::GlobalColor::darkGreen); case Kernel::ThreadStatus::Ready: + case Kernel::ThreadStatus::Paused: return QColor(Qt::GlobalColor::darkBlue); case Kernel::ThreadStatus::WaitHLEEvent: case Kernel::ThreadStatus::WaitIPC: From a3d78b77f8734cba6e73d3b57b0d6af68e7ca110 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Tue, 4 Dec 2018 02:25:34 -0500 Subject: [PATCH 2/2] debugger: Set paused thread color --- src/yuzu/debugger/wait_tree.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 293351c759..fd4ddbd446 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -264,8 +264,9 @@ QColor WaitTreeThread::GetColor() const { case Kernel::ThreadStatus::Running: return QColor(Qt::GlobalColor::darkGreen); case Kernel::ThreadStatus::Ready: - case Kernel::ThreadStatus::Paused: return QColor(Qt::GlobalColor::darkBlue); + case Kernel::ThreadStatus::Paused: + return QColor(Qt::GlobalColor::lightGray); case Kernel::ThreadStatus::WaitHLEEvent: case Kernel::ThreadStatus::WaitIPC: return QColor(Qt::GlobalColor::darkRed);