diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/arm/arm_interface.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_interrupt_manager.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_interrupt_manager.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.cpp | 76 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.h | 4 |
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 | ||
| 39 | void 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 | ||
| 12 | namespace KInterruptManager { | 12 | namespace KInterruptManager { |
| 13 | void HandleInterrupt(KernelCore& kernel, s32 core_id); | 13 | void HandleInterrupt(KernelCore& kernel, s32 core_id); |
| 14 | } | 14 | void 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 | ||
| 40 | namespace { | 41 | namespace { |
| 42 | |||
| 43 | constexpr inline s32 TerminatingThreadPriority = Kernel::Svc::SystemThreadPriorityHighest - 1; | ||
| 44 | |||
| 41 | static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, | 45 | static 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 | ||
| 1080 | Result 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 | |||
| 1095 | ThreadState 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 | |||
| 1076 | Result KThread::Sleep(s64 timeout) { | 1152 | Result 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 | } |