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-94hswTimer *timer = &SwooleG.timer;timer->interval = interval;timer->lasttime = interval;#
ifndef HAVE_TIMERFDSwooleG.use_timerfd =
0;
#
endiftimer->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-344hSwooleG.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-334huint64_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 100hif (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 = data;node->exec_msec = now_ms + timeout_ms;
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 emptyif (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 = data;node->exec_msec = now_msec + _msec;node->interval = interval ?
_msec : 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鏈表
轉載于:https://www.cnblogs.com/mfrbuaa/p/5284137.html
總結
以上是生活随笔為你收集整理的Swoole源代码学习记录(十五)——Timer模块分析的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。