生活随笔
收集整理的這篇文章主要介紹了
nginx的定时器
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在nginx中有兩種事件類型,其中一種的引發點是epoll,也就是通過epoll來獲取事件的源頭,另外一種就是定時時間。。在前面的代碼中就已經遇到過了,例如當nginx獲取到一個客戶端的連接時,需要對該連接進行初始化,同時還要給這個連接增加一個定時器,如果都超時了請求的數據都還沒有接收完整,那么就直接斷開這個連接。。。
這里,nginx中的定時功能并沒有采用操作系統提供的定時器,而是自己實現了一個模擬定時器的方法。。。最核心的就是一顆紅黑樹。。。。
在Ngx_times.c文件中定義了很多關于時間的全局變量,其中對于定時時間最為重要的是:
[cpp]?view plaincopy
volatile?ngx_msec_t??????ngx_current_msec;??
ngx_msec_t為一個無符號的整形,用于代表當前的UTC時間,單位是毫秒。。
我們首先來看添加定時事件的函數吧:
[cpp]?view plaincopy
?? static?ngx_inline?void?? ngx_event_add_timer(ngx_event_t?*ev,?ngx_msec_t?timer)????? {?? ????ngx_msec_t??????key;?? ????ngx_msec_int_t??diff;?? ?? ????key?=?ngx_current_msec?+?timer;???? ?? ????if?(ev->timer_set)?{?? ?? ????????? ? ? ? ?? ?? ????????diff?=?(ngx_msec_int_t)?(key?-?ev->timer.key);?? ?? ????????if?(ngx_abs(diff)?<?NGX_TIMER_LAZY_DELAY)?{?? ????????????ngx_log_debug3(NGX_LOG_DEBUG_EVENT,?ev->log,?0,?? ???????????????????????????"event?timer:?%d,?old:?%M,?new:?%M",?? ????????????????????????????ngx_event_ident(ev->data),?ev->timer.key,?key);?? ????????????return;?? ????????}?? ?? ????????ngx_del_timer(ev);?? ????}?? ?? ????ev->timer.key?=?key;?? ?? ????ngx_log_debug3(NGX_LOG_DEBUG_EVENT,?ev->log,?0,?? ???????????????????"event?timer?add:?%d:?%M:%M",?? ????????????????????ngx_event_ident(ev->data),?timer,?ev->timer.key);?? ?? ????ngx_mutex_lock(ngx_event_timer_mutex);?? ?? ????ngx_rbtree_insert(&ngx_event_timer_rbtree,?&ev->timer);?????? ?? ????ngx_mutex_unlock(ngx_event_timer_mutex);?? ?? ????ev->timer_set?=?1;?? }??
代碼其實還是比較的簡單,核心就是將當前event的timer插入到事件紅黑樹當中,其超時時間為當前的時間加上傳進來的超時時間。。。
我們接著來看ngx_process_events_and_timers函數,
[html]?view plaincopy
timer?=?ngx_event_find_timer();???
這里用于獲取當前事件紅黑樹中最小的超時時間(也就是紅黑樹中最左邊的節點),將其提供給epoll,讓epoll的wait在這個時間內喚醒。。。
接下來再來看ngx_epoll_process_events函數,
[html]?view plaincopy
events?=?epoll_wait(ep,?event_list,?(int)?nevents,?timer);????//這個超時事件是從紅黑樹里面獲取的,當前最近的超時,這樣可以保證epoll的wait能夠在合適的時間內返回,保證定義的超時事件可以執行?? ?? ?err?=?(events?==?-1)???ngx_errno?:?0;?? ?? ?if?(flags?&?NGX_UPDATE_TIME?||?ngx_event_timer_alarm)?{?? ?????ngx_time_update();?? ?}?? ?? ?if?(err??
每一次wait之后就會調用ngx_time_updateh函數來更新當前的與時間相關的全局變量。。。
接下來回到ngx_process_event_and_timers中,
[html]?view plaincopy
if?(delta)?{?? ????ngx_event_expire_timers();?? }??
這部分代碼用于處理所有的超時時間。。來看看它的代碼吧:
[cpp]?view plaincopy
?? void?? ngx_event_expire_timers(void)?? {?? ????ngx_event_t????????*ev;?? ????ngx_rbtree_node_t??*node,?*root,?*sentinel;?? ?? ????sentinel?=?ngx_event_timer_rbtree.sentinel;?? ?? ?? ????for?(?;;?)?{?? ?? ????????ngx_mutex_lock(ngx_event_timer_mutex);?? ?? ????????root?=?ngx_event_timer_rbtree.root;?? ?? ????????if?(root?==?sentinel)?{?? ????????????return;?? ????????}?? ?? ????????node?=?ngx_rbtree_min(root,?sentinel);????? ?? ?????????? ?? ????????if?((ngx_msec_int_t)?(node->key?-?ngx_current_msec)?<=?0)?{????? ?????????????? ????????????ev?=?(ngx_event_t?*)?((char?*)?node?-?offsetof(ngx_event_t,?timer));?? ?? #if?(NGX_THREADS)?? ?? ????????????if?(ngx_threaded?&&?ngx_trylock(ev->lock)?==?0)?{?? ?? ????????????????? ? ? ? ? ? ?? ?? ????????????????ngx_log_debug1(NGX_LOG_DEBUG_EVENT,?ev->log,?0,?? ???????????????????????????????"event?%p?is?busy?in?expire?timers",?ev);?? ????????????????break;?? ????????????}?? #endif?? ?? ????????????ngx_log_debug2(NGX_LOG_DEBUG_EVENT,?ev->log,?0,?? ???????????????????????????"event?timer?del:?%d:?%M",?? ???????????????????????????ngx_event_ident(ev->data),?ev->timer.key);?? ?? ????????????ngx_rbtree_delete(&ngx_event_timer_rbtree,?&ev->timer);?? ?? ????????????ngx_mutex_unlock(ngx_event_timer_mutex);?? ?? #if?(NGX_DEBUG)?? ????????????ev->timer.left?=?NULL;?? ????????????ev->timer.right?=?NULL;?? ????????????ev->timer.parent?=?NULL;?? #endif?? ?? ????????????ev->timer_set?=?0;?? ?? #if?(NGX_THREADS)?? ????????????if?(ngx_threaded)?{?? ????????????????ev->posted_timedout?=?1;?? ?? ????????????????ngx_post_event(ev,?&ngx_posted_events);?? ?? ????????????????ngx_unlock(ev->lock);?? ?? ????????????????continue;?? ????????????}?? #endif?? ?? ????????????ev->timedout?=?1;?? ?? ????????????ev->handler(ev);????? ?? ????????????continue;?? ????????}?? ?? ????????break;?? ????}?? ?? ????ngx_mutex_unlock(ngx_event_timer_mutex);?? }??
其實還是很簡單的,說白了就是不斷的從紅黑樹中獲取key值最小的節點,然后判斷它是否已經超時,如果超時的話就將其從紅黑樹中刪除,然后調用處理函數。。。
這樣子nginx的定時時間處理也就ok了。。。。
總結
以上是生活随笔為你收集整理的nginx的定时器的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。