您的位置:首页 > 其它

libevent2.0分析:事件循环的一生

2014-02-22 14:36 369 查看
对于一个网络框架而言,其中的事件循环无疑是重要的组成部分,下面,我们就来分析一下libevent的事件循环。

一:关键结构体event_base

libevent中的事件循环信息主要是存在结构体event_base中

PS:这个结构体成员太多,我没有全部列出,只是列出了一部分比较重要的

struct event_base {
//指定某个eventop结构体,它决定了该event_base使用哪种I/O多路复用技术(注解1)
const struct eventop *evsel;
void *evbase;

//告知后端下次执行事件分发时需要注意的哪些事件
struct event_changelist changelist;

//一个eventop,专门用来处理信号事件的
const struct eventop *evsigsel;
//存储信号处理的信息
struct evsig_info sig;

//虚拟事件的个数
int virtual_event_count;
//总事件个数
int event_count;
//活跃事件个数
int event_count_active;

//处理完当前所有的事件之后退出
int event_gotterm;
//立即退出
int event_break;
//立即启动一个新的事件循环
int event_continue;

//当前运行事件的优先级
int event_running_priority;

//是否正在进行事件循环
int running_loop;

//活跃事件的链表
struct event_list *activequeues;
//活跃事件的个数
int nactivequeues;

//要延迟处理的事件队列
struct deferred_cb_queue defer_queue;

//IO事件队列(这个命名。。。)
struct event_io_map io;

//信号事件队列
struct event_signal_map sigmap;

//所有注册事件的队列
struct event_list eventqueue;

//管理定时事件的最小堆
struct min_heap timeheap;

//IO就绪的时候和缓存时间(这里我也不会怎么说明)
struct timeval event_tv;
struct timeval tv_cache;

......
};


二:event_base的创建

创建一个event_base,要使用event_base_new函数,而这个函数主要是调用了event_base_new_with_config,下面对其进行分析
struct event_base *event_base_new_with_config(const struct event_config *cfg)
{
int i;
struct event_base *base;
int should_check_environment;

#ifndef _EVENT_DISABLE_DEBUG_MODE
event_debug_mode_too_late = 1;
#endif

//为结构体分配内存
if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) {
event_warn("%s: calloc", __func__);
return NULL;
}

//确定程序是否能使用monotonic时间
detect_monotonic();
//获取当前系统时间
gettime(base, &base->event_tv);

//初始化定时器小根堆
min_heap_ctor(&base->timeheap);
//初始化事件队列
TAILQ_INIT(&base->eventqueue);

//初始化用于信号事件的pair
base->sig.ev_signal_pair[0] = -1;
base->sig.ev_signal_pair[1] = -1;
//初始化用于线程通信的pair
base->th_notify_fd[0] = -1;
base->th_notify_fd[1] = -1;

//初始化deferred_queue
event_deferred_cb_queue_init(&base->defer_queue);
base->defer_queue.notify_fn = notify_base_cbq_callback;
base->defer_queue.notify_arg = base;

//设置标识位
if (cfg)
base->flags = cfg->flags;

//初始化各个队列
evmap_io_initmap(&base->io);
evmap_signal_initmap(&base->sigmap);
event_changelist_init(&base->changelist);

base->evbase = NULL;

should_check_environment =
!(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));

//遍历整个eventops数组,选择最优的IO复用机制(注解1)
for (i = 0; eventops[i] && !base->evbase; i++) {
if (cfg != NULL) {
/* determine if this backend should be avoided */

if (event_config_is_avoided_method(cfg,
eventops[i]->name))
continue;
if ((eventops[i]->features & cfg->require_features)
!= cfg->require_features)
continue;
}

/* also obey the environment variables */
if (should_check_environment &&
event_is_method_disabled(eventops[i]->name))
continue;

//选择之后,对其进行初始化
base->evsel = eventops[i];
base->evbase = base->evsel->init(base);
}

