libevent支持多种多路复用函数select, poll, epoll, kqueue, event port
实现分别在select.c poll.c epoll.c kqueue.c evport.c文件中
这些文件功能等效,不同的操作系统最后会使用不同的多路复用函数(按照一定优先级)
如果想看实际使用的是哪种复用函数,可以在执行程序前export EVENT_SHOW_METHOD环境变量,会在终端显示使用了哪种函数
1:等效的地方
1.1 每个.c文件都实例了一个结构变量
struct eventop {
char *name;
void *(*init)(struct event_base *);
int (*add)(void *, struct event *);
int (*del)(void *, struct event *);
int (*recalc)(struct event_base *, void *, int);
int (*dispatch)(struct event_base *, void *, struct timeval *);
void (*dealloc)(struct event_base *, void *); };
|
比如
select.c中
const struct eventop selectops = {
"select",
select_init,
select_add,
select_del,
select_recalc,
select_dispatch,
select_dealloc };
|
poll.c中
const struct eventop pollops = {
"poll",
poll_init,
poll_add,
poll_del,
poll_recalc,
poll_dispatch,
poll_dealloc };
|
在
struct event_base中有一个指向struct eventop的指针event_base在整个库中只有一个对象,在event_init时分配内存并初始化
struct event_base {
const struct eventop *evsel;
这个evsel是在初始化函数event_init中决定值的
base->evbase = NULL;
for (i = 0; eventops[i] && !base->evbase; i++) {
base->evsel = eventops[i];
这样通过指针可以调用不同的实现函数
1.2 每个实现文件定义了一个各自的结构
比如select.c
struct selectop { int event_fds; /* Highest fd in fd set */ int event_fdsz; fd_set *event_readset_in; fd_set *event_writeset_in; fd_set *event_readset_out; fd_set *event_writeset_out; struct event **event_r_by_fd; struct event **event_w_by_fd; };
|
poll.c
struct pollop { int event_count; /* Highest number alloc */ int nfds; /* Size of event_* */ int fd_count; /* Size of idxplus1_by_fd */ struct pollfd *event_set; struct event **event_r_back; struct event **event_w_back; int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so * that 0 (which is easy to memset) can mean * "no entry." */ }; struct pollop { int event_count; /* Highest number alloc */ int nfds; /* Size of event_* */ int fd_count; /* Size of idxplus1_by_fd */ struct pollfd *event_set; struct event **event_r_back; struct event **event_w_back; int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so * that 0 (which is easy to memset) can mean * "no entry." */ };
|
每种多路复用函数需要的参数是不一样的,不能用统一的结构。
这个在struct event_base中用一个void指针来指出void *evbase;
在event_init初始化函数决定了用哪种多路函数之后就会调用相应的init函数,这个函数里面会初始化这个结构变量base->evbase = base->evsel->init(base);
2:怎么决定用哪个多路复用函数
#ifdef HAVE_EVENT_PORTS
extern const struct eventop evportops;
#endif
#ifdef HAVE_SELECT
extern const struct eventop selectops;
#endif
#ifdef HAVE_POLL
extern const struct eventop pollops;
#endif
#ifdef HAVE_RTSIG
extern const struct eventop rtsigops;
#endif
#ifdef HAVE_EPOLL
extern const struct eventop epollops;
#endif
#ifdef HAVE_WORKING_KQUEUE
extern const struct eventop kqops;
#endif
#ifdef HAVE_DEVPOLL
extern const struct eventop devpollops;
#endif
#ifdef WIN32
extern const struct eventop win32ops;
#endif
/* In order of preference */
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_RTSIG
&rtsigops,
#endif
#ifdef HAVE_POLL
&pollops,
#endif
#ifdef HAVE_SELECT
&selectops,
#endif
#ifdef WIN32
&win32ops,
#endif
NULL
};
|
如果该操作系统支持某种多路复用函数,在编译前configure时生成的config.h头文件中会定义相应的宏,根据上面的代码在
eventops数组中就会有这样的项。每一项就是每个实现文件中定义的struct eventop结构变量。在初始化函数event_init中
base->evbase = NULL;
for (i = 0; eventops[i] && !base->evbase; i++) {
base->evsel = eventops[i];
base->evbase = base->evsel->init(base);
}
|
base是struct event_base变量,整个库中只有一个,他有const struct eventop *evsel;成员变量
上面的代码取eventops数组中第一个变量(优先级高的在eventops数组定义时放在前面),也就是优先级最高的哪种多路复用函数,同时调用其初始化函数如果使用的是select函数,就会调用select_init函数;如果是poll,就是poll_init函数。另外,也可以在程序运行前设置EVENT_NOPOLL等环境变量,这样就能使不用这种多路复用函数,比如操作系统只提供了poll select,按照上面的逻辑会使用poll,如果我想用select,那么可以运行前export EVENT_NOPOLL环境变量(具体值没关系)
对poll.c select.c devpoll.c等文件只要看一个可以了
阅读(1584) | 评论(0) | 转发(0) |