Matter SDK Coverage Report
Current view: top level - system - SystemClock.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 86.7 % 15 13
Test Date: 2025-01-17 19:00:11 Functions: 66.7 % 3 2

            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     26826944 : 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     26826944 :     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     26826944 :     __atomic_signal_fence(__ATOMIC_SEQ_CST);
      77              : #else
      78              :     uint64_t prevTimestamp = mLastTimestamp;
      79              : #endif // CHIP_DEVICE_LAYER_USE_ATOMICS_FOR_CLOCK
      80              : 
      81     26826944 :     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     26826944 :     VerifyOrDie(newTimestamp.count() >= prevTimestamp);
      86              : 
      87              : #if CHIP_DEVICE_LAYER_USE_ATOMICS_FOR_CLOCK
      88              :     // newTimestamp guaranteed to never be < the last timestamp.
      89     26826944 :     __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     26826944 :     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      6601584 : void ToTimeval(Microseconds64 in, timeval & out)
     259              : {
     260      6601584 :     Seconds32 seconds = std::chrono::duration_cast<Seconds32>(in);
     261      6601584 :     in -= seconds;
     262      6601584 :     out.tv_sec  = static_cast<time_t>(seconds.count());
     263      6601584 :     out.tv_usec = static_cast<suseconds_t>(in.count());
     264      6601584 : }
     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 2.0-1