Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / system / SystemClock.cpp
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 // __STDC_LIMIT_MACROS must be defined for UINT8_MAX to be defined for pre-C++11 clib
26 #ifndef __STDC_LIMIT_MACROS
27 #define __STDC_LIMIT_MACROS
28 #endif // __STDC_LIMIT_MACROS
29
30 // __STDC_CONSTANT_MACROS must be defined for INT64_C and UINT64_C to be defined for pre-C++11 clib
31 #ifndef __STDC_CONSTANT_MACROS
32 #define __STDC_CONSTANT_MACROS
33 #endif // __STDC_CONSTANT_MACROS
34
35 // config
36 #include <system/SystemConfig.h>
37
38 #if !CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME
39
40 // module header
41 #include <system/SystemClock.h>
42 // common private
43 #include "SystemLayerPrivate.h"
44
45 #include <support/CodeUtils.h>
46 #include <system/SystemError.h>
47
48 #if CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS
49 #include <time.h>
50 #if !(HAVE_CLOCK_GETTIME)
51 #include <sys/time.h>
52 #endif
53 #include <errno.h>
54 #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS
55
56 #if CHIP_SYSTEM_CONFIG_USE_LWIP
57 #include <lwip/sys.h>
58 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
59
60 #include <stdint.h>
61 #include <stdlib.h>
62
63 namespace chip {
64 namespace System {
65 namespace Platform {
66 namespace Layer {
67
68 // -------------------- Default Get/SetClock Functions for POSIX Systems --------------------
69
70 #if CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS
71
72 #if !HAVE_CLOCK_GETTIME && !HAVE_GETTIMEOFDAY
73 #error "CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS requires either clock_gettime() or gettimeofday()"
74 #endif
75
76 #if HAVE_CLOCK_GETTIME
77 #if HAVE_DECL_CLOCK_BOOTTIME
78 // CLOCK_BOOTTIME is a Linux-specific option to clock_gettime for a clock which compensates for system sleep.
79 #define MONOTONIC_CLOCK_ID CLOCK_BOOTTIME
80 #define MONOTONIC_RAW_CLOCK_ID CLOCK_MONOTONIC_RAW
81 #else // HAVE_DECL_CLOCK_BOOTTIME
82 // CLOCK_MONOTONIC is defined in POSIX and hence is the default choice
83 #define MONOTONIC_CLOCK_ID CLOCK_MONOTONIC
84 #endif
85 #endif // HAVE_CLOCK_GETTIME
86
87 uint64_t GetClock_Monotonic()
88 {
89 #if HAVE_CLOCK_GETTIME
90     struct timespec ts;
91     int res = clock_gettime(MONOTONIC_CLOCK_ID, &ts);
92     VerifyOrDie(res == 0);
93     return (static_cast<uint64_t>(ts.tv_sec) * UINT64_C(1000000)) + (static_cast<uint64_t>(ts.tv_nsec) / 1000);
94 #else  // HAVE_CLOCK_GETTIME
95     struct timeval tv;
96     int res = gettimeofday(&tv, NULL);
97     VerifyOrDie(res == 0);
98     return (tv.tv_sec * UINT64_C(1000000)) + tv.tv_usec;
99 #endif // HAVE_CLOCK_GETTIME
100 }
101
102 uint64_t GetClock_MonotonicMS()
103 {
104     return GetClock_Monotonic() / 1000;
105 }
106
107 uint64_t GetClock_MonotonicHiRes()
108 {
109 #if HAVE_CLOCK_GETTIME && defined(MONOTONIC_RAW_CLOCK_ID)
110     struct timespec ts;
111     int res = clock_gettime(MONOTONIC_RAW_CLOCK_ID, &ts);
112     VerifyOrDie(res == 0);
113     return (ts.tv_sec * UINT64_C(1000000)) + (ts.tv_nsec / 1000);
114 #else  // HAVE_CLOCK_GETTIME
115     return GetClock_Monotonic();
116 #endif // HAVE_CLOCK_GETTIME
117 }
118
119 Error GetClock_RealTime(uint64_t & curTime)
120 {
121 #if HAVE_CLOCK_GETTIME
122     struct timespec ts;
123     int res = clock_gettime(CLOCK_REALTIME, &ts);
124     if (res != 0)
125     {
126         return MapErrorPOSIX(errno);
127     }
128     if (ts.tv_sec < CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD)
129     {
130         return CHIP_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED;
131     }
132     curTime = (static_cast<uint64_t>(ts.tv_sec) * UINT64_C(1000000)) + (static_cast<uint64_t>(ts.tv_nsec) / 1000);
133     return CHIP_SYSTEM_NO_ERROR;
134 #else  // HAVE_CLOCK_GETTIME
135     struct timeval tv;
136     int res = gettimeofday(&tv, NULL);
137     if (res != 0)
138     {
139         return MapErrorPOSIX(errno);
140     }
141     if (tv.tv_sec < CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD)
142     {
143         return CHIP_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED;
144     }
145     curTime = (tv.tv_sec * UINT64_C(1000000)) + tv.tv_usec;
146     return CHIP_SYSTEM_NO_ERROR;
147 #endif // HAVE_CLOCK_GETTIME
148 }
149
150 Error GetClock_RealTimeMS(uint64_t & curTime)
151 {
152     Error err = GetClock_RealTime(curTime);
153     curTime   = curTime / 1000;
154     return err;
155 }
156
157 #if HAVE_CLOCK_SETTIME || HAVE_SETTIMEOFDAY
158
159 Error SetClock_RealTime(uint64_t newCurTime)
160 {
161 #if HAVE_CLOCK_SETTIME
162     struct timespec ts;
163     ts.tv_sec  = static_cast<time_t>(newCurTime / UINT64_C(1000000));
164     ts.tv_nsec = static_cast<long>(newCurTime % UINT64_C(1000000)) * 1000;
165     int res    = clock_settime(CLOCK_REALTIME, &ts);
166     if (res != 0)
167     {
168         return (errno == EPERM) ? CHIP_SYSTEM_ERROR_ACCESS_DENIED : MapErrorPOSIX(errno);
169     }
170     return CHIP_SYSTEM_NO_ERROR;
171 #else  // HAVE_CLOCK_SETTIME
172     struct timeval tv;
173     tv.tv_sec  = static_cast<time_t>(newCurTime / UINT64_C(1000000));
174     tv.tv_usec = static_cast<long>(newCurTime % UINT64_C(1000000));
175     int res    = settimeofday(&tv, NULL);
176     if (res != 0)
177     {
178         return (errno == EPERM) ? CHIP_SYSTEM_ERROR_ACCESS_DENIED : MapErrorPOSIX(errno);
179     }
180     return CHIP_SYSTEM_NO_ERROR;
181 #endif // HAVE_CLOCK_SETTIME
182 }
183
184 #else // !HAVE_CLOCK_SETTTIME
185
186 Error SetClock_RealTime(uint64_t newCurTime)
187 {
188     return CHIP_SYSTEM_ERROR_NOT_SUPPORTED;
189 }
190
191 #endif // HAVE_CLOCK_SETTIME || HAVE_SETTIMEOFDAY
192
193 #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS
194
195 // -------------------- Default Get/SetClock Functions for LwIP Systems --------------------
196
197 #if CHIP_SYSTEM_CONFIG_USE_LWIP_MONOTONIC_TIME
198
199 uint64_t GetClock_Monotonic(void)
200 {
201     return GetClock_MonotonicMS();
202 }
203
204 uint64_t GetClock_MonotonicMS(void)
205 {
206     static volatile uint64_t overflow        = 0;
207     static volatile u32_t lastSample         = 0;
208     static volatile uint8_t lock             = 0;
209     static const uint64_t kOverflowIncrement = static_cast<uint64_t>(0x100000000);
210
211     uint64_t overflowSample;
212     u32_t sample;
213
214     // Tracking timer wrap assumes that this function gets called with
215     // a period that is less than 1/2 the timer range.
216     if (__sync_bool_compare_and_swap(&lock, 0, 1))
217     {
218         sample = sys_now();
219
220         if (lastSample > sample)
221         {
222             overflow += kOverflowIncrement;
223         }
224
225         lastSample     = sample;
226         overflowSample = overflow;
227
228         __sync_bool_compare_and_swap(&lock, 1, 0);
229     }
230     else
231     {
232         // a lower priority task is in the block above. Depending where that
233         // lower task is blocked can spell trouble in a timer wrap condition.
234         // the question here is what this task should use as an overflow value.
235         // To fix this race requires a platform api that can be used to
236         // protect critical sections.
237         overflowSample = overflow;
238         sample         = sys_now();
239     }
240
241     return static_cast<uint64_t>(overflowSample | static_cast<uint64_t>(sample));
242 }
243
244 uint64_t GetClock_MonotonicHiRes(void)
245 {
246     return GetClock_MonotonicMS();
247 }
248
249 Error GetClock_RealTime(uint64_t & curTime)
250 {
251     return CHIP_SYSTEM_ERROR_NOT_SUPPORTED;
252 }
253
254 Error GetClock_RealTimeMS(uint64_t & curTime)
255 {
256     return CHIP_SYSTEM_ERROR_NOT_SUPPORTED;
257 }
258
259 Error SetClock_RealTime(uint64_t newCurTime)
260 {
261     return CHIP_SYSTEM_ERROR_NOT_SUPPORTED;
262 }
263
264 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP_MONOTONIC_TIME
265
266 } // namespace Layer
267 } // namespace Platform
268 } // namespace System
269 } // namespace chip
270
271 #endif // CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME