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
|