a8/a8/xtimer.cc
2019-10-08 14:04:04 +08:00

393 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <a8/a8.h>
#include <a8/xtimer.h>
#define CONFIG_BASE_SMALL 0
#define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6)
#define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 8)
#define TVN_SIZE (1 << TVN_BITS)
#define TVR_SIZE (1 << TVR_BITS)
#define TVN_MASK (TVN_SIZE - 1)
#define TVR_MASK (TVR_SIZE - 1)
#define INDEX(N) ((base->timer_tick >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK)
struct xtvec {
struct list_head vec[TVN_SIZE];
};
struct xtvec_root {
struct list_head vec[TVR_SIZE];
};
struct xtvec_base {
struct xtimer_list *running_timer;
long long timer_tick;
list_head free_timer;
int free_timer_num;
struct xtvec_root tv1;
struct xtvec tv2;
struct xtvec tv3;
struct xtvec tv4;
struct xtvec tv5;
};
struct xtimer_list {
struct list_head entry;
struct list_head attach_entry;
int timer_type; // 0:deadline 1: repeattimer 2:fixedtimer outher:deadline
long long expires;
int expire_time;
int fixed_timer_execute_times;
struct xtvec_base *base;
a8::XTimerFunc timer_func;
a8::XTimerAfterFunc timer_after_func;
a8::XParams param;
};
static void InternalAddXTimer(struct xtvec_base *base, struct xtimer_list *timer)
{
long long expires = timer->expires;
long long idx = expires - base->timer_tick;
struct list_head *vec;
if (idx < 0) {
vec = base->tv1.vec + (base->timer_tick & TVR_MASK);
}else if (idx < TVR_SIZE) {
int i = expires & TVR_MASK;
vec = base->tv1.vec + i;
} else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
int i = (expires >> TVR_BITS) & TVN_MASK;
vec = base->tv2.vec + i;
} else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
vec = base->tv3.vec + i;
} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
vec = base->tv4.vec + i;
} else {
int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
vec = base->tv5.vec + i;
}
list_add_tail(&timer->entry, vec);
}
static int Cascade(struct xtvec_base *base, struct xtvec *tv, int index)
{
/* cascade all the timers from tv up one level */
struct xtimer_list *timer, *tmp;
struct list_head tv_list;
// 将tv数组中以index为下标的定时器队列取出准备搬移
list_replace_init(tv->vec + index, &tv_list);
// 根据超时时间,将队列中的定时器重新排队。定时器往上一级时间轮排队的过程就 // 在这里发生。
list_for_each_entry_safe(timer, tmp, &tv_list, entry) {
InternalAddXTimer(base, timer);
}
return index;
}
static inline int DetachTimer(struct xtimer_list *timer)
{
if (!list_empty(&timer->entry)) {
list_del_init(&timer->entry);
}
return 1;
}
static inline void InitTimerList(xtvec_base* base, xtimer_list* timer, int timer_type,
long long expires, int expire_time, a8::XParams& param,
a8::XTimerFunc timer_func, a8::XTimerAfterFunc timer_after_func)
{
INIT_LIST_HEAD(&timer->entry);
INIT_LIST_HEAD(&timer->attach_entry);
timer->timer_type = timer_type;
timer->expires = expires;
timer->expire_time = expire_time;
timer->fixed_timer_execute_times = 0;
timer->base = base;
timer->timer_func = timer_func;
timer->timer_after_func = timer_after_func;
timer->param = param;
}
namespace a8
{
XTimer::XTimer()
{
base_ = new xtvec_base();
base_->running_timer = nullptr;
INIT_LIST_HEAD(&base_->free_timer);
base_->free_timer_num = 0;
for (int j = 0; j < TVN_SIZE; j++) {
INIT_LIST_HEAD(base_->tv5.vec + j);
INIT_LIST_HEAD(base_->tv4.vec + j);
INIT_LIST_HEAD(base_->tv3.vec + j);
INIT_LIST_HEAD(base_->tv2.vec + j);
}
for (int j = 0; j < TVR_SIZE; j++) {
INIT_LIST_HEAD(base_->tv1.vec + j);
}
}
XTimer::~XTimer()
{
Clear();
delete base_;
base_ = nullptr;
}
void XTimer::Init(XGetTickCountFunc func, void* context, int gc_time, int cache_timer_num)
{
get_tick_count_func_ = func;
context_ = context;
gc_time_ = gc_time;
cache_timer_num_ = cache_timer_num;
#if 1
base_->timer_tick = get_tick_count_func_(context_);
#endif
AddRepeatTimer(gc_time_,
a8::XParams().SetSender(this),
&XTimer::GC_XTimerFunc);
}
void XTimer::Update()
{
if (get_tick_count_func_(context_) >= base_->timer_tick) {
UpdateTimer();
}
}
xtimer_list* XTimer::AddDeadLineTimer(int expire_time, a8::XParams param, a8::XTimerFunc timer_func,
a8::XTimerAfterFunc timer_after_func)
{
xtimer_list *timer = NewTimerList();
InitTimerList(base_,
timer,
0,
get_tick_count_func_(context_) + expire_time,
expire_time,
param,
timer_func,
timer_after_func);
ModifyTimer(timer, expire_time);
return timer;
}
xtimer_list* XTimer::AddDeadLineTimerAndAttach(int expire_time, a8::XParams param, a8::XTimerFunc timer_func,
list_head* attach_list, a8::XTimerAfterFunc timer_after_func)
{
xtimer_list* timer = AddDeadLineTimer(expire_time, param, timer_func, timer_after_func);
list_add_tail(&timer->attach_entry, attach_list);
return timer;
}
xtimer_list* XTimer::AddRepeatTimer(int expire_time, a8::XParams param, a8::XTimerFunc timer_func)
{
xtimer_list *timer = NewTimerList();
InitTimerList(base_,
timer,
1,
get_tick_count_func_(context_) + expire_time,
expire_time,
param,
timer_func,
nullptr);
ModifyTimer(timer, expire_time);
return timer;
}
xtimer_list* XTimer::AddRepeatTimerAndAttach(int expire_time, a8::XParams param, a8::XTimerFunc timer_func,
list_head* attach_list)
{
xtimer_list* timer = AddRepeatTimer(expire_time, param, timer_func);
list_add_tail(&timer->attach_entry, attach_list);
return timer;
}
void XTimer::ModifyTimer(xtimer_list* timer, int expire_time)
{
DetachTimer(timer);
timer->expire_time = expire_time;
if (timer->timer_type == 2) {
long long tick = get_tick_count_func_(context_);
long long today_passed_seconds = time(nullptr) - a8::GetDaySeconds(time(nullptr), 0);
timer->expires = (tick - today_passed_seconds * 1000) + expire_time;
if (timer->fixed_timer_execute_times > 0) {
if (timer->expires <= tick) { //已过期
timer->expires += 1000 * 3600 * 24;
}
}
}else {
timer->expires = get_tick_count_func_(context_) + expire_time;
}
InternalAddXTimer(base_, timer);
}
void XTimer::DeleteTimer(xtimer_list* timer)
{
if (!timer) {
abort();
}
if (base_->running_timer == timer) {
base_->running_timer = nullptr;
}
if (timer->timer_after_func) {
timer->timer_after_func(timer->param);
}
DetachTimer(timer);
if (!list_empty(&timer->attach_entry)) {
list_del_init(&timer->attach_entry);
}
AddToFreeList(timer);
}
xtimer_list* XTimer::GetTimerByAttach(list_head* attach_entry)
{
if (attach_entry) {
xtimer_list* timer = list_entry(attach_entry, struct xtimer_list, attach_entry);
return timer;
} else {
return nullptr;
}
}
a8::XParams* XTimer::MutableParams(xtimer_list* timer)
{
if (!timer) {
abort();
}
return &timer->param;
}
long long XTimer::GetRemainTime(xtimer_list* timer)
{
if (!timer) {
abort();
}
long long remain_time = get_tick_count_func_(context_) - timer->expires;
return std::max(remain_time, (long long)0);
}
xtimer_list* XTimer::GetRunningTimer()
{
return base_->running_timer;
}
void XTimer::UpdateTimer()
{
struct xtvec_base *base = base_;
while (get_tick_count_func_(context_) >= base->timer_tick) {
struct list_head work_list;
struct list_head *head = &work_list;
int index = base->timer_tick & TVR_MASK;
if (!index &&
(!Cascade(base, &base->tv2, INDEX(0))) &&
(!Cascade(base, &base->tv3, INDEX(1))) &&
!Cascade(base, &base->tv4, INDEX(2))) {
Cascade(base, &base->tv5, INDEX(3));
}
++base->timer_tick;
list_replace_init(base->tv1.vec + index, &work_list);
while (!list_empty(head)) {
struct xtimer_list *timer;
timer = list_first_entry(head, struct xtimer_list,entry);
base->running_timer = timer;
if (timer->timer_func) {
timer->timer_func(timer->param);
}
if (timer->timer_after_func) {
timer->timer_after_func(timer->param);
}
if (base_->running_timer) {
switch (timer->timer_type) {
case 1:
case 2: //循环类定时 fixed timer也是循环定时器
{
if (timer->timer_type == 2) {
timer->fixed_timer_execute_times++;
}
ModifyTimer(timer, timer->expire_time);
}
break;
default: //deadline timer
{
DetachTimer(timer);
if (!list_empty(&timer->attach_entry)) {
list_del_init(&timer->attach_entry);
}
AddToFreeList(timer);
}
break;
}
}
}
}
base->running_timer = nullptr;
}
xtimer_list* XTimer::NewTimerList()
{
if (!list_empty(&base_->free_timer)) {
xtimer_list* timer = list_first_entry(&base_->free_timer, struct xtimer_list,entry);
list_del_init(&timer->entry);
base_->free_timer_num--;
return timer;
} else {
return new xtimer_list();
}
}
void XTimer::AddToFreeList(xtimer_list* timer)
{
list_add_tail(&timer->entry, &base_->free_timer);
base_->free_timer_num++;
}
void XTimer::Clear()
{
auto free_timers =
[] (list_head* head)
{
while (!list_empty(head)) {
struct xtimer_list *timer;
timer = list_first_entry(head, struct xtimer_list,entry);
DetachTimer(timer);
if (!list_empty(&timer->attach_entry)) {
list_del_init(&timer->attach_entry);
}
delete timer;
}
};
for (int j = 0; j < TVN_SIZE; j++) {
free_timers(base_->tv5.vec + j);
free_timers(base_->tv4.vec + j);
free_timers(base_->tv3.vec + j);
free_timers(base_->tv2.vec + j);
}
for (int j = 0; j < TVR_SIZE; j++) {
free_timers(base_->tv1.vec + j);
}
free_timers(&base_->free_timer);
}
void XTimer::GC_XTimerFunc(const a8::XParams& param)
{
XTimer* timer = (XTimer*)param.sender.GetUserData();
int i = 0;
while (!list_empty(&timer->base_->free_timer) &&
timer->base_->free_timer_num > timer->cache_timer_num_ && i < 1000) {
xtimer_list* timer1 = list_first_entry(&timer->base_->free_timer, struct xtimer_list, entry);
list_del_init(&timer1->entry);
delete timer1;
timer->base_->free_timer_num--;
i++;
}
}
}