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 692 : constexpr Milliseconds64 operator""_ms(unsigned long long int ms)
97 : {
98 692 : return Milliseconds64(ms);
99 : }
100 : constexpr Milliseconds64 operator""_ms64(unsigned long long int ms)
101 : {
102 : return Milliseconds64(ms);
103 : }
104 24033 : constexpr Milliseconds32 operator""_ms32(unsigned long long int ms)
105 : {
106 24033 : 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 884 : inline Clock::ClockBase & SystemClock()
378 : {
379 884 : return *Clock::Internal::gClockBase;
380 : }
381 :
382 : } // namespace System
383 : } // namespace chip
|