LCOV - code coverage report
Current view: top level - system - SystemClock.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 13 15 86.7 %
Date: 2024-02-15 08:20:41 Functions: 2 3 66.7 %

          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             :  *      Provides default implementations for the platform Get/SetClock_ functions
      22             :  *      for POSIX and LwIP platforms.
      23             :  */
      24             : 
      25             : #include <system/SystemClock.h>
      26             : 
      27             : #include <lib/support/CodeUtils.h>
      28             : #include <lib/support/TimeUtils.h>
      29             : #include <system/SystemError.h>
      30             : 
      31             : #include <limits>
      32             : #include <stdint.h>
      33             : #include <stdlib.h>
      34             : 
      35             : #if !CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME
      36             : 
      37             : #if CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_SOCKETS
      38             : #include <errno.h>
      39             : #include <time.h>
      40             : #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_SOCKETS
      41             : 
      42             : #if CHIP_SYSTEM_CONFIG_USE_LWIP
      43             : #include <lwip/sys.h>
      44             : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
      45             : 
      46             : #endif // !CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME
      47             : 
      48             : namespace chip {
      49             : namespace System {
      50             : namespace Clock {
      51             : 
      52             : namespace Internal {
      53             : 
      54             : #if CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME
      55             : extern ClockImpl gClockImpl;
      56             : #else  // CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME
      57             : ClockImpl gClockImpl;
      58             : #endif // CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME
      59             : 
      60             : ClockBase * gClockBase = &gClockImpl;
      61             : 
      62             : } // namespace Internal
      63             : 
      64    16760594 : Timestamp ClockBase::GetMonotonicTimestamp()
      65             : {
      66             :     // Below implementation uses `__atomic_*` API which has wider support than
      67             :     // <atomic> on embedded platforms, so that embedded platforms can use
      68             :     // it by widening the #ifdefs later.
      69             : #if CHIP_DEVICE_LAYER_USE_ATOMICS_FOR_CLOCK
      70    16760594 :     uint64_t prevTimestamp = __atomic_load_n(&mLastTimestamp, __ATOMIC_SEQ_CST);
      71             :     static_assert(sizeof(prevTimestamp) == sizeof(Timestamp), "Must have scalar match between timestamp and uint64_t for atomics.");
      72             : 
      73             :     // Force a reorder barrier to prevent GetMonotonicMilliseconds64() from being
      74             :     // optimizer-called before prevTimestamp loading, so that newTimestamp acquisition happens-after
      75             :     // the prevTimestamp load.
      76    16760594 :     __atomic_signal_fence(__ATOMIC_SEQ_CST);
      77             : #else
      78             :     uint64_t prevTimestamp = mLastTimestamp;
      79             : #endif // CHIP_DEVICE_LAYER_USE_ATOMICS_FOR_CLOCK
      80             : 
      81    16760594 :     Timestamp newTimestamp = GetMonotonicMilliseconds64();
      82             : 
      83             :     // Need to guarantee the invariant that monotonic clock never goes backwards, which would break multiple system
      84             :     // assumptions which use these clocks.
      85    16760594 :     VerifyOrDie(newTimestamp.count() >= prevTimestamp);
      86             : 
      87             : #if CHIP_DEVICE_LAYER_USE_ATOMICS_FOR_CLOCK
      88             :     // newTimestamp guaranteed to never be < the last timestamp.
      89    16760594 :     __atomic_store_n(&mLastTimestamp, newTimestamp.count(), __ATOMIC_SEQ_CST);
      90             : #else
      91             :     mLastTimestamp         = newTimestamp.count();
      92             : #endif // CHIP_DEVICE_LAYER_USE_ATOMICS_FOR_CLOCK
      93             : 
      94    16760594 :     return newTimestamp;
      95             : }
      96             : 
      97             : #if !CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME
      98             : 
      99             : #if CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS
     100             : 
     101             : // -------------------- Default Get/SetClock Functions for POSIX Systems --------------------
     102             : 
     103             : #if !HAVE_CLOCK_GETTIME && !HAVE_GETTIMEOFDAY
     104             : #error "CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS requires either clock_gettime() or gettimeofday()"
     105             : #endif
     106             : 
     107             : #if HAVE_CLOCK_GETTIME
     108             : 
     109             : #if defined(HAVE_DECL_CLOCK_BOOTTIME) && HAVE_DECL_CLOCK_BOOTTIME
     110             : // CLOCK_BOOTTIME is a Linux-specific option to clock_gettime for a clock which compensates for system sleep.
     111             : #define MONOTONIC_CLOCK_ID CLOCK_BOOTTIME
     112             : #define MONOTONIC_RAW_CLOCK_ID CLOCK_MONOTONIC_RAW
     113             : #else // HAVE_DECL_CLOCK_BOOTTIME
     114             : // CLOCK_MONOTONIC is defined in POSIX and hence is the default choice
     115             : #define MONOTONIC_CLOCK_ID CLOCK_MONOTONIC
     116             : #endif
     117             : 
     118             : CHIP_ERROR ClockImpl::GetClock_RealTime(Microseconds64 & aCurTime)
     119             : {
     120             :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     121             : }
     122             : 
     123             : CHIP_ERROR ClockImpl::GetClock_RealTimeMS(Milliseconds64 & aCurTime)
     124             : {
     125             :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     126             : }
     127             : 
     128             : CHIP_ERROR ClockImpl::SetClock_RealTime(Microseconds64 aNewCurTime)
     129             : {
     130             :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     131             : }
     132             : 
     133             : Microseconds64 ClockImpl::GetMonotonicMicroseconds64()
     134             : {
     135             :     struct timespec ts;
     136             :     int res = clock_gettime(MONOTONIC_CLOCK_ID, &ts);
     137             :     VerifyOrDie(res == 0);
     138             :     return Seconds64(ts.tv_sec) +
     139             :         std::chrono::duration_cast<Microseconds64>(std::chrono::duration<uint64_t, std::nano>(ts.tv_nsec));
     140             : }
     141             : 
     142             : Milliseconds64 ClockImpl::GetMonotonicMilliseconds64()
     143             : {
     144             :     return std::chrono::duration_cast<Milliseconds64>(GetMonotonicMicroseconds64());
     145             : }
     146             : 
     147             : #endif // HAVE_CLOCK_GETTIME
     148             : 
     149             : #if HAVE_GETTIMEOFDAY
     150             : 
     151             : CHIP_ERROR ClockImpl::GetClock_RealTime(Microseconds64 & aCurTime)
     152             : {
     153             :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     154             : }
     155             : 
     156             : CHIP_ERROR ClockImpl::GetClock_RealTimeMS(Milliseconds64 & aCurTime)
     157             : {
     158             :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     159             : }
     160             : 
     161             : CHIP_ERROR ClockImpl::SetClock_RealTime(Microseconds64 aNewCurTime)
     162             : {
     163             :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     164             : }
     165             : 
     166             : Microseconds64 ClockImpl::GetMonotonicMicroseconds64()
     167             : {
     168             :     struct timeval tv;
     169             :     int res = gettimeofday(&tv, NULL);
     170             :     VerifyOrDie(res == 0);
     171             :     return TimevalToMicroseconds(tv);
     172             : }
     173             : 
     174             : Milliseconds64 ClockImpl::GetMonotonicMilliseconds64()
     175             : {
     176             :     return std::chrono::duration_cast<Milliseconds64>(GetMonotonicMicroseconds64());
     177             : }
     178             : 
     179             : #endif // HAVE_GETTIMEOFDAY
     180             : 
     181             : #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS
     182             : 
     183             : #if CHIP_SYSTEM_CONFIG_USE_LWIP_MONOTONIC_TIME
     184             : 
     185             : // -------------------- Default Get/SetClock Functions for LwIP Systems --------------------
     186             : 
     187             : CHIP_ERROR ClockImpl::GetClock_RealTime(Microseconds64 & aCurTime)
     188             : {
     189             :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     190             : }
     191             : 
     192             : CHIP_ERROR ClockImpl::GetClock_RealTimeMS(Milliseconds64 & aCurTime)
     193             : {
     194             :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     195             : }
     196             : 
     197             : CHIP_ERROR ClockImpl::SetClock_RealTime(Microseconds64 aNewCurTime)
     198             : {
     199             :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     200             : }
     201             : 
     202             : Microseconds64 ClockImpl::GetMonotonicMicroseconds64()
     203             : {
     204             :     return GetMonotonicMilliseconds64();
     205             : }
     206             : 
     207             : Milliseconds64 ClockImpl::GetMonotonicMilliseconds64()
     208             : {
     209             :     static volatile uint64_t overflow        = 0;
     210             :     static volatile u32_t lastSample         = 0;
     211             :     static volatile uint8_t lock             = 0;
     212             :     static const uint64_t kOverflowIncrement = static_cast<uint64_t>(0x100000000);
     213             : 
     214             :     uint64_t overflowSample;
     215             :     u32_t sample;
     216             : 
     217             :     // Tracking timer wrap assumes that this function gets called with
     218             :     // a period that is less than 1/2 the timer range.
     219             :     if (__sync_bool_compare_and_swap(&lock, 0, 1))
     220             :     {
     221             :         sample = sys_now();
     222             : 
     223             :         if (lastSample > sample)
     224             :         {
     225             :             overflow += kOverflowIncrement;
     226             :         }
     227             : 
     228             :         lastSample     = sample;
     229             :         overflowSample = overflow;
     230             : 
     231             :         __sync_bool_compare_and_swap(&lock, 1, 0);
     232             :     }
     233             :     else
     234             :     {
     235             :         // a lower priority task is in the block above. Depending where that
     236             :         // lower task is blocked can spell trouble in a timer wrap condition.
     237             :         // the question here is what this task should use as an overflow value.
     238             :         // To fix this race requires a platform api that can be used to
     239             :         // protect critical sections.
     240             :         overflowSample = overflow;
     241             :         sample         = sys_now();
     242             :     }
     243             : 
     244             :     return Milliseconds64(overflowSample | static_cast<uint64_t>(sample));
     245             : }
     246             : 
     247             : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP_MONOTONIC_TIME
     248             : 
     249             : #endif // CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME
     250             : 
     251             : #if CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_SOCKETS
     252             : 
     253           0 : Microseconds64 TimevalToMicroseconds(const timeval & tv)
     254             : {
     255           0 :     return Seconds64(tv.tv_sec) + Microseconds64(tv.tv_usec);
     256             : }
     257             : 
     258     4092525 : void ToTimeval(Microseconds64 in, timeval & out)
     259             : {
     260     4092525 :     Seconds32 seconds = std::chrono::duration_cast<Seconds32>(in);
     261     4092525 :     in -= seconds;
     262     4092525 :     out.tv_sec  = static_cast<time_t>(seconds.count());
     263     4092525 :     out.tv_usec = static_cast<suseconds_t>(in.count());
     264     4092525 : }
     265             : 
     266             : #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS || CHIP_SYSTEM_CONFIG_USE_SOCKETS
     267             : 
     268             : static_assert(std::numeric_limits<Microseconds64::rep>::is_integer, "Microseconds64 must be an integer type");
     269             : static_assert(std::numeric_limits<Microseconds32::rep>::is_integer, "Microseconds32 must be an integer type");
     270             : static_assert(std::numeric_limits<Milliseconds64::rep>::is_integer, "Milliseconds64 must be an integer type");
     271             : static_assert(std::numeric_limits<Milliseconds32::rep>::is_integer, "Milliseconds32 must be an integer type");
     272             : static_assert(std::numeric_limits<Seconds64::rep>::is_integer, "Seconds64 must be an integer type");
     273             : static_assert(std::numeric_limits<Seconds32::rep>::is_integer, "Seconds32 must be an integer type");
     274             : static_assert(std::numeric_limits<Seconds16::rep>::is_integer, "Seconds16 must be an integer type");
     275             : 
     276             : static_assert(std::numeric_limits<Microseconds64::rep>::digits >= 64, "Microseconds64 must be at least 64 bits");
     277             : static_assert(std::numeric_limits<Microseconds32::rep>::digits >= 32, "Microseconds32 must be at least 32 bits");
     278             : static_assert(std::numeric_limits<Milliseconds64::rep>::digits >= 64, "Milliseconds64 must be at least 64 bits");
     279             : static_assert(std::numeric_limits<Milliseconds32::rep>::digits >= 32, "Milliseconds32 must be at least 32 bits");
     280             : static_assert(std::numeric_limits<Seconds64::rep>::digits >= 64, "Seconds64 must be at least 64 bits");
     281             : static_assert(std::numeric_limits<Seconds32::rep>::digits >= 32, "Seconds32 must be at least 32 bits");
     282             : static_assert(std::numeric_limits<Seconds16::rep>::digits >= 16, "Seconds16 must be at least 16 bits");
     283             : 
     284             : } // namespace Clock
     285             : } // namespace System
     286             : } // namespace chip

Generated by: LCOV version 1.14