Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / system / SystemTimer.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2016-2017 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 file defines the member functions and private data for
22  *      the chip::System::Timer class, which is used for
23  *      representing an in-progress one-shot timer.
24  */
25
26 // Include module header
27 #include <system/SystemTimer.h>
28
29 // Include common private header
30 #include "SystemLayerPrivate.h"
31
32 // Include local headers
33 #include <string.h>
34
35 #include <system/SystemError.h>
36 #include <system/SystemFaultInjection.h>
37 #include <system/SystemLayer.h>
38
39 #include <support/CodeUtils.h>
40
41 /*******************************************************************************
42  * Timer state
43  *
44  * There are two fundamental state-change variables: Object::mSystemLayer and
45  * Timer::OnComplete. These must be checked and changed atomically. The state
46  * of the timer is governed by the following state machine:
47  *
48  *  INITIAL STATE: mSystemLayer == NULL, OnComplete == NULL
49  *      |
50  *      V
51  *  UNALLOCATED<-----------------------------+
52  *      |                                    |
53  *  (set mSystemLayer != NULL)               |
54  *      |                                    |
55  *      V                                    |
56  *  ALLOCATED-------(set mSystemLayer NULL)--+
57  *      |    \-----------------------------+
58  *      |                                  |
59  *  (set OnComplete != NULL)               |
60  *      |                                  |
61  *      V                                  |
62  *    ARMED ---------( clear OnComplete )--+
63  *
64  * When in the ARMED state:
65  *
66  *     * None of the member variables may mutate.
67  *     * OnComplete must only be cleared by Cancel() or HandleComplete()
68  *     * Cancel() and HandleComplete() will test that they are the one to
69  *       successfully set OnComplete NULL. And if so, that will be the
70  *       thread that must call Object::Release().
71  *
72  *******************************************************************************
73  */
74
75 namespace chip {
76 namespace System {
77
78 ObjectPool<Timer, CHIP_SYSTEM_CONFIG_NUM_TIMERS> Timer::sPool;
79
80 /**
81  *  This method returns the current epoch, corrected by system sleep with the system timescale, in milliseconds.
82  *
83  *  DEPRECATED -- Please use System::Layer::GetClock_MonotonicMS() instead.
84  *
85  *  @return A timestamp in milliseconds.
86  */
87 Timer::Epoch Timer::GetCurrentEpoch()
88 {
89     return Platform::Layer::GetClock_MonotonicMS();
90 }
91
92 /**
93  *  Compares two Timer::Epoch values and returns true if the first value is earlier than the second value.
94  *
95  *  @brief
96  *      A static API that gets called to compare 2 time values.  This API attempts to account for timer wrap by assuming that the
97  *      difference between the 2 input values will only be more than half the Epoch scalar range if a timer wrap has occurred
98  *      between the 2 samples.
99  *
100  *  @note
101  *      This implementation assumes that Timer::Epoch is an unsigned scalar type.
102  *
103  *  @return true if the first param is earlier than the second, false otherwise.
104  */
105 bool Timer::IsEarlierEpoch(const Timer::Epoch & inFirst, const Timer::Epoch & inSecond)
106 {
107     static const Epoch kMaxTime_2 = static_cast<Epoch>((static_cast<Epoch>(0) - static_cast<Epoch>(1)) / 2);
108
109     // account for timer wrap with the assumption that no two input times will "naturally"
110     // be more than half the timer range apart.
111     return (((inFirst < inSecond) && (inSecond - inFirst < kMaxTime_2)) ||
112             ((inFirst > inSecond) && (inFirst - inSecond > kMaxTime_2)));
113 }
114
115 /**
116  *  This method registers an one-shot timer with the underlying timer mechanism provided by the platform.
117  *
118  *  @param[in]  aDelayMilliseconds  The number of milliseconds before this timer fires
119  *  @param[in]  aOnComplete          A pointer to the callback function when this timer fires
120  *  @param[in]  aAppState            An arbitrary pointer to be passed into onComplete when this timer fires
121  *
122  *  @retval #CHIP_SYSTEM_NO_ERROR Unconditionally.
123  *
124  */
125 Error Timer::Start(uint32_t aDelayMilliseconds, OnCompleteFunct aOnComplete, void * aAppState)
126 {
127     Layer & lLayer = this->SystemLayer();
128
129     CHIP_SYSTEM_FAULT_INJECT(FaultInjection::kFault_TimeoutImmediate, aDelayMilliseconds = 0);
130
131     this->AppState     = aAppState;
132     this->mAwakenEpoch = Timer::GetCurrentEpoch() + static_cast<Epoch>(aDelayMilliseconds);
133     if (!__sync_bool_compare_and_swap(&this->OnComplete, nullptr, aOnComplete))
134     {
135         chipDie();
136     }
137
138 #if CHIP_SYSTEM_CONFIG_USE_LWIP
139     // add to the sorted list of timers. Earliest timer appears first.
140     if (lLayer.mTimerList == NULL || this->IsEarlierEpoch(this->mAwakenEpoch, lLayer.mTimerList->mAwakenEpoch))
141     {
142         this->mNextTimer  = lLayer.mTimerList;
143         lLayer.mTimerList = this;
144
145         // this is the new earliest timer and so the timer needs (re-)starting provided that
146         // the system is not currently processing expired timers, in which case it is left to
147         // HandleExpiredTimers() to re-start the timer.
148         if (!lLayer.mTimerComplete)
149         {
150             lLayer.StartPlatformTimer(aDelayMilliseconds);
151         }
152     }
153     else
154     {
155         Timer * lTimer = lLayer.mTimerList;
156
157         while (lTimer->mNextTimer)
158         {
159             if (this->IsEarlierEpoch(this->mAwakenEpoch, lTimer->mNextTimer->mAwakenEpoch))
160             {
161                 // found the insert location.
162                 break;
163             }
164
165             lTimer = lTimer->mNextTimer;
166         }
167
168         this->mNextTimer   = lTimer->mNextTimer;
169         lTimer->mNextTimer = this;
170     }
171 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
172 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
173     lLayer.WakeSelect();
174 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
175
176     return CHIP_SYSTEM_NO_ERROR;
177 }
178
179 Error Timer::ScheduleWork(OnCompleteFunct aOnComplete, void * aAppState)
180 {
181     Error err      = CHIP_SYSTEM_NO_ERROR;
182     Layer & lLayer = this->SystemLayer();
183
184     this->AppState     = aAppState;
185     this->mAwakenEpoch = Timer::GetCurrentEpoch();
186     if (!__sync_bool_compare_and_swap(&this->OnComplete, nullptr, aOnComplete))
187     {
188         chipDie();
189     }
190
191 #if CHIP_SYSTEM_CONFIG_USE_LWIP
192     err = lLayer.PostEvent(*this, chip::System::kEvent_ScheduleWork, 0);
193 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
194 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
195     lLayer.WakeSelect();
196 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
197
198     return err;
199 }
200
201 /**
202  *  This method de-initializes the timer object, and prevents this timer from firing if it hasn't done so.
203  *
204  *  @retval #CHIP_SYSTEM_NO_ERROR Unconditionally.
205  */
206 Error Timer::Cancel()
207 {
208 #if CHIP_SYSTEM_CONFIG_USE_LWIP
209     Layer & lLayer = this->SystemLayer();
210 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
211     OnCompleteFunct lOnComplete = this->OnComplete;
212
213     // Check if the timer is armed
214     VerifyOrExit(lOnComplete != nullptr, );
215     // Atomically disarm if the value has not changed
216     VerifyOrExit(__sync_bool_compare_and_swap(&this->OnComplete, lOnComplete, nullptr), );
217
218     // Since this thread changed the state of OnComplete, release the timer.
219     this->AppState = nullptr;
220
221 #if CHIP_SYSTEM_CONFIG_USE_LWIP
222     if (lLayer.mTimerList)
223     {
224         if (this == lLayer.mTimerList)
225         {
226             lLayer.mTimerList = this->mNextTimer;
227         }
228         else
229         {
230             Timer * lTimer = lLayer.mTimerList;
231
232             while (lTimer->mNextTimer)
233             {
234                 if (this == lTimer->mNextTimer)
235                 {
236                     lTimer->mNextTimer = this->mNextTimer;
237                     break;
238                 }
239
240                 lTimer = lTimer->mNextTimer;
241             }
242         }
243
244         this->mNextTimer = NULL;
245     }
246 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
247
248     this->Release();
249 exit:
250     return CHIP_SYSTEM_NO_ERROR;
251 }
252
253 /**
254  *  This method is called by the underlying timer mechanism provided by the platform when the timer fires.
255  */
256 void Timer::HandleComplete()
257 {
258     // Save information needed to perform the callback.
259     Layer & lLayer                    = this->SystemLayer();
260     const OnCompleteFunct lOnComplete = this->OnComplete;
261     void * lAppState                  = this->AppState;
262
263     // Check if timer is armed
264     VerifyOrExit(lOnComplete != nullptr, );
265     // Atomically disarm if the value has not changed.
266     VerifyOrExit(__sync_bool_compare_and_swap(&this->OnComplete, lOnComplete, nullptr), );
267
268     // Since this thread changed the state of OnComplete, release the timer.
269     AppState = nullptr;
270     this->Release();
271
272     // Invoke the app's callback, if it's still valid.
273     if (lOnComplete != nullptr)
274         lOnComplete(&lLayer, lAppState, CHIP_SYSTEM_NO_ERROR);
275
276 exit:
277     return;
278 }
279
280 #if CHIP_SYSTEM_CONFIG_USE_LWIP
281 /**
282  * Completes any timers that have expired.
283  *
284  *  @brief
285  *      A static API that gets called when the platform timer expires. Any expired timers are completed and removed from the list
286  *      of active timers in the layer object. If unexpired timers remain on completion, StartPlatformTimer will be called to
287  *      restart the platform timer.
288  *
289  *  @note
290  *      It's harmless if this API gets called and there are no expired timers.
291  *
292  *  @return CHIP_SYSTEM_NO_ERROR on success, error code otherwise.
293  *
294  */
295 Error Timer::HandleExpiredTimers(Layer & aLayer)
296 {
297     size_t timersHandled = 0;
298
299     // Expire each timer in turn until an unexpired timer is reached or the timerlist is emptied.  We set the current expiration
300     // time outside the loop; that way timers set after the current tick will not be executed within this expiration window
301     // regardless how long the processing of the currently expired timers took
302     Epoch currentEpoch = Timer::GetCurrentEpoch();
303
304     while (aLayer.mTimerList)
305     {
306         // limit the number of timers handled before the control is returned to the event queue.  The bound is similar to
307         // (though not exactly same) as that on the sockets-based systems.
308
309         // The platform timer API has MSEC resolution so expire any timer with less than 1 msec remaining.
310         if ((timersHandled < Timer::sPool.Size()) && Timer::IsEarlierEpoch(aLayer.mTimerList->mAwakenEpoch, currentEpoch + 1))
311         {
312             Timer & lTimer    = *aLayer.mTimerList;
313             aLayer.mTimerList = lTimer.mNextTimer;
314             lTimer.mNextTimer = NULL;
315
316             aLayer.mTimerComplete = true;
317             lTimer.HandleComplete();
318             aLayer.mTimerComplete = false;
319
320             timersHandled++;
321         }
322         else
323         {
324             // timers still exist so restart the platform timer.
325             uint64_t delayMilliseconds = 0ULL;
326
327             currentEpoch = Timer::GetCurrentEpoch();
328
329             // the next timer expires in the future, so set the delayMilliseconds to a non-zero value
330             if (currentEpoch < aLayer.mTimerList->mAwakenEpoch)
331             {
332                 delayMilliseconds = aLayer.mTimerList->mAwakenEpoch - currentEpoch;
333             }
334             /*
335              * StartPlatformTimer() accepts a 32bit value in milliseconds.  Epochs are 64bit numbers.  The only way in which this
336              * could overflow is if time went backwards (e.g. as a result of a time adjustment from time synchronization).  Verify
337              * that the timer can still be executed (even if it is very late) and exit if that is the case.  Note: if the time sync
338              * ever ends up adjusting the clock, we should implement a method that deals with all the timers in the system.
339              */
340             VerifyOrDie(delayMilliseconds <= UINT32_MAX);
341
342             aLayer.StartPlatformTimer(static_cast<uint32_t>(delayMilliseconds));
343             break; // all remaining timers are still ticking.
344         }
345     }
346
347     return CHIP_SYSTEM_NO_ERROR;
348 }
349 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
350
351 } // namespace System
352 } // namespace chip