lokinet/llarp/timer.cpp

218 lines
3.9 KiB
C++
Raw Normal View History

2018-04-30 18:18:18 +00:00
#include <llarp/timer.h>
#include <atomic>
2018-04-30 18:18:34 +00:00
#include <condition_variable>
2018-04-30 18:18:18 +00:00
#include <list>
2018-04-30 18:18:34 +00:00
#include <map>
2018-04-30 18:18:18 +00:00
namespace llarp
{
struct timer
{
static uint64_t
now()
{
return std::chrono::duration_cast< std::chrono::milliseconds >(
std::chrono::steady_clock::now().time_since_epoch())
.count();
}
2018-04-30 18:18:34 +00:00
llarp_timer_context* parent;
void* user;
uint64_t started;
uint64_t timeout;
llarp_timer_handler_func func;
uint32_t id;
timer(llarp_timer_context* ctx = nullptr, uint64_t ms = 0,
void* _user = nullptr, llarp_timer_handler_func _func = nullptr,
uint32_t _id = 0)
: parent(ctx)
, user(_user)
, started(now())
, timeout(ms)
, func(_func)
, id(_id)
{
}
2018-04-30 18:18:34 +00:00
void
exec();
2018-05-18 17:50:21 +00:00
static void
call(void* user)
{
static_cast< timer* >(user)->exec();
}
2018-05-18 17:50:21 +00:00
operator llarp_thread_job()
{
return {this, timer::call};
}
};
2018-04-30 18:18:34 +00:00
}; // namespace llarp
2018-04-30 18:18:18 +00:00
struct llarp_timer_context
{
llarp_threadpool* threadpool;
2018-04-30 18:18:18 +00:00
std::mutex timersMutex;
std::map< uint32_t, llarp::timer > timers;
2018-04-30 18:18:18 +00:00
std::mutex tickerMutex;
std::condition_variable ticker;
2018-05-18 17:50:21 +00:00
std::chrono::milliseconds nextTickLen = std::chrono::milliseconds(10);
2018-04-30 18:18:18 +00:00
uint32_t ids = 0;
std::atomic< bool > _run = true;
2018-04-30 18:18:18 +00:00
bool
run()
{
return _run.load();
}
2018-04-30 18:18:34 +00:00
void
stop()
{
_run.store(false);
}
2018-04-30 18:18:18 +00:00
void
cancel(uint32_t id, bool lockit = true)
{
std::unique_lock< std::mutex >* lock = nullptr;
if(lockit)
lock = new std::unique_lock< std::mutex >(timersMutex);
2018-04-30 18:18:18 +00:00
auto itr = timers.find(id);
if(itr != timers.end())
{
2018-05-18 17:50:21 +00:00
itr->second.exec();
2018-04-30 18:18:18 +00:00
}
2018-04-30 18:18:34 +00:00
if(lock)
delete lock;
2018-04-30 18:18:18 +00:00
}
void
remove(uint32_t id)
2018-05-18 17:50:21 +00:00
{
std::unique_lock< std::mutex > lock(timersMutex);
2018-05-18 17:50:21 +00:00
timers.erase(id);
}
uint32_t
call_later(void* user, llarp_timer_handler_func func, uint64_t timeout_ms)
{
std::unique_lock< std::mutex > lock(timersMutex);
2018-05-10 23:32:46 +00:00
uint32_t id = ++ids;
timers[id] = llarp::timer(this, timeout_ms, user, func, id);
2018-04-30 18:18:18 +00:00
return id;
}
2018-04-30 18:18:34 +00:00
void
cancel_all()
{
std::unique_lock< std::mutex > lock(timersMutex);
2018-04-30 18:18:34 +00:00
std::list< uint32_t > ids;
2018-04-30 18:18:34 +00:00
for(auto& item : timers)
{
2018-04-30 18:18:18 +00:00
ids.push_back(item.first);
}
2018-04-30 18:18:34 +00:00
for(auto id : ids)
{
2018-04-30 18:18:18 +00:00
cancel(id, false);
}
}
};
extern "C" {
struct llarp_timer_context*
llarp_init_timer()
{
2018-04-30 18:18:34 +00:00
return new llarp_timer_context;
}
2018-04-30 18:18:18 +00:00
uint32_t
llarp_timer_call_later(struct llarp_timer_context* t,
struct llarp_timeout_job job)
{
2018-04-30 18:18:34 +00:00
return t->call_later(job.user, job.handler, job.timeout);
}
2018-04-30 18:18:18 +00:00
void
llarp_free_timer(struct llarp_timer_context** t)
{
if(*t)
delete *t;
2018-04-30 18:18:34 +00:00
*t = nullptr;
}
2018-04-30 18:18:18 +00:00
void
llarp_timer_stop(struct llarp_timer_context* t)
{
2018-04-30 18:18:34 +00:00
t->stop();
2018-05-18 18:27:13 +00:00
{
std::unique_lock< std::mutex > lock(t->tickerMutex);
2018-05-18 18:27:13 +00:00
auto itr = t->timers.begin();
while(itr != t->timers.end())
2018-05-18 18:27:13 +00:00
{
// timer expired
llarp_threadpool_queue_job(t->threadpool, itr->second);
++itr;
}
}
2018-04-30 18:18:34 +00:00
}
2018-04-30 18:18:18 +00:00
void
llarp_timer_cancel(struct llarp_timer_context* t, uint32_t id)
{
2018-04-30 18:18:34 +00:00
t->cancel(id);
}
2018-04-30 18:18:18 +00:00
void
llarp_timer_run(struct llarp_timer_context* t, struct llarp_threadpool* pool)
{
2018-05-18 17:50:21 +00:00
t->threadpool = pool;
while(t->run())
{
std::unique_lock< std::mutex > lock(t->tickerMutex);
2018-05-18 17:50:21 +00:00
t->ticker.wait_for(lock, t->nextTickLen);
// we woke up
auto now = llarp::timer::now();
auto itr = t->timers.begin();
while(itr != t->timers.end())
2018-05-18 17:50:21 +00:00
{
if(now - itr->second.started >= itr->second.timeout)
{
// timer hit
llarp_threadpool_queue_job(pool, itr->second);
}
2018-05-18 18:27:13 +00:00
++itr;
2018-04-30 18:18:18 +00:00
}
}
}
2018-04-30 18:18:34 +00:00
}
2018-05-18 17:50:21 +00:00
namespace llarp
{
void
timer::exec()
2018-05-18 17:50:21 +00:00
{
if(func)
{
auto ms = now();
2018-05-18 17:50:21 +00:00
auto diff = ms - started;
if(diff >= timeout)
2018-05-18 17:50:21 +00:00
func(user, timeout, 0);
else
func(user, timeout, diff);
}
if(parent)
parent->remove(id);
}
}