系列目录
(1)libevent源码深度剖析一 序 (2)libevent源码深度剖析二 Reactor模式 (3)libevent源码深度剖析三 libevent基本使用场景和事件流程 (4)libevent源码深度剖析四 libevent源代码文件组织 (5)libevent源码深度剖析五 libevent的核心:事件event (6)libevent源码深度剖析六 初见事件处理框架 (7)libevent源码深度剖析七 事件主循环 (8)libevent源码深度剖析八 集成信号处理 (9)libevent源码深度剖析九 集成定时器事件 (10)libevent源码深度剖析十 支持I/O多路复用技术 (11)libevent源码深度剖析十一 时间管理 (12)libevent源码深度剖析十二 让libevent支持多线程 (13)libevent源码深度剖析十三 libevent信号处理注意点
前面已经对libevent的事件处理框架和event结构体做了描述,现在是时候剖析libevent对事件的详细处理流程了,本节将分析libevent的事件处理框架event_base和libevent注册、删除事件的具体流程,可结合前一节libevent对event的管理。
回想Reactor模式的几个基本组件,本节讲解的部分对应于Reactor框架组件。在libevent中,这就表现为event_base结构体,结构体声明如下,它位于event-internal.h文件中:
1struct event_base {
2 const struct eventop *evsel;
3 void *evbase;
4 int event_count;
5 /* counts number of active events */
6 int event_count_active;
7 /* Set to terminate loop */
8 int event_gotterm;
9 /* Set to terminate loop immediately */
10 int event_break;
11 /* active event management */
12 struct event_list **activequeues;
13 int nactivequeues;
14 /* signal handling info */
15 struct evsignal_info sig;
16 struct event_list eventqueue;
17 struct timeval event_tv;
18 struct min_heap timeheap;
19 struct timeval tv_cache;
20};
下面详细解释一下结构体中各字段的含义。
创建一个event_base对象也既是创建了一个新的libevent实例,程序需要通过调用event_init()(内部调用event_base_new函数执行具体操作)函数来创建,该函数同时还对新生成的libevent实例进行了初始化。
函数还检测了系统的时间设置,为后面的时间管理打下基础。
前面提到Reactor框架的作用就是提供事件的注册、注销接口;根据系统提供的事件多路分发机制执行事件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数来处理事件。 Libevent中对应的接口函数主要就是:
1int event_add(struct event *ev, const struct timeval *timeout);
2int event_del(struct event *ev);
3int event_base_loop(struct event_base *base, int loops);
4void event_active(struct event *event, int res, short events);
5void event_process_active(struct event_base *base);
本节将按介绍事件注册和删除的代码流程,libevent的事件循环框架将在下一节再具体描述。
这些组件将在后面的内容描述。
1)注册事件 函数原型:
1int event_add(struct event *ev, const struct timeval *tv)
参数:ev:指向要注册的事件; tv:超时时间;
e函数将ev注册到ev->ev_base上,事件类型由ev->ev_events指明,
如果其中有一步操作失败,那么函数保证没有事件会被注册,可以讲这相当于一个原子操作。这个函数也体现了libevent细节之处的巧妙设计,且仔细看程序代码,部分有省略,注释直接附在代码中。
1int event_add(struct event *ev,
2 const struct timeval *tv)
3 {
4 struct event_base *base = ev->ev_base; // 要注册到的event_base
5 const struct eventop *evsel = base->evsel;
6 void *evbase = base->evbase; // base使用的系统I/O策略
7 // 新的timer事件,调用timer heap接口在堆上预留一个位置
8 // 注:这样能保证该操作的原子性:
9 // 向系统I/O机制注册可能会失败,而当在堆上预留成功后,
10 // 定时事件的添加将肯定不会失败;
11 // 而预留位置的可能结果是堆扩充,但是内部元素并不会改变
12 if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
13 if (min_heap_reserve(&base->timeheap,
14 1 + min_heap_size(&base->timeheap)) == -1)
15 return (-1); /* ENOMEM == errno */
16 }
17
18 // 如果事件ev不在已注册或者激活链表中,则调用evbase注册事件
19 if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
20 !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
21 res = evsel->add(evbase, ev);
22 if (res != -1) // 注册成功,插入event到已注册链表中
23 event_queue_insert(base, ev, EVLIST_INSERTED);
24 }
25 // 准备添加定时事件
26 if (res != -1 && tv != NULL) {
27 struct timeval now;
28 // EVLIST_TIMEOUT表明event已经在定时器堆中了,删除旧的
29 if (ev->ev_flags & EVLIST_TIMEOUT)
30 event_queue_remove(base, ev, EVLIST_TIMEOUT);
31 // 如果事件已经是就绪状态则从激活链表中删除
32 if ((ev->ev_flags & EVLIST_ACTIVE) &&
33 (ev->ev_res & EV_TIMEOUT)) {
34 // 将ev_callback调用次数设置为0
35 if (ev->ev_ncalls && ev->ev_pncalls) {
36 *ev->ev_pncalls = 0;
37 }
38 event_queue_remove(base, ev, EVLIST_ACTIVE);
39 }
40 // 计算时间,并插入到timer小根堆中
41 gettime(base, &now);
42 evutil_timeradd(&now, tv, &ev->ev_timeout);
43 event_queue_insert(base, ev, EVLIST_TIMEOUT);
44 }
45 return (res);
46}
1void event_queue_insert(struct event_base *base,
2 struct event *ev,
3 int queue)
4{
5 // ev可能已经在激活列表中了,避免重复插入
6 if (ev->ev_flags & queue) {
7 if (queue & EVLIST_ACTIVE)
8 return;
9 }
10
11 // ...
12 ev->ev_flags |= queue; // 记录queue标记
13 switch (queue) {
14 case EVLIST_INSERTED: // I/O或Signal事件,加入已注册事件链表
15 TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
16 break;
17 case EVLIST_ACTIVE: // 就绪事件,加入激活链表
18 base->event_count_active++;
19 TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], ev, ev_active_next);
20 break;
21 case EVLIST_TIMEOUT: // 定时事件,加入堆
22 min_heap_push(&base->timeheap, ev);
23 break;
24 }
25
26}
2)删除事件: 函数原型为:
1int event_del(struct event *ev);
该函数将删除事件ev
同样删除事件的操作则不一定是原子的,比如删除时间事件之后,有可能从系统I/O机制中注销会失败。
1int event_del(struct event *ev)
2 {
3 struct event_base *base;
4 const struct eventop *evsel;
5 void *evbase;
6 // ev_base为NULL,表明ev没有被注册
7 if (ev->ev_base == NULL)
8 return (-1);
9 // 取得ev注册的event_base和eventop指针
10 base = ev->ev_base;
11 evsel = base->evsel;
12 evbase = base->evbase;
13 // 将ev_callback调用次数设置为
14 if (ev->ev_ncalls && ev->ev_pncalls) {
15 *ev->ev_pncalls = 0;
16 }
17
18 // 从对应的链表中删除
19 if (ev->ev_flags & EVLIST_TIMEOUT)
20 event_queue_remove(base, ev, EVLIST_TIMEOUT);
21 if (ev->ev_flags & EVLIST_ACTIVE)
22 event_queue_remove(base, ev, EVLIST_ACTIVE);
23 if (ev->ev_flags & EVLIST_INSERTED) {
24 event_queue_remove(base, ev, EVLIST_INSERTED);
25 // EVLIST_INSERTED表明是I/O或者Signal事件,
26 // 需要调用I/O demultiplexer注销事件
27 return (evsel->del(evbase, ev));
28 }
29 return (0);
30}
分析了event_base这一重要结构体,初步看到了libevent对系统的I/O demultiplex机制的封装event_op结构,并结合源代码分析了事件的注册和删除处理,下面将会接着分析事件管理框架中的主事件循环部分。