diff --git a/src/i_time.c b/src/i_time.c
index fae26abede3f646252abd7c04ff826bbf89ae2ba..39854b242db15dae5b89c634a938783e35691df2 100644
--- a/src/i_time.c
+++ b/src/i_time.c
@@ -30,12 +30,6 @@ static precise_t enterprecise, oldenterprecise;
 static fixed_t entertic, oldentertics;
 static double tictimer;
 
-// A little more than the minimum sleep duration on Windows.
-// May be incorrect for other platforms, but we don't currently have a way to
-// query the scheduler granularity. SDL will do what's needed to make this as
-// low as possible though.
-#define MIN_SLEEP_DURATION_MS 2.1
-
 tic_t I_GetTime(void)
 {
 	return g_time.time;
@@ -88,38 +82,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)
-		{
-			I_Sleep(sleepvalue);
-		}
-
-		// Otherwise, this is a spinloop.
-
-		cur = I_GetPreciseTime();
-	}
-}
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index 51c89f78d8977d531d99e3ca0ee5cd6afbc0036d..847806270f78175624fd2fabcdcf32a0b9e0e29e 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -41,6 +41,12 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
 #include <ntsecapi.h>
 #undef SystemFunction036
 
+// A little more than the minimum sleep duration on Windows.
+// May be incorrect for other platforms, but we don't currently have a way to
+// query the scheduler granularity. SDL will do what's needed to make this as
+// low as possible though.
+#define MIN_SLEEP_DURATION_MS 2.1
+
 #endif
 #include <stdio.h>
 #include <stdlib.h>
@@ -2275,6 +2281,52 @@ void I_Sleep(UINT32 ms)
 	SDL_Delay(ms);
 }
 
+void I_SleepDuration(precise_t duration)
+{
+#if defined(__linux__) || defined(__FreeBSD__)
+	UINT64 precision = I_GetPrecisePrecision();
+	struct timespec ts = {
+		.tv_sec = duration / precision,
+		.tv_nsec = duration * 1000000000 / precision % 1000000000,
+	};
+	int status;
+	do status = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &ts);
+	while (status == EINTR);
+#else
+	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
 ATTRNORETURN static FUNCNORETURN void newsignalhandler_Warn(const char *pr)
 {