日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Swoole源代码学习记录(十五)——Timer模块分析

發布時間:2025/3/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 *rootafter的鏈表根節點
swHashMap *listtimer的鏈表根節點
int num當前定時器的數量
int interval定時器的基礎響應間隔
int use_pipe是否使用管道通信
int lasttime持續時間(已廢棄)
int fd管道的寫fd
swPipe pipe管道
struct timeval basetimeEventTimer的基礎時間

說明:
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模块分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。