//选择IO机制失败或对其进行初始化失败,返回NULL
if (base->evbase == NULL) {
event_warnx("%s: no event mechanism available",
__func__);
base->evsel = NULL;
event_base_free(base);
return NULL;
}

if (evutil_getenv("EVENT_SHOW_METHOD"))
event_msgx("libevent using: %s", base->evsel->name);

//初始化优先级队列
if (event_base_priority_init(base, 1) < 0) {
event_base_free(base);
return NULL;
}

/* prepare for threading */

//以下都是线程或WINDOWS方面内容的初始化,略过
..............

return (base);
}


三:开始事件循环

libevent中,开始事件要使用event_base_dispatch函数,这个函数只是event_base_loop的马甲
int event_base_loop(struct event_base *base, int flags)
{
const struct eventop *evsel = base->evsel;
struct timeval tv;
struct timeval *tv_p;
int res, done, retval = 0;

/* Grab the lock.  We will release it inside evsel.dispatch, and again
* as we invoke user callbacks. */
EVBASE_ACQUIRE_LOCK(base, th_base_lock);

//如果running_loop非零,证明该事件循环已启动,直接返回-1
if (base->running_loop) {
event_warnx("%s: reentrant invocation.  Only one event_base_loop"
" can run on each event_base at once.", __func__);
EVBASE_RELEASE_LOCK(base, th_base_lock);
return -1;
}

base->running_loop = 1;

//清空时间缓存
clear_time_cache(base);

//如果加入了信号事件,就初始化与信号相关的全局变量
if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)
evsig_set_base(base);

done = 0;

#ifndef _EVENT_DISABLE_THREAD_SUPPORT
base->th_owner_id = EVTHREAD_GET_ID();
#endif

base->event_gotterm = base->event_break = 0;

while (!done) {
base->event_continue = 0;

/* Terminate the loop if we have been asked to */
if (base->event_gotterm) {
break;
}

if (base->event_break) {
break;
}

//更新时间缓存
timeout_correct(base, &tv);

tv_p = &tv;
//如果有活动event或者指定标识EVLOOP_NONBLOCK,清空时间tv。
//否则计算一下要等待下一个定时事件发生的时间。
if (!N_ACTIVE_CALLBACKS(base) && !(flags & EVLOOP_NONBLOCK)) {
timeout_next(base, &tv_p);
} else {
/*
* if we have active events, we just poll new events
* without waiting.
*/
evutil_timerclear(&tv);
}

/* If we have no events, we just exit */
if (!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
event_debug(("%s: no events registered.", __func__));
retval = 1;
goto done;
}

/* update last old time */
gettime(base, &base->event_tv);

clear_time_cache(base);

//调用后端的处理函数(注1)
res = evsel->dispatch(base, tv_p);

if (res == -1) {
event_debug(("%s: dispatch returned unsuccessfully.",
__func__));
retval = -1;
goto done;
}

//更新时间缓存
update_time_cache(base);

//处理已过期的事件
//将这些事件从各个队列中取出,加入active队列,并在ev_res中设置EV_TIMEOUT标识
timeout_process(base);

//关键的事件处理函数event_process_active,以后的文章会详细介绍
//如果没有事件了,就结束循环
if (N_ACTIVE_CALLBACKS(base)) {
int n = event_process_active(base);
if ((flags & EVLOOP_ONCE)
&& N_ACTIVE_CALLBACKS(base) == 0
&& n != 0)
done = 1;
} else if (flags & EVLOOP_NONBLOCK)
done = 1;
}
event_debug(("%s: asked to terminate loop.", __func__));

done:

clear_time_cache(base);
base->running_loop = 0;

EVBASE_RELEASE_LOCK(base, th_base_lock);

return (retval);
}


四:结束事件循环

libevent中,我们使用event_base_loopexit函数结束一个事件循环,这个函数其实只是注册了一个只运行一次的定时器(event_loopexit_cb),而event_loopexit_cb只是简单地将标志位(event_gotterm)设置为1,请看代码:
int event_base_loopexit(struct event_base *event_base, const struct timeval *tv)
{
return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb,
event_base, tv));
}

