libevent源码分析一--io事件响应
这篇文章将分析libevent如何组织io事件,如何捕捉事件的发生并进行相应的响应。这里不会详细分析event与event_base的细节,仅描述io事件如何存储与如何响应。
1. select
libevent实现io事件的backend实际上使用的是io复用接口,如select, poll, epoll等,这里以最简单的select为例进行说明。首先简单介绍一下select接口:
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
readfds, writefds, exceptfds均是文件描述符集合指针,调用该函数后,若readfds集合中的fd可读,或者writefds集合中的fd可写,或者exceptfds集合中的fd发生错误,或者阻塞的时间达到了timeout,函数返回。
函数返回0,返回结果readfds集合中包含了入参readfds中现在读不会被阻塞的fd,返回结果writefds包含了对应的写不会被阻塞的fd,exceptfds包含了所有发生异常的fd。如果超时,函数返回-1,这些集合为空。
可以看到,select调用需要传入感兴趣的io的文件描述符fd,而libevent中大家熟悉的是event_base,event结构体,event添加到event_base后就可以等待事件触发了,libevent是如何关联event, event_base与select的呢?
事实上,在libevent的源码select.c的,定义了一个数据结构struct selectop,
struct selectop {
int event_fds; /* Highest fd in fd set */
int event_fdsz;
int resize_out_sets;
fd_set *event_readset_in;
fd_set *event_writeset_in;
fd_set *event_readset_out;
fd_set *event_writeset_out;
};
它保存了libevent每次调用select需要使用到的入参与出参,这里保存的文件描述符是与加入到event_base中的event对应的。每当一个新的io的event加入到event_base, 内部都会将event对应的文件描述符fd加入到event_readset_in与event_writeset_in中,这取决于event感兴趣的是读事件还是写事件。相应的函数调用栈是:
event_add->event_add_nolock_->evmap_io_add_->select_add
当libevent使用select作为io的backend时,event_base中的成员evbase即指向动态分配的结构selectop,那么所有感兴趣的io事件的文件描述符都已经保存在了属于event_base的selectop结构中,调用select时即可使用。
2. event_io_map
前面分析了select使用的入参如何保存,但除了事件对应的文件描述符,libevent同样需要保存结构event,因为event中还记录了许多其它的信息,如事件发生时调用的回调函数,事件的超时时间等。因此,加入到event_base中的event结构也需要保存,event_base中的成员struct event_io_map io的作用正是用来保存添加的io事件的event结构。
struct event_io_map是一个hash表,如果是在非windows环境下,这个hash表可以简单地以一个动态数组实现。为描述简单,这里假设是在非windows环境下。其定义如下:
struct event_signal_map {
/* An array of evmap_io * or of evmap_signal *; empty entries are
* set to NULL. */
void **entries;
/* The number of entries available in entries */
int nentries;
};
它包含一个动态数组entries,数组长度以nentries表示。动态数组的内容是指向动态分配的结构evmap_io的指针。event对应的文件描述符fd作为它在动态数组中的索引,而同一个fd可能有多个感兴趣的事件加入到同一个event_base中,因此将它们连接起来构成双向链表以解决冲突,这个双向链表就是struct evmap_io,即以event的fd作为索引即可以找到这些事件组成的双向链表。event结构中的成员ev_io包含两个指针即双向链表的前驱指针与后继指针。event_base中的成员io的存储结构可以用图2-1表示,

图2-1 event_io_map
3. event_base_loop
包含回调信息的event结构已经存入了event_base的io成员,对于select,event相应的文件描述符也已经保存在了event_base的evbase成员指向的struct selectop结构中。那么libevent最终是如何等待读写事件的发生并最终调用相应的回调函数的呢?答案是event_base_loop函数。
首先,针对io事件,event_base_loop每一次循环,都会调用后端的dispatch函数,针对select后端,这个dispatch函数是select_dispatch,而select_dispatch又会调用select函数。然后,当select返回结果后,select_dispatch根据文件描述符从event_base的hash表io中将触发的event的回调函数加入到event_base的待执行回调函数链表,这个待执行回调函数链表由event_base的成员struct evcallback_list *activequeues保存。最后,event_base_loop在dispatch之后即会执行链表上的回调函数,完成事件响应。
4. activequeues
activequeues是一个evcallback_list类型的动态数组,用来实现事件的优先级,数组每一个成员都是一个待执行回调函数的链表。event_base_loop中执行这些链表上的函数时,以索引0开始按递增的顺序扫描数组,若数组成员指向的链表不为空,则依次执行上面的回调函数,索引越小,对应链表上的回调函数越先被执行,构成了事件的优先级。activequeues的结构可使用图4-1表示,

