libevent源码详解(三)数据结构之event、event_base
来源:互联网 发布:amtemu mac使用方法 编辑:程序博客网 时间:2024/05/29 16:32
- sturct event
- 事件定义
- 事件类型
- 事件状态
- 三个链表
- event_base
- Reactor模式
- Reactor模式组成
- handleEventHandler事件源事件处理程序
- Synchrounous Event Demultiplexer同步事件多路复用器
- Reactor反应器
- Reactor模式处理流程
- Reactor模式组成
- event_base定义
- libevent对Reactor反应器接口的实现
- Reactor模式
libevent中最重要的两个数据结构莫过于event 跟event_base。弄明白这两个数据结构基本上也就弄明白libevent了。
sturct event
事件定义
libevent中,不论是IO事件,timeout事件,还是signal事件,都是用struct event来描述。具体的实现代码如下。
struct event { TAILQ_ENTRY(event) ev_active_next; TAILQ_ENTRY(event) ev_next; /* 用来描述timeout事件 */ union { TAILQ_ENTRY(event) ev_next_with_common_timeout; int min_heap_idx; } ev_timeout_pos; evutil_socket_t ev_fd; //对IO事件而言,为文件描述符。对信号事件而言,为绑定的信号。 struct event_base *ev_base;//绑定的event_base union { /* 用来描述IO事件 */ struct { TAILQ_ENTRY(event) ev_io_next; struct timeval ev_timeout; } ev_io; /* 用来描述signal事件 */ struct { TAILQ_ENTRY(event) ev_signal_next; short ev_ncalls; short *ev_pncalls; } ev_signal; } _ev; short ev_events;//事件类型 short ev_res; //传递给回调函数的结果 short ev_flags; //事件的状态标志 ev_uint8_t ev_pri; //事件的优先级。值越小优先级越高 ev_uint8_t ev_closure; struct timeval ev_timeout; /* allows us to adopt for different types of events */ void (*ev_callback)(evutil_socket_t, short, void *arg);//事件的回调函数 void *ev_arg; //事件回调函数参数};
我用的代码是2.0.22-stable版。这个版本中的代码比之前比较旧的版本实现得更清晰。
事件类型
事件类型由ev_events成员描述,总共有三种:IO事件、timeout事件、signal事件.EV_READ和EV_WRITE都是用来描述IO事件。
#define EV_TIMEOUT 0x01#define EV_READ 0x02#define EV_WRITE 0x04#define EV_SIGNAL 0x08
事件状态
#define EVLIST_TIMEOUT 0x01 // event在time堆中 #define EVLIST_INSERTED 0x02 // event在已注册事件链表中 #define EVLIST_SIGNAL 0x04 // 未见使用 #define EVLIST_ACTIVE 0x08 // event在激活链表中 #define EVLIST_INTERNAL 0x10 // 内部使用标记 #define EVLIST_INIT 0x80 // event已被初始化
三个链表
我们可以看到描述事件的结构体中有两个尾队列:ev_active_next,ev_next。ev_next用来描述已经注册的事件链表。ev_active_next用来描述激活链表。
//
如果事件类型是IO事件,那么事件还会处于ev_io_next队列。如果事件类型是signal事件,那么事件还会处于ev_signal_next队列。如果是timeout事件,则有两种可能:要不处于ev_next_with_common_timeout队列,要不处于最小堆。libevent默认将timeout事件放在最小堆中。如果timeout事件数量很多,那么可以将事件放在ev_next_with_common_timeout队列,那样处理起来速度会更快。
event_base
Reactor模式
Reactor模式组成
Reactor模式大致由如下几个部分组成:handle/EventHandler事件源/事件处理接口、Synchrounous Event Demultiplexer事件多路复用器、Reactor反应器、Concrete Event handler特定事件处理接口。盗用一下别人的图。
1.handle/EventHandler事件源/事件处理程序
handle即事件源。libevent中的信号、文件描述符都是handle。
2.Synchrounous Event Demultiplexer同步事件多路复用器
同步事件多路复用器实际上是内核实现的一个函数。这个函数会阻塞等待已经注册事件集合。当有注册事件发生时,事件进入就绪状态,复用器会通知反应器。反应器收到通知后就可以调用事件的回调函数处理事件。linux系统下的select, poll,epoll都是Demultiplexer。libevent把这些复用器叫做backend,并用struct eventop来描述。
3.Reactor反应器
反应器的功能如下:
- 运行事件循环
- 当有事件(handle)就绪时,调用事件的回调函数
- 注册/删除事件
Reactor模式处理流程
- 1.注册事件/事件处理接口到Reactor中
- 2.调用event_loop()进入循环,等待事件发生
- 3.事件发生,Demultiplexer返回,Reactor调用回调函数进行处理
event_base定义
struct event_base { const struct eventop *evsel; void *evbase; struct common_timeout_list **common_timeout_queues; struct min_heap timeheap;//管理timeout事件的最小堆 struct event_list *activequeues;//就绪队列。 struct event_list eventqueue;//所有调用event_add接口的事件都会被加入到这个队列,调用后event状态为EVLIST_INSERTED. struct event_signal_map sigmap; struct event_io_map io; struct timeval event_tv; struct timeval tv_cache;};
- evsel :reactor模式的demultiplexer。libevent用struct eventop统一封装了demultiplexer,并强制不同系统的demultiplexer统一提供init、add、del、dispatch、dealloc接口。详见struct eventop的定义。
- io/sigmap
linux下,这两个的数据成员结构为
struct event_signal_map { void **entries; int nentries;};
entries是一个数组。如果事件类型为信号事件,则数组成员类型为struct evmap_signal。如果事件类型为IO事件,则数组成员为struct evmap_io。这两个成员的数据结构如下:
struct evmap_io { struct event_list events; ev_uint16_t nread; ev_uint16_t nwrite;};struct evmap_signal { struct event_list events;};
Q: event_base中为什么会存在这两个数据成员?
A: 因为libevent允许将同一个fd/signal映射到不同的事件,即fd/signal—->struct event*的映射。struct event_signal_map中的数组entries的索引就是fd/signal的值,对应的事件struct event则存放在evmap_io/evmap_signal中的尾队列events中。在windows中,文件描述符是一个比较大的值,不适合放到event_signal_map结构的数组中,libevent会先将fd值做一个hash然后再用链表定址存放在struct event_map_entry的尾队列中。linux下由于遵循POSIX标准的文件描述符是从0开始递增的,一般都不会太大,可以用event_signal_map中的数组来映射fd的值。windows下fd映射到struct event的具体实现分析可以参考这篇:Libevent源码分析—–event_io_map哈希表
libevent对Reactor反应器接口的实现
每个event_base就相当于一个Reactor框架。
上面我们介绍了Reactor模式中reactor反应器的三个主要功能:注册/注销事件、运行事件主循环、等待事件就绪然后调用事件处理函数。在libevent中实现这些功能的对应接口如下:
- event_add(struct event *ev, const struct timeval *tv) 注册事件
- event_del(struct event *ev) 注销事件
- event_base_loop(struct event_base *) 运行事件主循环
- libevent源码详解(三)数据结构之event、event_base
- Libevent源码分析-event_base
- libevent---核心event和event_base
- libevent : struct event & struct event_base
- libevent之event_base
- Libevent源码分析-----配置event_base
- Libevent源码分析-----配置event_base
- Libevent源码分析-----配置event_base
- Libevent源码分析-----配置event_base
- Libevent(2)— event、event_base
- Libevent(2)— event、event_base
- [libevent]event,event_base结构体描述
- libevent使用(二) ----- event_base 和 event
- Libevent— event、event_base(常用api)
- [libevent]event/event_base/epollop/evsignal_info分析
- libevent源码学习-----event_base事件循环
- 【libevent】源码学习(2)--配置event_base
- libevent源码详解(一)数据结构之尾队列
- MongoDB的初次相遇(四)
- OpenNI的安装与配置
- AngularJS1.0的使用总结笔记------003
- Activity和Fragment用Intent和Bundle传递参数--总结
- android pcm
- libevent源码详解(三)数据结构之event、event_base
- javafx模态窗口
- 几种分类问题的区别:多类分类,多标签分类,多示例学习,多任务学习
- 使用yum provides lspci 命令查lspci 命令在哪个rpm包里
- const关键字详解
- Maven清除LastUpdated文件
- 在centos6.5环境下搭建多版本python(python2.6、python2.7、python3.5)共存环境
- ODI使用技巧_01利用变量实现增量抽取
- 阿里巴巴集团2017暑期实习生在线编程测试题分析-Java研发工程师