summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/k_thread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/k_thread.cpp')
-rw-r--r--src/core/hle/kernel/k_thread.cpp155
1 files changed, 116 insertions, 39 deletions
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 174afc80d..cc88d08f0 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -30,6 +30,7 @@
#include "core/hle/kernel/k_worker_task_manager.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc_results.h"
+#include "core/hle/kernel/svc_types.h"
#include "core/hle/result.h"
#include "core/memory.h"
@@ -38,6 +39,9 @@
#endif
namespace {
+
+constexpr inline s32 TerminatingThreadPriority = Kernel::Svc::SystemThreadPriorityHighest - 1;
+
static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top,
u32 entry_point, u32 arg) {
context = {};
@@ -144,7 +148,9 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack
physical_affinity_mask.SetAffinity(phys_core, true);
// Set the thread state.
- thread_state = (type == ThreadType::Main) ? ThreadState::Runnable : ThreadState::Initialized;
+ thread_state = (type == ThreadType::Main || type == ThreadType::Dummy)
+ ? ThreadState::Runnable
+ : ThreadState::Initialized;
// Set TLS address.
tls_address = 0;
@@ -241,7 +247,7 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack
}
}
- return ResultSuccess;
+ R_SUCCEED();
}
Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg,
@@ -254,7 +260,7 @@ Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_
thread->host_context = std::make_shared<Common::Fiber>(std::move(init_func));
thread->is_single_core = !Settings::values.use_multi_core.GetValue();
- return ResultSuccess;
+ R_SUCCEED();
}
Result KThread::InitializeDummyThread(KThread* thread) {
@@ -264,31 +270,32 @@ Result KThread::InitializeDummyThread(KThread* thread) {
// Initialize emulation parameters.
thread->stack_parameters.disable_count = 0;
- return ResultSuccess;
+ R_SUCCEED();
}
Result KThread::InitializeMainThread(Core::System& system, KThread* thread, s32 virt_core) {
- return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
- system.GetCpuManager().GetGuestActivateFunc());
+ R_RETURN(InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {},
+ ThreadType::Main, system.GetCpuManager().GetGuestActivateFunc()));
}
Result KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
- return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
- system.GetCpuManager().GetIdleThreadStartFunc());
+ R_RETURN(InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {},
+ ThreadType::Main, system.GetCpuManager().GetIdleThreadStartFunc()));
}
Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
KThreadFunction func, uintptr_t arg, s32 virt_core) {
- return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority,
- system.GetCpuManager().GetShutdownThreadStartFunc());
+ R_RETURN(InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr,
+ ThreadType::HighPriority,
+ system.GetCpuManager().GetShutdownThreadStartFunc()));
}
Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func,
uintptr_t arg, VAddr user_stack_top, s32 prio, s32 virt_core,
KProcess* owner) {
system.Kernel().GlobalSchedulerContext().AddThread(thread);
- return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
- ThreadType::User, system.GetCpuManager().GetGuestThreadFunc());
+ R_RETURN(InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
+ ThreadType::User, system.GetCpuManager().GetGuestThreadFunc()));
}
void KThread::PostDestroy(uintptr_t arg) {
@@ -538,7 +545,7 @@ Result KThread::GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask) {
*out_ideal_core = virtual_ideal_core_id;
*out_affinity_mask = virtual_affinity_mask;
- return ResultSuccess;
+ R_SUCCEED();
}
Result KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask) {
@@ -554,7 +561,7 @@ Result KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask)
*out_affinity_mask = original_physical_affinity_mask.GetAffinityMask();
}
- return ResultSuccess;
+ R_SUCCEED();
}
Result KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) {
@@ -666,7 +673,7 @@ Result KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) {
} while (retry_update);
}
- return ResultSuccess;
+ R_SUCCEED();
}
void KThread::SetBasePriority(s32 value) {
@@ -839,7 +846,7 @@ Result KThread::SetActivity(Svc::ThreadActivity activity) {
} while (thread_is_current);
}
- return ResultSuccess;
+ R_SUCCEED();
}
Result KThread::GetThreadContext3(std::vector<u8>& out) {
@@ -874,7 +881,7 @@ Result KThread::GetThreadContext3(std::vector<u8>& out) {
}
}
- return ResultSuccess;
+ R_SUCCEED();
}
void KThread::AddWaiterImpl(KThread* thread) {
@@ -1038,7 +1045,7 @@ Result KThread::Run() {
// Set our state and finish.
SetState(ThreadState::Runnable);
- return ResultSuccess;
+ R_SUCCEED();
}
}
@@ -1073,6 +1080,78 @@ void KThread::Exit() {
UNREACHABLE_MSG("KThread::Exit() would return");
}
+Result KThread::Terminate() {
+ ASSERT(this != GetCurrentThreadPointer(kernel));
+
+ // Request the thread terminate if it hasn't already.
+ if (const auto new_state = this->RequestTerminate(); new_state != ThreadState::Terminated) {
+ // If the thread isn't terminated, wait for it to terminate.
+ s32 index;
+ KSynchronizationObject* objects[] = {this};
+ R_TRY(KSynchronizationObject::Wait(kernel, std::addressof(index), objects, 1,
+ Svc::WaitInfinite));
+ }
+
+ R_SUCCEED();
+}
+
+ThreadState KThread::RequestTerminate() {
+ ASSERT(this != GetCurrentThreadPointer(kernel));
+
+ KScopedSchedulerLock sl{kernel};
+
+ // Determine if this is the first termination request.
+ const bool first_request = [&]() -> bool {
+ // Perform an atomic compare-and-swap from false to true.
+ bool expected = false;
+ return termination_requested.compare_exchange_strong(expected, true);
+ }();
+
+ // If this is the first request, start termination procedure.
+ if (first_request) {
+ // If the thread is in initialized state, just change state to terminated.
+ if (this->GetState() == ThreadState::Initialized) {
+ thread_state = ThreadState::Terminated;
+ return ThreadState::Terminated;
+ }
+
+ // Register the terminating dpc.
+ this->RegisterDpc(DpcFlag::Terminating);
+
+ // If the thread is pinned, unpin it.
+ if (this->GetStackParameters().is_pinned) {
+ this->GetOwnerProcess()->UnpinThread(this);
+ }
+
+ // If the thread is suspended, continue it.
+ if (this->IsSuspended()) {
+ suspend_allowed_flags = 0;
+ this->UpdateState();
+ }
+
+ // Change the thread's priority to be higher than any system thread's.
+ if (this->GetBasePriority() >= Svc::SystemThreadPriorityHighest) {
+ this->SetBasePriority(TerminatingThreadPriority);
+ }
+
+ // If the thread is runnable, send a termination interrupt to other cores.
+ if (this->GetState() == ThreadState::Runnable) {
+ if (const u64 core_mask =
+ physical_affinity_mask.GetAffinityMask() & ~(1ULL << GetCurrentCoreId(kernel));
+ core_mask != 0) {
+ Kernel::KInterruptManager::SendInterProcessorInterrupt(kernel, core_mask);
+ }
+ }
+
+ // Wake up the thread.
+ if (this->GetState() == ThreadState::Waiting) {
+ wait_queue->CancelWait(this, ResultTerminationRequested, true);
+ }
+ }
+
+ return this->GetState();
+}
+
Result KThread::Sleep(s64 timeout) {
ASSERT(!kernel.GlobalSchedulerContext().IsLocked());
ASSERT(this == GetCurrentThreadPointer(kernel));
@@ -1086,7 +1165,7 @@ Result KThread::Sleep(s64 timeout) {
// Check if the thread should terminate.
if (this->IsTerminationRequested()) {
slp.CancelSleep();
- return ResultTerminationRequested;
+ R_THROW(ResultTerminationRequested);
}
// Wait for the sleep to end.
@@ -1094,33 +1173,34 @@ Result KThread::Sleep(s64 timeout) {
SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep);
}
- return ResultSuccess;
+ R_SUCCEED();
}
-void KThread::IfDummyThreadTryWait() {
- if (!IsDummyThread()) {
- return;
- }
+void KThread::RequestDummyThreadWait() {
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
+ ASSERT(this->IsDummyThread());
+
+ // We will block when the scheduler lock is released.
+ dummy_thread_runnable.store(false);
+}
- if (GetState() != ThreadState::Waiting) {
+void KThread::DummyThreadBeginWait() {
+ if (!this->IsDummyThread() || kernel.IsPhantomModeForSingleCore()) {
+ // Occurs in single core mode.
return;
}
- ASSERT(!kernel.IsPhantomModeForSingleCore());
-
- // Block until we are no longer waiting.
- std::unique_lock lk(dummy_wait_lock);
- dummy_wait_cv.wait(
- lk, [&] { return GetState() != ThreadState::Waiting || kernel.IsShuttingDown(); });
+ // Block until runnable is no longer false.
+ dummy_thread_runnable.wait(false);
}
-void KThread::IfDummyThreadEndWait() {
- if (!IsDummyThread()) {
- return;
- }
+void KThread::DummyThreadEndWait() {
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
+ ASSERT(this->IsDummyThread());
// Wake up the waiting thread.
- dummy_wait_cv.notify_one();
+ dummy_thread_runnable.store(true);
+ dummy_thread_runnable.notify_one();
}
void KThread::BeginWait(KThreadQueue* queue) {
@@ -1154,9 +1234,6 @@ void KThread::EndWait(Result wait_result_) {
}
wait_queue->EndWait(this, wait_result_);
-
- // Special case for dummy threads to wakeup if necessary.
- IfDummyThreadEndWait();
}
}