From 105548345ec674b01abccfc94555185416870cdb Mon Sep 17 00:00:00 2001 From: Kevin Schoedel <67607049+kpschoedel@users.noreply.github.com> Date: Thu, 21 Oct 2021 09:12:18 -0400 Subject: [PATCH] Type-safe System::Clock (#10589) * Type-safe System::Clock #### Problem Issue #10062 _Some operations on System::Clock types are not safe_ #### Change overview Introduce safe types based on `std::chrono::duration` to `System::Clock`. Future changes will use these types, starting with system timers and proceeding upward through the stack. #### Testing Updated `src/system/tests/TestSystemClock.cpp` * review --- .../minimal_mdns/ActiveResolveAttempts.h | 4 +- .../tests/TestActiveResolveAttempts.cpp | 6 +- src/platform/ESP32/SystemTimeSupport.cpp | 10 +- src/platform/FreeRTOS/SystemTimeSupport.cpp | 10 +- src/platform/Linux/SystemTimeSupport.cpp | 16 +- src/platform/Zephyr/SystemTimeSupport.cpp | 10 +- src/platform/mbed/SystemTimeSupport.cpp | 10 +- src/system/SystemClock.cpp | 58 ++++--- src/system/SystemClock.h | 157 +++++++++++++++--- src/system/tests/TestSystemClock.cpp | 40 +++-- 10 files changed, 232 insertions(+), 89 deletions(-) diff --git a/src/lib/dnssd/minimal_mdns/ActiveResolveAttempts.h b/src/lib/dnssd/minimal_mdns/ActiveResolveAttempts.h index 9f05c7b9dc8148..ff09aeae690313 100644 --- a/src/lib/dnssd/minimal_mdns/ActiveResolveAttempts.h +++ b/src/lib/dnssd/minimal_mdns/ActiveResolveAttempts.h @@ -41,7 +41,7 @@ class ActiveResolveAttempts static constexpr size_t kRetryQueueSize = 4; static constexpr uint32_t kMaxRetryDelaySec = 16; - ActiveResolveAttempts(chip::System::ClockBase * clock) : mClock(clock) { Reset(); } + ActiveResolveAttempts(chip::System::Clock::ClockBase * clock) : mClock(clock) { Reset(); } /// Clear out the internal queue void Reset(); @@ -92,7 +92,7 @@ class ActiveResolveAttempts uint32_t nextRetryDelaySec = 1; }; - chip::System::ClockBase * mClock; + chip::System::Clock::ClockBase * mClock; RetryEntry mRetryQueue[kRetryQueueSize]; }; diff --git a/src/lib/dnssd/minimal_mdns/tests/TestActiveResolveAttempts.cpp b/src/lib/dnssd/minimal_mdns/tests/TestActiveResolveAttempts.cpp index 92da4d1ef30359..0170bf6142a48a 100644 --- a/src/lib/dnssd/minimal_mdns/tests/TestActiveResolveAttempts.cpp +++ b/src/lib/dnssd/minimal_mdns/tests/TestActiveResolveAttempts.cpp @@ -24,11 +24,11 @@ namespace { using namespace chip; -class MockClock : public System::ClockBase +class MockClock : public System::Clock::ClockBase { public: - MonotonicMicroseconds GetMonotonicMicroseconds() override { return mUsec; } - MonotonicMilliseconds GetMonotonicMilliseconds() override { return mUsec / 1000; } + System::Clock::Microseconds64 GetMonotonicMicroseconds64() override { return System::Clock::Microseconds64(mUsec); } + System::Clock::Milliseconds64 GetMonotonicMilliseconds64() override { return System::Clock::Milliseconds64(mUsec / 1000); } void AdvanceMs(MonotonicMilliseconds ms) { mUsec += ms * 1000L; } void AdvanceSec(uint32_t s) { AdvanceMs(s * 1000); } diff --git a/src/platform/ESP32/SystemTimeSupport.cpp b/src/platform/ESP32/SystemTimeSupport.cpp index acddd0e6d6a737..a0b1d734d1bc1e 100644 --- a/src/platform/ESP32/SystemTimeSupport.cpp +++ b/src/platform/ESP32/SystemTimeSupport.cpp @@ -32,20 +32,22 @@ namespace chip { namespace System { +namespace Clock { namespace Internal { ClockImpl gClockImpl; } // namespace Internal -Clock::MonotonicMicroseconds ClockImpl::GetMonotonicMicroseconds(void) +Microseconds64 ClockImpl::GetMonotonicMicroseconds64(void) { - return (Clock::MonotonicMicroseconds)::esp_timer_get_time(); + return Clock::Microseconds64(::esp_timer_get_time()); } -Clock::MonotonicMilliseconds GetMonotonicMilliseconds(void) +Milliseconds64 ClockImpl::GetMonotonicMilliseconds64(void) { - return (Clock::MonotonicMilliseconds)::esp_timer_get_time() / kMicrosecondsPerMillisecond; + return std::chrono::duration_cast(GetMonotonicMicroseconds64()); } +} // namespace Clock } // namespace System } // namespace chip diff --git a/src/platform/FreeRTOS/SystemTimeSupport.cpp b/src/platform/FreeRTOS/SystemTimeSupport.cpp index 80d15fb702ce70..712879ee4ef854 100644 --- a/src/platform/FreeRTOS/SystemTimeSupport.cpp +++ b/src/platform/FreeRTOS/SystemTimeSupport.cpp @@ -31,6 +31,7 @@ namespace chip { namespace System { +namespace Clock { namespace Internal { ClockImpl gClockImpl; @@ -89,15 +90,16 @@ uint64_t FreeRTOSTicksSinceBoot(void) return static_cast(timeOut.xTimeOnEntering) + (static_cast(timeOut.xOverflowCount) << kTicksOverflowShift); } -Clock::MonotonicMicroseconds ClockImpl::GetMonotonicMicroseconds(void) +Clock::Microseconds64 ClockImpl::GetMonotonicMicroseconds64(void) { - return (FreeRTOSTicksSinceBoot() * kMicrosecondsPerSecond) / configTICK_RATE_HZ; + return Clock::Microseconds64((FreeRTOSTicksSinceBoot() * kMicrosecondsPerSecond) / configTICK_RATE_HZ); } -Clock::MonotonicMilliseconds ClockImpl::GetMonotonicMilliseconds(void) +Clock::Milliseconds64 ClockImpl::GetMonotonicMilliseconds64(void) { - return (FreeRTOSTicksSinceBoot() * kMillisecondsPerSecond) / configTICK_RATE_HZ; + return Clock::Milliseconds64((FreeRTOSTicksSinceBoot() * kMillisecondsPerSecond) / configTICK_RATE_HZ); } +} // namespace Clock } // namespace System } // namespace chip diff --git a/src/platform/Linux/SystemTimeSupport.cpp b/src/platform/Linux/SystemTimeSupport.cpp index 496630a35f2179..3397bd185a0dd4 100644 --- a/src/platform/Linux/SystemTimeSupport.cpp +++ b/src/platform/Linux/SystemTimeSupport.cpp @@ -34,26 +34,22 @@ namespace chip { namespace System { +namespace Clock { namespace Internal { ClockImpl gClockImpl; } // namespace Internal -Clock::MonotonicMicroseconds ClockImpl::GetMonotonicMicroseconds() +Microseconds64 ClockImpl::GetMonotonicMicroseconds64() { - std::chrono::microseconds epoch = - std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()); - // count() is nominally signed, but for a monotonic clock it cannot be negative. - return static_cast(epoch.count()); + return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()); } -Clock::MonotonicMilliseconds ClockImpl::GetMonotonicMilliseconds() +Milliseconds64 ClockImpl::GetMonotonicMilliseconds64() { - std::chrono::milliseconds epoch = - std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()); - // count() is nominally signed, but for a monotonic clock it cannot be negative. - return static_cast(epoch.count()); + return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()); } +} // namespace Clock } // namespace System } // namespace chip diff --git a/src/platform/Zephyr/SystemTimeSupport.cpp b/src/platform/Zephyr/SystemTimeSupport.cpp index fabb7ce97ad265..0eacdb7b2ce364 100644 --- a/src/platform/Zephyr/SystemTimeSupport.cpp +++ b/src/platform/Zephyr/SystemTimeSupport.cpp @@ -32,21 +32,23 @@ namespace chip { namespace System { +namespace Clock { namespace Internal { ClockImpl gClockImpl; } // namespace Internal -Clock::MonotonicMicroseconds ClockImpl::GetMonotonicMicroseconds(void) +Microseconds64 ClockImpl::GetMonotonicMicroseconds64(void) { - return k_ticks_to_us_floor64(k_uptime_ticks()); + return Microseconds64(k_ticks_to_us_floor64(k_uptime_ticks())); } -Clock::MonotonicMilliseconds ClockImpl::GetMonotonicMilliseconds(void) +Milliseconds64 ClockImpl::GetMonotonicMilliseconds64(void) { - return k_uptime_get(); + return Milliseconds64(k_uptime_get()); } +} // namespace Clock } // namespace System } // namespace chip diff --git a/src/platform/mbed/SystemTimeSupport.cpp b/src/platform/mbed/SystemTimeSupport.cpp index 076f44cb276513..1f4311eaebf74e 100644 --- a/src/platform/mbed/SystemTimeSupport.cpp +++ b/src/platform/mbed/SystemTimeSupport.cpp @@ -37,6 +37,7 @@ namespace chip { namespace System { +namespace Clock { namespace Internal { ClockImpl gClockImpl; @@ -58,17 +59,18 @@ extern "C" uint64_t get_clock_monotonic() // Platform-specific function for getting monotonic system time in microseconds. // Returns elapsed time in microseconds since an arbitrary, platform-defined epoch. -Clock::MonotonicMicroseconds ClockImpl::GetMonotonicMicroseconds() +Microseconds64 ClockImpl::GetMonotonicMicroseconds64() { - return get_clock_monotonic(); + return Microseconds64(get_clock_monotonic()); } // Platform-specific function for getting monotonic system time in milliseconds. // Return elapsed time in milliseconds since an arbitrary, platform-defined epoch. -Clock::MonotonicMilliseconds ClockImpl::GetMonotonicMilliseconds() +Milliseconds64 ClockImpl::GetMonotonicMilliseconds64() { - return get_clock_monotonic() / kMicrosecondsPerMillisecond; + return std::chrono::duration_cast(GetMonotonicMicroseconds64()); } +} // namespace Clock } // namespace System } // namespace chip diff --git a/src/system/SystemClock.cpp b/src/system/SystemClock.cpp index 2ea39427fec423..0912bbae53f2a3 100644 --- a/src/system/SystemClock.cpp +++ b/src/system/SystemClock.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -46,6 +47,7 @@ namespace chip { namespace System { +namespace Clock { namespace Internal { @@ -80,35 +82,35 @@ ClockBase * gClockBase = &gClockImpl; #define MONOTONIC_CLOCK_ID CLOCK_MONOTONIC #endif -Clock::MonotonicMicroseconds ClockImpl::GetMonotonicMicroseconds() +Microseconds64 ClockImpl::GetMonotonicMicroseconds64() { struct timespec ts; int res = clock_gettime(MONOTONIC_CLOCK_ID, &ts); VerifyOrDie(res == 0); - return (static_cast(ts.tv_sec) * kMicrosecondsPerSecond) + - (static_cast(ts.tv_nsec) / kNanosecondsPerMicrosecond); + return Seconds64(ts.tv_sec) + + std::chrono::duration_cast(std::chrono::duration(ts.tv_nsec)); } -Clock::MonotonicMilliseconds ClockImpl::GetMonotonicMilliseconds() +Milliseconds64 ClockImpl::GetMonotonicMilliseconds64() { - return GetMonotonicMicroseconds() / kMicrosecondsPerMillisecond; + return std::chrono::duration_cast(GetMonotonicMicroseconds64()); } #endif // HAVE_CLOCK_GETTIME #if HAVE_GETTIMEOFDAY -Clock::MonotonicMicroseconds ClockImpl::GetMonotonicMicroseconds() +Microseconds64 ClockImpl::GetMonotonicMicroseconds64() { struct timeval tv; int res = gettimeofday(&tv, NULL); VerifyOrDie(res == 0); - return (tv.tv_sec * kMicrosecondsPerSecond) + tv.tv_usec; + return TimevalToMicroseconds(tv); } -Clock::MonotonicMilliseconds ClockImpl::GetMonotonicMilliseconds() +Milliseconds64 ClockImpl::GetMonotonicMilliseconds64() { - return GetMonotonicMicroseconds() / kMicrosecondsPerMillisecond; + return std::chrono::duration_cast(GetMonotonicMicroseconds64()); } #endif // HAVE_GETTIMEOFDAY @@ -119,12 +121,12 @@ Clock::MonotonicMilliseconds ClockImpl::GetMonotonicMilliseconds() // -------------------- Default Get/SetClock Functions for LwIP Systems -------------------- -Clock::MonotonicMilliseconds ClockImpl::GetMonotonicMicroseconds(void) +Microseconds64 ClockImpl::GetMonotonicMicroseconds64(void) { - return GetMonotonicMilliseconds() * kMicrosecondsPerMillisecond; + return GetMonotonicMilliseconds64(); } -Clock::MonotonicMilliseconds ClockImpl::GetMonotonicMilliseconds(void) +Milliseconds64 ClockImpl::GetMonotonicMilliseconds64(void) { static volatile uint64_t overflow = 0; static volatile u32_t lastSample = 0; @@ -161,15 +163,13 @@ Clock::MonotonicMilliseconds ClockImpl::GetMonotonicMilliseconds(void) sample = sys_now(); } - return static_cast(overflowSample | static_cast(sample)); + return Milliseconds64(overflowSample | static_cast(sample)); } #endif // CHIP_SYSTEM_CONFIG_USE_LWIP_MONOTONIC_TIME #endif // CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME -namespace Clock { - static_assert(std::is_unsigned::value, "ClockBase::Tick must be unsigned"); constexpr ClockBase::Tick kMaxTick = static_cast(0) - static_cast(1); constexpr ClockBase::Tick kHalfMaxTick = static_cast(kMaxTick / 2); @@ -190,13 +190,17 @@ ClockBase::Tick AddOffset(const ClockBase::Tick & base, const ClockBase::Tick & #if CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_SOCKETS -Clock::MonotonicMilliseconds TimevalToMilliseconds(const timeval & in) +Microseconds64 TimevalToMicroseconds(const timeval & tv) { - return static_cast(in.tv_sec) * 1000 + - static_cast(in.tv_usec / 1000); + return Seconds64(tv.tv_sec) + Microseconds64(tv.tv_usec); } -void MillisecondsToTimeval(Clock::MonotonicMilliseconds in, timeval & out) +MonotonicMilliseconds TimevalToMilliseconds(const timeval & in) +{ + return static_cast(in.tv_sec) * 1000 + static_cast(in.tv_usec / 1000); +} + +void MillisecondsToTimeval(MonotonicMilliseconds in, timeval & out) { out.tv_sec = static_cast(in / 1000); out.tv_usec = static_cast((in % 1000) * 1000); @@ -204,6 +208,22 @@ void MillisecondsToTimeval(Clock::MonotonicMilliseconds in, timeval & out) #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_SOCKETS +static_assert(std::numeric_limits::is_integer, "Microseconds64 must be an integer type"); +static_assert(std::numeric_limits::is_integer, "Microseconds32 must be an integer type"); +static_assert(std::numeric_limits::is_integer, "Milliseconds64 must be an integer type"); +static_assert(std::numeric_limits::is_integer, "Milliseconds32 must be an integer type"); +static_assert(std::numeric_limits::is_integer, "Seconds64 must be an integer type"); +static_assert(std::numeric_limits::is_integer, "Seconds32 must be an integer type"); +static_assert(std::numeric_limits::is_integer, "Seconds16 must be an integer type"); + +static_assert(std::numeric_limits::digits >= 64, "Microseconds64 must be at least 64 bits"); +static_assert(std::numeric_limits::digits >= 32, "Microseconds32 must be at least 32 bits"); +static_assert(std::numeric_limits::digits >= 64, "Milliseconds64 must be at least 64 bits"); +static_assert(std::numeric_limits::digits >= 32, "Milliseconds32 must be at least 32 bits"); +static_assert(std::numeric_limits::digits >= 64, "Seconds64 must be at least 64 bits"); +static_assert(std::numeric_limits::digits >= 32, "Seconds32 must be at least 32 bits"); +static_assert(std::numeric_limits::digits >= 16, "Seconds16 must be at least 16 bits"); + } // namespace Clock } // namespace System } // namespace chip diff --git a/src/system/SystemClock.h b/src/system/SystemClock.h index f9c12bf5e371de..d918dad3e86fed 100644 --- a/src/system/SystemClock.h +++ b/src/system/SystemClock.h @@ -36,52 +36,164 @@ #include #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_SOCKETS +#include #include namespace chip { namespace System { +namespace Clock { + +/* + * We use `std::chrono::duration` for clock types to provide type safety. But unlike the predefined std types + * (`std::chrono::milliseconds` et al), CHIP uses unsigned base types, and types are explicity sized, with + * smaller-size types available for members and arguments where appropriate. + * + * Most conversions are handled by the types transparently. To convert with possible loss of information, use + * `std::chrono::duration_cast<>()`. + */ + +using Microseconds64 = std::chrono::duration; +using Microseconds32 = std::chrono::duration; + +using Milliseconds64 = std::chrono::duration; +using Milliseconds32 = std::chrono::duration; + +using Seconds64 = std::chrono::duration; +using Seconds32 = std::chrono::duration; +using Seconds16 = std::chrono::duration; + +constexpr Seconds16 Zero{ 0 }; + +namespace Literals { + +constexpr Microseconds64 operator""_us(unsigned long long int us) +{ + return Microseconds64(us); +} +constexpr Microseconds64 operator""_us64(unsigned long long int us) +{ + return Microseconds64(us); +} +constexpr Microseconds32 operator""_us32(unsigned long long int us) +{ + return Microseconds32(us); +} + +constexpr Milliseconds64 operator""_ms(unsigned long long int ms) +{ + return Milliseconds64(ms); +} +constexpr Milliseconds64 operator""_ms64(unsigned long long int ms) +{ + return Milliseconds64(ms); +} +constexpr Milliseconds32 operator""_ms32(unsigned long long int ms) +{ + return Milliseconds32(ms); +} + +constexpr Seconds64 operator""_s(unsigned long long int s) +{ + return Seconds64(s); +} +constexpr Seconds64 operator""_s64(unsigned long long int s) +{ + return Seconds64(s); +} +constexpr Seconds32 operator""_s32(unsigned long long int s) +{ + return Seconds32(s); +} +constexpr Seconds16 operator""_s16(unsigned long long int s) +{ + return Seconds16(s); +} + +} // namespace Literals + +/** + * Type for System time stamps. + */ +using Timestamp = Milliseconds64; + +/** + * Type for System time offsets (i.e. `StartTime()` duration). + * + * It is required of platforms that time stamps from `GetMonotonic…()` have the high bit(s) zero, + * so the sum of a `Milliseconds64` time stamp and `Milliseconds32` offset will never overflow. + */ +using Timeout = Milliseconds32; + class ClockBase { public: + // Backwards compatibility types; avoid using in new code. These only provide documentation, not type safety. using Tick = uint64_t; static_assert(std::is_unsigned::value, "Tick must be unsigned"); - - // Note: these provide documentation, not type safety. using MonotonicMicroseconds = Tick; using MonotonicMilliseconds = Tick; virtual ~ClockBase() = default; + /** + * Returns a monotonic system time. + * + * This function returns an elapsed time since an arbitrary, platform-defined epoch. + * The value returned is guaranteed to be ever-increasing (i.e. never wrapping or decreasing) between + * reboots of the system. Additionally, the underlying time source is guaranteed to tick + * continuously during any system sleep modes that do not entail a restart upon wake. + * + * Although some platforms may choose to return a value that measures the time since boot for the + * system, applications must *not* rely on this. + */ + Timestamp GetMonotonicTimestamp() { return GetMonotonicMilliseconds64(); } + /** * Returns a monotonic system time in units of microseconds. * - * This function returns an elapsed time in microseconds since an arbitrary, platform-defined - * epoch. The value returned is guaranteed to be ever-increasing (i.e. never wrapping) between + * This function returns an elapsed time in microseconds since an arbitrary, platform-defined epoch. + * The value returned is guaranteed to be ever-increasing (i.e. never wrapping or decreasing) between * reboots of the system. Additionally, the underlying time source is guaranteed to tick * continuously during any system sleep modes that do not entail a restart upon wake. * * Although some platforms may choose to return a value that measures the time since boot for the * system, applications must *not* rely on this. * + * Applications must not rely on the time returned by GetMonotonicMicroseconds64() actually having + * granularity finer than milliseconds. + * + * Platform implementations *must* use the same epoch for GetMonotonicMicroseconds64() and GetMonotonicMilliseconds64(). + * + * Platforms *must* use an epoch such that the upper bit of a value returned by GetMonotonicMicroseconds64() is zero + * for the expected operational life of the system. + * * @returns Elapsed time in microseconds since an arbitrary, platform-defined epoch. */ - virtual MonotonicMicroseconds GetMonotonicMicroseconds() = 0; + virtual Microseconds64 GetMonotonicMicroseconds64() = 0; /** * Returns a monotonic system time in units of milliseconds. * - * This function returns an elapsed time in milliseconds since an arbitrary, platform-defined - * epoch. The value returned is guaranteed to be ever-increasing (i.e. never wrapping) between + * This function returns an elapsed time in milliseconds since an arbitrary, platform-defined epoch. + * The value returned is guaranteed to be ever-increasing (i.e. never wrapping or decreasing) between * reboots of the system. Additionally, the underlying time source is guaranteed to tick * continuously during any system sleep modes that do not entail a restart upon wake. * * Although some platforms may choose to return a value that measures the time since boot for the * system, applications must *not* rely on this. * + * Platform implementations *must* use the same epoch for GetMonotonicMicroseconds64() and GetMonotonicMilliseconds64(). + * (As a consequence of this, and the requirement for GetMonotonicMicroseconds64() to return high bit zero, values + * returned by GetMonotonicMilliseconds64() will have the high ten bits zero.) + * * @returns Elapsed time in milliseconds since an arbitrary, platform-defined epoch. */ - virtual MonotonicMilliseconds GetMonotonicMilliseconds() = 0; + virtual Milliseconds64 GetMonotonicMilliseconds64() = 0; + + // Backwards compatibility methods; avoid using in new code. These only provide documentation, not type safety. + MonotonicMicroseconds GetMonotonicMicroseconds() { return GetMonotonicMicroseconds64().count(); } + MonotonicMilliseconds GetMonotonicMilliseconds() { return GetMonotonicMilliseconds64().count(); } }; // Currently we have a single implementation class, ClockImpl, whose members are implemented in build-specific files. @@ -89,28 +201,25 @@ class ClockImpl : public ClockBase { public: ~ClockImpl() = default; - MonotonicMicroseconds GetMonotonicMicroseconds() override; - MonotonicMilliseconds GetMonotonicMilliseconds() override; + Microseconds64 GetMonotonicMicroseconds64() override; + Milliseconds64 GetMonotonicMilliseconds64() override; }; namespace Internal { + // This should only be used via SystemClock() below. extern ClockBase * gClockBase; -} // namespace Internal -inline ClockBase & SystemClock() +inline void SetSystemClockForTesting(Clock::ClockBase * clock) { - return *Internal::gClockBase; + Clock::Internal::gClockBase = clock; } -inline void SetSystemClockForTesting(System::ClockBase * clock) -{ - Internal::gClockBase = clock; -} +} // namespace Internal -namespace Clock { +// Backwards compatibility types; avoid using in new code. These only provide documentation, not type safety. using MonotonicMicroseconds = ClockBase::MonotonicMicroseconds; -using MonotonicMilliseconds = ClockBase::MonotonicMicroseconds; +using MonotonicMilliseconds = ClockBase::MonotonicMilliseconds; /** * Compares two time values and returns true if the first value is earlier than the second value. @@ -132,11 +241,17 @@ bool IsEarlier(const ClockBase::Tick & first, const ClockBase::Tick & second); ClockBase::Tick AddOffset(const ClockBase::Tick & base, const ClockBase::Tick & offset); #if CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_SOCKETS -Clock::MonotonicMilliseconds TimevalToMilliseconds(const timeval & in); -void MillisecondsToTimeval(Clock::MonotonicMilliseconds in, timeval & out); +Microseconds64 TimevalToMicroseconds(const timeval & in); +MonotonicMilliseconds TimevalToMilliseconds(const timeval & in); +void MillisecondsToTimeval(MonotonicMilliseconds in, timeval & out); #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_SOCKETS } // namespace Clock +inline Clock::ClockBase & SystemClock() +{ + return *Clock::Internal::gClockBase; +} + } // namespace System } // namespace chip diff --git a/src/system/tests/TestSystemClock.cpp b/src/system/tests/TestSystemClock.cpp index c8bf0e74b9bf6f..8eb96de9b745ad 100644 --- a/src/system/tests/TestSystemClock.cpp +++ b/src/system/tests/TestSystemClock.cpp @@ -47,14 +47,17 @@ namespace { void TestRealClock(nlTestSuite * inSuite, void * inContext) { - Clock::MonotonicMilliseconds oldMilli = SystemClock().GetMonotonicMilliseconds(); - Clock::MonotonicMilliseconds newMilli = SystemClock().GetMonotonicMilliseconds(); + Clock::Milliseconds64 oldMilli = SystemClock().GetMonotonicMilliseconds64(); + Clock::Milliseconds64 newMilli = SystemClock().GetMonotonicMilliseconds64(); NL_TEST_ASSERT(inSuite, newMilli >= oldMilli); - Clock::MonotonicMicroseconds oldMicro = SystemClock().GetMonotonicMicroseconds(); - Clock::MonotonicMicroseconds newMicro = SystemClock().GetMonotonicMicroseconds(); + Clock::Microseconds64 oldMicro = SystemClock().GetMonotonicMicroseconds64(); + Clock::Microseconds64 newMicro = SystemClock().GetMonotonicMicroseconds64(); NL_TEST_ASSERT(inSuite, newMicro >= oldMicro); + Clock::Microseconds64::rep microseconds = newMicro.count(); + NL_TEST_ASSERT(inSuite, (microseconds & 0x8000'0000'0000'0000) == 0); + #if !CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME && \ (CHIP_SYSTEM_CONFIG_USE_LWIP_MONOTONIC_TIME || CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS) constexpr int kDelayMilliseconds = 3; @@ -70,10 +73,10 @@ void TestRealClock(nlTestSuite * inSuite, void * inContext) } #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS - newMilli = SystemClock().GetMonotonicMilliseconds(); + newMilli = SystemClock().GetMonotonicMilliseconds64(); NL_TEST_ASSERT(inSuite, newMilli > oldMilli); - newMicro = SystemClock().GetMonotonicMicroseconds(); + newMicro = SystemClock().GetMonotonicMicroseconds64(); NL_TEST_ASSERT(inSuite, newMicro > oldMicro); #endif // !CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME && (CHIP_SYSTEM_CONFIG_USE_LWIP_MONOTONIC_TIME || @@ -82,26 +85,27 @@ void TestRealClock(nlTestSuite * inSuite, void * inContext) void TestMockClock(nlTestSuite * inSuite, void * inContext) { - class MockClock : public ClockBase + class MockClock : public Clock::ClockBase { public: - MonotonicMicroseconds GetMonotonicMicroseconds() override { return mTime * chip::kMicrosecondsPerMillisecond; } - MonotonicMilliseconds GetMonotonicMilliseconds() override { return mTime; } - MonotonicMilliseconds mTime = 0; + Clock::Microseconds64 GetMonotonicMicroseconds64() override { return mTime; } + Clock::Milliseconds64 GetMonotonicMilliseconds64() override { return mTime; } + Clock::Milliseconds64 mTime{ 0 }; }; MockClock clock; - ClockBase * savedRealClock = &SystemClock(); - SetSystemClockForTesting(&clock); + Clock::ClockBase * savedRealClock = &SystemClock(); + Clock::Internal::SetSystemClockForTesting(&clock); - NL_TEST_ASSERT(inSuite, SystemClock().GetMonotonicMilliseconds() == 0); - NL_TEST_ASSERT(inSuite, SystemClock().GetMonotonicMicroseconds() == 0); + NL_TEST_ASSERT(inSuite, SystemClock().GetMonotonicMilliseconds64() == Clock::Zero); + NL_TEST_ASSERT(inSuite, SystemClock().GetMonotonicMicroseconds64() == Clock::Zero); - clock.mTime = 1234; - NL_TEST_ASSERT(inSuite, SystemClock().GetMonotonicMilliseconds() == 1234); - NL_TEST_ASSERT(inSuite, SystemClock().GetMonotonicMicroseconds() == 1234 * chip::kMicrosecondsPerMillisecond); + constexpr Clock::Milliseconds64 k1234{ 1234 }; + clock.mTime = k1234; + NL_TEST_ASSERT(inSuite, SystemClock().GetMonotonicMilliseconds64() == k1234); + NL_TEST_ASSERT(inSuite, SystemClock().GetMonotonicMicroseconds64() == k1234); - SetSystemClockForTesting(savedRealClock); + Clock::Internal::SetSystemClockForTesting(savedRealClock); } } // namespace