libev源码解析——I/O模型
在《libev源码解析——总览》一文中,我们介绍过,libev是一个基于事件的循环库。本文将介绍其和事件及循环之间的关系。(转载请指明出于breaksoftware的csdn博客)
目前ibev支持如下IO事件模型:
- select模型。对应文件是ev_select.c。
- poll模型。对应文件是ev_poll.c。
- epoll模型。对应的文件是ev_epoll.c。
- port模型。对应文件是ev_port.c。
- kqueue模型。对应的文件是ev_kqueue.c。
- iocp模型。即IO完成端口模型(I/O Completion Port)。
这些模型并不是我们这个系列介绍的重点。如果想了解select、poll、epoll模型,可以参阅《朴素、Select、Poll和Epoll网络编程模型实现和分析》系列博文。(下图是select模型的调用逻辑图)
此处我们只要知道它们是libev可选的事件模型即可。至于选择什么模型。要视loop_init的入参flags。
static void noinline ecb_cold
loop_init (EV_P_ unsigned int flags) EV_THROW
{
……
#if EV_USE_IOCP
if (!backend && (flags & EVBACKEND_IOCP )) backend = iocp_init (EV_A_ flags);
#endif
#if EV_USE_PORT
if (!backend && (flags & EVBACKEND_PORT )) backend = port_init (EV_A_ flags);
#endif
#if EV_USE_KQUEUE
if (!backend && (flags & EVBACKEND_KQUEUE)) backend = kqueue_init (EV_A_ flags);
#endif
#if EV_USE_EPOLL
if (!backend && (flags & EVBACKEND_EPOLL )) backend = epoll_init (EV_A_ flags);
#endif
#if EV_USE_POLL
if (!backend && (flags & EVBACKEND_POLL )) backend = poll_init (EV_A_ flags);
#endif
#if EV_USE_SELECT
if (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags);
#endif
……
}
backend是一个用于记录libev使用的是哪种IO模型的标记位。
在每个模型初始化函数中,都需要指定两个模型相关的函数指针。比如epoll模型的初始化函数epoll_init中
int inline_size
epoll_init (EV_P_ int flags)
{
……
backend_mintime = 1e-3; /* epoll does sometimes return early, this is just to avoid the worst */
backend_modify = epoll_modify;
backend_poll = epoll_poll;
……
}
而在select模型中则是
int inline_size
select_init (EV_P_ int flags)
{
backend_mintime = 1e-6;
backend_modify = select_modify;
backend_poll = select_poll;
……
}
backend_mintime是需要等待事件的超时秒数;backend_modify是轮询中修改事件信息的函数。backend_poll则是等待事件的函数。libev通过上述四个变量,隔离了不同模型选择导致不同函数调用的问题。
但是这儿需要指出的是,libev并没有将这种隔离做彻底。因为在关闭IO模型时,它仍然依靠backend的值,调用了不同函数(ev_loop_destroy中)
#if EV_USE_IOCP
if (backend == EVBACKEND_IOCP ) iocp_destroy (EV_A);
#endif
#if EV_USE_PORT
if (backend == EVBACKEND_PORT ) port_destroy (EV_A);
#endif
#if EV_USE_KQUEUE
if (backend == EVBACKEND_KQUEUE) kqueue_destroy (EV_A);
#endif
#if EV_USE_EPOLL
if (backend == EVBACKEND_EPOLL ) epoll_destroy (EV_A);
#endif
#if EV_USE_POLL
if (backend == EVBACKEND_POLL ) poll_destroy (EV_A);
#endif
#if EV_USE_SELECT
if (backend == EVBACKEND_SELECT) select_destroy (EV_A);
#endif
个人认为,可以在各个模型的初始化中,将其对应的销毁函数指针赋值给一个叫backend_destory的变量。这样上述代表就可以变成一行了。
结合《libev源码解析——调度策略》的内容,我们可以用下图表达出libev运转的大体流程。
针对上图,可能有人会问:为什么backend_poll函数需要指定超时?我们让其一直等待到有事件发生不是更好么?
还有人会问:“符合条件的监视器”是否可以表述为“本次触发事件对应的监视器”?
对于这些问题,我们将在之后章节给出答案。
- 数据库中间件 Sharding-JDBC 源码分析 —— SQL 解析(三)之查询SQL
- zephir-(11)流程控制语句
- phalcon-入门篇7(Model层基础使用)
- Sharding-JDBC 源码分析 —— SQL 解析(二)之SQL解析
- zephir-(1)开篇介绍
- phalcon-入门篇6(控制器)
- phalcon-入门篇5(请求与返回)
- phalcon-入门篇2(HelloWord与PhalconTools)
- 数据库中间件 Sharding-JDBC 源码分析 —— SQL 解析(一)之语法解析
- phalcon-入门篇4(log日志和session缓存)
- zephir-(5)类型
- zephir-(10)内置函数
- zephir-(9)类和对象2
- 深度学习中的动手实践:在CIFAR-10上进行图像分类
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PHP7 安装event扩展的实现方法
- 在laravel框架中使用model层的方法
- 漂亮的thinkphp 跳转页封装示例
- thinkphp5框架前后端分离项目实现分页功能的方法分析
- laravel 根据不同组织加载不同视图的实现
- 详解将数据从Laravel传送到vue的四种方式
- Laravel实现ApiToken认证请求
- laravel 实现划分admin和home 模块分组
- laravel在中间件内生成参数并且传递到控制器中的2种姿势
- 在laravel框架中实现封装公共方法全局调用
- laravel通过a标签从视图向控制器实现传值
- 在Laravel 的 Blade 模版中实现定义变量
- 解决Laravel5.5下的toArray问题
- Laravel基础_关于view共享数据的示例讲解
- 解决在laravel中leftjoin带条件查询没有返回右表为NULL的问题