libevent(三)event_base
阅读原文时间:2023年07月09日阅读:2

libevent能够处理三种事件: I/O、定时器、信号。

统一管理所有事件。

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,
, /* need reinit */
EV_FEATURE_ET|EV_FEATURE_O1,

};

在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, , base->sig.ev_signal_pair) == -) {
#ifdef WIN32
/* Make this nonfatal on win32, where sometimes people
have localhost firewalled. */
event_sock_warn(-, "%s: socketpair", __func__);
#else
event_sock_err(, -, "%s: socketpair", __func__);
#endif
return -;
}

evutil\_make\_socket\_closeonexec(base->sig.ev\_signal\_pair\[\]);  
evutil\_make\_socket\_closeonexec(base->sig.ev\_signal\_pair\[\]);  
base->sig.sh\_old = NULL;  
base->sig.sh\_old\_max = ;

evutil\_make\_socket\_nonblocking(base->sig.ev\_signal\_pair\[\]);  
evutil\_make\_socket\_nonblocking(base->sig.ev\_signal\_pair\[\]);

event\_assign(&base->sig.ev\_signal, base, base->sig.ev\_signal\_pair\[\],  
    EV\_READ | EV\_PERSIST, evsig\_cb, base);

base->sig.ev\_signal.ev\_flags |= EVLIST\_INTERNAL;  
event\_priority\_set(&base->sig.ev\_signal, );

**base->evsigsel = &evsigops;** return ;  

}

evsigops结构如下:

static const struct eventop evsigops = {
"signal",
NULL,
evsig_add,
evsig_del,
NULL,
NULL,
, ,
};