|
@@ -30,6 +30,7 @@
|
|
|
#include "core/hle/kernel/k_worker_task_manager.h"
|
|
#include "core/hle/kernel/k_worker_task_manager.h"
|
|
|
#include "core/hle/kernel/kernel.h"
|
|
#include "core/hle/kernel/kernel.h"
|
|
|
#include "core/hle/kernel/svc_results.h"
|
|
#include "core/hle/kernel/svc_results.h"
|
|
|
|
|
+#include "core/hle/kernel/svc_types.h"
|
|
|
#include "core/hle/result.h"
|
|
#include "core/hle/result.h"
|
|
|
#include "core/memory.h"
|
|
#include "core/memory.h"
|
|
|
|
|
|
|
@@ -38,6 +39,9 @@
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
namespace {
|
|
namespace {
|
|
|
|
|
+
|
|
|
|
|
+constexpr inline s32 TerminatingThreadPriority = Kernel::Svc::SystemThreadPriorityHighest - 1;
|
|
|
|
|
+
|
|
|
static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top,
|
|
static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top,
|
|
|
u32 entry_point, u32 arg) {
|
|
u32 entry_point, u32 arg) {
|
|
|
context = {};
|
|
context = {};
|
|
@@ -1073,6 +1077,78 @@ void KThread::Exit() {
|
|
|
UNREACHABLE_MSG("KThread::Exit() would return");
|
|
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));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return ResultSuccess;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+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) {
|
|
Result KThread::Sleep(s64 timeout) {
|
|
|
ASSERT(!kernel.GlobalSchedulerContext().IsLocked());
|
|
ASSERT(!kernel.GlobalSchedulerContext().IsLocked());
|
|
|
ASSERT(this == GetCurrentThreadPointer(kernel));
|
|
ASSERT(this == GetCurrentThreadPointer(kernel));
|