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-94hswTimer *timer = &SwooleG.timer;timer->interval = interval;timer->lasttime = interval;#ifndef HAVE_TIMERFDSwooleG.use_timerfd = 0;
#endiftimer->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-344hSwooleG.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-334huint64_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 100hif (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 emptyif (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链表

转载于:https://www.cnblogs.com/mfrbuaa/p/5284137.html

Swoole源代码学习记录(十五)——Timer模块分析相关推荐

  1. BT源代码学习心得(十五):客户端源代码分析(下载过程中的块选取策略)

    BT源代码学习心得(十五):客户端源代码分析(下载过程中的块选取策略) 发信人: wolfenstein (NeverSayNever), 个人文集 标  题: BT源代码学习心得(十五):客户端源代 ...

  2. java学习记录十五:集合二Collections、Set、Map

    java学习记录十五:集合二 一.Collections工具类 一.解释 二.常用方法 1.打乱集合顺序 2.按照默认规则排序 3.按指定规则排序 4.批量添加元素 二.可变参数 一.解释 二.写法 ...

  3. Web前端学习记录(十五)

    写在前面: 由于w小小的失误,这篇其实应该是(十二),害,这件事情说来话长,尽管想改一下名字,但时间的先后没办法呀,只好将错就错了. w:开始表演. y:视而不见. w:······ 实现shoppi ...

  4. Dubbo学习记录(十五) - 服务调用【一】-之 服务端Netty的hander包装过程与 服务端线程模型

    Dubbo服务调用 之前写十几篇文章, 自己对Dubbo的运行有了一定的了解.而Dubbo服务调用则是重中之重, 目测将这个过程写出来起码需要5-6篇文章: 服务端Netty的hander包装 服务导 ...

  5. Python学习日记(十五) collections模块

    在内置函数(dict.list.set.tuple)的基础上,collections模块还提供了几个其他的数据类型:Counter.deque.defaultdict.namedtuple和Order ...

  6. BT源代码学习心得(十):客户端源代码分析(相关对象一览) -- 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(十):客户端源代码分析(相关对象一览) Author:wolfenstein(NeverSayNever), BitTorrent/download.py中的Multitorren ...

  7. 《SysML精粹》学习记录--第五章

    <SysML精粹>学习记录 第五章:用例图(Use Case Diagram) 用例图简介 用例图外框 小结 第五章:用例图(Use Case Diagram) 用例图简介   用例图可以 ...

  8. python学习[第十五篇] 文件系统

    python学习[第十五篇] 文件系统 对文件系统访问大多数都通过os模块实现. os 模块文件/目录访问函数 文件处理 mkfifo() 创建命名通道只用于linux remove(path)/un ...

  9. Polyworks脚本开发学习笔记(十五)-用Python连接Polyworks的COM组件

    Polyworks脚本开发学习笔记(十五)-用Python连接Polyworks的COM组件 用Polyworks脚本开发,没有高级语言的支持,功能难免单一,一些比较复杂的交互实现不了,界面和报告也很 ...

最新文章

  1. pdf 中的java运行,java - 从pdf文件读取特定位置的itext在intellij中运行,并提供所需的输出,但是可执行jar抛出错误 - 堆栈内存溢出...
  2. IRC 聊天工具(xchat,chatzilla,pidgin)入门教程
  3. 【Python】自动化升级所有pip安装的包
  4. php日历排班表,日历排班表软件下载
  5. js的隐含参数(arguments,callee,caller)使用方法
  6. Ubuntu 下如何执行脚本文件
  7. 你还在用迭代器处理集合吗?试试Stream,真香!
  8. springBoot微信支付(native)基本使用
  9. TTS 语音修复 ,缺少文件的,没注册类的
  10. 数学建模:Malthus人口模型
  11. Redis过期删除策略
  12. word文档怎样删除最后一页空白页
  13. Bomb Game(翻译)
  14. 编译原理——自下而上语法分析
  15. 基于Spring Boot的点餐微信小程序设计与实现
  16. 触觉马达DRV2605
  17. 卡迪夫大数据专业排名_2019QS排名出炉啦!看看卡迪夫大学那些世界前百强的学科...
  18. esp8266 AP模式控制继电器开关
  19. 3226. 【HBOI2013】ALO
  20. 豪华曹操传2014 (数据以及存档文件修改)

热门文章

  1. Git 中的对象模型和文件的详细视图 —— Git 学习笔记 13
  2. PriorityQueue源码解析
  3. C语言再学习 -- 结构和其他数据形式
  4. Linux动态频率调节系统CPUFreq
  5. 手动命令行编译APK
  6. Plasma链0x1的构造
  7. 深入了解以太坊虚拟机第4部分——ABI编码外部方法调用的方式
  8. Android 插件化原理解析——Activity生命周期管理
  9. origin纵坐标如何改成百分制,origin作图时,坐标刻度默认向外,我知道如何改成向内,但每次改很麻烦,如何设置使刻度默认向内?...
  10. php ajax 框架,PHP开发框架kohana中处理ajax请求的例子