From 4ce247a7a34fd3e16e0a4d5412b4bb795ed28b88 Mon Sep 17 00:00:00 2001 From: aozhiwei Date: Sat, 13 Apr 2019 14:01:21 +0800 Subject: [PATCH] add xtimer --- a8/xtimer.cc | 352 +++++++++++++++++++++++++++++++++++++++++++++++++++ a8/xtimer.h | 60 +++++++++ 2 files changed, 412 insertions(+) create mode 100644 a8/xtimer.cc create mode 100644 a8/xtimer.h diff --git a/a8/xtimer.cc b/a8/xtimer.cc new file mode 100644 index 0000000..824cc82 --- /dev/null +++ b/a8/xtimer.cc @@ -0,0 +1,352 @@ +#include + +#include + +#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; + base_->timer_tick = get_tick_count_func_(context_); + 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; + 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; + } + + 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->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; + } + } + + 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); + } + 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++; + } + } + +} diff --git a/a8/xtimer.h b/a8/xtimer.h new file mode 100644 index 0000000..f398f74 --- /dev/null +++ b/a8/xtimer.h @@ -0,0 +1,60 @@ +/* + * 仿照linux2.6内核定时器实现 + */ +#ifndef A8_XTIMER_H +#define A8_XTIMER_H + +struct xtimer_list; +struct xtvec_base; + +namespace a8 +{ + typedef void (*XTimerFunc)(const a8::XParams& param); + typedef void (*XTimerAfterFunc)(const a8::XParams& param); + typedef long long (*XGetTickCountFunc)(void*); + + class XTimer + { + private: + XTimer(); + ~XTimer(); + + public: + void Init(XGetTickCountFunc func, void* context, int gc_time, int cache_timer_num); + + void Update(); + + //添加截止时间定时器(一次性定时器) + xtimer_list* AddDeadLineTimer(int expire_time, a8::XParams param, a8::XTimerFunc timer_func, + a8::XTimerAfterFunc timer_after_func = nullptr); + xtimer_list* AddDeadLineTimerAndAttach(int expire_time, a8::XParams, + a8::XTimerFunc timer_func, + list_head* attach_list, + a8::XTimerAfterFunc timer_after_func = nullptr); + //添加重复执行定时器(周期性定时器) + xtimer_list* AddRepeatTimer(int expire_time, a8::XParams param, a8::XTimerFunc timer_func); + //修改定时器参数 + void ModifyTimer(xtimer_list* timer, int expire_time); + //删除定时器 + void DeleteTimer(xtimer_list* timer); + //通过关联的list_head获取定时器对象 + xtimer_list* GetTimerByAttach(list_head* attach_entry); + + private: + void UpdateTimer(); + xtimer_list* NewTimerList(); + void AddToFreeList(xtimer_list* timer); + void Clear(); + static void GC_XTimerFunc(const a8::XParams& param); + + private: + xtvec_base* base_ = nullptr; + XGetTickCountFunc get_tick_count_func_ = nullptr; + void* context_ = nullptr; + int gc_time_ = 10; + int cache_timer_num_ = 100; + }; + +} + +#endif