From 87885fafdbff4d3ca9c6b9cfb03b0af787acbc7c Mon Sep 17 00:00:00 2001 From: NepDisk Date: Tue, 5 May 2026 08:08:48 -0400 Subject: [PATCH] Port using nanosleep on *nix from SRB2Classic --- src/i_time.c | 40 ---------------------------- src/sdl/i_system.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 40 deletions(-) diff --git a/src/i_time.c b/src/i_time.c index f0b2b1ff4..cb5eb8bc0 100644 --- a/src/i_time.c +++ b/src/i_time.c @@ -118,43 +118,3 @@ void I_UpdateTime(fixed_t timescale) g_time.timefrac = FLOAT_TO_FIXED(fractional); } } - -void I_SleepDuration(precise_t duration) -{ - UINT64 precision = I_GetPrecisePrecision(); - INT32 sleepvalue = cv_sleep.value; - UINT64 delaygranularity; - precise_t cur; - precise_t dest; - - { - double gran = round(((double)(precision / 1000) * sleepvalue * MIN_SLEEP_DURATION_MS)); - delaygranularity = (UINT64)gran; - } - - cur = I_GetPreciseTime(); - dest = cur + duration; - - // the reason this is not dest > cur is because the precise counter may wrap - // two's complement arithmetic is our friend here, though! - // e.g. cur 0xFFFFFFFFFFFFFFFE = -2, dest 0x0000000000000001 = 1 - // 0x0000000000000001 - 0xFFFFFFFFFFFFFFFE = 3 - while ((INT64)(dest - cur) > 0) - { - // If our cv_sleep value exceeds the remaining sleep duration, use the - // hard sleep function. - if (sleepvalue > 0 && (dest - cur) > delaygranularity) - { -#if defined(_WIN32) - DWORD sleepDuration = (DWORD)min((INT64)(dest - cur), sleepvalue); - SleepEx(sleepDuration, TRUE); -#else - I_Sleep(sleepvalue); -#endif - } - - // Otherwise, this is a spinloop. - - cur = I_GetPreciseTime(); - } -} diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index 680233dea..39b30a3d3 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -1281,6 +1281,69 @@ void I_Sleep(UINT32 ms) SDL_Delay(ms); } +void I_SleepDuration(precise_t duration) +{ +#if defined(__linux__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__OpenBSD__) + UINT64 precision = I_GetPrecisePrecision(); + precise_t dest = I_GetPreciseTime() + duration; +#ifdef __OpenBSD__ + precise_t slack = (precision / 50); // 20 ms slack +#else + precise_t slack = (precision / 5000); // 0.2 ms slack +#endif + if (duration > slack) + { + duration -= slack; + struct timespec ts = { + .tv_sec = static_cast<__time_t>(duration / precision), + .tv_nsec = static_cast<__syscall_slong_t>(duration * 1000000000 / precision % 1000000000), + }; + int status; +#ifdef __OpenBSD__ + do status = nanosleep(&ts, &ts); +#else + do status = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &ts); +#endif + while (status == EINTR); + } + + // busy-wait the rest + while (((INT64)dest - (INT64)I_GetPreciseTime()) > 0); +#elif defined (MIN_SLEEP_DURATION_MS) + UINT64 precision = I_GetPrecisePrecision(); + INT32 sleepvalue = cv_sleep.value; + UINT64 delaygranularity; + precise_t cur; + precise_t dest; + + { + double gran = round(((double)(precision / 1000) * sleepvalue * MIN_SLEEP_DURATION_MS)); + delaygranularity = (UINT64)gran; + } + + cur = I_GetPreciseTime(); + dest = cur + duration; + + // the reason this is not dest > cur is because the precise counter may wrap + // two's complement arithmetic is our friend here, though! + // e.g. cur 0xFFFFFFFFFFFFFFFE = -2, dest 0x0000000000000001 = 1 + // 0x0000000000000001 - 0xFFFFFFFFFFFFFFFE = 3 + while ((INT64)(dest - cur) > 0) + { + // If our cv_sleep value exceeds the remaining sleep duration, use the + // hard sleep function. + if (sleepvalue > 0 && (dest - cur) > delaygranularity) + { + I_Sleep(sleepvalue); + } + + // Otherwise, this is a spinloop. + + cur = I_GetPreciseTime(); + } +#endif +} + #ifdef NEWSIGNALHANDLER static void newsignalhandler_Warn(const char *pr) {