Browse Source

fix: don't use `CLOCK_MONOTONIC_RAW` on Android

Older Android phones have a kernel bug where time is not properly calculated
when calling `clock_gettime(CLOCK_MONOTONIC_RAW, ...)`. The returned time
either has nanoseconds out of range (outside of [0, 999999999]) or the returned
time is not monotonic in regards to previous call or both.

The issue is reproducible in Android Studio on arm64 emulators from at least
Android 7.0 (didn't try older versions) up to including Android 8.1 (kernel
3.18.94). The issue is in the kernel, these are just the versions of Android
emulator with buggy kernels.

The kernel commit that fixed this is [1]. Because this fix was backported to
various LTS releases of kernels it's hard to find out exactly which kernels are
buggy and which not. Therefore always use `CLOCK_MONOTONIC` on Android.

The `CLOCK_MONOTONIC` is slowly adjusted in case of NTP changes but not for
more than 0.5ms per second [2]. So it should be good enough for measuring
elapsed time.

---

An option would be to dynamically select
`CLOCK_MONOTONIC_RAW`/`CLOCK_MONOTONIC` at runtime by checking at init time
that `clock_gettime(CLOCK_MONOTONIC_RAW, ...)` returns nanoseconds in range.
Testing showed that nanosecons are out of range for 999/1000 cases. I guess
this could be good enough for support on older phones.

But because this would introduce a small perf hit by always reading a global
variable for first argument to `clock_gettime` and because `CLOCK_MONOTONIC`
does not have that high time deviation, this commit uses `CLOCK_MONOTONIC` on
Android always. It is also less burden to maintain.

---

[1] https://github.com/torvalds/linux/commit/dbb236c1ceb697a559e0694ac4c9e7b9131d0b16
[2] https://github.com/torvalds/linux/blob/master/include/linux/timex.h#L136
Blaž Tomažič 1 tuần trước cách đây
mục cha
commit
62d82ffc15
1 tập tin đã thay đổi với 3 bổ sung1 xóa
  1. 3 1
      src/timer/unix/SDL_systimer.c

+ 3 - 1
src/timer/unix/SDL_systimer.c

@@ -53,7 +53,9 @@
 
 // Use CLOCK_MONOTONIC_RAW, if available, which is not subject to adjustment by NTP
 #ifdef HAVE_CLOCK_GETTIME
-#ifdef CLOCK_MONOTONIC_RAW
+// Older Android phones have a buggy CLOCK_MONOTONIC_RAW, use CLOCK_MONOTONIC
+// See fix: https://github.com/torvalds/linux/commit/dbb236c1ceb697a559e0694ac4c9e7b9131d0b16
+#if defined(CLOCK_MONOTONIC_RAW) && !defined(__ANDROID__)
 #define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC_RAW
 #else
 #define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC