MDGSF Software Engineer

[Nginx] 定时器

2017-08-09
mdgsf

源文件如下:

nginx-1.13.1\src\event\ngx_event_timer.h

nginx-1.13.1\src\event\ngx_event_timer.c

nginx这里的定时器是用红黑树实现的。

linux中是用时间轮实现的。

我记得还有用最小堆实现定时器的。

全局数据变量

#define NGX_TIMER_INFINITE  (ngx_msec_t) -1

#define NGX_TIMER_LAZY_DELAY  300

ngx_rbtree_t              ngx_event_timer_rbtree;

static ngx_rbtree_node_t  ngx_event_timer_sentinel;

ngx_event_timer_init

/*
 * the event timer rbtree may contain the duplicate keys, however,
 * it should not be a problem, because we use the rbtree to find
 * a minimum timer value only
 */

/*
@brief: 定时器初始化,其实就是初始化一颗红黑树。
*/
ngx_int_t
ngx_event_timer_init(ngx_log_t *log)
{
    ngx_rbtree_init(&ngx_event_timer_rbtree, &ngx_event_timer_sentinel,
                    ngx_rbtree_insert_timer_value);

    return NGX_OK;
}

/*
@brief: 红黑树中的插入函数。
@param temp: 临时指针,指向红黑树中的节点。
@param node: 要插入的新节点。
@param sentinel: 哨兵节点。
*/
void
ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
    ngx_rbtree_node_t *sentinel)
{
    ngx_rbtree_node_t  **p;

    for ( ;; ) {

        /*
         * Timer values
         * 1) are spread in small range, usually several minutes,
         * 2) and overflow each 49 days, if milliseconds are stored in 32 bits.
         * The comparison takes into account that overflow.
         */

        /*  node->key < temp->key */

        p = ((ngx_rbtree_key_int_t) (node->key - temp->key) < 0)
            ? &temp->left : &temp->right;

        if (*p == sentinel) {
            break;
        }

        temp = *p;
    }

    *p = node;
    node->parent = temp;
    node->left = sentinel;
    node->right = sentinel;
    ngx_rbt_red(node);
}

ngx_event_add_timer

/*
@brief: 把时间ev添加到定时器中去,超时时间是timer,单位应该是毫秒。
可以看到这里定时器和事件是一起使用的。
@param ev: 事件。
@param timer: 超时时间,比如说100ms,就表示100ms后定时器促发,就会执行这个事件。
@tips:
//ngx_current_msec在源文件 nginx-1.13.1\src\core\ngx_times.c
volatile ngx_msec_t      ngx_current_msec;
我猜这个应该就是当前时间的意思。
*/
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;

    //ngx_current_msec:当前时间, timer:超时时间, key:定时器促发的时间。
    key = ngx_current_msec + timer;

    if (ev->timer_set) {
        //如果定时器被设置过了

        /*
         * Use a previous timer value if difference between it and a new
         * value is less than NGX_TIMER_LAZY_DELAY milliseconds: this allows
         * to minimize the rbtree operations for fast connections.
         */

        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_rbtree_insert(&ngx_event_timer_rbtree, &ev->timer); //把新的定时器插入红黑树中。

    ev->timer_set = 1;
}

ngx_event_del_timer

/*
@brief: 把事件ev从定时器中删除。
@param ev: 事件。
*/
static ngx_inline void
ngx_event_del_timer(ngx_event_t *ev)
{
    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;
}

ngx_event_find_timer

/*
@brief:
如果没有一个定时器,那就返回NGX_TIMER_INFINITE。
如果最近的一个定时器还没有超时,那就返回这个定时器还有多久促发。
否则返回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;
    }

    root = ngx_event_timer_rbtree.root;
    sentinel = ngx_event_timer_rbtree.sentinel;

    node = ngx_rbtree_min(root, sentinel);

    timer = (ngx_msec_int_t) (node->key - ngx_current_msec);

    return (ngx_msec_t) (timer > 0 ? timer : 0);
}

ngx_event_expire_timers

/*
@brief: 执行所有已经超时的定时器。
*/
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;
        }

        //通过node获取到对应的事件结构体的指针。
        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); //促发该事件。
    }
}

ngx_event_no_timers_left

/*
@brief:
*/
ngx_int_t
ngx_event_no_timers_left(void)
{
    ngx_event_t        *ev;
    ngx_rbtree_node_t  *node, *root, *sentinel;

    sentinel = ngx_event_timer_rbtree.sentinel;
    root = ngx_event_timer_rbtree.root;

    if (root == sentinel) {
        return NGX_OK;
    }

    for (node = ngx_rbtree_min(root, sentinel);
         node;
         node = ngx_rbtree_next(&ngx_event_timer_rbtree, node))
    {
        ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));

        if (!ev->cancelable) { //不知道cancelable这个代表什么意思。
            return NGX_AGAIN;
        }
    }

    /* only cancelable timers left */

    return NGX_OK;
}

weixingongzhonghao

下一篇 [Nginx] list链表

Comments

Content