nginx学习 - timer
想好好啃啃nginx的代码。已经将网上容易找到的nginx源码分析系列粗略过了一遍,也开发过几个简单的nginx-module,接下来想要提升一个档次只能自己来啃代码了。
//source: /src/event/ngx_event_timer.c
timer负责事件相关的计时功能,时间存储在一个RB-tree(红黑树)。【Tengine团队将rb-tree改为四叉最小堆,并声称有10%以上的性能提升,期待并后续学习】
static ngx_rbtree_node_t ngx_event_timer_sentinel; //定义一个全局的rbtree根节点,该根节点只起到一个哨兵作用,不存具体的值
struct ngx_rbtree_node_s { //红黑树节点的六个值 ngx_rbtree_key_t key; ngx_rbtree_node_t *left; ngx_rbtree_node_t *right; ngx_rbtree_node_t *parent; u_char color; u_char data; };
再来认识一下ngx_rbtree_s
struct ngx_rbtree_s { ngx_rbtree_node_t *root; //根节点 ngx_rbtree_node_t *sentinel; //哨兵节点,即NIL节点,空节点 ngx_rbtree_insert_pt insert; //插入回调函数句柄 };
在接下来的ngx_event_timer_init中调用了ngx_rbtree_init初始化这个rbtree,这里rbtree相关的操作在 /src/core/ngx_rbtree.c实现。
ngx_event_find_timer完成查找时间功能:从rbtree中找出最小时间,并计算与当前时间之差。查找timer,返回距离最近超时事件的时间,若有事件超时则返回0。
ngx_msec_t ngx_event_find_timer(void) { ngx_msec_int_t timer; ngx_rbtree_node_t *node, *root, *sentinel; if (ngx_event_timer_rbtree.root == &ngx_event_timer_sentinel) { //根节点为空 return NGX_TIMER_INFINITE; //返回无限,即无时间限制 } ngx_mutex_lock(ngx_event_timer_mutex); //对rbtree操作需要加锁 root = ngx_event_timer_rbtree.root; sentinel = ngx_event_timer_rbtree.sentinel; node = ngx_rbtree_min(root, sentinel); //获取rb-tree中的最小节点 ngx_mutex_unlock(ngx_event_timer_mutex); //解锁 timer = (ngx_msec_int_t) node->key - (ngx_msec_int_t) ngx_current_msec; //最小值-当前时间,当该值大于0即表明没有需要处理的超时事件 return (ngx_msec_t) (timer > 0 ? timer : 0); }
接下来一个主要的函数是ngx_event_expire_timers(void),这个函数不接收任何参数,也没有返回值。这个函数的功能是处理rb_tree中所有超时事件。
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); //找到最小时间点 /* node->key <= ngx_current_time */ if ((ngx_msec_int_t) node->key - (ngx_msec_int_t) ngx_current_msec <= 0) //小于0代表这个key已经超时了 { ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); //offsetof 算的是timer在ngx_event_t结构体中的偏移量,ev是通过node找到对应的事件 //这里ev的原理:node为结构体ngx_event_t的一个变量,通过指针往回移动偏移量的大小,就能将指针指向ngx_event_t的开头,即指向事件的开头。 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "event timer del: %d: %M", ngx_event_ident(ev->data), ev->timer.key); //ngx_event_ident 是从event的data部分获取其connection信息。 ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer); //将找到的事件对应的timer从rbtree中删除 ngx_mutex_unlock(ngx_event_timer_mutex); ev->timer_set = 0; ev->timedout = 1; //表明超时了 ev->handler(ev); //调用超时的回调函数进行事件处理 continue; //再取下一个超时待处理事件 } break; //没有找到超时需要处理的事件,就退出返回了
}
好了,只有短短几十行代码的分析。其它的下回分解。