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