Setup a KTIMER for the other functions using WaitApc too
This commit is contained in:
parent
fad4120841
commit
745f450a6c
|
@ -960,7 +960,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(SignalObjectAndWait)
|
|||
NewTime.QuadPart += (static_cast<xbox::ulonglong_xt>(dwMilliseconds) * CLOCK_TIME_INCREMENT);
|
||||
}
|
||||
|
||||
xbox::dword_xt ret = WaitApc([hObjectToSignal, hObjectToWaitOn, bAlertable]() -> std::optional<DWORD> {
|
||||
xbox::dword_xt ret = WaitApc<true>([hObjectToSignal, hObjectToWaitOn, bAlertable]() -> std::optional<DWORD> {
|
||||
DWORD dwRet = SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, 0, bAlertable);
|
||||
if (dwRet == WAIT_TIMEOUT) {
|
||||
return std::nullopt;
|
||||
|
|
|
@ -110,15 +110,15 @@ void RestoreInterruptMode(bool value);
|
|||
void CallSoftwareInterrupt(const xbox::KIRQL SoftwareIrql);
|
||||
|
||||
template<typename T>
|
||||
std::optional<xbox::ntstatus_xt> SatisfyWait(T &&Lambda, xbox::PETHREAD eThread, xbox::boolean_xt Alertable, xbox::char_xt WaitMode)
|
||||
std::optional<xbox::ntstatus_xt> SatisfyWait(T &&Lambda, xbox::PKTHREAD kThread, xbox::boolean_xt Alertable, xbox::char_xt WaitMode)
|
||||
{
|
||||
if (const auto ret = Lambda()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
xbox::KiApcListMtx.lock();
|
||||
bool EmptyKernel = IsListEmpty(&eThread->Tcb.ApcState.ApcListHead[xbox::KernelMode]);
|
||||
bool EmptyUser = IsListEmpty(&eThread->Tcb.ApcState.ApcListHead[xbox::UserMode]);
|
||||
bool EmptyKernel = IsListEmpty(&kThread->ApcState.ApcListHead[xbox::KernelMode]);
|
||||
bool EmptyUser = IsListEmpty(&kThread->ApcState.ApcListHead[xbox::UserMode]);
|
||||
xbox::KiApcListMtx.unlock();
|
||||
|
||||
if (EmptyKernel == false) {
|
||||
|
@ -135,18 +135,20 @@ std::optional<xbox::ntstatus_xt> SatisfyWait(T &&Lambda, xbox::PETHREAD eThread,
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<bool setup_ktimer, typename T>
|
||||
xbox::ntstatus_xt WaitApc(T &&Lambda, xbox::PLARGE_INTEGER Timeout, xbox::boolean_xt Alertable, xbox::char_xt WaitMode)
|
||||
{
|
||||
// NOTE: kThread->Alerted is currently never set. When the alerted mechanism is implemented, the alerts should
|
||||
// also interrupt the wait
|
||||
|
||||
xbox::PETHREAD eThread = reinterpret_cast<xbox::PETHREAD>(EmuKeGetPcr()->Prcb->CurrentThread);
|
||||
xbox::PKTHREAD kThread = EmuKeGetPcr()->Prcb->CurrentThread;
|
||||
|
||||
if (Timeout == nullptr) {
|
||||
// No timout specified, so this is an infinite wait until an alert, a user apc or the object(s) become(s) signalled
|
||||
kThread->State = xbox::Waiting;
|
||||
while (true) {
|
||||
if (const auto ret = SatisfyWait(Lambda, eThread, Alertable, WaitMode)) {
|
||||
if (const auto ret = SatisfyWait(Lambda, kThread, Alertable, WaitMode)) {
|
||||
kThread->State = xbox::Running;
|
||||
return *ret;
|
||||
}
|
||||
|
||||
|
@ -155,7 +157,7 @@ xbox::ntstatus_xt WaitApc(T &&Lambda, xbox::PLARGE_INTEGER Timeout, xbox::boolea
|
|||
}
|
||||
else if (Timeout->QuadPart == 0) {
|
||||
// A zero timeout means that we only have to check the conditions once and then return immediately if they are not satisfied
|
||||
if (const auto ret = SatisfyWait(Lambda, eThread, Alertable, WaitMode)) {
|
||||
if (const auto ret = SatisfyWait(Lambda, kThread, Alertable, WaitMode)) {
|
||||
return *ret;
|
||||
}
|
||||
else {
|
||||
|
@ -164,20 +166,37 @@ xbox::ntstatus_xt WaitApc(T &&Lambda, xbox::PLARGE_INTEGER Timeout, xbox::boolea
|
|||
}
|
||||
else {
|
||||
// A non-zero timeout means we have to check the conditions until we reach the requested time
|
||||
xbox::LARGE_INTEGER ExpireTime, DueTime, NewTime;
|
||||
xbox::ulonglong_xt Now;
|
||||
ExpireTime.QuadPart = DueTime.QuadPart = Timeout->QuadPart; // either positive, negative, but not NULL
|
||||
xbox::PLARGE_INTEGER AbsoluteExpireTime = xbox::KiComputeWaitInterval(&ExpireTime, &DueTime, &NewTime, &Now);
|
||||
while (Now <= static_cast<xbox::ulonglong_xt>(AbsoluteExpireTime->QuadPart)) {
|
||||
if (const auto ret = SatisfyWait(Lambda, eThread, Alertable, WaitMode)) {
|
||||
if constexpr (setup_ktimer) {
|
||||
// Setup a timer if it wasn't already by our caller. This is necessary because in this way, KiTimerExpiration can discover the timeout
|
||||
// and yield to us. Otherwise, we will only be able to discover the timeout when Windows decides to schedule us again, and testing shows that
|
||||
// tends to happen much later than the due time
|
||||
xbox::KiTimerLock();
|
||||
xbox::PKWAIT_BLOCK WaitBlock = &kThread->TimerWaitBlock;
|
||||
kThread->WaitBlockList = WaitBlock;
|
||||
xbox::PKTIMER Timer = &kThread->Timer;
|
||||
WaitBlock->NextWaitBlock = WaitBlock;
|
||||
Timer->Header.WaitListHead.Flink = &WaitBlock->WaitListEntry;
|
||||
Timer->Header.WaitListHead.Blink = &WaitBlock->WaitListEntry;
|
||||
if (xbox::KiInsertTreeTimer(Timer, *Timeout) == FALSE) {
|
||||
xbox::KiTimerUnlock();
|
||||
return X_STATUS_TIMEOUT;
|
||||
}
|
||||
xbox::KiTimerUnlock();
|
||||
}
|
||||
kThread->State = xbox::Waiting;
|
||||
while (true) {
|
||||
if (const auto ret = SatisfyWait(Lambda, kThread, Alertable, WaitMode)) {
|
||||
kThread->State = xbox::Running;
|
||||
return *ret;
|
||||
}
|
||||
|
||||
std::this_thread::yield();
|
||||
Now = xbox::KeQueryInterruptTime();
|
||||
}
|
||||
if (setup_ktimer && (kThread->State == xbox::Ready)) {
|
||||
kThread->State = xbox::Running;
|
||||
return kThread->WaitStatus;
|
||||
}
|
||||
|
||||
return X_STATUS_TIMEOUT;
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -711,7 +711,7 @@ 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
|
||||
|
||||
xbox::ntstatus_xt ret = WaitApc([Alertable]() -> std::optional<ntstatus_xt> {
|
||||
xbox::ntstatus_xt ret = WaitApc<true>([Alertable]() -> std::optional<ntstatus_xt> {
|
||||
NtDll::LARGE_INTEGER ExpireTime;
|
||||
ExpireTime.QuadPart = 0;
|
||||
NTSTATUS Status = NtDll::NtDelayExecution(Alertable, &ExpireTime);
|
||||
|
@ -2334,7 +2334,7 @@ XBSYSAPI EXPORTNUM(158) xbox::ntstatus_xt NTAPI xbox::KeWaitForMultipleObjects
|
|||
//}
|
||||
|
||||
// TODO: Remove this after we have our own scheduler and the above is implemented
|
||||
WaitStatus = WaitApc([Thread]() -> std::optional<ntstatus_xt> {
|
||||
WaitStatus = WaitApc<false>([Thread]() -> std::optional<ntstatus_xt> {
|
||||
if (Thread->State == Ready) {
|
||||
// We have been readied to resume execution, so exit the wait
|
||||
return std::make_optional<ntstatus_xt>(Thread->WaitStatus);
|
||||
|
@ -2522,7 +2522,7 @@ XBSYSAPI EXPORTNUM(159) xbox::ntstatus_xt NTAPI xbox::KeWaitForSingleObject
|
|||
KiWaitListUnlock();
|
||||
|
||||
// TODO: Remove this after we have our own scheduler and the above is implemented
|
||||
WaitStatus = WaitApc([Thread]() -> std::optional<ntstatus_xt> {
|
||||
WaitStatus = WaitApc<false>([Thread]() -> std::optional<ntstatus_xt> {
|
||||
if (Thread->State == Ready) {
|
||||
// We have been readied to resume execution, so exit the wait
|
||||
return std::make_optional<ntstatus_xt>(Thread->WaitStatus);
|
||||
|
|
|
@ -2229,7 +2229,7 @@ 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
|
||||
|
||||
xbox::ntstatus_xt ret = WaitApc([Count, &nativeHandles, WaitType, Alertable]() -> std::optional<ntstatus_xt> {
|
||||
xbox::ntstatus_xt ret = WaitApc<true>([Count, &nativeHandles, WaitType, Alertable]() -> std::optional<ntstatus_xt> {
|
||||
NtDll::LARGE_INTEGER ExpireTime;
|
||||
ExpireTime.QuadPart = 0;
|
||||
NTSTATUS Status = NtDll::NtWaitForMultipleObjects(
|
||||
|
|
Loading…
Reference in New Issue