reimplement suspend xbox threads so we can shutdown emulation properly

This commit is contained in:
RadWolfie 2022-01-29 13:09:28 -06:00 committed by ergo720
parent 0b90a48434
commit 8c7247abf5
5 changed files with 55 additions and 0 deletions

View File

@ -102,6 +102,7 @@ xbox::void_xt xbox::KiInitSystem()
{
KiUniqueProcess.StackCount = 0;
KiUniqueProcess.ThreadQuantum = X_THREAD_QUANTUM;
InitializeListHead(&KiUniqueProcess.ThreadListHead);
InitializeListHead(&KiWaitInListHead);

View File

@ -294,6 +294,7 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
ObfReferenceObject(eThread);
KeQuerySystemTime(&eThread->CreateTime);
InsertTailList(&KiUniqueProcess.ThreadListHead, &eThread->Tcb.ThreadListEntry);
KiUniqueProcess.StackCount++;
RegisterXboxHandle(*ThreadHandle, handle);
HANDLE dupHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadId);

View File

@ -72,6 +72,8 @@
#include "common\crypto\EmuSha.h" // For the SHA1 functions
#include "Timer.h" // For Timer_Init
#include "common\input\InputManager.h" // For the InputDeviceManager
#include "core/kernel/support/NativeHandle.h"
#include "common/win32/Util.h" // for WinError2Str
#include "common/FilePaths.hpp"
@ -1573,6 +1575,51 @@ static void CxbxrKrnlInitHacks()
CxbxKrnlShutDown();
}
void CxbxrKrnlSuspendThreads()
{
xbox::PLIST_ENTRY ThreadListEntry = KiUniqueProcess.ThreadListHead.Flink;
std::vector<NtDll::HANDLE> threads;
threads.reserve(KiUniqueProcess.StackCount);
xbox::KPCR* Pcr = EmuKeGetPcr();
// If there's nothing in list entry, skip this step.
if (!ThreadListEntry) {
return;
}
while (ThreadListEntry != &KiUniqueProcess.ThreadListHead) {
xbox::HANDLE UniqueThread = CONTAINING_RECORD(ThreadListEntry, xbox::ETHREAD, Tcb.ThreadListEntry)->UniqueThread;
if (UniqueThread) {
// Current thread is an xbox thread
if (Pcr) {
const auto& nHandle = GetNativeHandle<true>(UniqueThread);
if (nHandle) {
// We do not want to suspend current thread, so we let it skip this one.
if (*nHandle != NtCurrentThread()) {
threads.push_back(*nHandle);
}
}
}
// Otherwise, convert all UniqueThread to host thead handles.
else {
const auto& nHandle = GetNativeHandle<false>(UniqueThread);
if (nHandle) {
threads.push_back(*nHandle);
}
}
}
ThreadListEntry = ThreadListEntry->Flink;
}
for (const auto& thread : threads) {
DWORD PrevCount = SuspendThread(thread);
if (PrevCount == -1) {
EmuLog(LOG_LEVEL::ERROR2, "Unable to suspend thread 0x%X for: %s", thread, WinError2Str().c_str());
}
}
}
void CxbxKrnlShutDown(bool is_reboot)
{
if (!is_reboot) {
@ -1581,6 +1628,9 @@ void CxbxKrnlShutDown(bool is_reboot)
g_EmuShared->SetBootFlags(&BootFlags);
}
// This is very important process to prevent false positive report and allow IDEs to continue debug multiple reboots.
CxbxrKrnlSuspendThreads();
// NOTE: This causes a hang when exiting while NV2A is processing
// This is okay for now: It won't leak memory or resources since TerminateProcess will free everything
// delete g_NV2A; // TODO : g_pXbox

View File

@ -228,6 +228,8 @@ void EmuKeFreeThread(xbox::ntstatus_xt ExitStatus)
xbox::KeQuerySystemTime(&eThread->ExitTime);
eThread->Tcb.HasTerminated = 1;
RemoveEntryList(&eThread->Tcb.ThreadListEntry);
// Emulate our exit strategy for GetExitCodeThread
eThread->ExitStatus = ExitStatus;
eThread->Tcb.Header.SignalState = 1;

View File

@ -32,6 +32,7 @@
#include "assert.h"
#include "NativeHandle.h"
#include "core\kernel\init\CxbxKrnl.h"
#include "core/kernel/support/EmuFS.h"
std::unordered_map<xbox::HANDLE, HANDLE> g_RegisteredHandles;