zoukankan      html  css  js  c++  java
  • Swoole源代码学习记录(十五)——Timer模块分析

    swoole版本号:1.7.7-stable Github地址:点此查看


    1.Timer

    1.1.swTimer_interval_node

    声明:

    // swoole.h 1045-1050h
    typedef struct _swTimer_interval_node
    {
        struct _swTimerList_node *next, *prev;
        struct timeval lasttime;
        uint32_t interval;
    } swTimer_interval_node;
    成员 说明
    next,prev 链表的后继、前驱指针
    struct timeval lasttime 持续时间
    uint32_t interval 间隔时间

    说明:
    swTimer_interval_node结构体是一个链表节点,存放一个固定间隔的定时器,当中lasttime为当前定时器从上一次运行到如今经过的时间。interval存放了定时器间隔。


    该结构体用于swoole原本的timer相关操作。

    1.2.swTimer_node

    声明:

    // swoole.h 1052-1058h
    typedef struct _swTimer_node
    {
        struct _swTimer_node *next, *prev;
        void *data;
        uint32_t exec_msec;
        uint32_t interval;
    } swTimer_node;
    成员 说明
    next,prev 链表的后继、前驱指针
    void *data 数据域。存放额外的变量
    uint32_t exec_msec 定时器应当运行的时间
    uint32_t interval 间隔时间(无用,应废弃)

    说明:
    swTimer_node结构体是一个链表节点,存放一个须要在指定时间运行的定时器,当中exec_msec为当前定时器须要运行的指定时间,interval存放了定时器间隔。


    该结构体用于swoole的after函数操作。

    1.3.swTimer

    声明:

    // swoole.h 1060-1081h
    typedef struct _swTimer
    {
        swTimer_node *root;
        /*--------------timerfd & signal timer--------------*/
        swHashMap *list;
        int num;
        int interval;
        int use_pipe;
        int lasttime;
        int fd;
        swPipe pipe;
        /*-----------------for EventTimer-------------------*/
        struct timeval basetime;
        /*--------------------------------------------------*/
        int (*add)(struct _swTimer *timer, int _msec, int _interval, void *data);
        int (*del)(struct _swTimer *timer, int _interval_ms);
        int (*select)(struct _swTimer *timer);
        void (*free)(struct _swTimer *timer);
        /*-----------------event callback-------------------*/
        void (*onTimer)(struct _swTimer *timer, int interval_msec);
        void (*onTimeout)(struct _swTimer *timer, void *data);
    } swTimer;
    成员 说明
    swTimer_node *root after的链表根节点
    swHashMap *list timer的链表根节点
    int num 当前定时器的数量
    int interval 定时器的基础响应间隔
    int use_pipe 是否使用管道通信
    int lasttime 持续时间(已废弃)
    int fd 管道的写fd
    swPipe pipe 管道
    struct timeval basetime EventTimer的基础时间

    说明:
    swTimer结构体定时器的实体对象,用于存储、管理和运行众多定时任务,包含timer和after两种不同类型的定时任务。


    1.4.swTimer公共操作函数

    1.4.1.swTimer_init

    声明:

    // swoole.h 1083
    int swTimer_init(int interval_ms, int no_pipe);

    功能:初始化一个swTimer对象
    核心源代码:

        // timer.c 38-94h
        swTimer *timer = &SwooleG.timer;
        timer->interval = interval;
        timer->lasttime = interval;
    
    #ifndef HAVE_TIMERFD
        SwooleG.use_timerfd = 0;
    #endif
    
        timer->list = swHashMap_new(SW_HASHMAP_INIT_BUCKET_N, free);
        if (!timer->list)
        {
            return SW_ERR;
        }
    
        if (SwooleG.use_timerfd)
        {
            if (swTimer_timerfd_set(timer, interval) < 0)
            {
                return SW_ERR;
            }
            timer->use_pipe = 0;
        }
        else
        {
            if (use_pipe)
            {
                if (swPipeNotify_auto(&timer->pipe, 0, 0) < 0)
                {
                    return SW_ERR;
                }
                timer->fd = timer->pipe.getFd(&timer->pipe, 0);
                timer->use_pipe = 1;
            }
            else
            {
                timer->fd = 1;
                timer->use_pipe = 0;
            }
    
            if (swTimer_signal_set(timer, interval) < 0)
            {
                return SW_ERR;
            }
            swSignal_add(SIGALRM, swTimer_signal_handler);
        }
    
        if (timer->fd > 1)
        {
            SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_TIMER, swTimer_event_handler);
            SwooleG.main_reactor->add(SwooleG.main_reactor, SwooleG.timer.fd, SW_FD_TIMER);
        }
    
        timer->add = swTimer_add;
        timer->del = swTimer_del;
        timer->select = swTimer_select;
        timer->free = swTimer_free;

    源代码解释:
    获取SwooleG中的timer对象,设置timer响应间隔和lasttime參数。

    假设未定义HAVE_TIMERFD。则设置不使用timerfd。

    随后,使用HashMap初始化timer链表list。
    假设使用了timerfd,调用swTimer_timerfd_set函数设置timer的基础响应间隔,并设置不使用管道。
    假设不使用timerfd而使用signalfd,则先判定是否须要管道,假设须要。则创建管道并获取管道的写fd。随后。调用swTimer_signal_set函数设置Linux系统提供的精确定时器。并通过swSignal_add加入对SIGALRM信号的处理回调函数swTimer_signal_handler
    接着,将管道写fd增加main_reactor的监听中。并设置回调函数swTimer_event_handler
    最后设置swTimer的四个回调操作函数。


    1.4.2.swTimer_signal_handler

    声明:

    // swoole.h 1085
    void swTimer_signal_handler(int sig);

    功能:SIGALRM信号的回调处理函数
    核心源代码:

        // timer.c 338-344h
        SwooleG.signal_alarm = 1;
        uint64_t flag = 1;
    
        if (SwooleG.timer.use_pipe)
        {
            SwooleG.timer.pipe.write(&SwooleG.timer.pipe, &flag, sizeof(flag));
        }

    源代码解释:
    设置SwooleG的signal_alarm标记为true,假设设定使用了管道。则通过管道发送一个flag通知Timer。

    1.4.3.swTimer_event_handler

    声明:

    // swoole.h 1086
    int swTimer_event_handler(swReactor *reactor, swEvent *event);

    功能:timer的事件处理回调函数
    核心源代码:

        // timer.c 323-334h
        uint64_t exp;
        swTimer *timer = &SwooleG.timer;
    
        if (read(timer->fd, &exp, sizeof(uint64_t)) < 0)
        {
            return SW_ERR;
        }
        SwooleG.signal_alarm = 0;
        return swTimer_select(timer);

    源代码解释:
    尝试从管道中读取数据,假设读取成功,则重置SwooleG的signal_alarm标记,并调用swTimer_select来处理定时任务;

    1.4.4.其它函数

    swTimer_node_insertswTimer_node_printswTimer_node_deleteswTimer_node_destory四个函数是链表操作函数,不再具体分析。

    1.5.Timer私有操作函数

    1.5.1.swTimer_signal_set

    声明:

    // timer.c 24h
    static int swTimer_signal_set(swTimer *timer, int interval);

    功能:调用系统settimer函数启动定时器
    核心源代码:

        struct itimerval timer_set;
        int sec = interval / 1000;
        int msec = (((float) interval / 1000) - sec) * 1000;
    
        struct timeval now;
        if (gettimeofday(&now, NULL) < 0)
        {
            swWarn("gettimeofday() failed. Error: %s[%d]", strerror(errno), errno);
            return SW_ERR;
        }
    
        memset(&timer_set, 0, sizeof(timer_set));
        timer_set.it_interval.tv_sec = sec;
        timer_set.it_interval.tv_usec = msec * 1000;
    
        timer_set.it_value.tv_sec = sec;
        timer_set.it_value.tv_usec = timer_set.it_interval.tv_usec;
    
        if (timer_set.it_value.tv_usec > 1e6)
        {
            timer_set.it_value.tv_usec = timer_set.it_value.tv_usec - 1e6;
            timer_set.it_value.tv_sec += 1;
        }
    
        if (setitimer(ITIMER_REAL, &timer_set, NULL) < 0)
        {
            swWarn("setitimer() failed. Error: %s[%d]", strerror(errno), errno);
            return SW_ERR;
        }

    源代码解释:
    首先将interval拆分成秒和毫秒,并将两个值加入进timer_set。随后调用setitimer函数设置系统定时器。

    1.5.2.swTimer_timerfd_set

    声明:

    // timer.c 25h
    static int swTimer_timerfd_set(swTimer *timer, int interval);

    功能:调用timerfd相关函数启动timerfd定时器
    核心源代码:

        // timer.c 100h
        if (timer->fd == 0)
        {
            timer->fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC);
            if (timer->fd < 0)
            {
                swWarn("timerfd_create() failed. Error: %s[%d]", strerror(errno), errno);
                return SW_ERR;
            }
        }
    
        timer_set.it_interval.tv_sec = sec;
        timer_set.it_interval.tv_nsec = msec * 1000 * 1000;
    
        timer_set.it_value.tv_sec = now.tv_sec + sec;
        timer_set.it_value.tv_nsec = (now.tv_usec * 1000) + timer_set.it_interval.tv_nsec;
    
        if (timer_set.it_value.tv_nsec > 1e9)
        {
            timer_set.it_value.tv_nsec = timer_set.it_value.tv_nsec - 1e9;
            timer_set.it_value.tv_sec += 1;
        }
    
        if (timerfd_settime(timer->fd, TFD_TIMER_ABSTIME, &timer_set, NULL) == -1)
        {
            swWarn("timerfd_settime() failed. Error: %s[%d]", strerror(errno), errno);
            return SW_ERR;
        }

    源代码解释:
    调用timerfd_create函数创建一个timerfd。并将返回的fd赋值给timer.fd;随后设置timer_set的值。并调用timerfd_settime函数设置定时器相关属性。

    1.5.3.swTimer_del

    声明:

    // timer.c 26h
    static int swTimer_del(swTimer *timer, int ms);

    功能:从timer的列表中移除一个指定定时器
    核心源代码:

        swHashMap_del_int(timer->list, ms);
        return SW_OK;

    源代码解释:
    从timer的list中移除ms相应的定时器

    1.5.4.swTimer_free

    声明:

    // timer.c 27h
    static void swTimer_free(swTimer *timer);

    功能:释放timer的内存
    核心源代码:

        swHashMap_free(timer->list);
        if (timer->use_pipe)
        {
            timer->pipe.close(&timer->pipe);
        }
        else if (close(timer->fd) < 0)
        {
            swSysError("close(%d) failed.", timer->fd);
        }
        if (timer->root)
        {
            swTimer_node_destory(&timer->root);
        }

    源代码解释:
    释放list,关闭管道,释放root指向的链表

    1.5.5.swTimer_add

    声明:

    // timer.c 28h
    static int swTimer_add(swTimer *timer, int msec, int interval, void *data);

    功能:向timer中加入一个定时器
    核心源代码:

        if (interval == 0)
        {
            return swTimer_addtimeout(timer, msec, data);
        }
        swTimer_interval_node *node = sw_malloc(sizeof(swTimer_interval_node));
        if (node == NULL)
        {
            swWarn("malloc failed.");
            return SW_ERR;
        }
    
        bzero(node, sizeof(swTimer_interval_node));
        node->interval = msec;
        if (gettimeofday(&node->lasttime, NULL) < 0)
        {
            swSysError("gettimeofday() failed.");
            return SW_ERR;
        }
    
        if (msec < timer->interval)
        {
            int new_interval = swoole_common_divisor(msec, timer->interval);
            timer->interval = new_interval;
            swTimer_set(timer, new_interval);
        }
        swHashMap_add_int(timer->list, msec, node, NULL);
        timer->num++;

    源代码解释:
    假设interval为0,说明这个定时器是个timeout类型定时器,调用swTimer_addtimeout函数。


    否则,创建一个swTimer_interval_node结构体。设置其相关属性,并依据interval计算timer的基础响应间隔。并调用swTimer_set函数设置新的定时间隔。
    最后,将新的定时任务节点加入进timer的list。并将定时器数量添加1。

    1.5.6.swTimer_set

    声明:

    // timer.c 29h
    static int swTimer_set(swTimer *timer, int new_interval);

    功能:设置timer的定时器响应间隔
    核心源代码:

        if (SwooleG.use_timerfd)
        {
            return swTimer_timerfd_set(timer, new_interval);
        }
        else
        {
            return swTimer_signal_set(timer, new_interval);
        }

    源代码解释:
    假设使用了timerfd,调用swTimer_timerfd_set;否则,调用swTimer_signal_set;

    1.5.7.swTimer_addtimeout

    声明:

    // timer.c 30h
    int swTimer_addtimeout(swTimer *timer, int timeout_ms, void *data);

    功能:从timer的列表中移除一个指定定时器
    核心源代码:

        int new_interval = swoole_common_divisor(timeout_ms, timer->interval);
        if (new_interval < timer->interval)
        {
            swTimer_set(timer, new_interval);
            timer->interval = new_interval;
        }
    
        struct timeval now;
        if (gettimeofday(&now, NULL) < 0)
        {
            swWarn("gettimeofday() failed. Error: %s[%d]", strerror(errno), errno);
            return SW_ERR;
        }
    
        uint32_t now_ms = now.tv_sec * 1000 + now.tv_usec / 1000;
        swTimer_node *node = sw_malloc(sizeof(swTimer_node));
        if (node == NULL)
        {
            swWarn("malloc(%d) failed. Error: %s[%d]", (int ) sizeof(swTimer_node), strerror(errno), errno);
            return SW_ERR;
        }
    
        bzero(node, sizeof(swTimer_node));
        node->data = data;
        node->exec_msec = now_ms + timeout_ms;
        swTimer_node_insert(&timer->root, node);

    源代码解释:
    首先计算timer定时器最小时间间隔,并设置新的定时器基础响应间隔。

    随后创建新的swTimer_node节点,并设置其属性值,然后调用swTimer_node_insert函数在timer的root链表中加入新节点。(须要注意的是,由于这个定时器是一次性的。因此并不会改变timer->num的值)

    1.5.8.swTimer_select

    声明:

    // timer.c 31h
    int swTimer_select(swTimer *timer);

    功能:遍历timer列表找到须要响应的定时器
    核心源代码:

        uint64_t key;
        swTimer_interval_node *timer_node;
        struct timeval now;
    
        if (gettimeofday(&now, NULL) < 0)
        {
            swSysError("gettimeofday() failed.");
            return SW_ERR;
        }
        //swWarn("%d.%d", now.tv_sec, now.tv_usec);
    
        if (timer->onTimeout == NULL)
        {
            swWarn("timer->onTimeout is NULL");
            return SW_ERR;
        }
        /**
         * timeout task list
         */
        uint32_t now_ms = now.tv_sec * 1000 + now.tv_usec / 1000;
        swTimer_node *tmp = timer->root;
        while (tmp)
        {
            if (tmp->exec_msec > now_ms)
            {
                break;
            }
            else
            {
                timer->onTimeout(timer, tmp->data);
                timer->root = tmp->next;
                sw_free(tmp);
                tmp = timer->root;
            }
        }
    
        if (timer->onTimer == NULL)
        {
            swWarn("timer->onTimer is NULL");
            return SW_ERR;
        }
        uint32_t interval = 0;
        do
        {
            //swWarn("timer foreach start
    ----------------------------------------------");
            timer_node = swHashMap_each_int(timer->list, &key);
    
            //hashmap empty
            if (timer_node == NULL)
            {
                break;
            }
            //the interval time(ms)
            interval = (now.tv_sec - timer_node->lasttime.tv_sec) * 1000 + (now.tv_usec - timer_node->lasttime.tv_usec) / 1000;
    
            /**
             * deviation 1ms
             */
            if (interval >= timer_node->interval - 1)
            {
                memcpy(&timer_node->lasttime, &now, sizeof(now));
                timer->onTimer(timer, timer_node->interval);
            }
        } while (timer_node);

    源代码解释:
    首先获取当前系统时间。


    判定onTimeout回调是否被设置,假设未设置则返回错误。随后,遍历timeout定时任务列表,找到exec_msec时间小于等于当前时间的任务,调用onTimeout响应这些回调,并移除该任务。


    判定onTimer回调是否被设置,假设未设置则返回错误。

    随后。遍历定时任务列表,判定当前节点是否须要响应(当前时间 - lasttime >= interval - 1ms),假设须要响应则设置新的lasttime并调用onTimer回调。

    2.EventTimer

    2.1.EventTimer原理

    EventTimer的实现原理是利用了epoll的timeout超时设置。

    通过设置epoll的timeout。就能在timeout时间后捕获一个事件。在捕获该事件后,通过遍历相应的事件列表就可以得知哪些事件须要处理。

    2.2.EventTimer私有操作函数

    2.2.1.swEventTimer_add

    声明:

    // EventTimer.c 19h
    static int swEventTimer_add(swTimer *timer, int _msec, int interval, void *data);

    功能:向timer中加入一个定时器
    核心源代码:

        swTimer_node *node = sw_malloc(sizeof(swTimer_node));
        if (!node)
        {
            swSysError("malloc(%d) failed.", (int )sizeof(swTimer_node));
            return SW_ERR;
        }
    
        int now_msec = swEventTimer_get_relative_msec();
        if (now_msec < 0)
        {
            return SW_ERR;
        }
        node->data = data;
        node->exec_msec = now_msec + _msec;
        node->interval = interval ?

    _msec : 0; swTimer_node_insert(&timer->root, node);

    源代码解释:
    初始化并向Timer的root中加入一个节点。

    2.2.2.swEventTimer_del

    声明:

    // timer.c 20h
    static int swEventTimer_del(swTimer *timer, int _msec);

    功能:从timer的列表中移除一个指定定时器
    核心源代码:

        if (timer->root)
        {
            swTimer_node_destory(&timer->root);
        }

    源代码解释:
    从timer的root中移除ms相应的定时器

    2.2.3.swEventTimer_select

    声明:

    // timer.c 21h
    static int swEventTimer_select(swTimer *timer);

    功能:从timer中选出须要响应的定时器
    核心源代码:

        uint32_t now_msec = swEventTimer_get_relative_msec();
        if (now_msec < 0)
        {
            return SW_ERR;
        }
    
        swTimer_node *tmp = timer->root;
        while (tmp)
        {
            if (tmp->exec_msec > now_msec)
            {
                break;
            }
            else
            {
                if (tmp->interval > 0)
                {
                    timer->onTimer(timer, tmp->interval);
                }
                else
                {
                    timer->onTimeout(timer, tmp->data);
                }
    
                timer->root = tmp->next;
                if (timer->root)
                {
                    timer->root->prev = NULL;
                }
                if (tmp->interval > 0)
                {
                    tmp->exec_msec += tmp->interval;
                    swTimer_node_insert(&SwooleG.timer.root, tmp);
                }
                else
                {
                    sw_free(tmp);
                }
                tmp = timer->root;
            }
        }
        if (timer->root == NULL)
        {
            SwooleG.main_reactor->timeout_msec = -1;
        }
        else
        {
            SwooleG.main_reactor->timeout_msec = timer->root->exec_msec - now_msec;
        }

    源代码解释:
    遍历root链表。假设节点已经须要响应(exec_msec大于当前时间),则依据interval是否为0来运行各种不同的回调函数。而且假设interval为0,还须要移除当前节点。
    最后,又一次设置SwooleG.main_reactor的timeout时间。假设timer中没有定时任务,则设定为无超时。

    2.2.4.swEventTimer_free

    声明:

    // timer.c 22h
    static void swEventTimer_free(swTimer *timer);

    功能:释放timer
    核心源代码:

        if (timer->root)
        {
            swTimer_node_destory(&timer->root);
        }

    源代码解释:
    释放timer的root链表

  • 相关阅读:
    powermock测试
    一些疑惑
    Java基础总结3
    Java学习路线
    Java基础总结2
    关于我
    翻转单词序列
    和为s的两个数字
    和为s的连续正数序列
    数组中只出现一次的数字
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5284137.html
Copyright © 2011-2022 走看看