/* * * Copyright (c) 2020 Project CHIP Authors * Copyright (c) 2016-2017 Nest Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * This file defines the chip::System::Timer class and related types that can be used for representing * an in-progress one-shot timer. Implementations of System::Layer may (but are not required to) use * these for their versions of timer events. */ #pragma once // Include configuration headers #include // Include dependent headers #include #include #include #include #include #include #if CHIP_SYSTEM_CONFIG_USE_DISPATCH #include #endif namespace chip { namespace System { class Layer; /** * Basic Timer information: time and callback. */ class DLL_EXPORT TimerData { public: class Callback { public: Callback(Layer & systemLayer, TimerCompleteCallback onComplete, void * appState) : mSystemLayer(&systemLayer), mOnComplete(onComplete), mAppState(appState) {} void Invoke() const { mOnComplete(mSystemLayer, mAppState); } const TimerCompleteCallback & GetOnComplete() const { return mOnComplete; } void * GetAppState() const { return mAppState; } Layer * GetSystemLayer() const { return mSystemLayer; } private: #if CHIP_SYSTEM_CONFIG_USE_LIBEV friend class LayerImplSelect; #endif Layer * mSystemLayer; TimerCompleteCallback mOnComplete; void * mAppState; }; TimerData(Layer & systemLayer, System::Clock::Timestamp awakenTime, TimerCompleteCallback onComplete, void * appState) : mAwakenTime(awakenTime), mCallback(systemLayer, onComplete, appState) {} ~TimerData() = default; /** * Return the expiration time. */ Clock::Timestamp AwakenTime() const { return mAwakenTime; } /** * Return callback information. */ const Callback & GetCallback() const { return mCallback; } private: Clock::Timestamp mAwakenTime; Callback mCallback; #if CHIP_SYSTEM_CONFIG_USE_DISPATCH friend class LayerImplSelect; dispatch_source_t mTimerSource = nullptr; #elif CHIP_SYSTEM_CONFIG_USE_LIBEV friend class LayerImplSelect; struct ev_timer mLibEvTimer; #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH // Not defined TimerData(const TimerData &) = delete; TimerData & operator=(const TimerData &) = delete; }; /** * List of `Timer`s ordered by expiration time. */ class TimerList { public: class Node : public TimerData { public: Node(Layer & systemLayer, System::Clock::Timestamp awakenTime, TimerCompleteCallback onComplete, void * appState) : TimerData(systemLayer, awakenTime, onComplete, appState), mNextTimer(nullptr) {} Node * mNextTimer; }; TimerList() : mEarliestTimer(nullptr) {} /** * Add a timer to the list * * @return The new earliest timer in the list. If this is the newly added timer, that implies it is earlier * than any existing timer. */ Node * Add(Node * timer); /** * Remove the given timer from the list, if present. It is not an error for the timer not to be present. * * @return The new earliest timer in the list, or nullptr if the list is empty. */ Node * Remove(Node * remove); /** * Remove the first timer with the given properties, if present. It is not an error for no such timer to be present. * * @return The removed timer, or nullptr if the list contains no matching timer. */ Node * Remove(TimerCompleteCallback onComplete, void * appState); /** * Remove and return the earliest timer in the list. * * @return The earliest timer, or nullptr if the list is empty. */ Node * PopEarliest(); /** * Remove and return the earliest timer in the list, provided it expires earlier than the given time @a t. * * @return The earliest timer expiring before @a t, or nullptr if there is no such timer. */ Node * PopIfEarlier(Clock::Timestamp t); /** * Get the earliest timer in the list. * * @return The earliest timer, or nullptr if there are no timers. */ Node * Earliest() const { return mEarliestTimer; } /** * Test whether there are any timers. */ bool Empty() const { return mEarliestTimer == nullptr; } /** * Remove and return all timers that expire before the given time @a t. */ TimerList ExtractEarlier(Clock::Timestamp t); /** * Remove all timers. */ void Clear() { mEarliestTimer = nullptr; } /** * Find the timer with the given properties, if present, and return its remaining time * * @return The remaining time on this partifcular timer or 0 if not found. */ Clock::Timeout GetRemainingTime(TimerCompleteCallback aOnComplete, void * aAppState); private: Node * mEarliestTimer; }; /** * ObjectPool wrapper that keeps System Timer statistics. */ template class TimerPool { public: using Timer = T; /** * Create a new timer from the pool. */ Timer * Create(Layer & systemLayer, System::Clock::Timestamp awakenTime, TimerCompleteCallback onComplete, void * appState) { Timer * timer = mTimerPool.CreateObject(systemLayer, awakenTime, onComplete, appState); SYSTEM_STATS_INCREMENT(Stats::kSystemLayer_NumTimers); return timer; } /** * Release a timer to the pool. */ void Release(Timer * timer) { SYSTEM_STATS_DECREMENT(Stats::kSystemLayer_NumTimers); mTimerPool.ReleaseObject(timer); } /** * Release all timers. */ void ReleaseAll() { SYSTEM_STATS_RESET(Stats::kSystemLayer_NumTimers); mTimerPool.ReleaseAll(); } /** * Release a timer to the pool and invoke its callback. */ void Invoke(Timer * timer) { typename Timer::Callback callback = timer->GetCallback(); Release(timer); callback.Invoke(); } private: friend class TestSystemTimer_CheckTimerPool_Test; ObjectPool mTimerPool; }; } // namespace System } // namespace chip