feat add timer
This commit is contained in:
parent
f6b9cc5aee
commit
b94e31983b
@ -49,6 +49,8 @@ target_sources(
|
|||||||
src/system/thread.cc
|
src/system/thread.cc
|
||||||
src/task_queue/pending_task_safety_flag.cc
|
src/task_queue/pending_task_safety_flag.cc
|
||||||
src/task_queue/task_queue_base.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/time_delta.cc
|
||||||
src/units/timestamp.cc
|
src/units/timestamp.cc
|
||||||
src/operations_chain.cc
|
src/operations_chain.cc
|
||||||
|
@ -53,6 +53,22 @@ public:
|
|||||||
PostDelayedTaskImpl(std::move(task), delay, traits, location);
|
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();
|
static TaskQueueBase *Current();
|
||||||
|
|
||||||
bool IsCurrent() const { return Current() == this; };
|
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…
Reference in New Issue
Block a user