首页 > 代码库 > Swoole源码学习记录(十五)——Timer模块分析
Swoole源码学习记录(十五)——Timer模块分析
swoole版本:1.7.7-stable Github地址:点此查看
1.Timer
1.1.swTimer_interval_node
声明:
// swoole.h 1045-1050h typedef struct _swTimer_interval_node { struct _swTimerList_node *next, *prev; struct timeval lasttime; uint32_t interval; } swTimer_interval_node;
成员 | 说明 |
---|---|
next,prev | 链表的后继、前驱指针 |
struct timeval lasttime | 持续时间 |
uint32_t interval | 间隔时间 |
说明:
swTimer_interval_node结构体是一个链表节点,存放一个固定间隔的定时器,其中lasttime为当前定时器从上一次执行到现在经过的时间,interval存放了定时器间隔。
该结构体用于swoole原本的timer相关操作。
1.2.swTimer_node
声明:
// swoole.h 1052-1058h typedef struct _swTimer_node { struct _swTimer_node *next, *prev; void *data; uint32_t exec_msec; uint32_t interval; } swTimer_node;
成员 | 说明 |
---|---|
next,prev | 链表的后继、前驱指针 |
void *data | 数据域,存放额外的变量 |
uint32_t exec_msec | 定时器应当执行的时间 |
uint32_t interval | 间隔时间(无用,应废弃) |
说明:
swTimer_node结构体是一个链表节点,存放一个需要在指定时间执行的定时器,其中exec_msec为当前定时器需要执行的指定时间,interval存放了定时器间隔。
该结构体用于swoole的after函数操作。
1.3.swTimer
声明:
// swoole.h 1060-1081h typedef struct _swTimer { swTimer_node *root; /*--------------timerfd & signal timer--------------*/ swHashMap *list; int num; int interval; int use_pipe; int lasttime; int fd; swPipe pipe; /*-----------------for EventTimer-------------------*/ struct timeval basetime; /*--------------------------------------------------*/ int (*add)(struct _swTimer *timer, int _msec, int _interval, void *data); int (*del)(struct _swTimer *timer, int _interval_ms); int (*select)(struct _swTimer *timer); void (*free)(struct _swTimer *timer); /*-----------------event callback-------------------*/ void (*onTimer)(struct _swTimer *timer, int interval_msec); void (*onTimeout)(struct _swTimer *timer, void *data); } swTimer;
成员 | 说明 |
---|---|
swTimer_node *root | after的链表根节点 |
swHashMap *list | timer的链表根节点 |
int num | 当前定时器的数量 |
int interval | 定时器的基础响应间隔 |
int use_pipe | 是否使用管道通信 |
int lasttime | 持续时间(已废弃) |
int fd | 管道的写fd |
swPipe pipe | 管道 |
struct timeval basetime | EventTimer的基础时间 |
说明:
swTimer结构体定时器的实体对象,用于存储、管理和执行众多定时任务,包括timer和after两种不同类型的定时任务。
1.4.swTimer公共操作函数
1.4.1.swTimer_init
声明:
// swoole.h 1083 int swTimer_init(int interval_ms, int no_pipe);
功能:初始化一个swTimer对象
核心源码:
// timer.c 38-94h swTimer *timer = &SwooleG.timer; timer->interval = interval; timer->lasttime = interval; #ifndef HAVE_TIMERFD SwooleG.use_timerfd = 0; #endif timer->list = swHashMap_new(SW_HASHMAP_INIT_BUCKET_N, free); if (!timer->list) { return SW_ERR; } if (SwooleG.use_timerfd) { if (swTimer_timerfd_set(timer, interval) < 0) { return SW_ERR; } timer->use_pipe = 0; } else { if (use_pipe) { if (swPipeNotify_auto(&timer->pipe, 0, 0) < 0) { return SW_ERR; } timer->fd = timer->pipe.getFd(&timer->pipe, 0); timer->use_pipe = 1; } else { timer->fd = 1; timer->use_pipe = 0; } if (swTimer_signal_set(timer, interval) < 0) { return SW_ERR; } swSignal_add(SIGALRM, swTimer_signal_handler); } if (timer->fd > 1) { SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_TIMER, swTimer_event_handler); SwooleG.main_reactor->add(SwooleG.main_reactor, SwooleG.timer.fd, SW_FD_TIMER); } timer->add = swTimer_add; timer->del = swTimer_del; timer->select = swTimer_select; timer->free = swTimer_free;
源码解释:
获取SwooleG中的timer对象,设置timer响应间隔和lasttime参数。如果没有定义HAVE_TIMERFD,则设置不使用timerfd。随后,使用HashMap初始化timer链表list。
如果使用了timerfd,调用swTimer_timerfd_set函数设置timer的基础响应间隔,并设置不使用管道。
如果不使用timerfd而使用signalfd,则先判定是否需要管道,如果需要,则创建管道并获取管道的写fd。随后,调用swTimer_signal_set函数设置Linux系统提供的精确定时器,并通过swSignal_add添加对SIGALRM信号的处理回调函数swTimer_signal_handler。
接着,将管道写fd加入main_reactor的监听中,并设置回调函数swTimer_event_handler。
最后设置swTimer的四个回调操作函数。
1.4.2.swTimer_signal_handler
声明:
// swoole.h 1085 void swTimer_signal_handler(int sig);
功能:SIGALRM信号的回调处理函数
核心源码:
// timer.c 338-344h SwooleG.signal_alarm = 1; uint64_t flag = 1; if (SwooleG.timer.use_pipe) { SwooleG.timer.pipe.write(&SwooleG.timer.pipe, &flag, sizeof(flag)); }
源码解释:
设置SwooleG的signal_alarm标记为true,如果设定使用了管道,则通过管道发送一个flag通知Timer。
1.4.3.swTimer_event_handler
声明:
// swoole.h 1086 int swTimer_event_handler(swReactor *reactor, swEvent *event);
功能:timer的事件处理回调函数
核心源码:
// timer.c 323-334h uint64_t exp; swTimer *timer = &SwooleG.timer; if (read(timer->fd, &exp, sizeof(uint64_t)) < 0) { return SW_ERR; } SwooleG.signal_alarm = 0; return swTimer_select(timer);
源码解释:
尝试从管道中读取数据,如果读取成功,则重置SwooleG的signal_alarm标记,并调用swTimer_select来处理定时任务;
1.4.4.其他函数
swTimer_node_insert,swTimer_node_print,swTimer_node_delete,swTimer_node_destory四个函数是链表操作函数,不再详细分析。
1.5.Timer私有操作函数
1.5.1.swTimer_signal_set
声明:
// timer.c 24h static int swTimer_signal_set(swTimer *timer, int interval);
功能:调用系统settimer函数启动定时器
核心源码:
struct itimerval timer_set; int sec = interval / 1000; int msec = (((float) interval / 1000) - sec) * 1000; struct timeval now; if (gettimeofday(&now, NULL) < 0) { swWarn("gettimeofday() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } memset(&timer_set, 0, sizeof(timer_set)); timer_set.it_interval.tv_sec = sec; timer_set.it_interval.tv_usec = msec * 1000; timer_set.it_value.tv_sec = sec; timer_set.it_value.tv_usec = timer_set.it_interval.tv_usec; if (timer_set.it_value.tv_usec > 1e6) { timer_set.it_value.tv_usec = timer_set.it_value.tv_usec - 1e6; timer_set.it_value.tv_sec += 1; } if (setitimer(ITIMER_REAL, &timer_set, NULL) < 0) { swWarn("setitimer() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; }
源码解释:
首先将interval拆分成秒和毫秒,并将两个值添加进timer_set,随后调用setitimer函数设置系统定时器。
1.5.2.swTimer_timerfd_set
声明:
// timer.c 25h static int swTimer_timerfd_set(swTimer *timer, int interval);
功能:调用timerfd相关函数启动timerfd定时器
核心源码:
// timer.c 100h if (timer->fd == 0) { timer->fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC); if (timer->fd < 0) { swWarn("timerfd_create() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } } timer_set.it_interval.tv_sec = sec; timer_set.it_interval.tv_nsec = msec * 1000 * 1000; timer_set.it_value.tv_sec = now.tv_sec + sec; timer_set.it_value.tv_nsec = (now.tv_usec * 1000) + timer_set.it_interval.tv_nsec; if (timer_set.it_value.tv_nsec > 1e9) { timer_set.it_value.tv_nsec = timer_set.it_value.tv_nsec - 1e9; timer_set.it_value.tv_sec += 1; } if (timerfd_settime(timer->fd, TFD_TIMER_ABSTIME, &timer_set, NULL) == -1) { swWarn("timerfd_settime() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; }
源码解释:
调用timerfd_create函数创建一个timerfd,并将返回的fd赋值给timer.fd;随后设置timer_set的值,并调用timerfd_settime函数设置定时器相关属性。
1.5.3.swTimer_del
声明:
// timer.c 26h static int swTimer_del(swTimer *timer, int ms);
功能:从timer的列表中移除一个指定定时器
核心源码:
swHashMap_del_int(timer->list, ms); return SW_OK;
源码解释:
从timer的list中移除ms对应的定时器
1.5.4.swTimer_free
声明:
// timer.c 27h static void swTimer_free(swTimer *timer);
功能:释放timer的内存
核心源码:
swHashMap_free(timer->list); if (timer->use_pipe) { timer->pipe.close(&timer->pipe); } else if (close(timer->fd) < 0) { swSysError("close(%d) failed.", timer->fd); } if (timer->root) { swTimer_node_destory(&timer->root); }
源码解释:
释放list,关闭管道,释放root指向的链表
1.5.5.swTimer_add
声明:
// timer.c 28h static int swTimer_add(swTimer *timer, int msec, int interval, void *data);
功能:向timer中添加一个定时器
核心源码:
if (interval == 0) { return swTimer_addtimeout(timer, msec, data); } swTimer_interval_node *node = sw_malloc(sizeof(swTimer_interval_node)); if (node == NULL) { swWarn("malloc failed."); return SW_ERR; } bzero(node, sizeof(swTimer_interval_node)); node->interval = msec; if (gettimeofday(&node->lasttime, NULL) < 0) { swSysError("gettimeofday() failed."); return SW_ERR; } if (msec < timer->interval) { int new_interval = swoole_common_divisor(msec, timer->interval); timer->interval = new_interval; swTimer_set(timer, new_interval); } swHashMap_add_int(timer->list, msec, node, NULL); timer->num++;
源码解释:
如果interval为0,说明这个定时器是个timeout类型定时器,调用swTimer_addtimeout函数。
否则,创建一个swTimer_interval_node结构体,设置其相关属性,并根据interval计算timer的基础响应间隔,并调用swTimer_set函数设置新的定时间隔。
最后,将新的定时任务节点添加进timer的list,并将定时器数量增加1。
1.5.6.swTimer_set
声明:
// timer.c 29h static int swTimer_set(swTimer *timer, int new_interval);
功能:设置timer的定时器响应间隔
核心源码:
if (SwooleG.use_timerfd) { return swTimer_timerfd_set(timer, new_interval); } else { return swTimer_signal_set(timer, new_interval); }
源码解释:
如果使用了timerfd,调用swTimer_timerfd_set;否则,调用swTimer_signal_set;
1.5.7.swTimer_addtimeout
声明:
// timer.c 30h int swTimer_addtimeout(swTimer *timer, int timeout_ms, void *data);
功能:从timer的列表中移除一个指定定时器
核心源码:
int new_interval = swoole_common_divisor(timeout_ms, timer->interval); if (new_interval < timer->interval) { swTimer_set(timer, new_interval); timer->interval = new_interval; } struct timeval now; if (gettimeofday(&now, NULL) < 0) { swWarn("gettimeofday() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } uint32_t now_ms = now.tv_sec * 1000 + now.tv_usec / 1000; swTimer_node *node = sw_malloc(sizeof(swTimer_node)); if (node == NULL) { swWarn("malloc(%d) failed. Error: %s[%d]", (int ) sizeof(swTimer_node), strerror(errno), errno); return SW_ERR; } bzero(node, sizeof(swTimer_node)); node->data = http://www.mamicode.com/data;"nf" style="color:rgb(148,82,119); font-weight:bold">swTimer_node_insert(&timer->root, node);
源码解释:
首先计算timer定时器最小时间间隔,并设置新的定时器基础响应间隔。随后创建新的swTimer_node节点,并设置其属性值,然后调用swTimer_node_insert函数在timer的root链表中添加新节点。(需要注意的是,因为这个定时器是一次性的,因此并不会改变timer->num的值)
1.5.8.swTimer_select
声明:
// timer.c 31h int swTimer_select(swTimer *timer);
功能:遍历timer列表找到需要响应的定时器
核心源码:
uint64_t key; swTimer_interval_node *timer_node; struct timeval now; if (gettimeofday(&now, NULL) < 0) { swSysError("gettimeofday() failed."); return SW_ERR; } //swWarn("%d.%d", now.tv_sec, now.tv_usec); if (timer->onTimeout == NULL) { swWarn("timer->onTimeout is NULL"); return SW_ERR; } /** * timeout task list */ uint32_t now_ms = now.tv_sec * 1000 + now.tv_usec / 1000; swTimer_node *tmp = timer->root; while (tmp) { if (tmp->exec_msec > now_ms) { break; } else { timer->onTimeout(timer, tmp->data); timer->root = tmp->next; sw_free(tmp); tmp = timer->root; } } if (timer->onTimer == NULL) { swWarn("timer->onTimer is NULL"); return SW_ERR; } uint32_t interval = 0; do { //swWarn("timer foreach start\n----------------------------------------------"); timer_node = swHashMap_each_int(timer->list, &key); //hashmap empty if (timer_node == NULL) { break; } //the interval time(ms) interval = (now.tv_sec - timer_node->lasttime.tv_sec) * 1000 + (now.tv_usec - timer_node->lasttime.tv_usec) / 1000; /** * deviation 1ms */ if (interval >= timer_node->interval - 1) { memcpy(&timer_node->lasttime, &now, sizeof(now)); timer->onTimer(timer, timer_node->interval); } } while (timer_node);
源码解释:
首先获取当前系统时间。
判定onTimeout回调是否被设置,如果未设置则返回错误。随后,遍历timeout定时任务列表,找到exec_msec时间小于等于当前时间的任务,调用onTimeout响应这些回调,并移除该任务。
判定onTimer回调是否被设置,如果未设置则返回错误。随后,遍历定时任务列表,判定当前节点是否需要响应(当前时间 - lasttime >= interval - 1ms),如果需要响应则设置新的lasttime并调用onTimer回调。
2.EventTimer
2.1.EventTimer原理
EventTimer的实现原理是利用了epoll的timeout超时设置。通过设置epoll的timeout,就能在timeout时间后捕获一个事件,在捕获该事件后,通过遍历对应的事件列表即可得知哪些事件需要处理。
2.2.EventTimer私有操作函数
2.2.1.swEventTimer_add
声明:
// EventTimer.c 19h static int swEventTimer_add(swTimer *timer, int _msec, int interval, void *data);
功能:向timer中添加一个定时器
核心源码:
后
swTimer_node *node = sw_malloc(sizeof(swTimer_node)); if (!node) { swSysError("malloc(%d) failed.", (int )sizeof(swTimer_node)); return SW_ERR; } int now_msec = swEventTimer_get_relative_msec(); if (now_msec < 0) { return SW_ERR; } node->data = http://www.mamicode.com/data;"m" style="color:rgb(148,82,119)">0; swTimer_node_insert(&timer->root, node);
源码解释:
初始化并向Timer的root中添加一个节点。
2.2.2.swEventTimer_del
声明:
// timer.c 20h static int swEventTimer_del(swTimer *timer, int _msec);
功能:从timer的列表中移除一个指定定时器
核心源码:
if (timer->root) { swTimer_node_destory(&timer->root); }
源码解释:
从timer的root中移除ms对应的定时器
2.2.3.swEventTimer_select
声明:
// timer.c 21h static int swEventTimer_select(swTimer *timer);
功能:从timer中选出需要响应的定时器
核心源码:
uint32_t now_msec = swEventTimer_get_relative_msec(); if (now_msec < 0) { return SW_ERR; } swTimer_node *tmp = timer->root; while (tmp) { if (tmp->exec_msec > now_msec) { break; } else { if (tmp->interval > 0) { timer->onTimer(timer, tmp->interval); } else { timer->onTimeout(timer, tmp->data); } timer->root = tmp->next; if (timer->root) { timer->root->prev = NULL; } if (tmp->interval > 0) { tmp->exec_msec += tmp->interval; swTimer_node_insert(&SwooleG.timer.root, tmp); } else { sw_free(tmp); } tmp = timer->root; } } if (timer->root == NULL) { SwooleG.main_reactor->timeout_msec = -1; } else { SwooleG.main_reactor->timeout_msec = timer->root->exec_msec - now_msec; }
源码解释:
遍历root链表,如果节点已经需要响应(exec_msec大于当前时间),则根据interval是否为0来执行各种不同的回调函数,并且如果interval为0,还需要移除当前节点。
最后,重新设置SwooleG.main_reactor的timeout时间。如果timer中没有定时任务,则设定为无超时。
2.2.4.swEventTimer_free
声明:
// timer.c 22h static void swEventTimer_free(swTimer *timer);
功能:释放timer
核心源码:
if (timer->root) { swTimer_node_destory(&timer->root); }
源码解释:
释放timer的root链表
Swoole源码学习记录(十五)——Timer模块分析