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链表

最新文章

  1. Android实现TCP断点上传,后台C#服务实现接收
  2. HTML5的新语义化的标签
  3. python之路二十
  4. JS中的“!!”
  5. ionic build android error when download gradle
  6. JMeter学习-007-JMeter 断言实例之一 - 响应断言
  7. HTML布局与框架
  8. Android分步注册,Activity由B返回A修改再前往B,B中已填项不变
  9. 【转】Android Paint之 setXfermode PorterDuffXfermode 讲解
  10. poj 3625 Building Roads(最小生成树,二维坐标,基础)
  11. Excel 数据分析技巧
  12. ASP.NET MVC View向Controller传值方式总结
  13. crm高速开发之QueryExpression
  14. Java编程思想笔记(第二章)
  15. thinkphp 匹配qq 表情
  16. iOS控制器跳转动画
  17. ArcGIS API for JavaScript与 npm
  18. Wireless Penetration Testing(命令总结)
  19. Python 模块EasyGui详细介绍
  20. javaweb-Excel导入导出后台代码

热门文章

  1. SGU 133.Border
  2. shell 脚本中 命令
  3. width:100%缩小窗口时背景图片出现空白bug
  4. 七天学会 SALT STACK 自动化运维 (1)
  5. unix 环境高级编程 读书笔记与习题解答第四篇
  6. NLP相关资源
  7. Egret 双端接入爱贝支付遇到的问题
  8. 批处理文件的@echo off是什么意思?
  9. 未能加载文件或程序集XXX或它的某一个依赖项。试图加载格式不正确的程序。
  10. Hibernate中的事务隔离