Make sure to reset WaitStatus when a new wait starts
This fixes an issue in Panzer Dragoon Orta, where KeDelayExecutionThread would return X_STATUS_TIMEOUT | X_STATUS_USER_APC
This commit is contained in:
parent
680340f53d
commit
ac31523b09
|
@ -960,9 +960,10 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(SignalObjectAndWait)
|
|||
NewTime.QuadPart += (static_cast<xbox::ulonglong_xt>(dwMilliseconds) * CLOCK_TIME_INCREMENT);
|
||||
}
|
||||
|
||||
PKTHREAD kThread = KeGetCurrentThread();
|
||||
kThread->WaitStatus = X_STATUS_SUCCESS;
|
||||
if (!Timeout || (Timeout->QuadPart == 0)) {
|
||||
// Use the built-in ktimer as a dummy wait object, so that KiUnwaitThreadAndLock can still work
|
||||
PKTHREAD kThread = KeGetCurrentThread();
|
||||
xbox::PKWAIT_BLOCK WaitBlock = &kThread->TimerWaitBlock;
|
||||
kThread->WaitBlockList = WaitBlock;
|
||||
xbox::PKTIMER Timer = &kThread->Timer;
|
||||
|
@ -971,7 +972,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(SignalObjectAndWait)
|
|||
Timer->Header.WaitListHead.Blink = &WaitBlock->WaitListEntry;
|
||||
}
|
||||
|
||||
xbox::ntstatus_xt status = WaitApc<true>([hObjectToSignal, hObjectToWaitOn, bAlertable]() -> std::optional<DWORD> {
|
||||
xbox::ntstatus_xt status = WaitApc<true>([hObjectToSignal, hObjectToWaitOn, bAlertable, kThread]() -> std::optional<DWORD> {
|
||||
DWORD dwRet = SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, 0, bAlertable);
|
||||
if (dwRet == WAIT_TIMEOUT) {
|
||||
return std::nullopt;
|
||||
|
@ -986,7 +987,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(SignalObjectAndWait)
|
|||
case WAIT_OBJECT_0: Status = X_STATUS_SUCCESS; break;
|
||||
default: Status = X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
xbox::KiUnwaitThreadAndLock(xbox::KeGetCurrentThread(), Status, 0);
|
||||
xbox::KiUnwaitThreadAndLock(kThread, Status, 0);
|
||||
return std::make_optional<ntstatus_xt>(Status);
|
||||
}, Timeout, bAlertable, UserMode);
|
||||
|
||||
|
|
|
@ -733,9 +733,10 @@ XBSYSAPI EXPORTNUM(99) xbox::ntstatus_xt NTAPI xbox::KeDelayExecutionThread
|
|||
// We can't remove NtDll::NtDelayExecution until all APCs queued by Io are implemented by our kernel as well
|
||||
// Test case: Metal Slug 3
|
||||
|
||||
PKTHREAD kThread = KeGetCurrentThread();
|
||||
kThread->WaitStatus = X_STATUS_SUCCESS;
|
||||
if (!Interval || (Interval->QuadPart == 0)) {
|
||||
// Use the built-in ktimer as a dummy wait object, so that KiUnwaitThreadAndLock can still work
|
||||
PKTHREAD kThread = KeGetCurrentThread();
|
||||
xbox::PKWAIT_BLOCK WaitBlock = &kThread->TimerWaitBlock;
|
||||
kThread->WaitBlockList = WaitBlock;
|
||||
xbox::PKTIMER Timer = &kThread->Timer;
|
||||
|
@ -744,7 +745,7 @@ XBSYSAPI EXPORTNUM(99) xbox::ntstatus_xt NTAPI xbox::KeDelayExecutionThread
|
|||
Timer->Header.WaitListHead.Blink = &WaitBlock->WaitListEntry;
|
||||
}
|
||||
|
||||
xbox::ntstatus_xt ret = WaitApc<true>([Alertable]() -> std::optional<ntstatus_xt> {
|
||||
xbox::ntstatus_xt ret = WaitApc<true>([Alertable, kThread]() -> std::optional<ntstatus_xt> {
|
||||
NtDll::LARGE_INTEGER ExpireTime;
|
||||
ExpireTime.QuadPart = 0;
|
||||
NTSTATUS Status = NtDll::NtDelayExecution(Alertable, &ExpireTime);
|
||||
|
@ -752,9 +753,10 @@ XBSYSAPI EXPORTNUM(99) xbox::ntstatus_xt NTAPI xbox::KeDelayExecutionThread
|
|||
if (Status >= 0 && Status != STATUS_ALERTED && Status != STATUS_USER_APC) {
|
||||
return std::nullopt;
|
||||
}
|
||||
EmuLog(LOG_LEVEL::DEBUG, "KeDelayExecutionThread -> Staus: %X", Status);
|
||||
// If the wait was satisfied with the host, then also unwait the thread on the guest side, to be sure to remove WaitBlocks that might have been added
|
||||
// to the thread. Test case: Steel Battalion
|
||||
xbox::KiUnwaitThreadAndLock(xbox::KeGetCurrentThread(), Status, 0);
|
||||
xbox::KiUnwaitThreadAndLock(kThread, Status, 0);
|
||||
return std::make_optional<ntstatus_xt>(Status);
|
||||
}, Interval, Alertable, WaitMode);
|
||||
|
||||
|
|
|
@ -2231,9 +2231,10 @@ XBSYSAPI EXPORTNUM(235) xbox::ntstatus_xt NTAPI xbox::NtWaitForMultipleObjectsEx
|
|||
|
||||
// Because user APCs from NtQueueApcThread are now handled by the kernel, we need to wait for them ourselves
|
||||
|
||||
PKTHREAD kThread = KeGetCurrentThread();
|
||||
kThread->WaitStatus = X_STATUS_SUCCESS;
|
||||
if (!Timeout || (Timeout->QuadPart == 0)) {
|
||||
// Use the built-in ktimer as a dummy wait object, so that KiUnwaitThreadAndLock can still work
|
||||
PKTHREAD kThread = KeGetCurrentThread();
|
||||
xbox::PKWAIT_BLOCK WaitBlock = &kThread->TimerWaitBlock;
|
||||
kThread->WaitBlockList = WaitBlock;
|
||||
xbox::PKTIMER Timer = &kThread->Timer;
|
||||
|
@ -2242,7 +2243,7 @@ XBSYSAPI EXPORTNUM(235) xbox::ntstatus_xt NTAPI xbox::NtWaitForMultipleObjectsEx
|
|||
Timer->Header.WaitListHead.Blink = &WaitBlock->WaitListEntry;
|
||||
}
|
||||
|
||||
xbox::ntstatus_xt ret = WaitApc<true>([Count, &nativeHandles, WaitType, Alertable]() -> std::optional<ntstatus_xt> {
|
||||
xbox::ntstatus_xt ret = WaitApc<true>([Count, &nativeHandles, WaitType, Alertable, kThread]() -> std::optional<ntstatus_xt> {
|
||||
NtDll::LARGE_INTEGER ExpireTime;
|
||||
ExpireTime.QuadPart = 0;
|
||||
NTSTATUS Status = NtDll::NtWaitForMultipleObjects(
|
||||
|
@ -2256,7 +2257,7 @@ XBSYSAPI EXPORTNUM(235) xbox::ntstatus_xt NTAPI xbox::NtWaitForMultipleObjectsEx
|
|||
}
|
||||
// If the wait was satisfied with the host, then also unwait the thread on the guest side, to be sure to remove WaitBlocks that might have been added
|
||||
// to the thread. Test case: Steel Battalion
|
||||
xbox::KiUnwaitThreadAndLock(xbox::KeGetCurrentThread(), Status, 0);
|
||||
xbox::KiUnwaitThreadAndLock(kThread, Status, 0);
|
||||
return std::make_optional<ntstatus_xt>(Status);
|
||||
}, Timeout, Alertable, WaitMode);
|
||||
|
||||
|
|
Loading…
Reference in New Issue