libevent源码深度剖析(五) libevent的核心:事件event

系列目录

(1)libevent源码深度剖析一 序 (2)libevent源码深度剖析二 Reactor模式 (3)libevent源码深度剖析三 libevent基本使用场景和事件流程 (4)libevent源码深度剖析四 libevent源代码文件组织 (5)libevent源码深度剖析五 libevent的核心:事件event (6)libevent源码深度剖析六 初见事件处理框架 (7)libevent源码深度剖析七 事件主循环 (8)libevent源码深度剖析八 集成信号处理 (9)libevent源码深度剖析九 集成定时器事件 (10)libevent源码深度剖析十 支持I/O多路复用技术 (11)libevent源码深度剖析十一 时间管理 (12)libevent源码深度剖析十二 让libevent支持多线程 (13)libevent源码深度剖析十三 libevent信号处理注意点

对事件处理流程有了高层的认识后,本节将详细介绍libevent的核心结构event,以及libevent对event的管理。

1.libevent的核心-event

Libevent是基于事件驱动(event-driven)的,从名字也可以看到event是整个库的核心。event就是Reactor框架中的事件处理程序组件;它提供了函数接口,供Reactor在事件发生时调用,以执行相应的事件处理,通常它会绑定一个有效的句柄。 首先给出event结构体的声明,它位于event.h文件中:

 1struct event {
 2
 3     TAILQ_ENTRY (event) ev_next;
 4
 5     TAILQ_ENTRY (event) ev_active_next;
 6
 7     TAILQ_ENTRY (event) ev_signal_next;
 8
 9     unsigned int min_heap_idx; /* for managing timeouts */
10
11     struct event_base *ev_base;
12
13     int ev_fd;
14
15     short ev_events;
16
17     short ev_ncalls;
18
19     short *ev_pncalls; /* Allows deletes in callback */
20
21     struct timeval ev_timeout;
22
23     int ev_pri;  /* smaller numbers are higher priority */
24
25     void (*ev_callback)(int, short, void *arg);
26
27     void *ev_arg;
28
29     int ev_res;  /* result passed to event callback */
30
31     int ev_flags;
32
33};

ev_events:event关注的事件类型,它可以是以下3种类型:

  1. I/O事件: EV_WRITE和EV_READ 定时事件:EV_TIMEOUT 信号: EV_SIGNAL 辅助选项:EV_PERSIST,表明是一个永久事件 Libevent中的定义为: 1#define EV_TIMEOUT 0x01 2 3#define EV_READ 0x02 4 5#define EV_WRITE 0x04 6 7#define EV_SIGNAL 0x08 8 9#define EV_PERSIST 0x10 /* Persistant event */ 可以看出事件类型可以使用“|”运算符进行组合,需要说明的是,信号和I/O事件不能同时设置; 还可以看出libevent使用event结构体将这3种事件的处理统一起来;
  2. ev_next,ev_active_next和ev_signal_next都是双向链表节点指针;它们是libevent对不同事件类型和在不同的时期,对事件的管理时使用到的字段。 libevent使用双向链表保存所有注册的I/O和Signal事件
  3. ev_next就是该I/O事件在链表中的位置;称此链表为“已注册事件链表”;
  4. 同样ev_signal_next就是signal事件在signal事件链表中的位置;
  5. ev_active_next:libevent将所有的激活事件放入到链表active list中,然后遍历active list执行调度,ev_active_next就指明了event在active list中的位置;
  6. min_heap_idx和ev_timeout,如果是timeout事件,它们是event在小根堆中的索引和超时值,libevent使用小根堆来管理定时事件,这将在后面定时事件处理时专门讲解;
  7. ev_base该事件所属的反应堆实例,这是一个event_base结构体,下一节将会详细讲解;
  8. ev_fd,对于I/O事件,是绑定的文件描述符;对于signal事件,是绑定的信号;
  9. ev_callback,event的回调函数,被ev_base调用,执行事件处理程序,这是一个函数指针,原型为: 1void (*ev_callback)(int fd, short events, void *arg) 其中参数fd对应于ev_fd;events对应于ev_events;arg对应于ev_arg;
  10. ev_arg:void*,表明可以是任意类型的数据,在设置event时指定;
  11. eb_flags:libevent用于标记event信息的字段,表明其当前的状态,可能的值有: 1#define EVLIST_TIMEOUT 0x01 // event在time堆中 2 3#define EVLIST_INSERTED 0x02 // event在已注册事件链表中 4 5#define EVLIST_SIGNAL 0x04 // 未见使用 6 7#define EVLIST_ACTIVE 0x08 // event在激活链表中 8 9#define EVLIST_INTERNAL 0x10 // 内部使用标记 10 11#define EVLIST_INIT 0x80 // event已被初始化
  12. ev_ncalls:事件就绪执行时,调用ev_callback的次数,通常为1;
  13. ev_pncalls:指针,通常指向ev_ncalls或者为NULL;
  14. ev_res:记录了当前激活事件的类型;

