@@ -136,18 +136,29 @@ static bool EmuIsThreadObjectType(PVOID ObjectType)
136136
137137static ULONG EmuProbeThreadSuspendCount (HANDLE ThreadHandle)
138138{
139+ if (GetThreadId (ThreadHandle) == GetCurrentThreadId ())
140+ {
141+ return 0 ;
142+ }
143+
139144 DWORD Previous = SuspendThread (ThreadHandle);
140145 if (Previous == (DWORD )-1 )
146+ {
141147 return 0 ;
148+ }
142149
143- ResumeThread (ThreadHandle);
150+ if (ResumeThread (ThreadHandle) == (DWORD )-1 )
151+ {
152+ return 0 ;
153+ }
144154 return Previous;
145155}
146156
147157struct EmuThreadSuspendState
148158{
149159 ULONG LogicalCount = 0 ;
150160 ULONG HostCount = 0 ;
161+ bool SelfSuspendPending = false ;
151162};
152163
153164// Handles can be duplicated, so suspend state is shared by host thread ID.
@@ -578,10 +589,31 @@ static bool EmuResumeThreadState(
578589 return true ;
579590 }
580591
592+ if (SuspendState.SelfSuspendPending )
593+ {
594+ // The suspending thread publishes its intent before calling the host
595+ // API. A resumer can arrive in that narrow interval, so wait until the
596+ // host count becomes observable rather than losing the resume.
597+ DWORD HostPreviousCount = 0 ;
598+ do
599+ {
600+ HostPreviousCount = ResumeThread (ThreadHandle);
601+ if (HostPreviousCount == (DWORD )-1 )
602+ {
603+ return false ;
604+ }
605+ if (HostPreviousCount == 0 )
606+ {
607+ SwitchToThread ();
608+ }
609+ } while (HostPreviousCount == 0 );
610+
611+ SuspendState.SelfSuspendPending = false ;
612+ }
581613 // Logical-only suspensions sit above any real host suspension. Resume the
582614 // host only when the final logical layer covering it is removed.
583- if (SuspendState.HostCount == SuspendState.LogicalCount &&
584- SuspendState.HostCount != 0 )
615+ else if (SuspendState.HostCount == SuspendState.LogicalCount &&
616+ SuspendState.HostCount != 0 )
585617 {
586618 if (ResumeThread (ThreadHandle) == (DWORD )-1 )
587619 {
@@ -594,6 +626,23 @@ static bool EmuResumeThreadState(
594626 return true ;
595627}
596628
629+ static bool EmuSuspendCurrentThread (
630+ HANDLE ThreadHandle, std::unique_lock<std::mutex>& Lock,
631+ EmuThreadSuspendState& SuspendState)
632+ {
633+ SuspendState.SelfSuspendPending = true ;
634+ Lock.unlock ();
635+ const DWORD HostPreviousCount = SuspendThread (ThreadHandle);
636+ Lock.lock ();
637+ if (HostPreviousCount == (DWORD )-1 )
638+ {
639+ SuspendState.SelfSuspendPending = false ;
640+ return false ;
641+ }
642+
643+ return true ;
644+ }
645+
597646static EmuThreadObjectHeader *EmuThreadHeaderFromThread (xboxkrnl::PKTHREAD Thread)
598647{
599648 EmuThreadObjectHeader *Header = (EmuThreadObjectHeader*)((BYTE *)Thread - 16 );
@@ -6342,7 +6391,7 @@ extern "C" ULONG NTAPI EmuKeSuspendThread(xboxkrnl::PKTHREAD Thread)
63426391 return 0 ;
63436392 }
63446393
6345- const std::lock_guard <std::mutex> Lock (
6394+ std::unique_lock <std::mutex> Lock (
63466395 g_EmuThreadSuspendCountsMutex);
63476396 EmuThreadSuspendState& SuspendState =
63486397 EmuThreadSuspendStateForHandleLocked (ThreadHeader->HostHandle );
@@ -6374,12 +6423,27 @@ extern "C" ULONG NTAPI EmuKeSuspendThread(xboxkrnl::PKTHREAD Thread)
63746423 return PreviousCount;
63756424 }
63766425
6377- if (EmuSuspendThreadAtGuestBoundary (ThreadHeader->HostHandle ))
6426+ const DWORD ThreadId = GetThreadId (ThreadHeader->HostHandle );
6427+ if (ThreadId == GetCurrentThreadId ())
6428+ {
6429+ SuspendState.LogicalCount ++;
6430+ ThreadHeader->SuspendCount = SuspendState.LogicalCount ;
6431+ if (!EmuSuspendCurrentThread (
6432+ ThreadHeader->HostHandle , Lock, SuspendState))
6433+ {
6434+ SuspendState.LogicalCount --;
6435+ }
6436+ ThreadHeader->SuspendCount = SuspendState.LogicalCount ;
6437+ }
6438+ else
63786439 {
6379- SuspendState.HostCount ++;
6440+ if (EmuSuspendThreadAtGuestBoundary (ThreadHeader->HostHandle ))
6441+ {
6442+ SuspendState.HostCount ++;
6443+ }
6444+ SuspendState.LogicalCount ++;
6445+ ThreadHeader->SuspendCount = SuspendState.LogicalCount ;
63806446 }
6381- SuspendState.LogicalCount ++;
6382- ThreadHeader->SuspendCount = SuspendState.LogicalCount ;
63836447
63846448 EmuSwapFS (); // Xbox FS
63856449
@@ -10843,7 +10907,7 @@ extern "C" NTSTATUS NTAPI EmuNtSuspendThread
1084310907 }
1084410908 else
1084510909 {
10846- const std::lock_guard <std::mutex> Lock (
10910+ std::unique_lock <std::mutex> Lock (
1084710911 g_EmuThreadSuspendCountsMutex);
1084810912 EmuThreadSuspendState& SuspendState =
1084910913 EmuThreadSuspendStateForHandleLocked (ThreadHandle);
@@ -10860,11 +10924,25 @@ extern "C" NTSTATUS NTAPI EmuNtSuspendThread
1086010924 }
1086110925 else
1086210926 {
10863- if (EmuSuspendThreadAtGuestBoundary (ThreadHandle))
10927+ const DWORD ThreadId = GetThreadId (ThreadHandle);
10928+ if (ThreadId == GetCurrentThreadId ())
1086410929 {
10865- SuspendState.HostCount ++;
10930+ SuspendState.LogicalCount ++;
10931+ if (!EmuSuspendCurrentThread (
10932+ ThreadHandle, Lock, SuspendState))
10933+ {
10934+ SuspendState.LogicalCount --;
10935+ ret = 0xC0000008 ;
10936+ }
10937+ }
10938+ else
10939+ {
10940+ if (EmuSuspendThreadAtGuestBoundary (ThreadHandle))
10941+ {
10942+ SuspendState.HostCount ++;
10943+ }
10944+ SuspendState.LogicalCount ++;
1086610945 }
10867- SuspendState.LogicalCount ++;
1086810946 }
1086910947 }
1087010948
0 commit comments