/** Callback: used to implement event_base_loopexit by telling the event_base
* that it's time to exit its loop. */
static void
event_loopexit_cb(evutil_socket_t fd, short what, void *arg)
{
struct event_base *base = arg;
base->event_gotterm = 1;
}


五:event_base的销毁

这个函数比较简单,代码里的注释也比较详细,就不多作解释了
void event_base_free(struct event_base *base)
{
int i, n_deleted=0;
struct event *ev;
/* XXXX grab the lock? If there is contention when one thread frees
* the base, then the contending thread will be very sad soon. */

/* event_base_free(NULL) is how to free the current_base if we
* made it with event_init and forgot to hold a reference to it. */
if (base == NULL && current_base)
base = current_base;
/* If we're freeing current_base, there won't be a current_base. */
if (base == current_base)
current_base = NULL;
/* Don't actually free NULL. */
if (base == NULL) {
event_warnx("%s: no base to free", __func__);
return;
}
/* XXX(niels) - check for internal events first */

#ifdef WIN32
event_base_stop_iocp(base);
#endif

/* threading fds if we have them */
if (base->th_notify_fd[0] != -1) {
event_del(&base->th_notify);
EVUTIL_CLOSESOCKET(base->th_notify_fd[0]);
if (base->th_notify_fd[1] != -1)
EVUTIL_CLOSESOCKET(base->th_notify_fd[1]);
base->th_notify_fd[0] = -1;
base->th_notify_fd[1] = -1;
event_debug_unassign(&base->th_notify);
}

/* Delete all non-internal events. */
for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) {
struct event *next = TAILQ_NEXT(ev, ev_next);
if (!(ev->ev_flags & EVLIST_INTERNAL)) {
event_del(ev);
++n_deleted;
}
ev = next;
}
while ((ev = min_heap_top(&base->timeheap)) != NULL) {
event_del(ev);
++n_deleted;
}
for (i = 0; i < base->n_common_timeouts; ++i) {
struct common_timeout_list *ctl =
base->common_timeout_queues[i];
event_del(&ctl->timeout_event); /* Internal; doesn't count */
event_debug_unassign(&ctl->timeout_event);
for (ev = TAILQ_FIRST(&ctl->events); ev; ) {
struct event *next = TAILQ_NEXT(ev,
ev_timeout_pos.ev_next_with_common_timeout);
if (!(ev->ev_flags & EVLIST_INTERNAL)) {
event_del(ev);
++n_deleted;
}
ev = next;
}
mm_free(ctl);
}
if (base->common_timeout_queues)
mm_free(base->common_timeout_queues);

for (i = 0; i < base->nactivequeues; ++i) {
for (ev = TAILQ_FIRST(&base->activequeues[i]); ev; ) {
struct event *next = TAILQ_NEXT(ev, ev_active_next);
if (!(ev->ev_flags & EVLIST_INTERNAL)) {
event_del(ev);
++n_deleted;
}
ev = next;
}
}

if (n_deleted)
event_debug(("%s: %d events were still set in base",
__func__, n_deleted));

if (base->evsel != NULL && base->evsel->dealloc != NULL)
base->evsel->dealloc(base);

for (i = 0; i < base->nactivequeues; ++i)
EVUTIL_ASSERT(TAILQ_EMPTY(&base->activequeues[i]));

EVUTIL_ASSERT(min_heap_empty(&base->timeheap));
min_heap_dtor(&base->timeheap);

mm_free(base->activequeues);

EVUTIL_ASSERT(TAILQ_EMPTY(&base->eventqueue));

evmap_io_clear(&base->io);
evmap_signal_clear(&base->sigmap);
event_changelist_freemem(&base->changelist);

EVTHREAD_FREE_LOCK(base->th_base_lock, EVTHREAD_LOCKTYPE_RECURSIVE);
EVTHREAD_FREE_COND(base->current_event_cond);

mm_free(base);
}


六:注解

注解1:请见:http://blog.csdn.net/small_qch/article/details/19487929
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: