void SleepFor(SteadyClock::duration time) { #ifdef _WIN32 static ULONG maxRes = 0; static NTSTATUS(WINAPI * pNtSetTimerResolution)( ULONG resolution, BOOLEAN set_resolution, ULONG * current_resolution); static NTSTATUS(WINAPI * pNtDelayExecution)(BOOLEAN alertable, const LARGE_INTEGER* timeout); if (maxRes == 0) { // Load ntdll.dll functions std::string errorString; DynamicLib ntdll = DynamicLib::Open("ntdll.dll", errorString); if (!ntdll) Sys::Error("Failed to load ntdll.dll: %s", errorString); auto pNtQueryTimerResolution = ntdll.LoadSym<NTSTATUS WINAPI(ULONG*, ULONG*, ULONG*) >( "NtQueryTimerResolution", errorString); if (!pNtQueryTimerResolution) Sys::Error("Failed to load NtQueryTimerResolution from ntdll.dll: %s", errorString); pNtSetTimerResolution = ntdll.LoadSym<NTSTATUS WINAPI(ULONG, BOOLEAN, ULONG*) >( "NtSetTimerResolution", errorString); if (!pNtSetTimerResolution) Sys::Error("Failed to load NtSetTimerResolution from ntdll.dll: %s", errorString); pNtDelayExecution = ntdll.LoadSym<NTSTATUS WINAPI(BOOLEAN, const LARGE_INTEGER*) >( "NtDelayExecution", errorString); if (!pNtDelayExecution) Sys::Error("Failed to load NtDelayExecution from ntdll.dll: %s", errorString); // Determine the maximum available timer resolution ULONG minRes, curRes; if (pNtQueryTimerResolution(&minRes, &maxRes, &curRes) != 0) maxRes = 10000; // Default to 1ms } // Increase the system timer resolution for the duration of the sleep ULONG curRes; pNtSetTimerResolution(maxRes, TRUE, &curRes); // Convert to NT units of 100ns typedef std::chrono::duration<int64_t, std::ratio<1, 10000000>> NTDuration; auto ntTime = std::chrono::duration_cast<NTDuration>(time); // Store the delay as a negative number to indicate a relative sleep LARGE_INTEGER duration; duration.QuadPart = -ntTime.count(); pNtDelayExecution(FALSE, &duration); // Restore timer resolution after sleeping pNtSetTimerResolution(maxRes, FALSE, &curRes); #else std::this_thread::sleep_for(time); #endif }
void sleep(uint32_t milliseconds) { // This should only be the case at the very beginning of execution. if(pNtDelayExecution == NULL) { Sleep(milliseconds); return; } assert(pNtDelayExecution != NULL, "pNtDelayExecution is NULL!", ); LARGE_INTEGER li; li.QuadPart = -10000 * (uint64_t) milliseconds; pNtDelayExecution(FALSE, &li); }