49 lines
1.4 KiB
C++
49 lines
1.4 KiB
C++
#ifndef CORE_LIBS_PRX_LIBC_INCLUDE_PRECISEWAIT_HPP
|
|
#define CORE_LIBS_PRX_LIBC_INCLUDE_PRECISEWAIT_HPP
|
|
|
|
#include <chrono>
|
|
#include <thread>
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include "prx/libc/include/HostThreadLocal.hpp"
|
|
#endif
|
|
|
|
inline constexpr unsigned long long kSubTickWaitUs = 2000;
|
|
|
|
inline void PreciseSleepUs(unsigned long long micros) {
|
|
if (micros == 0) {
|
|
return;
|
|
}
|
|
#ifdef _WIN32
|
|
struct Timer {
|
|
HANDLE handle = CreateWaitableTimerExW(nullptr, nullptr,
|
|
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
|
|
~Timer() {
|
|
if (handle != nullptr) {
|
|
CloseHandle(handle);
|
|
}
|
|
}
|
|
};
|
|
auto& timer = HostThreadLocal<Timer, Timer>();
|
|
if (timer.handle != nullptr) {
|
|
LARGE_INTEGER due{};
|
|
due.QuadPart = -static_cast<LONGLONG>(micros * 10ULL);
|
|
if (SetWaitableTimerEx(timer.handle, &due, 0, nullptr, nullptr, nullptr, 0) != FALSE) {
|
|
WaitForSingleObject(timer.handle, INFINITE);
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
std::this_thread::sleep_for(std::chrono::microseconds(micros));
|
|
}
|
|
|
|
template <class TClock, class TDuration>
|
|
inline void PreciseSleepUntil(const std::chrono::time_point<TClock, TDuration>& deadline) {
|
|
for (auto now = TClock::now(); now < deadline; now = TClock::now()) {
|
|
PreciseSleepUs(static_cast<unsigned long long>(std::chrono::ceil<std::chrono::microseconds>(deadline - now).count()));
|
|
}
|
|
}
|
|
|
|
#endif
|