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;   //没有找到超时需要处理的事件,就退出返回了
}

 

好了,只有短短几十行代码的分析。其它的下回分解。

 

posted @ 2012-06-19 18:19  小获  阅读(1357)  评论(0编辑  收藏  举报