前言
之前说到过libevent是基于事件驱动模型的网络库,其中的事件,就是event,它的确算是libevent中最核心的部分,而上一节说到的event_base其实算是驱动部分,负责事件的各种处理。它们之间的关系是,一个event_base对应多个event。
下面主要讲解的是struct event结构体,位于event.h。
struct event
struct event {
/* 尾队列节点指针 用于保存所有注册了的I/O以及signal事件 以及激活的事件(其实libevent中的尾队列本质上就是一个双向链表)*/
TAILQ_ENTRY (event) ev_next; //已注册I/O事件链表
TAILQ_ENTRY (event) ev_active_next; //所有激活了的事件链表,通过遍历该链表进行调度
TAILQ_ENTRY (event) ev_signal_next; //已注册signal事件链表
unsigned int min_heap_idx; /* for managing timeouts */
struct event_base *ev_base; //该事件所属的反应堆实例
int ev_fd; //对于I/O事件,是绑定的文件描述符。对于signal事件,是绑定的信号
short ev_events; /* 事件的类型 */
short ev_ncalls; //事件就绪执行时,调用ev_callback的次数
short *ev_pncalls; /* Allows deletes in callback */
struct timeval ev_timeout; //定时的时长
int ev_pri; //优先级 smaller numbers are higher priority
/* event的回调函数,被ev_base调用
* int参数代表ev_fd
* short参数代表事件的类型,即ev_events
* void *arg对应ev_arg
*/
void (*ev_callback)(int, short, void *arg);
void *ev_arg;
int ev_res; //当前激活事件的类型 /* result passed to event callback */
int ev_flags; //表明当前event的状态
};
额外注意
有以下几点进行补充说明:
1. TAILQ_ENTRY()是一个宏,原型如下:
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
如你所见,它其实是一个尾队列结点。它的第一个成员tqe_next指向下一个元素,第二个成员tqe_prev是前一个元素的下个元素的地址。这样做的好处是,删除元素时不必遍历整个链表,同时也支持方向遍历。具体的操作等后面遇到了再讲。
2.
事件类型(short ev_events)有如下4种:
/* 定时事件 */
#define EV_TIMEOUT 0x01
/* I/O事件 */
#define EV_READ 0x02
#define EV_WRITE 0x04
/* 信号事件 */
#define EV_SIGNAL 0x08
/* 辅助选项:表明是永久(持续的)事件 */
#define EV_PERSIST 0x10 /* Persistant event */
这些事件可以进行|操作,即一个事件可以是多种类型的,不过signal类型不能和I/O类型同为同一事件。
3. event的状态(int ev_flags)有如下几种:
#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 已被初始化
4. 通过查看该结构体的成员,我们不难发现,libevent将事件分为了I/O事件、信号事件、定时事件这几类,并且管理注册事件的时候分了不同的链表来管理,已经激活等待调度的事件也有一个专门的链表来管理。
5. 还有一个优先级的概念,前面我们在介绍event_base结构体时,有个成员是activequeues,它专门用来按优先级管理已经激活(就绪)的事件。于是,每当有event被激活时,libevent就会把它移入activequeues[event->ev_pri]中。
6. 接着便是回调函数,event负责保管回调函数指针,真正来调用的是事件主循环中的event_process_active函数。
小结
OK,我们当前看了libevent中最主要的两个结构体:struct event和struct event_base,了解到event将事件分类管理,里面存放了重要的回调函数指针并且知道了它和event_base的关系(多对一)。下面我们可以忽略信号和定时部分,看一看event_base和event之间是如何协调的,这对我们理解event和event_base很有好处。

本文详细介绍了libevent中的核心结构体struct event,包括其在事件驱动模型中的作用、结构体成员、事件类型、事件状态、事件管理方式,以及回调函数的使用。重点讨论了event如何按优先级管理和激活事件,并与event_base的关系。
8411

被折叠的 条评论
为什么被折叠?



