summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/errors.h2
-rw-r--r--src/core/hle/kernel/svc.cpp38
-rw-r--r--src/core/hle/kernel/thread.cpp24
-rw-r--r--src/core/hle/kernel/thread.h14
-rw-r--r--src/yuzu/debugger/wait_tree.cpp4
5 files changed, 76 insertions, 6 deletions
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<u32>(ThreadActivity::Paused)) {
+ return ERR_INVALID_ENUM_VALUE;
+ }
+
+ const auto* current_process = Core::CurrentProcess();
+ const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(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<ThreadActivity>(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<Thread> 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<u8>;
@@ -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<TLSMemory>();
std::string name;
+
+ ThreadActivity activity = ThreadActivity::Normal;
};
/**
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 96c57fe97..293351c75 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: