1 event_base
01.struct event_base {
02. const struct eventop *evsel;
03. void *evbase;
04. int event_count;
05. int event_count_active;
06. int event_gotterm;
07. int event_break;
08. // active event management
09. struct event_list **activequeues;
10. int nactivequeues;
11. // signal handling info
12. struct evsignal_info sig;
13. struct event_list eventqueue;
14. struct timeval event_tv;
15. struct min_heap timeheap;
16. struct timeval tv_cache;
17.};
1)evsel和evbase这两个字段的设置可能会让人有些迷惑,这里你可以把evsel和evbase看作是类和静态函数的关系,比如添加事件时的调用行为:evsel->add(evbase, ev),实际执行操作的是evbase;
这相当于class::add(instance, ev),instance就是class的一个对象实例。evsel指向了全局变量static const struct eventop *eventops[]中的一个;
前面也说过,libevent将系统提供的I/O demultiplex机制统一封装成了eventop结构;
因此eventops[]包含了select、poll、kequeue和epoll等等其中的若干个全局实例对象。 evbase实际上是一个eventop实例对象;
先来看看eventop结构体,它的成员是一系列的函数指针, 在event-internal.h文件中:
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;
};
也就是说,在libevent中,每种I/O demultiplex机制的实现都必须提供这五个函数接口,来完成自身的初始化、销毁释放;对事件的注册、注销和分发。比如对于epoll,libevent实现了5个对应的接口函数,并在初始化时并将eventop的5个函数指针指向这5个函数,那么程序就可以使用epoll作为I/O demultiplex机制了,这个在后面会再次提到。
2)activequeues是一个二级指针,前面讲过libevent支持事件优先级,因此你可以把它看作是数组,其中的元素activequeues[priority]是一个链表,链表的每个节点指向一个优先级为priority的就绪事件event。
3)eventqueue,链表,保存了所有的注册事件event的指针。
4)sig是由来管理信号的结构体,将在后面信号处理时专门讲解;
5)timeheap是管理定时事件的小根堆,将在后面定时事件处理时专门讲解;
6)event_tv和tv_cache是libevent用于时间管理的变量,将在后面讲到; 其它各个变量都能因名知意,就不再啰嗦了。
2 event
01.struct event {
02. TAILQ_ENTRY (event) ev_next;
03. TAILQ_ENTRY (event) ev_active_next;
04. TAILQ_ENTRY (event) ev_signal_next;
05. unsigned int min_heap_idx;
06. struct event_base *ev_base;
07. int ev_fd;
08. short ev_events;
09. short ev_ncalls;
10. short *ev_pncalls;
11. struct timeval ev_timeout;
12. int ev_pri;
13. void (*ev_callback)(int, short, void *arg);
14. void *ev_arg;
15. int ev_res;
16. int ev_flags;
17.};
1)ev_events:event关注的事件类型,它可以是以下3种类型: I/O事件: EV_WRITE和EV_READ 定时事件:EV_TIMEOUT 信号: EV_SIGNAL 辅助选项:EV_PERSIST,表明是一个永久事件,如果没有此类型,那么event只被触发一次。
2)ev_next,ev_active_next和ev_signal_next都是双向链表节点指针;它们是libevent对不同事件类型和在不同的时期,对事件的管理时使用到的字段。
libevent使用双向链表保存所有注册的I/O和Signal事件,ev_next就是该I/O事件在链表中的位置;称此链表为“已注册事件链表“;同样ev_signal_next就是signal事件在signal事件链表中的位置; ev_active_next:libevent将所有的激活事件放入到链表active list中,然后遍历active list执行调度,ev_active_next就指明了event在active list中的位置;
3)min_heap_idx和ev_timeout,如果是timeout事件,它们是event在小根堆中的索引和超时值,libevent使用小根堆来管理定时事件,这将在后面定时事件处理时专门讲解 4)ev_base该事件所属的反应堆实例,这是一个event_base结构体,下一节将会详细讲解;
5)ev_fd,对于I/O事件,是绑定的文件描述符;对于signal事件,是绑定的信号;
6)ev_callback,event的回调函数,被ev_base调用,执行事件处理程序,这是一个函数指针,原型为: void (*ev_callback)(int fd, short events, void *arg) 其中参数fd对应于ev_fd;events对应于ev_events;arg对应于ev_arg;
7)ev_arg:void*,表明可以是任意类型的数据,在设置event时指定;
8)eb_flags:libevent用于标记event信息的字段,表明其当前的状态,可能的值有:
9)ev_ncalls:事件就绪执行时,调用ev_callback的次数,通常为1;
10)ev_pncalls:指针,通常指向ev_ncalls或者为NULL;
11)ev_res:记录了当前激活事件的类型;
来源: <http://blog.sina.com.cn/s/blog_695372590100sblx.html>