fixed_clock.c 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. // LD_PRELOAD shim for regression renders: the wall clock (time(), gettimeofday(),
  2. // clock_gettime(CLOCK_REALTIME*)) always reads LWE_FIXED_CLOCK (unix seconds). That covers
  3. // the day/night uniform, text clocks, script Date objects and QuickJS's Math.random seed.
  4. // Monotonic clocks are left alone so frame pacing and timeouts keep working.
  5. #define _GNU_SOURCE
  6. #include <dlfcn.h>
  7. #include <stdlib.h>
  8. #include <sys/time.h>
  9. #include <time.h>
  10. static time_t fixed_seconds (void) {
  11. static time_t value = -1;
  12. if (value == -1) {
  13. const char* env = getenv ("LWE_FIXED_CLOCK");
  14. value = env != NULL ? (time_t) strtoll (env, NULL, 10) : 1767268800; // 2026-01-01 12:00 UTC
  15. }
  16. return value;
  17. }
  18. time_t time (time_t* out) {
  19. const time_t now = fixed_seconds ();
  20. if (out != NULL) {
  21. *out = now;
  22. }
  23. return now;
  24. }
  25. int gettimeofday (struct timeval* tv, void* tz) {
  26. if (tv != NULL) {
  27. tv->tv_sec = fixed_seconds ();
  28. tv->tv_usec = 0;
  29. }
  30. return 0;
  31. }
  32. int clock_gettime (clockid_t clock, struct timespec* ts) {
  33. static int (*real) (clockid_t, struct timespec*) = NULL;
  34. if (clock == CLOCK_REALTIME || clock == CLOCK_REALTIME_COARSE) {
  35. ts->tv_sec = fixed_seconds ();
  36. ts->tv_nsec = 0;
  37. return 0;
  38. }
  39. if (real == NULL) {
  40. real = (int (*) (clockid_t, struct timespec*)) dlsym (RTLD_NEXT, "clock_gettime");
  41. }
  42. return real (clock, ts);
  43. }