Nginx實現了自己的定時器觸發機制,與內核無關。用於彌補當內核調用超時等狀況下,系統可以主動觸發事件。理解定時器主要有兩個方面,一個方面是時間管理,另一個方面是定時器的實現方式。
1.時間管理
定時間首先要弄清楚時間管理,Nginx使用全局變量用於緩存時間,這樣在獲取事件的時候只需要直接讀取幾個緩存變量就可以了,達到提高了執行效率。緩存的時間更新由ngx_epoll_process_events方法執行,當flags參數中有NGX_UPDATE_TIME標誌位或者ngx_event_time_alarm標誌位爲1時,就會調用ng_time_update方法更新緩存時間。緩存事件的精度有兩種控制方式,一種是主動更新,通過調用ngx_epoll_process_events時觸發,另一種時被動更新,通過配置文件設置最小更新時間(timer_resolution),然後由settimer系統調用告訴內核定時更新。除此之外,Nginx還有很多通過程序邏輯控制事件更新的輔助方式,彌補以上兩種更新的不足。
2.定時器的實現
知道了定時器的時間管理後再理解定時器的實現就方便多了。Nginx的定時器是一個紅黑樹,ngx_event_timer_rbtreed定義定時器,ngx_event_timer_sentimel作嘔紅黑樹的哨兵節點,代碼如下
ngx_rbtree_t ngx_event_timer_rbtree;
static ngx_rbtree_node_t ngx_event_timer_sentinel;
定時器的實現共有5個操作方法,其中ngx_event_expire_timers方法作用是觸發所有超時的事件,ngx_event_expire_timers會循環調用所有滿足條件的事件的handler方法。調用頻率參考ngx_event_find_timer方法, 這個方法會決定下一個最近的超時事件多久後可能會發生。
void
ngx_event_expire_timers(void)
{
ngx_event_t *ev;
ngx_rbtree_node_t *node, *root, *sentinel;/*定時器事件節點*/
sentinel = ngx_event_timer_rbtree.sentinel;/*哨兵節點*/
/*輪訓滿足條件的事件,輪訓頻率依賴操作系統的時鐘頻率*/
for ( ;; ) {
root = ngx_event_timer_rbtree.root;
if (root == sentinel) {
return;
}
node = ngx_rbtree_min(root, sentinel);
/* node->key > ngx_current_msec */
if ((ngx_msec_int_t) (node->key - ngx_current_msec) > 0) {
return;
}
ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
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);
#if (NGX_DEBUG)
ev->timer.left = NULL;
ev->timer.right = NULL;
ev->timer.parent = NULL;
#endif
ev->timer_set = 0;
ev->timedout = 1;
ev->handler(ev);/*調用滿足條件的事件的handler方法*/
}
}