diff --git a/src/Thunks/api-ms-win-core-io.hpp b/src/Thunks/api-ms-win-core-io.hpp index 35e6247..61c4f3b 100644 --- a/src/Thunks/api-ms-win-core-io.hpp +++ b/src/Thunks/api-ms-win-core-io.hpp @@ -92,18 +92,15 @@ namespace YY::Thunks if (fAlertable) { - // 使用 WaitForSingleObjectEx 进行等待触发 APC - auto _uStartTick = GetTickCount(); - for (;;) + constexpr auto kMaxSleepTime = 10; + // 使用 SleepEx 进行等待触发 APC + if (dwMilliseconds == INFINITE) { - const auto _uResult = WaitForSingleObjectEx(CompletionPort, dwMilliseconds, TRUE); - if (_uResult == WAIT_OBJECT_0) + for (;;) { - // 完成端口有数据了 auto _bRet = GetQueuedCompletionStatus(CompletionPort, &_Entry.dwNumberOfBytesTransferred, &_Entry.lpCompletionKey, &_Entry.lpOverlapped, 0); if (_bRet) { - *ulNumEntriesRemoved = 1; break; } @@ -112,47 +109,54 @@ namespace YY::Thunks return FALSE; } - // 无限等待时无脑继续等即可。 - if (dwMilliseconds == INFINITE) + if (SleepEx(kMaxSleepTime, TRUE) == WAIT_IO_COMPLETION) { - continue; + SetLastError(WAIT_IO_COMPLETION); + return FALSE; + } + } + } + else + { + const auto _uStartTick = GetTickCount(); + for (;;) + { + auto _bRet = GetQueuedCompletionStatus(CompletionPort, &_Entry.dwNumberOfBytesTransferred, &_Entry.lpCompletionKey, &_Entry.lpOverlapped, 0); + if (_bRet) + { + break; + } + + if (GetLastError() != WAIT_TIMEOUT) + { + return FALSE; } // 计算剩余等待时间,如果剩余等待时间归零则返回 - const DWORD _uTickSpan = GetTickCount() - _uStartTick; - if (_uTickSpan >= dwMilliseconds) + const auto _uTickSpan = GetTickCount() - _uStartTick; + if (dwMilliseconds > _uTickSpan) + { + if (SleepEx(min(kMaxSleepTime, dwMilliseconds - _uTickSpan), TRUE) == WAIT_IO_COMPLETION) + { + SetLastError(WAIT_IO_COMPLETION); + return FALSE; + } + } + else { + if (SleepEx(0, TRUE) == WAIT_IO_COMPLETION) + { + SetLastError(WAIT_IO_COMPLETION); + return FALSE; + } + SetLastError(WAIT_TIMEOUT); return FALSE; } - dwMilliseconds -= _uTickSpan; - _uStartTick += _uTickSpan; - continue; - } - else if (_uResult == WAIT_IO_COMPLETION || _uResult == WAIT_TIMEOUT) - { - // 很奇怪,微软原版遇到 APC唤醒直接会设置 LastError WAIT_IO_COMPLETION - // 遇到超时,LastError WAIT_TIMEOUT(注意不是预期的 ERROR_TIMEOUT)不知道是故意还是有意。 - SetLastError(_uResult); - return FALSE; - } - else if (_uResult == WAIT_ABANDONED) - { - SetLastError(ERROR_ABANDONED_WAIT_0); - return FALSE; - } - else if (_uResult == WAIT_FAILED) - { - // LastError - return FALSE; - } - else - { - // LastError ??? - return FALSE; } } + *ulNumEntriesRemoved = 1; return TRUE; } else