summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/arm/arm_interface.cpp8
-rw-r--r--src/core/hle/kernel/k_interrupt_manager.cpp8
-rw-r--r--src/core/hle/kernel/k_interrupt_manager.h4
-rw-r--r--src/core/hle/kernel/k_thread.cpp76
-rw-r--r--src/core/hle/kernel/k_thread.h4
5 files changed, 99 insertions, 1 deletions
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index 953d96439..29ba562dc 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -134,6 +134,14 @@ void ARM_Interface::Run() {
134 } 134 }
135 system.ExitDynarmicProfile(); 135 system.ExitDynarmicProfile();
136 136
137 // If the thread is scheduled for termination, exit the thread.
138 if (current_thread->HasDpc()) {
139 if (current_thread->IsTerminationRequested()) {
140 current_thread->Exit();
141 UNREACHABLE();
142 }
143 }
144
137 // Notify the debugger and go to sleep if a breakpoint was hit, 145 // Notify the debugger and go to sleep if a breakpoint was hit,
138 // or if the thread is unable to continue for any reason. 146 // or if the thread is unable to continue for any reason.
139 if (Has(hr, breakpoint) || Has(hr, no_execute)) { 147 if (Has(hr, breakpoint) || Has(hr, no_execute)) {
diff --git a/src/core/hle/kernel/k_interrupt_manager.cpp b/src/core/hle/kernel/k_interrupt_manager.cpp
index 1b577a5b3..ad73f3eab 100644
--- a/src/core/hle/kernel/k_interrupt_manager.cpp
+++ b/src/core/hle/kernel/k_interrupt_manager.cpp
@@ -36,4 +36,12 @@ void HandleInterrupt(KernelCore& kernel, s32 core_id) {
36 kernel.CurrentScheduler()->RequestScheduleOnInterrupt(); 36 kernel.CurrentScheduler()->RequestScheduleOnInterrupt();
37} 37}
38 38
39void SendInterProcessorInterrupt(KernelCore& kernel, u64 core_mask) {
40 for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; ++core_id) {
41 if (core_mask & (1ULL << core_id)) {
42 kernel.PhysicalCore(core_id).Interrupt();
43 }
44 }
45}
46
39} // namespace Kernel::KInterruptManager 47} // namespace Kernel::KInterruptManager
diff --git a/src/core/hle/kernel/k_interrupt_manager.h b/src/core/hle/kernel/k_interrupt_manager.h
index f103dfe3f..803dc9211 100644
--- a/src/core/hle/kernel/k_interrupt_manager.h
+++ b/src/core/hle/kernel/k_interrupt_manager.h
@@ -11,6 +11,8 @@ class KernelCore;
11 11
12namespace KInterruptManager { 12namespace KInterruptManager {
13void HandleInterrupt(KernelCore& kernel, s32 core_id); 13void HandleInterrupt(KernelCore& kernel, s32 core_id);
14} 14void SendInterProcessorInterrupt(KernelCore& kernel, u64 core_mask);
15
16} // namespace KInterruptManager
15 17
16} // namespace Kernel 18} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 174afc80d..89b32d509 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -30,6 +30,7 @@
30#include "core/hle/kernel/k_worker_task_manager.h" 30#include "core/hle/kernel/k_worker_task_manager.h"
31#include "core/hle/kernel/kernel.h" 31#include "core/hle/kernel/kernel.h"
32#include "core/hle/kernel/svc_results.h" 32#include "core/hle/kernel/svc_results.h"
33#include "core/hle/kernel/svc_types.h"
33#include "core/hle/result.h" 34#include "core/hle/result.h"
34#include "core/memory.h" 35#include "core/memory.h"
35 36
@@ -38,6 +39,9 @@
38#endif 39#endif
39 40
40namespace { 41namespace {
42
43constexpr inline s32 TerminatingThreadPriority = Kernel::Svc::SystemThreadPriorityHighest - 1;
44
41static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, 45static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top,
42 u32 entry_point, u32 arg) { 46 u32 entry_point, u32 arg) {
43 context = {}; 47 context = {};
@@ -1073,6 +1077,78 @@ void KThread::Exit() {
1073 UNREACHABLE_MSG("KThread::Exit() would return"); 1077 UNREACHABLE_MSG("KThread::Exit() would return");
1074} 1078}
1075 1079
1080Result KThread::Terminate() {
1081 ASSERT(this != GetCurrentThreadPointer(kernel));
1082
1083 // Request the thread terminate if it hasn't already.
1084 if (const auto new_state = this->RequestTerminate(); new_state != ThreadState::Terminated) {
1085 // If the thread isn't terminated, wait for it to terminate.
1086 s32 index;
1087 KSynchronizationObject* objects[] = {this};
1088 R_TRY(KSynchronizationObject::Wait(kernel, std::addressof(index), objects, 1,
1089 Svc::WaitInfinite));
1090 }
1091
1092 return ResultSuccess;
1093}
1094
1095ThreadState KThread::RequestTerminate() {
1096 ASSERT(this != GetCurrentThreadPointer(kernel));
1097
1098 KScopedSchedulerLock sl{kernel};
1099
1100 // Determine if this is the first termination request.
1101 const bool first_request = [&]() -> bool {
1102 // Perform an atomic compare-and-swap from false to true.
1103 bool expected = false;
1104 return termination_requested.compare_exchange_strong(expected, true);
1105 }();
1106
1107 // If this is the first request, start termination procedure.
1108 if (first_request) {
1109 // If the thread is in initialized state, just change state to terminated.
1110 if (this->GetState() == ThreadState::Initialized) {
1111 thread_state = ThreadState::Terminated;
1112 return ThreadState::Terminated;
1113 }
1114
1115 // Register the terminating dpc.
1116 this->RegisterDpc(DpcFlag::Terminating);
1117
1118 // If the thread is pinned, unpin it.
1119 if (this->GetStackParameters().is_pinned) {
1120 this->GetOwnerProcess()->UnpinThread(this);
1121 }
1122
1123 // If the thread is suspended, continue it.
1124 if (this->IsSuspended()) {
1125 suspend_allowed_flags = 0;
1126 this->UpdateState();
1127 }
1128
1129 // Change the thread's priority to be higher than any system thread's.
1130 if (this->GetBasePriority() >= Svc::SystemThreadPriorityHighest) {
1131 this->SetBasePriority(TerminatingThreadPriority);
1132 }
1133
1134 // If the thread is runnable, send a termination interrupt to other cores.
1135 if (this->GetState() == ThreadState::Runnable) {
1136 if (const u64 core_mask =
1137 physical_affinity_mask.GetAffinityMask() & ~(1ULL << GetCurrentCoreId(kernel));
1138 core_mask != 0) {
1139 Kernel::KInterruptManager::SendInterProcessorInterrupt(kernel, core_mask);
1140 }
1141 }
1142
1143 // Wake up the thread.
1144 if (this->GetState() == ThreadState::Waiting) {
1145 wait_queue->CancelWait(this, ResultTerminationRequested, true);
1146 }
1147 }
1148
1149 return this->GetState();
1150}
1151
1076Result KThread::Sleep(s64 timeout) { 1152Result KThread::Sleep(s64 timeout) {
1077 ASSERT(!kernel.GlobalSchedulerContext().IsLocked()); 1153 ASSERT(!kernel.GlobalSchedulerContext().IsLocked());
1078 ASSERT(this == GetCurrentThreadPointer(kernel)); 1154 ASSERT(this == GetCurrentThreadPointer(kernel));
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 9ee20208e..e2a27d603 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -180,6 +180,10 @@ public:
180 180
181 void Exit(); 181 void Exit();
182 182
183 Result Terminate();
184
185 ThreadState RequestTerminate();
186
183 [[nodiscard]] u32 GetSuspendFlags() const { 187 [[nodiscard]] u32 GetSuspendFlags() const {
184 return suspend_allowed_flags & suspend_request_flags; 188 return suspend_allowed_flags & suspend_request_flags;
185 } 189 }