event是Reactor模式中的最重要的组件。它包含了了一个句柄fd,并设置监听这个句柄上的哪些事件(读/写等),设置了对应的函数指针,在事件到来时,回调函数指针来处理事件。
先看一下event的结构。它位于include/event2/event_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;
struct event_base *ev_base;
union {
/* used for io events */
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 */
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 */
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;
};
TAILQ_ENTRY是宏定义,展开后为双向链表中的指针结点。
#define TAILQ_ENTRY(type) \
struct { struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
这个指针信息用来管理event事件。event事件在Reactor中,用链表存储。
ev_active_next
是激活事件在激活事件链表中的位置。Reactor中有激活事件列表,程序会遍历这个列表,执行响应的处理程序。
ev_next
保存了当前事件在注册链表中的位置。
ev_timeout_pos
是union,它是定时器或在超时链表中的位置。
ev_fd
时event管理的fd,可以时socket或signal。
ev_base
是event所在的Reactor。
_ev是个union,event可能是IO事件,也可能时signal事件。用一个union表示,节省了空间。
ev_events
表明监听事件的类型。可以是以下事件
#define EV_TIMEOUT 0x01 //定时器事件
#define EV_READ 0x02 //IO读事件
#define EV_WRITE 0x04 //IO写事件
#define EV_SIGNAL 0x08 //信号事件
#define EV_PERSIST 0x10 //永久事件
ev_flags
表示当前event的状态,值如下
#define EVLIST_TIMEOUT 0x01 //在time堆中
#define EVLIST_INSERTED 0x02 //已经添加到事件列表中
#define EVLIST_SIGNAL 0x04 //
#define EVLIST_ACTIVE 0x08 //在激活链表中
#define EVLIST_INTERNAL 0x10
#define EVLIST_INIT 0x80 //已经初始化
ev_pri
表示优先级。数字越小,优先级越高,可以调用函数设置
int event_priority_set(struct event *ev, int pri)
ev_closure
根据其类型来调用不同回调函数。
ev_callback
是event的回调函数。三个参数分别为ev_fd
、ev_events
、ev_arg
。
有关event的接口定义在event.c中。在前面程序中用到了
event_set(&listenEvent, sock, EV_READ|EV_PERSIST, handleAccept, NULL);
event_base_set(base, &listenEvent);
event_add(&listenEvent, NULL);
其中
void
event_set(struct event *ev, evutil_socket_t fd, short events,
void (*callback)(evutil_socket_t, short, void *), void *arg)
功能为设置event的参数。
ev
表示event事件。
fd
表示和事件相关联的fd。
callback
是函数指针,表示事件处理程序。
arg
为ev_arg的值。
int
event_base_set(struct event_base *base, struct event *ev)
功能为将event和Reactor关联起来。
base
是event所在的Reactor。
int
event_add(struct event *ev, const struct timeval *tv)
功能为将event添加到Reactor中。
tv
是超时时间。
借助别人博客的图,形象的看一下Reactor中,怎么管理event。在反应堆event_base中有相应的链表和堆,来管理event事件。不同的事件对应不同指针/字段,IO事件对应ev_next
,信号事件对应ev_signal_next
,定时器事件对应min_head_idx
,激活后的事件对应ev_active_next
。当事件激活后,把事件转移到list[priority]
队列,之后对事件一一处理。
参考:
深入理解TAILQ队列
libevent源码深度剖析五——libevent的核心:事件event
http://www.wangafu.net/~nickm/libevent-2.0/doxygen/html/structevent.html
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/kangroger/article/details/47734077