libevent能够处理三种事件: I/O、定时器、信号。
event_base
统一管理所有事件。
struct event_base { const struct eventop *evsel; // backend void *evbase; /** Pointer to backend-specific data. */ const struct eventop *evsigsel; // signal backend struct evsig_info sig; /** Data to implement the common signal handelr code. */ int event_count; // 事件总数 int event_count_active; // 激活事件总数 struct event_list eventqueue; // 存储所有事件,但不包括定时器事件 struct event_io_map io; // 存储I/O事件 struct event_signal_map sigmap; // 存储信号事件 struct min_heap timeheap; // 存储定时器事件 /* Active event management. */ /** An array of nactivequeues queues for active events (ones that * have triggered, and whose callbacks need to be called). Low * priority numbers are more important, and stall higher ones. */ struct event_list *activequeues; /** The length of the activequeues array */ int nactivequeues; ... };
eventop
用于描述event_base的底层实现机制
/** Structure to define the backend of a given event_base. */ struct eventop { const char *name; void *(*init)(struct event_base *); int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo); int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo); int (*dispatch)(struct event_base *, struct timeval *); void (*dealloc)(struct event_base *); int need_reinit; enum event_method_feature features; size_t fdinfo_len; };
libevent支持多种平台,因此定义了一个全局数组来存放多个eventop。
/* Array of backends in order of preference. */ static const struct eventop *eventops[] = { #ifdef _EVENT_HAVE_EVENT_PORTS &evportops, #endif #ifdef _EVENT_HAVE_WORKING_KQUEUE &kqops, #endif #ifdef _EVENT_HAVE_EPOLL &epollops, #endif #ifdef _EVENT_HAVE_DEVPOLL &devpollops, #endif #ifdef _EVENT_HAVE_POLL &pollops, #endif #ifdef _EVENT_HAVE_SELECT &selectops, #endif #ifdef WIN32 &win32ops, #endif NULL };
Linux平台的I/O多路复用机制是epoll,对应epollops。
const struct eventop epollops = { "epoll", epoll_init, epoll_nochangelist_add, epoll_nochangelist_del, epoll_dispatch, epoll_dealloc, 1, /* need reinit */ EV_FEATURE_ET|EV_FEATURE_O1, 0 };
在event_base中,evsigsel也对应一个后端,这个后端用于信号处理。
值得注意的是这个成员的初始化时间:
int evsig_init(struct event_base *base) { /* * Our signal handler is going to write to one end of the socket * pair to wake up our event loop. The event loop then scans for * signals that got delivered. */ if (evutil_socketpair( AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) { #ifdef WIN32 /* Make this nonfatal on win32, where sometimes people have localhost firewalled. */ event_sock_warn(-1, "%s: socketpair", __func__); #else event_sock_err(1, -1, "%s: socketpair", __func__); #endif return -1; } evutil_make_socket_closeonexec(base->sig.ev_signal_pair[0]); evutil_make_socket_closeonexec(base->sig.ev_signal_pair[1]); base->sig.sh_old = NULL; base->sig.sh_old_max = 0; evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]); evutil_make_socket_nonblocking(base->sig.ev_signal_pair[1]); event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[1], EV_READ | EV_PERSIST, evsig_cb, base); base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL; event_priority_set(&base->sig.ev_signal, 0); base->evsigsel = &evsigops; return 0; }
evsigops结构如下:
static const struct eventop evsigops = { "signal", NULL, evsig_add, evsig_del, NULL, NULL, 0, 0, 0 };