事件处理框架event_base
正如我们在libevent源码分析(二) Reactor模式中提到的 R e a c t o r Reactor Reactor模式,其中包含事件源、 R e a c t o r Reactor Reactor框架、多路复用机制以及事件处理机制;而 e v e n t event event_ b a s e base base对应于 R e a c t o r Reactor Reactor模式中的 R e a c t o r Reactor Reactor框架。
在 l i b e v e n t libevent libevent中,对应为 e v e n t event event_ b a s e base base结构体,定义于 e v e n t − i n t e r n a l . h event-internal.h event−internal.h文件:
struct event_base {
//初始化Reactor的时候选择一种后端I/O复用机制,并记录在如下字段中
const struct eventop *evsel;
/**指向I/O复用机制真正存储的数据,它通过evsel成员的init函数来初始化 */
void *evbase;
/** 事件变化队列。其用途:如果一个文件描述符上注册的事件被多次修改,则可以使用缓冲来避免重复的系统调用(比如epoll_ctl)。它仅能用于时间复杂度为O(1)的I/O复用技术*/
struct event_changelist changelist;
/** 指向信号的后端处理机制 */
const struct eventop *evsigsel;
/** 信号事件处理器使用的数据结构*/
struct evsig_info sig;
/** 添加到该event_base的虚拟事件、激活事件和所有事件的数量*/
int virtual_event_count;
int virtual_event_count_max;
int event_count;
/** 添加到该event_base中的所有事件最大数量*/
int event_count_max;
/** Number of total events active in this event_base */
int event_count_active;
/** Maximum number of total events active in this event_base */
int event_count_active_max;
/** 是否执行完活动事件队列上剩余的任务之后就退出事件循环 */
int event_gotterm;
/** 是否立即退出事件循环*/
int event_break;
/** 是否启动一个新的事件循环 */
int event_continue;
/** 目前正在处理的活动事件队列的优先级*/
int event_running_priority;
/** 事件循环是否已经启动 */
int running_loop;
/** Set to the number of deferred_cbs we've made 'active' in the
* loop. This is a hack to prevent starvation; it would be smarter
* to just use event_config_set_max_dispatch_interval's max_callbacks
* feature */
int n_deferreds_queued;
/* 活动事件队列数组 */
/** 索引值越小的队列,优先级越高。高优先级的活动事件队列中的事件处理器将被优先处理
*/
struct evcallback_list *activequeues;
/** 活动事件队列数组的大小 */
int nactivequeues;
/** 下一次处理事件变为活动的回调函数列表 */
struct evcallback_list active_later_queue;
/* 下面3个成员用于管理通用计时器队列 */
/** An array of common_timeout_list* for all of the common timeout
* values we know. */
struct common_timeout_list **common_timeout_queues;
/** The number of entries used in common_timeout_queues */
int n_common_timeouts;
/** The total size of common_timeout_queues. */
int n_common_timeouts_allocated;
/** 文件描述符和I/O事件之间的映射关系 */
struct event_io_map io;
/** 信号值和信号事件之间的映射关系表. */
struct event_signal_map sigmap;
/** 时间堆 */
struct min_heap timeheap;
/** 管理系统时间的一些成员*/
struct timeval tv_cache;
struct evutil_monotonic_timer monotonic_timer;
/** Difference between internal time (maybe from clock_gettime) and
* gettimeofday. */
struct timeval tv_clock_diff;
/** Second in which we last updated tv_clock_diff, in monotonic time. */
time_t last_updated_clock_diff;
/*多线程支持*/
#ifndef EVENT__DISABLE_THREAD_SUPPORT
/* threading support */
/** 当前运行该event_base的事件循环的线程 */
unsigned long th_owner_id;
/** 对event_base的独占锁*/
void *th_base_lock;
/** 条件变量。用于唤醒正在等待某个事件处理完毕的线程. */
void *current_event_cond;
/** 等待current_event_cond的线程数*/
int current_event_waiters;
#endif
/** 正在执行其回调的事件 */
struct event_callback *current_event;
#ifdef _WIN32
/** IOCP support structure, if IOCP is enabled. */
struct event_iocp_port *iocp;
#endif
/** 该event_base的一些配置参数*/
enum event_base_config_flag flags;
struct timeval max_dispatch_time;
int max_dispatch_callbacks;
int limit_callbacks_after_prio;
/* 下面这组成员变量给工作线程唤醒主线程提供了方法 */
/** True if the base already has a pending notify, and we don't need
* to add any more. */
int is_notify_pending;
/** A socketpair used by some th_notify functions to wake up the main
* thread. */
evutil_socket_t th_notify_fd[2];
/** An event used by some th_notify functions to wake up the main
* thread. */
struct event th_notify;
/** A function used to wake up the main thread from another thread. */
int (*th_notify_fn)(struct event_base *base);
};
(1)
e
v
s
e
l
evsel
evsel 和
e
v
b
a
s
e
evbase
evbase看作是类和静态函数的关系,比如添加事件时的调用行为:
e
v
s
e
l
−
>
a
d
d
(
e
v
b
a
s
e
,
e
v
)
evsel->add(evbase, ev)
evsel−>add(evbase,ev),实际执行操作的是
e
v
b
a
s
e
evbase
evbase;这相当于
c
l
a
s
s
:
:
a
d
d
(
i
n
s
t
a
n
c
e
,
e
v
)
class::add(instance, ev)
class::add(instance,ev),
i
n
s
t
a
n
c
e
instance
instance 就是
c
l
a
s
s
class
class 的一个对象实例。
e
v
s
e
l
evsel
evsel指向了全局变量
s
t
a
t
i
c
static
static
c
o
n
s
t
const
const
s
t
r
u
c
t
struct
struct
e
v
e
n
t
o
p
eventop
eventop
∗
e
v
e
n
t
o
p
s
[
]
*eventops[]
∗eventops[]中的一个;
前面也说过,
l
i
b
e
v
e
n
t
libevent
libevent将系统提供的
I
/
O
I/O
I/O
d
e
m
u
l
t
i
p
l
e
x
demultiplex
demultiplex机制统一封装成了
e
v
e
n
t
o
p
eventop
eventop结构;因此
e
v
e
n
t
o
p
s
[
]
eventops[]
eventops[]包含了
s
e
l
e
c
t
select
select、
p
o
l
l
poll
poll、
k
e
q
u
e
u
e
kequeue
kequeue和
e
p
o
l
l
epoll
epoll等等其中的若干个全局实例对象。
e
v
b
a
s
e
evbase
evbase实际上是一个
e
v
e
n
t
o
p
eventop
eventop实例对象;
先来看看
e
v
e
n
t
o
p
eventop
eventop结构体,它的成员是一系列的函数指针, 在
e
v
e
n
t
−
i
n
t
e
r
n
a
l
.
h
event-internal.h
event−internal.h文件中:
struct eventop {
/** 后端I/O复用技术的名称 */
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 *);
/** 释放I/O复用机制使用的资源*/
void (*dealloc)(struct event_base *);
/** 程序调用fork之后是否需要重新初始化event_base
*/
int need_reinit;
/**I/O复用技术支持的一些特性,可选如下3个值得按位或:EV_FEATURE_ET(支持边沿触发事件EV_ET)、EV_FEATURE_O1(事件检测算法的复杂度是O(1)和EV_FEATURE_FDS(不仅能监听socket上的事件,还能监听其它类型的文件描述符上的事件) */
enum event_method_feature features;
/** 有的I/O复用机制需要为每个I/O事件队列和信号事件队列分配额外的内存,以避免同一个文件描述符被重复插入I/O复用机制的事件表中。下面这个变量指定了这段内存的长度
*/
size_t fdinfo_len;
};
在
l
i
b
e
v
e
n
t
libevent
libevent 中,每种
I
/
O
I/O
I/O
d
e
m
u
l
t
i
p
l
e
x
demultiplex
demultiplex 机制的实现都必须提供这五个函数接口:
来完成自身的初始化、销毁释放、对事件的注册、注销和分发。
(2) l i b e v e n t libevent libevent提供的后端I/O复用技术,位于 e v e n t . c event.c event.c文件:
#ifdef EVENT__HAVE_EVENT_PORTS
extern const struct eventop evportops;
#endif
#ifdef EVENT__HAVE_SELECT
extern const struct eventop selectops;
#endif
#ifdef EVENT__HAVE_POLL
extern const struct eventop pollops;
#endif
#ifdef EVENT__HAVE_EPOLL
extern const struct eventop epollops;
#endif
#ifdef EVENT__HAVE_WORKING_KQUEUE
extern const struct eventop kqops;
#endif
#ifdef EVENT__HAVE_DEVPOLL
extern const struct eventop devpollops;
#endif
#ifdef _WIN32
extern const struct eventop win32ops;
#endif
/* 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
};
创建和初始化event_base
- 创建一个 e v e n t event event_ b a s e base base 对象也既是创建了一个新的 l i b e v e n t libevent libevent 实例,程序需要通过调用 e v e n t event event_ i n i t ( ) init() init()或 e v e n t event event_ b a s e base base_ n e w new new()(内部调用 e v e n t event event_ b a s e base base_ n e w new new_ w i t h with with_ c o n f i g config config 函数执行具体操作)函数来创建,该函数同时还对新生成的 l i b e v e n t libevent libevent 实例进行了初始化。
- 该函数首先为 e v e n t event event_ b a s e base base 实例申请空间,然后初始化 t i m e r timer timer m i n i − h e a p mini-heap mini−heap,选择并初始化合适的系统 I / O I/O I/O 的 d e m u l t i p l e x e r demultiplexer demultiplexer 机制,初始化各事件链表;
- 函数还检测了系统的时间设置,为后面的时间管理打下基础。
接口函数
R
e
a
c
t
o
r
Reactor
Reactor 框架的作用就是提供事件的注册、注销接口;根据系统提供的事件多
路分发机制执行事件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数来处理事件。
L i b e v e n t Libevent Libevent中对应的接口函数主要是:
int event_add(struct event *ev, const struct timeval *tv);
int event_del(struct event *ev);
int event_base_loop(struct event_base *base, int loops);
void event_active(struct event *event, int res, short events);
void event_process_active(struct event_base *base);
本节将按介绍事件注册和删除的代码流程, l i b e v e n t libevent libevent 的事件循环框架将在下一节再具体描述。
(1)注册事件
函数原型:
int event_add(struct event *ev, const struct timeval *tv)
参数:
e
v
ev
ev:指向要注册的事件;
t
v
tv
tv:超时时间;
函数将
e
v
ev
ev 注册到
e
v
−
>
e
v
ev->ev
ev−>ev_
b
a
s
e
base
base 上,事件类型由
e
v
−
>
e
v
ev->ev
ev−>ev_
e
v
e
n
t
s
events
events 指明,如果注册成功,
e
v
ev
ev将被插入到已注册链表中;如果
t
v
tv
tv 不是
N
U
L
L
NULL
NULL,则会同时注册定时事件,将
e
v
ev
ev 添加到
t
i
m
e
r
timer
timer堆上;
如果其中有一步操作失败,那么函数保证没有事件会被注册,可以讲这相当于一个原子
操作。
int
event_add(struct event *ev, const struct timeval *tv)
{
int res;
if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
event_warnx("%s: event has no event_base set.", __func__);
return -1;
}
/* 防止多线程访问出错,加了锁,并且调用了event_add_internal函数*/
EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
res = event_add_internal(ev, tv, 0);
EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
return (res);
}
int
event_add_internal(struct event *ev, const struct timeval *tv,
int tv_is_absolute)
{
struct event_base *base = ev->ev_base;
int res = 0;
int notify = 0;
EVENT_BASE_ASSERT_LOCKED(base);
_event_debug_assert_is_setup(ev);
event_debug((
"event_add: event: %p (fd "EV_SOCK_FMT"), %s%s%s%scall %p",
ev,
EV_SOCK_ARG(ev->ev_fd),
ev->ev_events & EV_READ ? "EV_READ " : " ",
ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
ev->ev_events & EV_CLOSED ? "EV_CLOSED " : " ",
tv ? "EV_TIMEOUT " : " ",
ev->ev_callback));
EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));
/*
*如果新添加的事件处理器是定时器,且它尚未被添加到通用定时器队列或时间堆中,则
*为定时器在时间堆上预留一个位置
*/
if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
if (min_heap_reserve(&base->timeheap,
1 + min_heap_size(&base->timeheap)) == -1)
return (-1); /* ENOMEM == errno */
}
/* 如果当前调用者不是主线程(执行事件循环的线程), 并且被添加的事件处理器是信号
*事件处理器,而且主线程正在执行该信号事件处理器的回调函数,则当前调用者必须
*等待主线程完成调用,否则将引起竞态条件. */
#ifndef EVENT__DISABLE_THREAD_SUPPORT
if (base->current_event == event_to_event_callback(ev) &&
(ev->ev_events & EV_SIGNAL)
&& !EVBASE_IN_THREAD(base)) {
++base->current_event_waiters;
EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
}
#endif
if ((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL)) &&
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
if (ev->ev_events & (EV_READ|EV_WRITE))
/*添加I/O事件和I/O事件处理器的映射关系 */
res = evmap_io_add(base, ev->ev_fd, ev);
else if (ev->ev_events & EV_SIGNAL)
/*添加信号事件和信号事件处理器的映射关系*/
res = evmap_signal_add(base, (int)ev->ev_fd, ev);
if (res != -1)
/*将事件处理器插入注册事件队列*/
event_queue_insert(base, ev, EVLIST_INSERTED);
if (res == 1) {
/* 事件多路分发器中添加了新事件,通知主线程 */
notify = 1;
res = 0;
}
}
/*
* 下面将事件处理器添加至通用计时器队列或时间堆中。对于信号事件处理器和I/O事件
* 处理器,根据evmap_*_add函数的结果决定是否添加(这是为了给事件设置超时);而对
* 于定时器,则始终应该添加之
*/
if (res != -1 && tv != NULL) {
struct timeval now;
int common_timeout;
/*
* 对于永久性事件处理器,如果其超时时间不是绝对时间,则将该事件处理器的超
* 时时间记录在变量ev->ev_io_timeout中
*/
if (ev->ev_closure == EV_CLOSURE_EVENT_PERSIST && !tv_is_absolute)
ev->ev_io_timeout = *tv;
/*
*如果该事件处理器已经被插入通用定时器队列或时间堆中,则先删除它
*/
if (ev->ev_flags & EVLIST_TIMEOUT) {
if (min_heap_elt_is_top(ev))
notify = 1;
event_queue_remove_timeout(base, ev);
}
/*
*如果待添加的事件处理器已经被激活,且原因是超时,则从活动事件队列中删
*除它,以避免其回调函数被执行。对于信号事件处理器,必要时还需将其ncalls
*成员设置为0.信号时间被触发时,ncalls指定其回调函数被执行的次数,将ncalls
*设置为0,可以干净地终止信号事件地处理
*/
if ((ev->ev_flags & EVLIST_ACTIVE) &&
(ev->ev_res & EV_TIMEOUT)) {
if (ev->ev_events & EV_SIGNAL) {
if (ev->ev_ncalls && ev->ev_pncalls) {
*ev->ev_pncalls = 0;
}
}
event_queue_remove(base, ev, EVLIST_ACTIVE);
}
gettime(base, &now);
common_timeout = is_common_timeout(tv, base);
if (tv_is_absolute) {
ev->ev_timeout = *tv;
/* 判断应该将定时器插入通用定时器队列,还是插入时间堆*/
} else if (common_timeout) {
struct timeval tmp = *tv;
tmp.tv_usec &= MICROSECONDS_MASK;
evutil_timeradd(&now, &tmp, &ev->ev_timeout);
ev->ev_timeout.tv_usec |=
(tv->tv_usec & ~MICROSECONDS_MASK);
} else {
/*加上当前系统时间,以取得定时器超时地绝对时间*/
evutil_timeradd(&now, tv, &ev->ev_timeout);
}
event_debug((
"event_add: event %p, timeout in %d seconds %d useconds, call %p",
ev, (int)tv->tv_sec, (int)tv->tv_usec, ev->ev_callback));
event_queue_insert(base, ev, EVLIST_TIMEOUT); //插入定时器
/*如果被插入的事件处理器是通用定时器队列中的第一个元素,则通过调用common_timeout_schedule函数将其转移到时间堆中*/
if (common_timeout) {
struct common_timeout_list *ctl =
get_common_timeout_list(base, &ev->ev_timeout);
if (ev == TAILQ_FIRST(&ctl->events)) {
common_timeout_schedule(ctl, &now, ev);
}
} else {
/* See if the earliest timeout is now earlier than it
* was before: if so, we will need to tell the main
* thread to wake up earlier than it would otherwise.
* We double check the timeout of the top element to
* handle time distortions due to system suspension.
*/
if (min_heap_elt_is_top(ev))
notify = 1;
}
}
/* 如果必要,唤醒主线程 */
if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
evthread_notify_base(base);
_event_debug_note_add(ev);
return (res);
}
e
v
e
n
t
event
event_
q
u
e
u
e
queue
queue_
i
n
s
e
r
t
insert
insert():负责将事件插入到对应的链表中
e
v
e
n
t
event
event_
q
u
e
u
e
queue
queue_
r
e
m
o
v
e
remove
remove():负责将事件从对应的链表中删除
void event_queue_insert(struct event_base *base, struct event *ev,
int queue)
{
EVENT_BASE_ASSERT_LOCKED(base);
// ev可能已经在激活列表中了,避免重复插入
if (ev->ev_flags & queue) {
if (queue & EVLIST_ACTIVE)
return;
event_errx(1. "%s: %p(fd %d) already on queue %x", __func__,
ev, ev->ev_fd, queue);
return;
}
if (~ev->ev_flags & EVLIST_INTERNAL)
base->event_count++; //将event_base拥有的事件处理器总数+1
ev->ev_flags |= queue; // 记录queue标记
switch (queue) {
case EVLIST_INSERTED: // I/O或Signal事件,加入已注册事件链表
TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
break;
case EVLIST_ACTIVE: // 就绪事件,加入激活链表
base->event_count_active++;
TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], ev,
ev_active_next);
break;
//将定时器插入通用计时器队列或时间堆
case EVLIST_TIMEOUT: {
if (is_common_timeout(&ev->ev_timeout, base)) {
struct common_timeout_list *ctl =
get_common_timeout_list(base, &ev->ev_timeout);
insert_common_timeout_inorder(ctl, ev);
} else
min_heap_push(&base->timeheap, ev);
break;
}
default:
event_errx(1, "%s: unknown queue %x", __func__, queue);
}
}
(2)删除事件
函数原型为:
int event_del(struct event *ev);
该函数将删除事件 e v ev ev,对于 I / O I/O I/O 事件,从 I / O I/O I/O 的 d e m u l t i p l e x e r demultiplexer demultiplexer 上将事件注销;对于 S i g n a l Signal Signal事件,将从 S i g n a l Signal Signal 事件链表中删除;对于定时事件,将从堆上删除;同样删除事件的操作则不一定是原子的,比如删除时间事件之后,有可能从系统 I / O I/O I/O 机制中注销会失败。
int
event_del(struct event *ev)
{
int res;
if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
event_warnx("%s: event has no event_base set.", __func__);
return -1;
}
EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
res = event_del_internal(ev);
EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
return (res);
}
static inline int
event_del_internal(struct event* ev)
{
struct event_base *base;
int res = 0, notify = 0;
event_debug(("event_del: %p (fd "EV_SOCK_FMT"), callback %p",
ev, EV_SOCK_ARG(ev->ev_fd), ev->ev_callback));
/* ev_base为NULL,表明ev没有被注册 */
if (ev->ev_base == NULL)
return (-1);
EVENT_BASE_ASSERT_LOCKED(ev->ev_base);
base = ev->ev_base;
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
if (base->current_event == ev && !EVBASE_IN_THREAD(base)) {
++base->current_event_waiters;
EVTHREAD_COND_WAIT(base->current_event_cond, base_th_base_lock);
}
#endif
EVUTIL_ASSERT(!(ev->ev_flags &~EVLIST_ALL));
//如果ev存在并且为信号事件则将ev_callback调用次数设置为0
if (ev->ev_events & EV_SIGNAL) {
if (ev->ev_ncalls && ev->ev_pncalls) {
ev->ev_ncalls = 0;
}
}
//从对应的链表中删除
if (ev->ev_flags & EVLIST_TIMEOUT) {
event_queue_remove(base, ev, EVLIST_TIMEOUT);
}
if (ev->ev_flags & EVLIST_ACTIVE)
event_queue_remove_active(base, event_to_event_callback(ev));
if (ev->ev_flags & EVLIST_INSERTED) {
event_queue_remove_inserted(base, ev);
if (ev->ev_events & (EV_READ|EV_WRITE))
res = evmap_io_del(base, ev->ev_fd, ev);
else
res = evmap_signal_del(base, (int)ev->ev_fd, ev);
if (res == 1) {
/* evmap says we need to notify the main thread. */
notify = 1;
res = 0;
}
}
/* 如果不是正确的线程,则需要重新开始循环 */
if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
evthread_notify_base(base);
_event_debug_note_del(ev);
return (res);
}