core: hle: kernel: KThread: Integrate with KWorkerTask and implement DoWorkerTaskImpl.
- This is used to terminate a thread asynchronously after it has been exited. - This fixes a crash that can occur in Pokemon Sword/Shield because a thread is incorrectly closed on svcExitThread, then, the thread is destroyed on svcCloseHandle while it is still scheduled. - Instead, we now wait for the thread to no longer be scheduled on all cores before destroying it from KWorkerTaskManager, which is accurate to HOS behavior.
This commit is contained in:
parent
d8b3f665db
commit
f499c8177e
|
@ -30,6 +30,7 @@
|
||||||
#include "core/hle/kernel/k_system_control.h"
|
#include "core/hle/kernel/k_system_control.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
#include "core/hle/kernel/k_thread_queue.h"
|
#include "core/hle/kernel/k_thread_queue.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/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
|
@ -332,7 +333,7 @@ void KThread::Finalize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform inherited finalization.
|
// Perform inherited finalization.
|
||||||
KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>::Finalize();
|
KSynchronizationObject::Finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KThread::IsSignaled() const {
|
bool KThread::IsSignaled() const {
|
||||||
|
@ -376,11 +377,28 @@ void KThread::StartTermination() {
|
||||||
|
|
||||||
// Register terminated dpc flag.
|
// Register terminated dpc flag.
|
||||||
RegisterDpc(DpcFlag::Terminated);
|
RegisterDpc(DpcFlag::Terminated);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KThread::FinishTermination() {
|
||||||
|
// Ensure that the thread is not executing on any core.
|
||||||
|
if (parent != nullptr) {
|
||||||
|
for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) {
|
||||||
|
KThread* core_thread{};
|
||||||
|
do {
|
||||||
|
core_thread = kernel.Scheduler(i).GetCurrentThread();
|
||||||
|
} while (core_thread == this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Close the thread.
|
// Close the thread.
|
||||||
this->Close();
|
this->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KThread::DoWorkerTaskImpl() {
|
||||||
|
// Finish the termination that was begun by Exit().
|
||||||
|
this->FinishTermination();
|
||||||
|
}
|
||||||
|
|
||||||
void KThread::Pin(s32 current_core) {
|
void KThread::Pin(s32 current_core) {
|
||||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
||||||
|
|
||||||
|
@ -1027,6 +1045,9 @@ void KThread::Exit() {
|
||||||
|
|
||||||
// Start termination.
|
// Start termination.
|
||||||
StartTermination();
|
StartTermination();
|
||||||
|
|
||||||
|
// Register the thread as a work task.
|
||||||
|
KWorkerTaskManager::AddTask(kernel, KWorkerTaskManager::WorkerType::Exit, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "core/hle/kernel/k_light_lock.h"
|
#include "core/hle/kernel/k_light_lock.h"
|
||||||
#include "core/hle/kernel/k_spin_lock.h"
|
#include "core/hle/kernel/k_spin_lock.h"
|
||||||
#include "core/hle/kernel/k_synchronization_object.h"
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
|
#include "core/hle/kernel/k_worker_task.h"
|
||||||
#include "core/hle/kernel/slab_helpers.h"
|
#include "core/hle/kernel/slab_helpers.h"
|
||||||
#include "core/hle/kernel/svc_common.h"
|
#include "core/hle/kernel/svc_common.h"
|
||||||
#include "core/hle/kernel/svc_types.h"
|
#include "core/hle/kernel/svc_types.h"
|
||||||
|
@ -100,7 +101,7 @@ enum class ThreadWaitReasonForDebugging : u32 {
|
||||||
[[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel);
|
[[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel);
|
||||||
[[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel);
|
[[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel);
|
||||||
|
|
||||||
class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>,
|
class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>,
|
||||||
public boost::intrusive::list_base_hook<> {
|
public boost::intrusive::list_base_hook<> {
|
||||||
KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
|
KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
|
||||||
|
|
||||||
|
@ -385,6 +386,8 @@ public:
|
||||||
|
|
||||||
void OnTimer();
|
void OnTimer();
|
||||||
|
|
||||||
|
void DoWorkerTaskImpl();
|
||||||
|
|
||||||
static void PostDestroy(uintptr_t arg);
|
static void PostDestroy(uintptr_t arg);
|
||||||
|
|
||||||
[[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread);
|
[[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread);
|
||||||
|
@ -679,6 +682,8 @@ private:
|
||||||
|
|
||||||
void StartTermination();
|
void StartTermination();
|
||||||
|
|
||||||
|
void FinishTermination();
|
||||||
|
|
||||||
[[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top,
|
[[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top,
|
||||||
s32 prio, s32 virt_core, KProcess* owner, ThreadType type);
|
s32 prio, s32 virt_core, KProcess* owner, ThreadType type);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue