3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2016-2017 Nest Labs, Inc.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
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.
26 // Include module header
27 #include <system/SystemTimer.h>
29 // Include common private header
30 #include "SystemLayerPrivate.h"
32 // Include local headers
35 #include <system/SystemError.h>
36 #include <system/SystemFaultInjection.h>
37 #include <system/SystemLayer.h>
39 #include <support/CodeUtils.h>
41 /*******************************************************************************
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:
48 * INITIAL STATE: mSystemLayer == NULL, OnComplete == NULL
51 * UNALLOCATED<-----------------------------+
53 * (set mSystemLayer != NULL) |
56 * ALLOCATED-------(set mSystemLayer NULL)--+
57 * | \-----------------------------+
59 * (set OnComplete != NULL) |
62 * ARMED ---------( clear OnComplete )--+
64 * When in the ARMED state:
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().
72 *******************************************************************************
78 ObjectPool<Timer, CHIP_SYSTEM_CONFIG_NUM_TIMERS> Timer::sPool;
81 * This method returns the current epoch, corrected by system sleep with the system timescale, in milliseconds.
83 * DEPRECATED -- Please use System::Layer::GetClock_MonotonicMS() instead.
85 * @return A timestamp in milliseconds.
87 Timer::Epoch Timer::GetCurrentEpoch()
89 return Platform::Layer::GetClock_MonotonicMS();
93 * Compares two Timer::Epoch values and returns true if the first value is earlier than the second value.
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.
101 * This implementation assumes that Timer::Epoch is an unsigned scalar type.
103 * @return true if the first param is earlier than the second, false otherwise.
105 bool Timer::IsEarlierEpoch(const Timer::Epoch & inFirst, const Timer::Epoch & inSecond)
107 static const Epoch kMaxTime_2 = static_cast<Epoch>((static_cast<Epoch>(0) - static_cast<Epoch>(1)) / 2);
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)));
116 * This method registers an one-shot timer with the underlying timer mechanism provided by the platform.
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
122 * @retval #CHIP_SYSTEM_NO_ERROR Unconditionally.
125 Error Timer::Start(uint32_t aDelayMilliseconds, OnCompleteFunct aOnComplete, void * aAppState)
127 Layer & lLayer = this->SystemLayer();
129 CHIP_SYSTEM_FAULT_INJECT(FaultInjection::kFault_TimeoutImmediate, aDelayMilliseconds = 0);
131 this->AppState = aAppState;
132 this->mAwakenEpoch = Timer::GetCurrentEpoch() + static_cast<Epoch>(aDelayMilliseconds);
133 if (!__sync_bool_compare_and_swap(&this->OnComplete, nullptr, aOnComplete))
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))
142 this->mNextTimer = lLayer.mTimerList;
143 lLayer.mTimerList = this;
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)
150 lLayer.StartPlatformTimer(aDelayMilliseconds);
155 Timer * lTimer = lLayer.mTimerList;
157 while (lTimer->mNextTimer)
159 if (this->IsEarlierEpoch(this->mAwakenEpoch, lTimer->mNextTimer->mAwakenEpoch))
161 // found the insert location.
165 lTimer = lTimer->mNextTimer;
168 this->mNextTimer = lTimer->mNextTimer;
169 lTimer->mNextTimer = this;
171 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
172 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
174 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
176 return CHIP_SYSTEM_NO_ERROR;
179 Error Timer::ScheduleWork(OnCompleteFunct aOnComplete, void * aAppState)
181 Error err = CHIP_SYSTEM_NO_ERROR;
182 Layer & lLayer = this->SystemLayer();
184 this->AppState = aAppState;
185 this->mAwakenEpoch = Timer::GetCurrentEpoch();
186 if (!__sync_bool_compare_and_swap(&this->OnComplete, nullptr, aOnComplete))
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
196 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
202 * This method de-initializes the timer object, and prevents this timer from firing if it hasn't done so.
204 * @retval #CHIP_SYSTEM_NO_ERROR Unconditionally.
206 Error Timer::Cancel()
208 #if CHIP_SYSTEM_CONFIG_USE_LWIP
209 Layer & lLayer = this->SystemLayer();
210 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
211 OnCompleteFunct lOnComplete = this->OnComplete;
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), );
218 // Since this thread changed the state of OnComplete, release the timer.
219 this->AppState = nullptr;
221 #if CHIP_SYSTEM_CONFIG_USE_LWIP
222 if (lLayer.mTimerList)
224 if (this == lLayer.mTimerList)
226 lLayer.mTimerList = this->mNextTimer;
230 Timer * lTimer = lLayer.mTimerList;
232 while (lTimer->mNextTimer)
234 if (this == lTimer->mNextTimer)
236 lTimer->mNextTimer = this->mNextTimer;
240 lTimer = lTimer->mNextTimer;
244 this->mNextTimer = NULL;
246 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
250 return CHIP_SYSTEM_NO_ERROR;
254 * This method is called by the underlying timer mechanism provided by the platform when the timer fires.
256 void Timer::HandleComplete()
258 // Save information needed to perform the callback.
259 Layer & lLayer = this->SystemLayer();
260 const OnCompleteFunct lOnComplete = this->OnComplete;
261 void * lAppState = this->AppState;
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), );
268 // Since this thread changed the state of OnComplete, release the timer.
272 // Invoke the app's callback, if it's still valid.
273 if (lOnComplete != nullptr)
274 lOnComplete(&lLayer, lAppState, CHIP_SYSTEM_NO_ERROR);
280 #if CHIP_SYSTEM_CONFIG_USE_LWIP
282 * Completes any timers that have expired.
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.
290 * It's harmless if this API gets called and there are no expired timers.
292 * @return CHIP_SYSTEM_NO_ERROR on success, error code otherwise.
295 Error Timer::HandleExpiredTimers(Layer & aLayer)
297 size_t timersHandled = 0;
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();
304 while (aLayer.mTimerList)
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.
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))
312 Timer & lTimer = *aLayer.mTimerList;
313 aLayer.mTimerList = lTimer.mNextTimer;
314 lTimer.mNextTimer = NULL;
316 aLayer.mTimerComplete = true;
317 lTimer.HandleComplete();
318 aLayer.mTimerComplete = false;
324 // timers still exist so restart the platform timer.
325 uint64_t delayMilliseconds = 0ULL;
327 currentEpoch = Timer::GetCurrentEpoch();
329 // the next timer expires in the future, so set the delayMilliseconds to a non-zero value
330 if (currentEpoch < aLayer.mTimerList->mAwakenEpoch)
332 delayMilliseconds = aLayer.mTimerList->mAwakenEpoch - currentEpoch;
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.
340 VerifyOrDie(delayMilliseconds <= UINT32_MAX);
342 aLayer.StartPlatformTimer(static_cast<uint32_t>(delayMilliseconds));
343 break; // all remaining timers are still ticking.
347 return CHIP_SYSTEM_NO_ERROR;
349 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
351 } // namespace System