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_insert,swTimer_node_print,swTimer_node_delete,swTimer_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\n----------------------------------------------");
        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链表

时间: 2024-10-01 04:35:12

Swoole源码学习记录(十五)——Timer模块分析的相关文章

Swoole源码学习记录(九)——Factory模块(上)

Swoole版本:1.7.5-stable Factory这个命名让我一度认为这是一个工厂模型--这个工厂实际上并不负责生产实例,而是根据类型的不同执行两项任务:Factory实现的功能是一个任务中心,一个task请求进入Factory,会进过dispatch分配.onTask处理.onFinish交付结果一系列流程:FactoryProcess用于管理manager和worker进程,也有对单独的writer线程的管理. (PS:Swoole源码中有FactoryThread模块,该模块是一个

Swoole源码学习记录(十四)——Server模块详解(下)

swoole版本:1.7.6-stable 上一章已经分析了如何启动swServer的相关函数.本章将继续分析swServer的相关函数, 1.swServer函数分析 swServer_addListener 该函数用于在swServer中添加一个需要监听的host及port.函数原型如下: // Server.h 438h int swServer_addListener(swServer *serv, int type, char *host,int port); 参数 说明 swServ

Swoole源码学习记录(十)——Factory模块(下)

Swoole版本:1.7.5-stable 本章将分析FactoryProcess.c中剩下的函数,这些函数用于操作worker.manager以及writer.这些函数提供了最核心的进程创建.管理等功能,是Swoole的master-worker结构的基石. 先从worker相关的函数开始(manager相关函数基本都涉及操作worker进程).在FactoryProcess.c中一共声明了4个操作函数,分别是: static int swFactoryProcess_worker_loop(

Swoole源码学习记录(十二)——ReactorThread模块

ReactorThread 这一章将分析Swoole的ReactorThread模块.虽然叫Thread,但是实际上使用的是swFactoryProcess也就是多进程模式.但是,在ReactorThread中,所有的事件监听是在线程中运行的(Rango只是简单提到了PHP不支持多线程安全,具体原因还有待请教--),比如在UDP模式下,是针对每一个监听的host开辟一个线程运行reactor,在TCP模式下,则是开启指定的reactor_num个线程用于运行reactor. 那么OK,先上swR

Swoole源码学习记录(十三)——Server模块详解(上)

终于可以正式进入Server.c模块了-- 在之前的分析中,可以看到很多相关模块的声明都已经写在了Server.h中,就是因为这些模块构成了Server的核心部分.而Server本身,则是一个最上层的对象,它包括了核心的Reactor和Factory模块,存放了消息队列的key值,控制着全部的Connection,所有PHP层面的回调函数也在这里指定:同时,Server存放了大量的属性值,这些值决定了整个Swoole的详细特征. 直接上源码.首先是swServer结构体,这个结构体定义了一个sw

Swoole源码学习记录(八)——Reactor模块-epoll

Swoole版本:1.7.5-beta Reactor模块可以说是Swoole中最核心的模块之一,正是这些reactor模型为swoole提供了异步操作的基础.Swoole中根据不同的内核函数,提供了四种Reactor封装,ReactorEpoll,ReactorKqueue,ReactorPoll和ReactorSelect.同时,Swoole通过结构体swReactor封装了对于reactor的操作函数和基本属性.本章,我将分析swReactor以及四种Reactor模型中的ReactorE

Swoole源码学习记录(十一)——Worker,Connection

Swoole版本:1.7.5-stable 本章将分析Swoole中的三个比较重要的模块,Worker,ReactorProcess和Connection.其中Worker和ReactorProcess其实是对前面三章的一个补充,在前面的章节中为了分析结果的流畅性没有针对这些模块做特定分析,在此做出补充. Worker模块 首先是Worker模块.Worker在Swoole中为核心工作进程的封装,包括用于处理核心逻辑的worker和用于处理任务的task_worker.在Swoole中使用了结构

OpenFire源码学习之十五:插件开发

Plugin接口规范 插件是openfire功能的增强表现,它的主要任务: l  在XMPP协议中作为附加功能实现 l  动态修改控制管理台 l  使用openfire api作为新功能添加到服务器 Openfire里面的插件都会存放在plugins(工程目录为:src/plugins)的住目录下.使用ant工具编译后插件会打成jar包生成在target/openfire/plugins目录下.一个完整的插件应该包含以下的结构: Yourplugin/ | -plugin.xml        

(转)OpenFire源码学习之十五:插件开发

转:http://blog.csdn.net/huwenfeng_2011/article/details/43418493 Plugin接口规范 插件是openfire功能的增强表现,它的主要任务: l  在XMPP协议中作为附加功能实现 l  动态修改控制管理台 l  使用openfire api作为新功能添加到服务器 Openfire里面的插件都会存放在plugins(工程目录为:src/plugins)的住目录下.使用ant工具编译后插件会打成jar包生成在target/openfire