From 7e2ade452a3fd77cedf99406591ca5231cb3d6c6 Mon Sep 17 00:00:00 2001 From: Ariel Abreu Date: Wed, 4 Oct 2023 00:27:01 -0400 Subject: [PATCH] Add `NOTE_MACHTIME` support This is actually used in libdispatch for pretty much all non-wall-clock timers, so as you might imagine, it's used quite frequently and we were processing it incorrectly, leading to stalls in some programs that use such timers for short intervals/deadlines. --- src/linux/timer.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/linux/timer.c b/src/linux/timer.c index b8c818d..50b0824 100644 --- a/src/linux/timer.c +++ b/src/linux/timer.c @@ -16,6 +16,7 @@ #include "private.h" #include +#include #ifndef HAVE_SYS_TIMERFD_H @@ -94,11 +95,15 @@ static void convert_to_itimerspec(struct itimerspec *dst, uint64_t src, bool one gettimeofday(&now, NULL); } + // for all these NOTE_ABSOLUTE __builtin_sub_overflow checks: + // not sure if we can just use `0` or if that's a special/reserved value, so let's use `1` to be safe + if (fflags & NOTE_SECONDS) { dbg_printf("...timer is in seconds: %llu\n", src); if (fflags & NOTE_ABSOLUTE) - src -= now.tv_sec; + if (__builtin_sub_overflow(src, now.tv_sec, &src)) + src = 1; sec = src; nsec = 0; @@ -107,7 +112,8 @@ static void convert_to_itimerspec(struct itimerspec *dst, uint64_t src, bool one { dbg_printf("...timer is in useconds: %llu\n", src); if (fflags & NOTE_ABSOLUTE) - src -= (now.tv_sec * 1000000ull) + now.tv_usec; + if (__builtin_sub_overflow(src, (now.tv_sec * 1000000ull) + now.tv_usec, &src)) + src = 1; sec = src / 1000000; nsec = (src % 1000000) * 1000; @@ -116,11 +122,26 @@ static void convert_to_itimerspec(struct itimerspec *dst, uint64_t src, bool one { dbg_printf("...timer is in nseconds: %llu\n", src); if (fflags & NOTE_ABSOLUTE) - src -= (now.tv_sec * 1000000000ull) + now.tv_usec*1000; + if (__builtin_sub_overflow(src, (now.tv_sec * 1000000000ull) + now.tv_usec*1000, &src)) + src = 1; sec = src / 1000000000; nsec = src % 1000000000; } + else if (fflags & NOTE_MACHTIME) + { + dbg_printf("...timer is in Mach-time-units: %llu\n", src); + if (fflags & NOTE_ABSOLUTE) + if (__builtin_sub_overflow(src, mach_absolute_time(), &src)) + src = 1; + + mach_timebase_info_data_t timebase; + mach_timebase_info(&timebase); + // the timebase info is in nanoseconds + uint64_t mach_nsec = (src * timebase.numer) / (timebase.denom); + sec = mach_nsec / 1000000000; + nsec = mach_nsec % 1000000000; + } else { dbg_printf("...timer is in mseconds: %llu\n", src);