图4-1 event_base的activequeues成员结构
libevent处理io事件的流程简化总结为:首先将io事件的event结构加入到event_base的io成员中,并将对应的fd保存到evbase指向的结构中;然后event_base_loop调用dispatch,将触发的事件的回调函数添加到activequeues多优先级链表上;最后event_base_loop中执行activequeues上的回调函数,完成事件响应。
5. 部分概念说明表
|
event_base |
libevent中的基本结构,所有的event添加到该结构的实例中,再调用event_base_loop处理其中的事件 |
|
event |
libevent中表达一个事件的结构,包含了文件描述符,回调函数等信息 |
|
struct selectop |
select后端的结构,存储select函数需要的参数信息的结构,event_base中使用evbase指向这些信息 |
|
select.c |
libevent中实现select后端的源码文件 |
|
struct event_io_map |
event_base中io成员的类型,用来存储io类型的event结构的hash表 |
|
struct evmap_io |
双向链表描述结构,用于io类型的event |
|
activequeues |
event_base结构中的成员,evcallback_list类型的动态数组,保存待执行的回调函数的链表。 |
select后端的定义在select.c源码文件中
event/event_callback结构定义在源码文件event_struct.h中
event_base结构定义在源码文件event-internal.h中
event_add/event_base_loop/event_add_nolock函数定义在event.c函数中
evmap_io_add_函数与evmap_io/event_io_map结构定义在evmap.c文件中
libevent源码分析一--io事件响应的更多相关文章
- libevent源码分析二--timeout事件响应
libevent不仅支持io事件,同时还支持timeout事件与signal事件,这篇文件将分析libevent是如何组织timeout事件以及如何响应timeout事件. 1. min_heap ...
- libevent源码分析三--signal事件响应
libevent支持io事件,timeout事件,signal事件,这篇文件将分析libevent是如何组织signal事件,以及如何实现signal事件响应的. 1. sigmap 类似于io事件 ...
- Libevent源码分析 (1) hello-world
Libevent源码分析 (1) hello-world ⑨月份接触了久闻大名的libevent,当时想读读源码,可是由于事情比较多一直没有时间,现在手头的东西基本告一段落了,我准备读读libeven ...
- 【转】libevent源码分析
libevent源码分析 转自:http://www.cnblogs.com/hustcat/archive/2010/08/31/1814022.html 这两天没事,看了一下Memcached和l ...
- [Abp vNext 源码分析] - 13. 本地事件总线与分布式事件总线 (Rabbit MQ)
一.简要介绍 ABP vNext 封装了两种事件总线结构,第一种是 ABP vNext 自己实现的本地事件总线,这种事件总线无法跨项目发布和订阅.第二种则是分布式事件总线,ABP vNext 自己封装 ...
- Vue.js 源码分析(四) 基础篇 响应式原理 data属性
官网对data属性的介绍如下: 意思就是:data保存着Vue实例里用到的数据,Vue会修改data里的每个属性的访问控制器属性,当访问每个属性时会访问对应的get方法,修改属性时会执行对应的set方 ...
- UiAutomator源码分析之注入事件
上一篇文章<UiAutomator源码分析之UiAutomatorBridge框架>中我们把UiAutomatorBridge以及它相关的类进行的描述,往下我们会尝试根据两个实例将这些类给 ...
- [置顶] Android源码分析-点击事件派发机制
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17339857 概述 一直想写篇关于Android事件派发机制的文章,却一直没 ...
- Libevent源码分析—event, event_base
event和event_base是libevent的两个核心结构体,分别是反应堆模式中的Event和Reactor.源码分别位于event.h和event-internal.h中 1.event: s ...
随机推荐
- dajngo控制台添加数据报错Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured.
报错: django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but set ...
- 第08组 Alpha冲刺(3/6)
队名:955 组长博客:https://www.cnblogs.com/cclong/p/11872693.html 作业博客:https://edu.cnblogs.com/campus/fzu/S ...
- 条件随机场CRF原理介绍 以及Keras实现
本文是对CRF基本原理的一个简明的介绍.当然,“简明”是相对而言中,要想真的弄清楚CRF,免不了要提及一些公式,如果只关心调用的读者,可以直接移到文末. 图示# 按照之前的思路,我们依旧来对比一下普通 ...
- 【技术博客】 关于laravel5.1中文件上传测试的若干尝试
关于laravel5.1中文件上传测试的若干尝试 作者:ZGJ 版本:v1.0 PM注:本人这两天也正在尝试解决这一问题,如有进展将及时更新这一博客 在我们的软工第二阶段中,我开始着手进行后端控制器的 ...
- 【转】聊聊并发(一)——深入分析Volatile的实现原理
即两个或多个进程读写某些共享数据,而最后的结果取决于进程运行的精确时序,称为竞争条件(race condition). 引言 在多线程并发编程中synchronized和Volatile都扮演着重要的 ...
- jQuery的zTree插件
写在前面 jQuery的 zTree插件 关键代码 <%@ page language="java" contentType="text/html; charset ...
- 【maven】命令
一.maven打包命令 mvn打包,并指定 Profiles配置文件 和 模块名 mvn clean package {-P prod} -pl {groupId}:{artifactId} -am ...
- 段地址机制以及段地址转换触发segmentation falt
推动存储管理方式从固定分区到动态分区分配,进而又发展到分页存储管理方式的主要动力是提高内存利用率.可以实现一个内存用于多个程序同时执行而不会发生地址冲突.引入分段存储管理方式的目的,则主要是为了满足用 ...
- Chrome:不受信任的证书----openssl签发带Subject Alternative Name的证书
Chrome下自签名证书提示无效的问题 发现chrome验证证书很严格,必须带有Subject Alternative Name.签发csr时,修改openssl.cnf : vi /etc/ssl/ ...
- Android 自己实现更新下载自动安装
1.一些公司开发完一款App之后可能并不会去上架App商店,但事后期也需要定时进行维护更新,所以会选择把打包好的apk 发布到自己的服务器,然后在数据库建一个版本号的表,然后剩下的就交给你androi ...