a8/a8/timer.cc
aozhiwei cdb87a3e67 1
2019-12-11 14:51:07 +08:00

413 lines
13 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/timer.h>
#if 0
const int g_time_zone = 8; // 默认东八区
static time_t GetDaySeconds(time_t time, int incdays = 0)
{
return time_t((time + g_time_zone * 3600)/3600/24 + incdays) * 3600 * 24 - 3600 * g_time_zone;
}
#endif
#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 tvec {
struct list_head vec[TVN_SIZE];
};
struct tvec_root {
struct list_head vec[TVR_SIZE];
};
struct tvec_base {
struct timer_list *running_timer;
long long timer_tick;
list_head free_timer;
int free_timer_num;
struct tvec_root tv1;
struct tvec tv2;
struct tvec tv3;
struct tvec tv4;
struct tvec tv5;
};
struct timer_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 milli_seconds;
int fixed_timer_execute_times;
struct tvec_base *base;
a8::TimerFunc timer_func;
a8::TimerAfterFunc timer_after_func;
a8::XParams param;
};
static void InternalAddTimer(struct tvec_base *base, struct timer_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 tvec_base *base, struct tvec *tv, int index)
{
/* cascade all the timers from tv up one level */
struct timer_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) {
InternalAddTimer(base, timer);
}
return index;
}
static inline int DetachTimer(struct timer_list *timer)
{
if (!list_empty(&timer->entry)) {
list_del_init(&timer->entry);
}
return 1;
}
static inline void InitTimerList(tvec_base* base, timer_list* timer, int timer_type,
int milli_seconds, a8::XParams& param,
a8::TimerFunc timer_func, a8::TimerAfterFunc timer_after_func)
{
INIT_LIST_HEAD(&timer->entry);
INIT_LIST_HEAD(&timer->attach_entry);
timer->timer_type = timer_type;
timer->expires = a8::XGetTickCount() + milli_seconds;
timer->milli_seconds = milli_seconds;
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
{
void Timer::Init()
{
base_ = new tvec_base();
base_->running_timer = nullptr;
base_->timer_tick = a8::XGetTickCount();
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);
}
AddRepeatTimer(1000 * 60 * 5,
a8::XParams().SetSender(this),
&Timer::GC_TimerFunc);
}
void Timer::UnInit()
{
Clear();
delete base_;
base_ = nullptr;
}
void Timer::Update()
{
#ifdef MONITOR
long long start_ns_tick = XGetNanoSeconds();
#endif
if (a8::XGetTickCount() >= base_->timer_tick) {
UpdateTimer();
}
#ifdef MONITOR
long long end_ns_tick = XGetNanoSeconds();
if (end_ns_tick - start_ns_tick > g_monitor->timer_max_ns) {
g_monitor->timer_max_ns = end_ns_tick - start_ns_tick;
}
#endif
}
timer_list* Timer::AddDeadLineTimer(int milli_seconds, a8::XParams param, a8::TimerFunc timer_func,
a8::TimerAfterFunc timer_after_func)
{
timer_list *timer = NewTimerList();
InitTimerList(base_, timer, 0, milli_seconds, param, timer_func, timer_after_func);
ModifyTimer(timer, milli_seconds);
return timer;
}
timer_list* Timer::AddDeadLineTimerAndAttach(int milli_seconds, a8::XParams param, a8::TimerFunc timer_func,
list_head* attach_list, a8::TimerAfterFunc timer_after_func)
{
timer_list* timer = AddDeadLineTimer(milli_seconds, param, timer_func, timer_after_func);
list_add_tail(&timer->attach_entry, attach_list);
return timer;
}
timer_list* Timer::AddRepeatTimer(int milli_seconds, a8::XParams param, a8::TimerFunc timer_func)
{
timer_list *timer = NewTimerList();
InitTimerList(base_, timer, 1, milli_seconds, param, timer_func, nullptr);
ModifyTimer(timer, milli_seconds);
return timer;
}
timer_list* Timer::AddFixedTimer(int milli_seconds, a8::XParams param, a8::TimerFunc timer_func)
{
timer_list *timer = NewTimerList();
InitTimerList(base_, timer, 2, milli_seconds, param, timer_func, nullptr);
ModifyTimer(timer, milli_seconds);
return timer;
}
void Timer::ModifyTimer(timer_list* timer, int milli_seconds)
{
DetachTimer(timer);
timer->milli_seconds = milli_seconds;
if (timer->timer_type == 2) {
long long tick = a8::XGetTickCount();
long long today_passed_seconds = time(nullptr) - a8::GetDaySeconds(time(nullptr), 0);
timer->expires = (tick - today_passed_seconds * 1000) + milli_seconds;
if (timer->fixed_timer_execute_times > 0) {
if (timer->expires <= tick) { //已过期
timer->expires += 1000 * 3600 * 24;
}
}
}else {
timer->expires = a8::XGetTickCount() + milli_seconds;
}
InternalAddTimer(base_, timer);
}
void Timer::DeleteTimer(timer_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);
}
timer_list* Timer::GetTimerByAttach(list_head* attach_entry)
{
if (attach_entry) {
timer_list* timer = list_entry(attach_entry, struct timer_list, attach_entry);
return timer;
} else {
return nullptr;
}
}
a8::XParams* Timer::MutableParams(timer_list* timer)
{
if (!timer) {
abort();
}
return &timer->param;
}
void Timer::RemoveTimerAfterFunc(timer_list* timer)
{
if (!timer) {
abort();
}
timer->timer_after_func = nullptr;
}
long long Timer::GetRemainTime(timer_list* timer)
{
if (!timer) {
abort();
}
long long remain_time = timer->expires - a8::XGetTickCount();
return std::max(remain_time, (long long)0);
}
timer_list* Timer::GetRunningTimer()
{
return base_->running_timer;
}
int Timer::GetIdleableMillSeconds()
{
#if 0
struct tvec_base *base = base_;
#endif
int idle_time = 1;
for (int lv1_idx = base_->timer_tick & TVR_MASK; lv1_idx < TVR_SIZE; ++lv1_idx) {
if (!list_empty(base_->tv1.vec + lv1_idx)) {
return idle_time <= 1 ? 1 : idle_time - 1;
}
++idle_time;
}
#if 0
for (int lv2_idx = INDEX(0); lv2_idx < TVN_SIZE; ++lv2_idx) {
if (!list_empty(base_->tv2.vec + lv2_idx)) {
return idle_time;
}
idle_time += TVR_SIZE;
}
#endif
return idle_time <= 1 ? 1 : idle_time - 1;
}
void Timer::UpdateTimer()
{
struct tvec_base *base = base_;
while (a8::XGetTickCount() >= 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 timer_list *timer;
timer = list_first_entry(head, struct timer_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->milli_seconds);
}
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;
}
timer_list* Timer::NewTimerList()
{
if (!list_empty(&base_->free_timer)) {
timer_list* timer = list_first_entry(&base_->free_timer, struct timer_list,entry);
list_del_init(&timer->entry);
base_->free_timer_num--;
return timer;
} else {
return new timer_list();
}
}
void Timer::AddToFreeList(timer_list* timer)
{
list_add_tail(&timer->entry, &base_->free_timer);
base_->free_timer_num++;
}
void Timer::Clear()
{
auto free_timers =
[] (list_head* head)
{
while (!list_empty(head)) {
struct timer_list *timer;
timer = list_first_entry(head, struct timer_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 Timer::GC_TimerFunc(const a8::XParams& param)
{
Timer* timer = (Timer*)param.sender.GetUserData();
int i = 0;
while (!list_empty(&timer->base_->free_timer) &&
timer->base_->free_timer_num > 1000 && i < 1000) {
timer_list* timer1 = list_first_entry(&timer->base_->free_timer, struct timer_list, entry);
list_del_init(&timer1->entry);
delete timer1;
timer->base_->free_timer_num--;
i++;
}
}
}