l i b e v e n t libevent libevent是基于事件驱动的。从其名字也可以看出, e v e n t event event是整个 l i b e v e n t libevent libevent框架的核心。正如在libevent源码分析(二) Reactor模式中提到, e v e n t event event是 R e a c t o r Reactor Reactor模式中的事件处理组件:提供了函数接口,当有事件发生时,会调用相应的接口执行事件处理,通常会绑定一个有效的句柄。
event结构体
首先来看一下 e v e n t event event结构体的设计,在 e v e n t 2 / e v e n t event2/event event2/event_ s t r u c t . h struct.h struct.h文件中:
struct event {
//活动事件队列
TAILQ_ENTRY(event) ev_active_next;
//所有已注册事件处理器队列
TAILQ_ENTRY(event) ev_next;
/* for managing timeouts */
union {
//定时器在通用定时器队列中的位置
TAILQ_ENTRY(event) ev_next_with_common_timeout;
//定时器在时间堆中的位置
int min_heap_idx;
} ev_timeout_pos;
//句柄集
evutil_socket_t ev_fd;
//事件处理器从属的event_base实例
struct event_base *ev_base;
union {
/* used for io events */
//I/O事件队列
struct {
TAILQ_ENTRY(event) ev_io_next;
struct timeval ev_timeout;
} ev_io;
/* used by signal events */
//信号事件队列
struct {
TAILQ_ENTRY(event) ev_signal_next;
//指定调用回调函数的次数
short ev_ncalls;
/* Allows deletes in callback */
//要么为NULL,要么指向ev_ncalls
short *ev_pncalls;
} ev_signal;
} _ev;
//事件类型
short ev_events;
//记录当前激活事件的类型
short ev_res; /* result passed to event callback */
//事件标志
short ev_flags;
//指定事件处理器优先级
ev_uint8_t ev_pri; /* smaller numbers are higher priority */
//指定event_base执行事件处理器的回调函数时的行为
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;
};
(1) 宏 T A I L Q TAILQ TAILQ_ E N T R Y ENTRY ENTRY是尾队列中的节点类型,定义在 c o m p a t / s y s / q u e u e . h compat/sys/queue.h compat/sys/queue.h文件中:
#define TAILQ_ENTRY(type)
struct {
struct type* tqe_next; //下一个元素
struct type** tqe_prev; //前一个元素的地址
}
(2) e v ev ev_ t i m e o u t timeout timeout_ p o s pos pos:这是一个联合体,仅用于定时事件处理
(3) e v ev ev_ f d fd fd:对于 I / O I/O I/O事件,它是文件描述符值;对于信号事件处理器,它是信号值
(4) e v ev ev_ b a s e base base:该事件处理器从属的 e v e n t event event_ b a s e base base实例
(5) _ e v ev ev:所有具有相同文件描述符值的 I / O I/O I/O事件或信号事件通过 e v ev ev. e v ev ev_ i o io io. e v ev ev_ i o io io_ n e x t next next或 e v ev ev. e v ev ev_ s i g n a l signal signal. e v ev ev_ s i g n a l signal signal_ n e x t next next串联成一个尾队列,称为I/O事件队列或信号事件队列。 e v ev ev. e v ev ev_ s i g n a l signal signal. e v ev ev_ n c a l l s ncalls ncalls指定信号事件发生时, R e a c t o r Reactor Reactor需要执行多少次该事件对应的事件处理器中的回调函数; e v ev ev. e v ev ev_ s i g n a l signal signal. e v ev ev_ p n c a l l s pncalls pncalls指针成员要么是 N U L L , 要 么 指 向 NULL,要么指向 NULL,要么指向ev . . .ev$_ s i g n a l signal signal. e v ev ev_ n c a l l s ncalls ncalls
(6) e v ev ev_ e v e n t s events events: e v e n t event event关注的事件类型,可以是以下三种类型:
I/O事件: EV_WRITE和EV_READ
定时事件:EV_TIMEOUT
信号: EV_SIGNAL
辅助选项:EV_PERSIST,表明是一个永久事件
L i b e v e n t Libevent Libevent定义如下,定义在 i n c l u d e / e v e n t 2 / e v e n t include/event2/event include/event2/event_ s t r u c t . h struct.h struct.h文件中( e v ev ev_ f l a g s flags flags):
#define EVLIST_TIMEOUT 0x01 //事件处理器从属于通用计时器队列或时间堆
#define EVLIST_INSERTED 0x02 //事件处理器从属于注册事件
#define EVLIST_SIGNAL 0x04 //未见使用
#define EVLIST_ACTIVE 0x08 //事件处理器从属于活动事件队列
#define EVLIST_INTERNAL 0x10 //内部使用
#define EVLIST_INIT 0x10 //事件处理器已经被初始化
#define EVLIST_ALL (0xf000 | 0x9f) //定义所有标志
事件类型使用"|"进行组合;信号事件与I/O事件不能同时被设置。
(7) e v ev ev_ r e s res res:记录当前激活事件的类型
(8) e v ev ev_ p r i pri pri:指定事件处理器优先级,值越小则优先级越高
(9) e v ev ev_ c l o s u r e closure closure:指定 e v e n t event event_ b a s e base base执行事件处理器的回调函数时的行为。其可选值定义于 e v e n t event event_ i n t e r n a l . h internal.h internal.h中:
//默认行为
#define EV_CLOSURE_NONE 0
//执行信号事件处理器的回调函数时,调用ev.ev_signal.ev_ncalls次该回调函数
#define EV_CLOSURE_SIGNAL 1
//执行完回调函数后,再次将事件处理器加入注册事件队列中
#define EV_CLOSURE_PERSIST 2
(10) e v ev ev_ t i m e o u t timeout timeout:仅对定时器有效,指定定时器的超时值
(11) e v ev ev_ c a l l b a c k callback callback:事件处理器的回调函数,由 e v e n t event event_ b a s e base base调用
(12) e v ev ev_ a r g arg arg:回调函数的参数
Libevent对于event的管理
- 从 e v e n t event event 结构体中的 3 个链表节点指针和一个堆索引出发,大体上也能窥出 l i b e v e n t 对 e v e n t libevent 对event libevent对event 的管理方法了,可以参见下面的示意图。
- 每次当有事件 e v e n t event event 转变为就绪状态时, l i b e v e n t libevent libevent 就会把它移入到 a c t i v e active active e v e n t event event l i s t [ p r i o r i t y ] list[priority] list[priority]中,其中 p r i o r i t y priority priority 是 e v e n t event event 的优先级;
- 接着
l
i
b
e
v
e
n
t
libevent
libevent 会根据自己的调度策略选择就绪事件,调用其
c
b
cb
cb_
c
a
l
l
b
a
c
k
(
)
callback()
callback()函数执行事件处理;并根据就绪的句柄和事件类型填充
c
b
cb
cb_
c
a
l
l
b
a
c
k
callback
callback 函数的参数。
事件设置的接口函数
要向 l i b e v e n t libevent libevent 添加一个事件,需要首先设置 e v e n t event event 对象,这通过调用 l i b e v e n t libevent libevent 提供的函数有: e v e n t event event_ s e t ( ) set() set(), e v e n t event event_ b a s e base base_ s e t ( ) set() set(), e v e n t event event_ p r i o r i t y priority priority_ s e t ( ) set() set()来完成,定义在 e v e n t . c event.c event.c文件中:
(1) e v e n t event event_ s e t ( ) set() set()
1.设置事件 ev 绑定的文件描述符或者信号,对于定时事件,设为-1 即可;
2.设置事件类型,比如 EV_READ|EV_PERSIST, EV_WRITE, EV_SIGNAL 等;
3.设置事件的回调函数以及参数 arg;
4.初始化其它字段,比如缺省的 event_base 和优先级;
int
event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
{
if (!base)
base = current_base;
_event_debug_assert_not_added(ev);
ev->ev_base = base; //设置event属于当前base
ev->ev_callback = callback; //设置回调函数
ev->ev_arg = arg; //设置回调函数的3个参数
ev->ev_fd = fd;
ev->ev_events = events;
ev->ev_res = 0;
ev->ev_flags = EVLIST_INIT; //设置event状态
ev->ev_ncalls = 0;
ev->ev_pncalls = NULL;
if (events & EV_SIGNAL) {
if ((events & (EV_READ|EV_WRITE|EV_CLOSED)) != 0) {
event_warnx("%s: EV_SIGNAL is not compatible with "
"EV_READ, EV_WRITE or EV_CLOSED", __func__);
return -1;
}
ev->ev_closure = EV_CLOSURE_EVENT_SIGNAL;
} else {
if (events & EV_PERSIST) {
evutil_timerclear(&ev->ev_io_timeout);
ev->ev_closure = EV_CLOSURE_EVENT_PERSIST;
} else {
ev->ev_closure = EV_CLOSURE_EVENT;
}
}
min_heap_elem_init_(ev); //初始化event在小根堆中索引为-1 min_heap.h
if (base != NULL) {
/* by default, we put new events into the middle priority */
ev->ev_pri = base->nactivequeues / 2; //设置event优先级
}
event_debug_note_setup_(ev);
return 0;
}
void
event_set(struct event *ev, evutil_socket_t fd, short events,
void (*callback)(evutil_socket_t, short, void *), void *arg)
{
int r;
r = event_assign(ev, current_base, fd, events, callback, arg);
EVUTIL_ASSERT(r == 0);
}
(2) e v e n t event event_ b a s e base base_ s e t ( ) set() set()
1.设置 event ev 将要注册到的 event_base;
2.libevent 有一个全局 event_base 指针 current_base,默认情况下事件 ev
将被注册到 current_base 上,使用该函数可以指定不同的 event_base;
3.如果一个进程中存在多个 libevent 实例,则必须要调用该函数为 event 设
置不同的 event_base;
int
event_base_set(struct event_base *base, struct event *ev)
{
/* Only innocent events may be assigned to a different base */
if (ev->ev_flags != EVLIST_INIT) //只能对新建的event设置event_base
return (-1);
event_debug_assert_is_setup_(ev);
ev->ev_base = base; //设置所属event_base
ev->ev_pri = base->nactivequeues/2; //设置event优先级
return (0);
}
(3) e v e n t event event_ p r i o r i t y priority priority_ s e t ( ) set() set()
1.设置event ev的优先级
2.当ev正处于就绪状态时,不能设置,返回-1。
int
event_priority_set(struct event *ev, int pri)
{
event_debug_assert_is_setup_(ev);
if (ev->ev_flags & EVLIST_ACTIVE) //不能对活跃的event设置优先级
return (-1);
if (pri < 0 || pri >= ev->ev_base->nactivequeues)
return (-1);
ev->ev_pri = pri; //设置优先级
return (0);
}