feat add timer
This commit is contained in:
parent
f6b9cc5aee
commit
b94e31983b
@ -49,6 +49,8 @@ target_sources(
|
||||
src/system/thread.cc
|
||||
src/task_queue/pending_task_safety_flag.cc
|
||||
src/task_queue/task_queue_base.cc
|
||||
src/timer/task_queue_timeout.cc
|
||||
src/timer/timer.cc
|
||||
src/units/time_delta.cc
|
||||
src/units/timestamp.cc
|
||||
src/operations_chain.cc
|
||||
|
@ -53,6 +53,22 @@ public:
|
||||
PostDelayedTaskImpl(std::move(task), delay, traits, location);
|
||||
}
|
||||
|
||||
void
|
||||
PostDelayedTaskWithPrecision(DelayPrecision precision,
|
||||
std::function<void()> &&task,
|
||||
TimeDelta delay,
|
||||
const Location &location = Location::Current())
|
||||
{
|
||||
switch (precision) {
|
||||
case DelayPrecision::kLow:
|
||||
PostDelayedTask(std::move(task), delay, location);
|
||||
break;
|
||||
case DelayPrecision::kHigh:
|
||||
PostDelayedHighPrecisionTask(std::move(task), delay, location);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static TaskQueueBase *Current();
|
||||
|
||||
bool IsCurrent() const { return Current() == this; };
|
||||
|
54
include/sled/timer/task_queue_timeout.h
Normal file
54
include/sled/timer/task_queue_timeout.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#ifndef SLED_TIMER_QUEUE_TIMEOUT_H
|
||||
#define SLED_TIMER_QUEUE_TIMEOUT_H
|
||||
|
||||
#include "sled/task_queue/task_queue_base.h"
|
||||
#include "sled/timer/timeout.h"
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
namespace sled {
|
||||
typedef uint64_t TimeMs;
|
||||
|
||||
class TaskQueueTimeoutFactory {
|
||||
public:
|
||||
TaskQueueTimeoutFactory(
|
||||
sled::TaskQueueBase &task_queue,
|
||||
std::function<TimeMs()> get_time,
|
||||
std::function<void(TimeoutID timeout_id)> on_expired)
|
||||
: task_queue_(task_queue),
|
||||
get_time_(get_time),
|
||||
on_expired_(on_expired)
|
||||
{}
|
||||
|
||||
std::unique_ptr<Timeout>
|
||||
CreateTimeout(sled::TaskQueueBase::DelayPrecision precision =
|
||||
sled::TaskQueueBase::DelayPrecision::kHigh)
|
||||
{
|
||||
return std::unique_ptr<TaskQueueTimeout>(
|
||||
new TaskQueueTimeout(*this, precision));
|
||||
}
|
||||
|
||||
private:
|
||||
class TaskQueueTimeout : public Timeout {
|
||||
public:
|
||||
TaskQueueTimeout(TaskQueueTimeoutFactory &parent,
|
||||
sled::TaskQueueBase::DelayPrecision precision);
|
||||
~TaskQueueTimeout() override;
|
||||
void Start(DurationMs duration, TimeoutID timeout_id) override;
|
||||
void Stop() override;
|
||||
|
||||
private:
|
||||
TaskQueueTimeoutFactory &parent_;
|
||||
const sled::TaskQueueBase::DelayPrecision precision_;
|
||||
TimeMs posted_task_expiration_ = std::numeric_limits<TimeMs>::max();
|
||||
TimeMs timeout_expiration_ = std::numeric_limits<TimeMs>::max();
|
||||
TimeoutID timeout_id_ = TimeoutID(0);
|
||||
};
|
||||
|
||||
sled::TaskQueueBase &task_queue_;
|
||||
const std::function<TimeMs()> get_time_;
|
||||
const std::function<void(TimeoutID)> on_expired_;
|
||||
};
|
||||
}// namespace sled
|
||||
#endif// SLED_TIMER_QUEUE_TIMEOUT_H
|
25
include/sled/timer/timeout.h
Normal file
25
include/sled/timer/timeout.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#ifndef SLED_TIMER_TIMEOUT_H
|
||||
#define SLED_TIMER_TIMEOUT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace sled {
|
||||
typedef uint32_t DurationMs;
|
||||
typedef uint64_t TimeoutID;
|
||||
|
||||
class Timeout {
|
||||
public:
|
||||
virtual ~Timeout() = default;
|
||||
virtual void Start(DurationMs duration, TimeoutID timeout_id) = 0;
|
||||
virtual void Stop() = 0;
|
||||
|
||||
virtual void Restart(DurationMs duration, TimeoutID timeout_id)
|
||||
{
|
||||
Stop();
|
||||
Start(duration, timeout_id);
|
||||
}
|
||||
};
|
||||
}// namespace sled
|
||||
//
|
||||
#endif// SLED_TIMER_TIMEOUT_H
|
74
include/sled/timer/timer.h
Normal file
74
include/sled/timer/timer.h
Normal file
@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
#ifndef SLED_TIMER_TIMER_H
|
||||
#define SLED_TIMER_TIMER_H
|
||||
|
||||
#include "timeout.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <sled/optional.h>
|
||||
#include <sled/task_queue/task_queue_base.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace sled {
|
||||
typedef uint64_t TimerID;
|
||||
typedef uint32_t TimerGeneration;
|
||||
|
||||
class Timer {
|
||||
public:
|
||||
using OnExpired = std::function<sled::optional<DurationMs>()>;
|
||||
Timer(const Timer &) = delete;
|
||||
Timer &operator=(const Timer &) = delete;
|
||||
~Timer();
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
void set_duration(DurationMs duration) { duration_ = duration; }
|
||||
|
||||
const DurationMs &duration() const { return duration_; }
|
||||
|
||||
int expireation_count() const { return expiration_count_; }
|
||||
|
||||
bool is_running() const { return is_running_; }
|
||||
|
||||
private:
|
||||
friend class TimerManager;
|
||||
using UnregisterHandler = std::function<void()>;
|
||||
Timer(TimerID id,
|
||||
const std::string &name,
|
||||
OnExpired on_expired,
|
||||
UnregisterHandler unregister_handler,
|
||||
std::unique_ptr<Timeout> timeout);
|
||||
|
||||
const TimerID id_;
|
||||
const std::string name_;
|
||||
const OnExpired on_expired_;
|
||||
const UnregisterHandler unregister_handler_;
|
||||
std::unique_ptr<Timeout> timeout_;
|
||||
|
||||
DurationMs duration_;
|
||||
|
||||
TimerGeneration generation_ = TimerGeneration(0);
|
||||
bool is_running_ = false;
|
||||
int expiration_count_ = 0;
|
||||
};
|
||||
|
||||
class TimerManager {
|
||||
using TimeoutCreator = std::function<std::unique_ptr<Timeout>(
|
||||
sled::TaskQueueBase::DelayPrecision)>;
|
||||
|
||||
public:
|
||||
explicit TimerManager(TimeoutCreator timeout_creator)
|
||||
: timeout_creator_(timeout_creator)
|
||||
{}
|
||||
|
||||
std::unique_ptr<Timer> CreateTimer(const std::string &name,
|
||||
Timer::OnExpired on_expired);
|
||||
void HandleTimeout(TimeoutID timeout_id);
|
||||
|
||||
private:
|
||||
const TimeoutCreator timeout_creator_;
|
||||
std::map<TimerID, Timer *> timers_;
|
||||
TimerID next_id_ = TimerID(0);
|
||||
};
|
||||
}// namespace sled
|
||||
#endif// SLED_TIMER_TIMER_H
|
58
src/timer/task_queue_timeout.cc
Normal file
58
src/timer/task_queue_timeout.cc
Normal file
@ -0,0 +1,58 @@
|
||||
#include "sled/timer/task_queue_timeout.h"
|
||||
#include "sled/log/log.h"
|
||||
#include "sled/units/time_delta.h"
|
||||
|
||||
namespace sled {
|
||||
TaskQueueTimeoutFactory::TaskQueueTimeout::TaskQueueTimeout(
|
||||
TaskQueueTimeoutFactory &parent,
|
||||
sled::TaskQueueBase::DelayPrecision precision)
|
||||
: parent_(parent),
|
||||
precision_(precision)
|
||||
{}
|
||||
|
||||
TaskQueueTimeoutFactory::TaskQueueTimeout::~TaskQueueTimeout() {}
|
||||
|
||||
void
|
||||
TaskQueueTimeoutFactory::TaskQueueTimeout::Start(DurationMs duration_ms,
|
||||
TimeoutID timeout_id)
|
||||
{
|
||||
timeout_expiration_ = parent_.get_time_() + duration_ms;
|
||||
timeout_id_ = timeout_id;
|
||||
|
||||
if (timeout_expiration_ >= posted_task_expiration_) { return; }
|
||||
if (posted_task_expiration_ != std::numeric_limits<TimeMs>::max()) {
|
||||
LOGV("timer",
|
||||
"New timeout duration is less than scheduled - "
|
||||
"ghosting old delayed task");
|
||||
}
|
||||
|
||||
posted_task_expiration_ = timeout_expiration_;
|
||||
parent_.task_queue_.PostDelayedTaskWithPrecision(
|
||||
precision_,
|
||||
[timeout_id, this]() {
|
||||
posted_task_expiration_ = std::numeric_limits<TimeMs>::max();
|
||||
if (timeout_expiration_ == std::numeric_limits<TimeMs>::max()) {
|
||||
// cancelled timer
|
||||
// do nothing
|
||||
} else {
|
||||
DurationMs remaining =
|
||||
timeout_expiration_ - parent_.get_time_();
|
||||
timeout_expiration_ = std::numeric_limits<TimeMs>::max();
|
||||
if (remaining > 0) {
|
||||
Start(remaining, timeout_id);
|
||||
} else {
|
||||
LOGD("", "Timeout Triggered: {}", timeout_id);
|
||||
parent_.on_expired_(timeout_id_);
|
||||
}
|
||||
}
|
||||
},
|
||||
sled::TimeDelta::Millis(duration_ms));
|
||||
}
|
||||
|
||||
void
|
||||
TaskQueueTimeoutFactory::TaskQueueTimeout::Stop()
|
||||
{
|
||||
timeout_expiration_ = std::numeric_limits<TimeMs>::max();
|
||||
}
|
||||
|
||||
}// namespace sled
|
60
src/timer/timer.cc
Normal file
60
src/timer/timer.cc
Normal file
@ -0,0 +1,60 @@
|
||||
#include "sled/timer/timer.h"
|
||||
|
||||
namespace sled {
|
||||
namespace {
|
||||
TimeoutID
|
||||
MakeTimeoutId(TimerID timer_id, TimerGeneration generation)
|
||||
{
|
||||
return TimeoutID(static_cast<uint64_t>((timer_id << 32) | generation));
|
||||
}
|
||||
}// namespace
|
||||
|
||||
Timer::Timer(TimerID id,
|
||||
const std::string &name,
|
||||
OnExpired on_expired,
|
||||
UnregisterHandler unregister_handler,
|
||||
std::unique_ptr<Timeout> timeout)
|
||||
: id_(id),
|
||||
name_(name),
|
||||
on_expired_(on_expired),
|
||||
unregister_handler_(unregister_handler),
|
||||
timeout_(std::move(timeout))
|
||||
{}
|
||||
|
||||
Timer::~Timer()
|
||||
{
|
||||
Stop();
|
||||
unregister_handler_();
|
||||
}
|
||||
|
||||
void
|
||||
Timer::Start()
|
||||
{
|
||||
expiration_count_ = 0;
|
||||
|
||||
if (!is_running()) {
|
||||
is_running_ = true;
|
||||
generation_ = TimerGeneration(generation_ + 1);
|
||||
timeout_->Start(duration_, MakeTimeoutId(id_, generation_));
|
||||
} else {
|
||||
generation_ = TimerGeneration(generation_ + 1);
|
||||
timeout_->Restart(duration_, MakeTimeoutId(id_, generation_));
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Timer>
|
||||
TimerManager::CreateTimer(const std::string &name, Timer::OnExpired on_expired)
|
||||
{
|
||||
next_id_ = TimerID(next_id_ + 1);
|
||||
TimerID id = next_id_;
|
||||
|
||||
std::unique_ptr<Timeout> timeout =
|
||||
timeout_creator_(sled::TaskQueueBase::DelayPrecision::kHigh);
|
||||
auto timer = std::unique_ptr<Timer>(new Timer(
|
||||
id, name, std::move(on_expired),
|
||||
/* ungrgister_handler=*/[this, id]() { timers_.erase(id); },
|
||||
std::move(timeout)));
|
||||
timers_[id] = timer.get();
|
||||
return timer;
|
||||
}
|
||||
}// namespace sled
|
Loading…
x
Reference in New Issue
Block a user