diff --git a/src/core/kernel/exports/EmuKrnlKe.cpp b/src/core/kernel/exports/EmuKrnlKe.cpp index 49a83e273..b39bc60ff 100644 --- a/src/core/kernel/exports/EmuKrnlKe.cpp +++ b/src/core/kernel/exports/EmuKrnlKe.cpp @@ -132,6 +132,28 @@ xbox::ulonglong_xt LARGE_INTEGER2ULONGLONG(xbox::LARGE_INTEGER value) } +xbox::void_xt xbox::KeResumeThreadEx +( + IN PKTHREAD Thread +) +{ + // This is only to be used to synchronize new thread creation with the thread that spawned it + + Thread->SuspendSemaphore.Header.SignalState = 1; + KiWaitTest(&Thread->SuspendSemaphore, 0); +} + +xbox::void_xt xbox::KeSuspendThreadEx +( + IN PKTHREAD Thread +) +{ + // This is only to be used to synchronize new thread creation with the thread that spawned it + + Thread->SuspendSemaphore.Header.SignalState = 0; + KiInsertQueueApc(&Thread->SuspendApc, 0); +} + // ****************************************************************** // * EmuKeGetPcr() // * NOTE: This is a macro on the Xbox, however we implement it @@ -1729,8 +1751,13 @@ XBSYSAPI EXPORTNUM(140) xbox::ulong_xt NTAPI xbox::KeResumeThread if (OldCount != 0) { --Thread->SuspendCount; if (Thread->SuspendCount == 0) { +#if 0 ++Thread->SuspendSemaphore.Header.SignalState; KiWaitTest(&Thread->SuspendSemaphore, 0); +#else + const auto &nativeHandle = GetNativeHandle(reinterpret_cast(Thread)->UniqueThread); + ResumeThread(*nativeHandle); +#endif } } @@ -2089,10 +2116,20 @@ XBSYSAPI EXPORTNUM(152) xbox::ulong_xt NTAPI xbox::KeSuspendThread if (Thread->ApcState.ApcQueueable == TRUE) { ++Thread->SuspendCount; if (OldCount == 0) { +#if 0 if (KiInsertQueueApc(&Thread->SuspendApc, 0) == FALSE) { --Thread->SuspendSemaphore.Header.SignalState; } +#else + // JSRF creates a thread at 0x0013BC30 and then it attempts to continuously suspend/resume it. Unfortunately, this thread performs a never ending loop (and + // terminates if it ever exit the loop), and never calls any kernel functions in the middle. This means that our suspend APC will never be executed and so + // we cannot suspend such thread. Thus, we will always have to rely on the host to do the suspension, as long as we do direct execution. Note that this is + // a general issue for all kernel APCs too. + const auto &nativeHandle = GetNativeHandle(reinterpret_cast(Thread)->UniqueThread); + SuspendThread(*nativeHandle); +#endif } + } KiUnlockDispatcherDatabase(OldIrql); diff --git a/src/core/kernel/exports/EmuKrnlKe.h b/src/core/kernel/exports/EmuKrnlKe.h index 03c514eca..02ca32c71 100644 --- a/src/core/kernel/exports/EmuKrnlKe.h +++ b/src/core/kernel/exports/EmuKrnlKe.h @@ -52,5 +52,15 @@ namespace xbox IN PKPROCESS Process ); + xbox::void_xt KeResumeThreadEx + ( + IN PKTHREAD Thread + ); + + xbox::void_xt KeSuspendThreadEx + ( + IN PKTHREAD Thread + ); + void_xt KeEmptyQueueApc(); } diff --git a/src/core/kernel/exports/EmuKrnlPs.cpp b/src/core/kernel/exports/EmuKrnlPs.cpp index 230c94995..033493269 100644 --- a/src/core/kernel/exports/EmuKrnlPs.cpp +++ b/src/core/kernel/exports/EmuKrnlPs.cpp @@ -122,7 +122,6 @@ static unsigned int WINAPI PCSTProxy params.TlsDataSize); xbox::KiExecuteKernelApc(); - eThread->Tcb.State = xbox::Running; auto routine = (xbox::PKSYSTEM_ROUTINE)StartFrame->SystemRoutine; // Debugging notice : When the below line shows up with an Exception dialog and a @@ -411,20 +410,24 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx g_AffinityPolicy->SetAffinityXbox(handle); + // Wait for the initialization of the remaining thread state + KeSuspendThreadEx(&eThread->Tcb); + ResumeThread(handle); + while (eThread->Tcb.State == Initialized) { + std::this_thread::yield(); + } + // Now that ThreadId is populated and affinity is changed, resume the thread (unless the guest passed CREATE_SUSPENDED), then wait until the new thread has // finished initialization if (CreateSuspended) { KeSuspendThread(&eThread->Tcb); } + KeResumeThreadEx(&eThread->Tcb); + // Log ThreadID identical to how GetCurrentThreadID() is rendered : EmuLog(LOG_LEVEL::DEBUG, "Created Xbox proxy thread. Handle : 0x%X, ThreadId : [0x%.4X], Native Handle : 0x%X, Native ThreadId : [0x%.4X]", *ThreadHandle, eThread->UniqueThread, handle, ThreadId); - - ResumeThread(handle); - while (eThread->Tcb.State == Initialized) { - std::this_thread::yield(); - } } RETURN(X_STATUS_SUCCESS);