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相关文章推荐
- libevent2.0分析:事件循环的一生
- libevent高性能网络库源码分析——事件循环(五)
- libevent源码分析(9)--2.1.8--事件注册和删除
- libevent源码分析--定时器和信号事件处理
- libevent事件处理框架分析
- libevent源码分析之带有定时器的事件
- libevent事件处理框架分析
- 第5章7节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 循环获取并执行事件
- 第5章7节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 循环获取并执行事件 - runMonkeyCycles(原创)
- LibEvent中文帮助文档-第7章【事件循环】
- libevent源码分析(10)--2.1.8--事件激活
- libevent源码剖析-事件主循环
- Muduo网络库源码分析(一) EventLoop事件循环(Poller和Channel)
- libevent源码分析--事件处理框架
- Nginx源码分析-事件循环
- [libevent]事件主循环
- 实例分析JS与Node.js中的事件循环
- GDB调试器源代码分析系列--事件循环机制(2)
- Tornado高性能的秘密:ioloop对象分析 (副标题:IOLoop是个事件循环)
- libevent源码分析之事件激活