您的位置:首页 > 其它

libevent事件(二)---event源码

2017-04-20 16:51 260 查看

libevent事件源码

接下来将学习libevent库中event的源码:

首先是event结构体:

struct event {
//ev_next ev_active_next等等都是双向链表的指针
//用来管理注册的事件如IO事件 Signal事件
//所有激活的事件将插入到ev_active_next链表中
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;  //所关注的字段类型比如:EV_READ EV_WRITE
short ev_res;       /* result passed to event callback *///记录当前激活事件的类型
short ev_flags;//事件状态,包括:INSERTED ACTIVE等
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;//参数
};


可移植性

我们知道libevent适合于各种平台,其底层的接口如BSD的kqueue还有linux下的epoll等等,那么其可移植性是如何实现的呢?

libevent里面定义了一个
eventop
结构体,里面就是一堆回调函数接口,libevent会在预编译期选择适当的底层接口。

struct eventop {
const char *name;
void *(*init)(struct event_base *);
int (*add)(void *, struct event *);
int (*del)(void *, struct event *);
int (*dispatch)(struct event_base *, void *, struct timeval *);
void (*dealloc)(struct event_base *, void *);
/* set if we need to reinitialize the event base */
int need_reinit;
};

static const struct eventop *eventops[] = {
#ifdef HAVE_EVENT_PORTS
&evportops,
#endif
#ifdef HAVE_WORKING_KQUEUE
&kqops,
#endif
#ifdef HAVE_EPOLL
&epollops,
#endif
#ifdef HAVE_DEVPOLL
&devpollops,
#endif
#ifdef HAVE_POLL
&pollops,
#endif
#ifdef HAVE_SELECT
&selectops,
#endif
#ifdef WIN32
&win32ops,
#endif
NULL
};


可以看到所有的选项,其实都是在相关的文件中定义,并且在
event.c
extern
一下就可以了,以epoll为例,其实就是对回调的赋值:

//结构体中的回调函数是对epoll三个函数的底层封装
const struct eventop epollops = {
"epoll",
epoll_init,
epoll_add,
epoll_del,
epoll_dispatch,
epoll_dealloc,
1 /* need reinit */
};


最后,在初始化阶段,
event_base
结构体成员中,包含一个指向上述结构的指针,并通过该指针直接调用这些回调函数。

例如在
event_base_new
中进行初始化:

for (i = 0; eventops[i] && !base->evbase; i++) {
base->evsel = eventops[i];

base->evbase = base->evsel->init(base);
}//


event_base_dispatch
中调用
eventop
结构体中的回调函数:

const struct eventop *evsel = base->evsel;
res = evsel->dispatch(base, evbase, tv_p);


参考

深入浅出libevent
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: