From a7a85a259c1515cbf557f86d82bd65706ac0f9cd Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Fri, 2 Oct 2026 10:13:35 +0200 Subject: [PATCH] Add os_tick_us() and os_tick_ns() monotonic high-resolution timers --- configure.ac | 3 +-- os/mingw.c | 27 +++++++++++++++++++++++++++ os/os.h | 12 ++++++++++++ os/portable.h | 5 ----- os/unix.c | 27 ++++++++++++++++++--------- 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/configure.ac b/configure.ac index dbc75081..b80ad099 100644 --- a/configure.ac +++ b/configure.ac @@ -71,7 +71,7 @@ AC_HEADER_ASSERT AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([dirent.h stdint.h inttypes.h unistd.h math.h execinfo.h strings.h getopt.h syslog.h grp.h pwd.h io.h alloca.h]) AC_CHECK_HEADERS([sys/file.h sys/sysctl.h sys/ioctl.h sys/time.h sys/types.h sys/mkdev.h sys/sysmacros.h sys/stat.h sys/prctl.h sys/sysinfo.h sys/utsname.h]) -AC_CHECK_HEADERS([linux/fs.h linux/btrfs.h linux/fiemap.h mach/mach_time.h]) +AC_CHECK_HEADERS([linux/fs.h linux/btrfs.h linux/fiemap.h]) # Check for the close_range(...,CLOSE_RANGE_CLOEXEC) AC_CHECK_HEADERS([linux/close_range.h]) @@ -126,7 +126,6 @@ AC_CHECK_FUNCS([fsync posix_fadvise sync_file_range syncfs]) AC_CHECK_FUNCS([getc_unlocked ferror_unlocked]) AC_CHECK_FUNCS([futimes futimens futimesat localtime_r lutimes utimensat]) AC_CHECK_FUNCS([fstatat flock renameat statx]) -AC_CHECK_FUNCS([mach_absolute_time]) AC_CHECK_FUNCS([backtrace backtrace_symbols]) AC_SEARCH_LIBS([clock_gettime], [rt]) AC_CHECK_FUNCS([clock_gettime]) diff --git a/os/mingw.c b/os/mingw.c index 3341e784..e457ea30 100644 --- a/os/mingw.c +++ b/os/mingw.c @@ -64,6 +64,7 @@ static windows_key_t last_error; */ static windows_mutex_t tick_lock; static uint64_t tick_last; +static uint64_t tick_frequency; /** * Mutex for process reference publication, termination, and unpublication. @@ -4498,6 +4499,24 @@ uint64_t os_tick_ms(void) return GetTickCount64(); } +uint64_t os_tick_us(void) +{ + uint64_t ticks = os_tick(); + uint64_t sec = ticks / tick_frequency; + uint64_t rem = ticks % tick_frequency; + + return sec * 1000000ULL + (rem * 1000000ULL) / tick_frequency; +} + +uint64_t os_tick_ns(void) +{ + uint64_t ticks = os_tick(); + uint64_t sec = ticks / tick_frequency; + uint64_t rem = ticks % tick_frequency; + + return sec * 1000000000ULL + (rem * 1000000000ULL) / tick_frequency; +} + int os_usleep(uint64_t usec) { while (usec > 0) { @@ -4609,6 +4628,13 @@ void os_init(unsigned opt) os_exit(); } + LARGE_INTEGER freq; + if (!QueryPerformanceFrequency(&freq) || freq.QuadPart <= 0) { + os_syslog(OS_LVL_CRITICAL, "error calling QueryPerformanceFrequency()"); + os_exit(); + } + tick_frequency = freq.QuadPart; + if (windows_mutex_init(&exec_mutex, 0) != 0) { os_syslog(OS_LVL_CRITICAL, "error calling windows_mutex_init()"); os_exit(); @@ -4684,6 +4710,7 @@ void os_done(void) windows_mutex_destroy(&exec_mutex); windows_mutex_destroy(&tick_lock); + tick_frequency = 0; /* restore the normal execution level */ SetThreadExecutionState(WIN32_ES_CONTINUOUS); diff --git a/os/os.h b/os/os.h index a0544181..8befff56 100644 --- a/os/os.h +++ b/os/os.h @@ -397,6 +397,18 @@ uint64_t os_tick(void); */ uint64_t os_tick_ms(void); +/** + * Get the os_tick counter value in microsecond. + * \return Monotonic clock value in microseconds. + */ +uint64_t os_tick_us(void); + +/** + * Get the os_tick counter value in nanosecond. + * \return Monotonic clock value in nanoseconds. + */ +uint64_t os_tick_ns(void); + /** * Get the os_tick counter value in seconds. * \return Monotonic clock value in seconds. diff --git a/os/portable.h b/os/portable.h index 1dcd0963..6b86dc78 100644 --- a/os/portable.h +++ b/os/portable.h @@ -132,7 +132,6 @@ #include #endif - /** * Includes some standard headers. */ @@ -174,10 +173,6 @@ #endif #endif -#if HAVE_MACH_MACH_TIME_H -#include -#endif - #if HAVE_DIRENT_H #include #endif diff --git a/os/unix.c b/os/unix.c index bc8e9ae0..41215329 100644 --- a/os/unix.c +++ b/os/unix.c @@ -2217,17 +2217,18 @@ void os_privileges_release(void) uint64_t os_tick(void) { -#if HAVE_MACH_ABSOLUTE_TIME - /* for Mac OS X */ - return mach_absolute_time(); -#elif HAVE_CLOCK_GETTIME && (defined(CLOCK_MONOTONIC) || defined(CLOCK_MONOTONIC_RAW)) - /* for Linux */ +#if HAVE_CLOCK_GETTIME && (defined(CLOCK_UPTIME_RAW) || defined(CLOCK_MONOTONIC_RAW) || defined(CLOCK_MONOTONIC)) struct timespec tv; /* nanosecond precision with clock_gettime() */ -#if defined(CLOCK_MONOTONIC_RAW) +#if defined(CLOCK_UPTIME_RAW) + /* for macOS (without sleep and without NTP slewing) */ + if (clock_gettime(CLOCK_UPTIME_RAW, &tv) != 0) { +#elif defined(CLOCK_MONOTONIC_RAW) + /* for Linux (without sleep and without NTP slewing) */ if (clock_gettime(CLOCK_MONOTONIC_RAW, &tv) != 0) { #else + /* for other POSIX */ if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) { #endif /* LCOV_EXCL_START */ @@ -2247,7 +2248,7 @@ uint64_t os_tick(void) /* LCOV_EXCL_STOP */ } - return tv.tv_sec * 1000000ULL + tv.tv_usec; + return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000ULL; #endif } @@ -2276,6 +2277,16 @@ uint64_t os_tick_ms(void) #endif } +uint64_t os_tick_us(void) +{ + return os_tick() / 1000; +} + +uint64_t os_tick_ns(void) +{ + return os_tick(); +} + uint64_t os_tick_sec(void) { #if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) @@ -2327,8 +2338,6 @@ int os_usleep(uint64_t usec) return 0; } - - int os_randomize(void* ptr, size_t size) { int f;