2.libevent对event的管理

从event结构体中的3个链表节点指针和一个堆索引出发,大体上也能窥出libevent对event的管理方法了,可以参见下面的示意图:

  • 每次当有事件event转变为就绪状态时,libevent就会把它移入到active event list[priority]中,其中priority是event的优先级;
  • 接着libevent会根据自己的调度策略选择就绪事件,调用其cb_callback()函数执行事件处理;并根据就绪的句柄和事件类型填充cb_callback函数的参数。

3.事件设置的接口函数

要向libevent添加一个事件,需要首先设置event对象,这通过调用libevent提供的函数有:event_set(), event_base_set(), event_priority_set()来完成;下面分别进行讲解。

1void event_set(struct event *ev, int fd, short events,
2   void (*callback)(int, short, void *), void *arg)
  1. 设置事件ev绑定的文件描述符或者信号,对于定时事件,设为-1即可;
  2. 设置事件类型,比如EV_READ|EV_PERSIST, EV_WRITE, EV_SIGNAL等;
  3. 设置事件的回调函数以及参数arg
  4. 初始化其它字段,比如缺省的event_base和优先级; int event_base_set(struct event_base *base, struct event *ev) 设置event ev将要注册到的event_base; libevent有一个全局event_base指针current_base,默认情况下事件ev将被注册到current_base上,使用该函数可以指定不同的event_base; 如果一个进程中存在多个libevent实例,则必须要调用该函数为event设置不同的event_base;
1int event_priority_set(struct event *ev, int pri)

设置event ev的优先级,没什么可说的,注意的一点就是:当ev正处于就绪状态时,不能设置,返回-1。

4. 小结

本节讲述了libevent的核心event结构,以及libevent支持的事件类型和libevent对event的管理模型;接下来将会描述libevent的事件处理框架,以及其中使用的重要的结构体event_base。

原文发布于微信公众号 - 高性能服务器开发(easyserverdev)

原文发表时间:2018-05-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏salesforce零基础学习

salesforce lightning零基础学习(九) Aura Js 浅谈二: Event篇

上一篇介绍了Aura Framework中 Component类的部分方法,本篇将要介绍Event常用的方法。

941
来自专栏HT

基于HT for Web矢量实现2D叶轮旋转

之前在拓扑上的应用都是些静态的图元,今天我们将在拓扑上设计一个会动的图元——叶轮旋转。 我们先来看下这个叶轮模型长什么样 ? 从模型上看,这个叶轮模型有三个叶片...

2065
来自专栏Python小屋

使用Jupyter Notebook+bokeh绘图入门完整步骤

Bokeh是一款基于浏览器的交互式绘图工具,在IPython Notebook中具有非常好的表现。 安装anaconda3,单击开始菜单,单击下图红色箭头所指菜...

2726
来自专栏IT开发技术与工作效率

VBA登录抓取网络数据

2644
来自专栏ytkah

excel隔行选中内容如何操作

  查看log日志是站长经常要做的事,从日志中可以发现很多问题,spider最近有没来爬,爬了哪些url,哪些页面不存在了等等,这些都可以看得到。然后你要根据不...

2934
来自专栏Danny的专栏

机房收费系统——将MSHFlexGrid控件中的数据导出到Excel

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/...

1322
来自专栏owent

Vim常用命令

之前有搜集过一些常用的命令脚本,其中有vim的部分。但是vim内置的很多功能那些个命令显然是不够的,而且那些记录的很多也不常用,于是想到专门开一个页面记录vim...

862
来自专栏hightopo

基于HT for Web矢量实现2D叶轮旋转

1942
来自专栏听雨堂

电子签名实现的思路、困难及解决方案

        在办公自动化的流程中希望实现电子签名。         思路:             1、图片的存放:安全起见存放在库中为宜。最好不能被轻易下...

2575
来自专栏黑泽君的专栏

day07_01_XML学习笔记

803

扫码关注云+社区

领取腾讯云代金券