blob: 54b07f8c092f4993eacfabea4e4e4f1c7d66fddb [file] [log] [blame]
/*
*
* 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 <system/SystemConfig.h>
// Include dependent headers
#include <lib/support/DLLUtil.h>
#include <lib/support/Pool.h>
#include <system/SystemClock.h>
#include <system/SystemError.h>
#include <system/SystemLayer.h>
#include <system/SystemStats.h>
#if CHIP_SYSTEM_CONFIG_USE_DISPATCH
#include <dispatch/dispatch.h>
#endif
namespace chip {
namespace System {
class Layer;
class TestTimer;
/**
* 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:
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;
#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; }
private:
Node * mEarliestTimer;
};
/**
* ObjectPool wrapper that keeps System Timer statistics.
*/
template <typename T = TimerList::Node>
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 TestTimer;
ObjectPool<Timer, CHIP_SYSTEM_CONFIG_NUM_TIMERS> mTimerPool;
};
} // namespace System
} // namespace chip