从简单使用到源码分析一步步学习
一个实例
任何一个代码的学习都是从hello world开始的
#include <sys/signal.h>
#include <event.h>
void signal_cb( int fd, short event, void *arg)
{
struct event_base *base = (struct event_base *)arg;
struct timeval delay = {2, 0};
printf("Caught an interrupt signal; exiting cleanly in 2s");
event_base_loopexit(base, &delay);
}
void timeout_cb( int fd, short event, void *argc)
{
printf("timeout\n");
}
int main(int argc, char **argv)
{
struct event_base *base = event_init();
struct event *signal_event = evsignal_new(base, SIGINT, signal_cb, base);
event_add(signal_event, NULL);
struct timeval tv = {1, 0};
struct event *timeout_event = evtimer_new(base, timeout_cb, NULL);
event_add(timeout_event, &tv);
event_base_dispatch(base);
event_free(timeout_event);
event_free(signal_event);
event_base_free(base);
return 0;
}
libevent库的主要逻辑
- 调用event_init 函数创建event_base 对象,一个event_base相当于一个reactor实例。
2)创建具体的事件处理器,并且设置它们所从属的Reactor实例,evsignal_new/evtimer_new 分别用于创建信号事件处理器和定时事件处理器,它们是定义在include/event2/event.h文件中的宏
#define evsignal_new(b, x, cb, arg) \
event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))
#define evtimer_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg))
它们的统一入口是event_new函数,用于创建事件处理器的函数
/*
*@parm base : 事件处理器从属的Reactor, fd:指定与该事件处理器关联的句柄(创建IO事件传描述符,创建信号事件是传信号值,创建定时事件处理器时传-1)
*@parm event 可选事件 (12-1)
* #define EV_TIMEOUT 0x01 //定时
* #define EV_READ 0x02 //可读
* #define EV_WRITE 0x04 //可写
* #define EV_SIGNAL 0x08 //信号
* #define EV_PRESIST 0x10 //永久事件
* #define EV_ET 0x20 //ET事件,需要EPOLL等系统调用的支持
* @parm cb : 指定目标事件对应的回调函数。相当与事件处理器中的handl_event
* @parm arg:Reactor传递给回调的参数
*return : libevent的事件处理器
*/
struct event* event_new(struct event_base *base, evutil_socket_t fd, short events,
coid (*cb)(evutil_socket_t, short, void *), void *arg);
libevent主要概念词汇描述
- 事件:指的是一个局柄上绑定的事件,比如文件描述符0上的可读事件
- 事件处理器:也就是event结构体类型的对象,除了包含事件必须具备的两个要素(句柄,事件类型)外,还要其他的成员比如回调函数
- 事件有事件多路分发器管理,事件处理器有事件队列管理。事件队列包括多种,比如event_base中的注册事件队列,活动事件队列和通用定时器队列,以及evmap中的IO事件队列,信号事件队列。
- 事件循环对一个被激活的事件(就绪事件)的处理,指的是执行其回调函数
3)调用event_add函数,将事件处理器添加到注册事件队列中,并将该事件处理器对应的事件添加到事件多路分发器中。event_add函数相当与Reactor中的register_handler方法。
4)调用event_base_dispatch函数来执行事件循环
5)事件循环结束后,是*_free系列函数释放系统资源
event结构体
struct event_callback {
TAILQ_ENTRY(event_callback) evcb_active_next;
short evcb_flags; /*事件标志*/
ev_uint8_t evcb_pri; /* smaller numbers are higher priority */
ev_uint8_t evcb_closure;
/* allows us to adopt for different types of events */
union {
void (*evcb_callback)(evutil_socket_t, short, void *);
void (*evcb_selfcb)(struct event_callback *, void *);
void (*evcb_evfinalize)(struct event *, void *);
void (*evcb_cbfinalize)(struct event_callback *, void *);
} evcb_cb_union;
void *evcb_arg;
};
struct event_base;
struct event {
struct event_callback ev_evcallback;
/* 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 {
LIST_ENTRY (event) ev_io_next;
struct timeval ev_timeout;
} ev_io;
/* used by signal events */
struct {
LIST_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 */
struct timeval ev_timeout;
};
- ev_events 代表事件类型,取值可以是上述可选事件所标志的按位或(互斥事件除外)
- ev_active_next:活动事件队列,所有被激活的事件处理器通过该成员串联成一个尾队列
- ev_time_pos:仅仅用于定时事件处理器
- _ev:一个union,所有具有相同文件描述符的IO事件处理器通过ev.ev_io_ev_io_next串联成一个尾队列,我们称之为IO事件队列