LCOV - code coverage report
Current view: top level - system - SystemClock.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 6 8 75.0 %
Date: 2024-02-15 08:20:41 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020 Project CHIP Authors
       4             :  *    Copyright (c) 2018 Nest Labs, Inc.
       5             :  *
       6             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7             :  *    you may not use this file except in compliance with the License.
       8             :  *    You may obtain a copy of the License at
       9             :  *
      10             :  *        http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  *    Unless required by applicable law or agreed to in writing, software
      13             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  *    See the License for the specific language governing permissions and
      16             :  *    limitations under the License.
      17             :  */
      18             : 
      19             : /**
      20             :  *    @file
      21             :  *      This is an internal header file that defines the interface to a platform-supplied
      22             :  *      function for retrieving the current system time.
      23             :  */
      24             : 
      25             : #pragma once
      26             : 
      27             : // Include configuration headers
      28             : #include <system/SystemConfig.h>
      29             : 
      30             : // Include dependent headers
      31             : #include <lib/support/DLLUtil.h>
      32             : #include <lib/support/TimeUtils.h>
      33             : #include <system/SystemError.h>
      34             : 
      35             : #if CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS
      36             : #include <sys/time.h>
      37             : #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS
      38             : 
      39             : #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKETS
      40             : #include <zephyr/net/socket.h>
      41             : #endif
      42             : 
      43             : #include <chrono>
      44             : #include <stdint.h>
      45             : 
      46             : #if CHIP_DEVICE_LAYER_TARGET_DARWIN || CHIP_DEVICE_LAYER_TARGET_LINUX
      47             : #define CHIP_DEVICE_LAYER_USE_ATOMICS_FOR_CLOCK 1
      48             : #endif // CHIP_DEVICE_LAYER_TARGET_DARWIN || CHIP_DEVICE_LAYER_TARGET_LINUX
      49             : 
      50             : #ifndef CHIP_DEVICE_LAYER_USE_ATOMICS_FOR_CLOCK
      51             : #define CHIP_DEVICE_LAYER_USE_ATOMICS_FOR_CLOCK 0
      52             : #endif
      53             : 
      54             : namespace chip {
      55             : namespace System {
      56             : 
      57             : namespace Clock {
      58             : 
      59             : /*
      60             :  * We use `std::chrono::duration` for clock types to provide type safety. But unlike the predefined std types
      61             :  * (`std::chrono::milliseconds` et al), CHIP uses unsigned base types, and types are explicity sized, with
      62             :  * smaller-size types available for members and arguments where appropriate.
      63             :  *
      64             :  * Most conversions are handled by the types transparently. To convert with possible loss of information, use
      65             :  * `std::chrono::duration_cast<>()`.
      66             :  */
      67             : 
      68             : using Microseconds64 = std::chrono::duration<uint64_t, std::micro>;
      69             : using Microseconds32 = std::chrono::duration<uint32_t, std::micro>;
      70             : 
      71             : using Milliseconds64 = std::chrono::duration<uint64_t, std::milli>;
      72             : using Milliseconds32 = std::chrono::duration<uint32_t, std::milli>;
      73             : using Milliseconds16 = std::chrono::duration<uint16_t, std::milli>;
      74             : 
      75             : using Seconds64 = std::chrono::duration<uint64_t>;
      76             : using Seconds32 = std::chrono::duration<uint32_t>;
      77             : using Seconds16 = std::chrono::duration<uint16_t>;
      78             : 
      79             : inline constexpr Seconds16 kZero{ 0 };
      80             : 
      81             : namespace Literals {
      82             : 
      83             : constexpr Microseconds64 operator""_us(unsigned long long int us)
      84             : {
      85             :     return Microseconds64(us);
      86             : }
      87             : constexpr Microseconds64 operator""_us64(unsigned long long int us)
      88             : {
      89             :     return Microseconds64(us);
      90             : }
      91             : constexpr Microseconds32 operator""_us32(unsigned long long int us)
      92             : {
      93             :     return Microseconds32(us);
      94             : }
      95             : 
      96       41183 : constexpr Milliseconds64 operator""_ms(unsigned long long int ms)
      97             : {
      98       41183 :     return Milliseconds64(ms);
      99             : }
     100             : constexpr Milliseconds64 operator""_ms64(unsigned long long int ms)
     101             : {
     102             :     return Milliseconds64(ms);
     103             : }
     104       10813 : constexpr Milliseconds32 operator""_ms32(unsigned long long int ms)
     105             : {
     106       10813 :     return Milliseconds32(ms);
     107             : }
     108             : constexpr Milliseconds16 operator""_ms16(unsigned long long int ms)
     109             : {
     110             :     return Milliseconds16(ms);
     111             : }
     112             : 
     113             : constexpr Seconds64 operator""_s(unsigned long long int s)
     114             : {
     115             :     return Seconds64(s);
     116             : }
     117             : constexpr Seconds64 operator""_s64(unsigned long long int s)
     118             : {
     119             :     return Seconds64(s);
     120             : }
     121             : constexpr Seconds32 operator""_s32(unsigned long long int s)
     122             : {
     123             :     return Seconds32(s);
     124             : }
     125           0 : constexpr Seconds16 operator""_s16(unsigned long long int s)
     126             : {
     127           0 :     return Seconds16(s);
     128             : }
     129             : 
     130             : } // namespace Literals
     131             : 
     132             : /**
     133             :  * Type for System time stamps.
     134             :  */
     135             : using Timestamp = Milliseconds64;
     136             : 
     137             : /**
     138             :  * Type for System time offsets (i.e. `StartTime()` duration).
     139             :  *
     140             :  * It is required of platforms that time stamps from `GetMonotonic…()` have the high bit(s) zero,
     141             :  * so the sum of a `Milliseconds64` time stamp and `Milliseconds32` offset will never overflow.
     142             :  */
     143             : using Timeout = Milliseconds32;
     144             : 
     145             : class ClockBase
     146             : {
     147             : public:
     148             :     virtual ~ClockBase() = default;
     149             : 
     150             :     /**
     151             :      * Returns a monotonic system time.
     152             :      *
     153             :      * This function returns an elapsed time since an arbitrary, platform-defined epoch.
     154             :      * The value returned is guaranteed to be ever-increasing (i.e. never wrapping or decreasing) between
     155             :      * reboots of the system.  Additionally, the underlying time source is guaranteed to tick
     156             :      * continuously during any system sleep modes that do not entail a restart upon wake.
     157             :      *
     158             :      * Although some platforms may choose to return a value that measures the time since boot for the
     159             :      * system, applications must *not* rely on this.
     160             :      *
     161             :      * WARNING: *** It is up to each platform to ensure that GetMonotonicTimestamp can be
     162             :      *              called safely in a re-entrant way from multiple contexts if making use
     163             :      *              of this method from the application, outside the Matter stack execution
     164             :      *              serialization context. ***
     165             :      */
     166             :     virtual Timestamp GetMonotonicTimestamp();
     167             : 
     168             :     /**
     169             :      * Returns a monotonic system time in units of microseconds, from the platform.
     170             :      *
     171             :      * This function returns an elapsed time in microseconds since an arbitrary, platform-defined epoch.
     172             :      * The value returned MUST BE guaranteed to be ever-increasing (i.e. never wrapping or decreasing) until
     173             :      * reboot of the system.  Additionally, the underlying time source is guaranteed to tick
     174             :      * continuously during any system sleep modes that do not entail a restart upon wake.
     175             :      *
     176             :      * Although some platforms may choose to return a value that measures the time since boot for the
     177             :      * system, applications must *not* rely on this.
     178             :      *
     179             :      * Applications must not rely on the time returned by GetMonotonicMicroseconds64() actually having
     180             :      * granularity finer than milliseconds.
     181             :      *
     182             :      * Platform implementations *must* use the same epoch for GetMonotonicMicroseconds64() and GetMonotonicMilliseconds64().
     183             :      *
     184             :      * Platforms *must* use an epoch such that the upper bit of a value returned by GetMonotonicMicroseconds64() is zero
     185             :      * for the expected operational life of the system.
     186             :      *
     187             :      * @returns Elapsed time in microseconds since an arbitrary, platform-defined epoch.
     188             :      */
     189             :     virtual Microseconds64 GetMonotonicMicroseconds64() = 0;
     190             : 
     191             :     /**
     192             :      * Returns a monotonic system time in units of microseconds, from the platform.
     193             :      *
     194             :      * This function returns an elapsed time in milliseconds since an arbitrary, platform-defined epoch.
     195             :      * The value returned MUST BE guaranteed to be ever-increasing (i.e. never wrapping or decreasing) until
     196             :      * reboot of the system.  Additionally, the underlying time source is guaranteed to tick
     197             :      * continuously during any system sleep modes that do not entail a restart upon wake.
     198             :      *
     199             :      * Although some platforms may choose to return a value that measures the time since boot for the
     200             :      * system, applications must *not* rely on this.
     201             :      *
     202             :      * Platform implementations *must* use the same epoch for GetMonotonicMicroseconds64() and GetMonotonicMilliseconds64().
     203             :      * (As a consequence of this, and the requirement for GetMonotonicMicroseconds64() to return high bit zero, values
     204             :      * returned by GetMonotonicMilliseconds64() will have the high ten bits zero.)
     205             :      *
     206             :      * @returns             Elapsed time in milliseconds since an arbitrary, platform-defined epoch.
     207             :      */
     208             :     virtual Milliseconds64 GetMonotonicMilliseconds64() = 0;
     209             : 
     210             :     /**
     211             :      * @brief
     212             :      *   Platform-specific function for getting the current real (civil) time in microsecond Unix time
     213             :      *   format.
     214             :      *
     215             :      * This function is expected to return the local platform's notion of current real time, expressed
     216             :      * as a Unix time value scaled to microseconds.  The underlying clock is required to tick at a
     217             :      * rate of least at whole seconds (values of 1,000,000), but may tick faster.
     218             :      *
     219             :      * On those platforms that are capable of tracking real time, GetClock_RealTime() must return the
     220             :      * error CHIP_ERROR_REAL_TIME_NOT_SYNCED whenever the system is unsynchronized with real time.
     221             :      *
     222             :      * Platforms that are incapable of tracking real time should not implement the GetClock_RealTime()
     223             :      * function, thereby forcing link-time failures of features that depend on access to real time.
     224             :      * Alternatively, such platforms may supply an implementation of GetClock_RealTime() that returns
     225             :      * the error CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE.
     226             :      *
     227             :      * This function is expected to be thread-safe on any platform that employs threading.
     228             :      *
     229             :      * @note
     230             :      *   This function is reserved for internal use by the System Clock.  Users of the System
     231             :      *   Clock should call System::Clock::GetClock_RealTime().
     232             :      *
     233             :      * @param[out] aCurTime                  The current time, expressed as Unix time scaled to microseconds.
     234             :      *
     235             :      * @retval #CHIP_NO_ERROR       If the method succeeded.
     236             :      * @retval #CHIP_ERROR_REAL_TIME_NOT_SYNCED
     237             :      *                                      If the platform is capable of tracking real time, but is
     238             :      *                                      is currently unsynchronized.
     239             :      * @retval #CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE
     240             :      *                                      If the platform is incapable of tracking real time.
     241             :      */
     242             :     virtual CHIP_ERROR GetClock_RealTime(Microseconds64 & aCurTime) = 0;
     243             : 
     244             :     /**
     245             :      * @brief
     246             :      *   Platform-specific function for getting the current real (civil) time in millisecond Unix time
     247             :      *   format.
     248             :      *
     249             :      * This function is expected to return the local platform's notion of current real time, expressed
     250             :      * as a Unix time value scaled to milliseconds.
     251             :      *
     252             :      * See the documentation for GetClock_RealTime() for details on the expected behavior.
     253             :      *
     254             :      * @note
     255             :      *   This function is reserved for internal use by the System Clock.  Users of the System
     256             :      *   Clock should call System::Clock::GetClock_RealTimeMS().
     257             :      *
     258             :      * @param[out] aCurTime                  The current time, expressed as Unix time scaled to milliseconds.
     259             :      *
     260             :      * @retval #CHIP_NO_ERROR       If the method succeeded.
     261             :      * @retval #CHIP_ERROR_REAL_TIME_NOT_SYNCED
     262             :      *                                      If the platform is capable of tracking real time, but is
     263             :      *                                      is currently unsynchronized.
     264             :      * @retval #CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE
     265             :      *                                      If the platform is incapable of tracking real time.
     266             :      */
     267             :     virtual CHIP_ERROR GetClock_RealTimeMS(Milliseconds64 & aCurTime) = 0;
     268             : 
     269             :     /**
     270             :      * @brief
     271             :      *   Platform-specific function for setting the current real (civil) time.
     272             :      *
     273             :      * This function set the local platform's notion of current real time.  The new current
     274             :      * time is expressed as a Unix time value scaled to microseconds.
     275             :      *
     276             :      * Once set, underlying platform clock is expected to track real time with a granularity of at least whole
     277             :      * seconds.
     278             :      *
     279             :      * On platforms that support tracking real time, the SetClock_RealTime() function must return the error
     280             :      * CHIP_ERROR_ACCESS_DENIED if the calling application does not have the privilege to set the
     281             :      * current time.
     282             :      *
     283             :      * Platforms that are incapable of tracking real time, or do not offer the ability to set real time,
     284             :      * should not implement the SetClock_RealTime() function, thereby forcing link-time failures of features
     285             :      * that depend on setting real time.  Alternatively, such platforms may supply an implementation of
     286             :      * SetClock_RealTime() that returns the error CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE.
     287             :      *
     288             :      * This function is expected to be thread-safe on any platform that employs threading.
     289             :      *
     290             :      * @note
     291             :      *   This function is reserved for internal use by the System Clock.  Users of the System
     292             :      *   Clock should call System::Clock::GetClock_RealTimeMS().
     293             :      *
     294             :      * @param[in] aNewCurTime                The new current time, expressed as Unix time scaled to microseconds.
     295             :      *
     296             :      * @retval #CHIP_NO_ERROR       If the method succeeded.
     297             :      * @retval #CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE
     298             :      *                                      If the platform is incapable of tracking real time.
     299             :      * @retval #CHIP_ERROR_ACCESS_DENIED
     300             :      *                                      If the calling application does not have the privilege to set the
     301             :      *                                      current time.
     302             :      */
     303             :     virtual CHIP_ERROR SetClock_RealTime(Microseconds64 aNewCurTime) = 0;
     304             : 
     305             : protected:
     306             :     uint64_t mLastTimestamp = 0;
     307             : };
     308             : 
     309             : // Currently we have a single implementation class, ClockImpl, whose members are implemented in build-specific files.
     310             : class ClockImpl : public ClockBase
     311             : {
     312             : public:
     313             :     ~ClockImpl() override = default;
     314             :     Microseconds64 GetMonotonicMicroseconds64() override;
     315             :     Milliseconds64 GetMonotonicMilliseconds64() override;
     316             :     CHIP_ERROR GetClock_RealTime(Microseconds64 & aCurTime) override;
     317             :     CHIP_ERROR GetClock_RealTimeMS(Milliseconds64 & aCurTime) override;
     318             :     CHIP_ERROR SetClock_RealTime(Microseconds64 aNewCurTime) override;
     319             : };
     320             : 
     321             : namespace Internal {
     322             : 
     323             : // This should only be used via SystemClock() below.
     324             : extern ClockBase * gClockBase;
     325             : 
     326             : inline void SetSystemClockForTesting(Clock::ClockBase * clock)
     327             : {
     328             :     Clock::Internal::gClockBase = clock;
     329             : }
     330             : 
     331             : // Provide a mock implementation for use by unit tests.
     332             : class MockClock : public ClockImpl
     333             : {
     334             : public:
     335             :     Microseconds64 GetMonotonicMicroseconds64() override { return mSystemTime; }
     336             :     Milliseconds64 GetMonotonicMilliseconds64() override { return std::chrono::duration_cast<Milliseconds64>(mSystemTime); }
     337             :     CHIP_ERROR GetClock_RealTime(Microseconds64 & aCurTime) override
     338             :     {
     339             :         aCurTime = mRealTime;
     340             :         return CHIP_NO_ERROR;
     341             :     }
     342             :     CHIP_ERROR GetClock_RealTimeMS(Milliseconds64 & aCurTime) override
     343             :     {
     344             :         aCurTime = std::chrono::duration_cast<Milliseconds64>(mRealTime);
     345             :         return CHIP_NO_ERROR;
     346             :     }
     347             :     CHIP_ERROR SetClock_RealTime(Microseconds64 aNewCurTime) override
     348             :     {
     349             :         mRealTime = aNewCurTime;
     350             :         return CHIP_NO_ERROR;
     351             :     }
     352             : 
     353             :     void SetMonotonic(Milliseconds64 timestamp)
     354             :     {
     355             :         mSystemTime = timestamp;
     356             : #if CHIP_DEVICE_LAYER_USE_ATOMICS_FOR_CLOCK
     357             :         __atomic_store_n(&mLastTimestamp, timestamp.count(), __ATOMIC_SEQ_CST);
     358             : #endif // CHIP_DEVICE_LAYER_USE_ATOMICS_FOR_CLOCK
     359             :     }
     360             : 
     361             :     void AdvanceMonotonic(Milliseconds64 increment) { mSystemTime += increment; }
     362             :     void AdvanceRealTime(Milliseconds64 increment) { mRealTime += increment; }
     363             : 
     364             :     Microseconds64 mSystemTime = Clock::kZero;
     365             :     Microseconds64 mRealTime   = Clock::kZero;
     366             : };
     367             : 
     368             : } // namespace Internal
     369             : 
     370             : #if CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_SOCKETS
     371             : Microseconds64 TimevalToMicroseconds(const timeval & in);
     372             : void ToTimeval(Microseconds64 in, timeval & out);
     373             : #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_SOCKETS
     374             : 
     375             : } // namespace Clock
     376             : 
     377         772 : inline Clock::ClockBase & SystemClock()
     378             : {
     379         772 :     return *Clock::Internal::gClockBase;
     380             : }
     381             : 
     382             : } // namespace System
     383             : } // namespace chip

Generated by: LCOV version 1.14