event_base_dispatch启动循环,其实是调用了event_base_loop
int
event_base_dispatch(struct event_base *event_base)
{
return (event_base_loop(event_base, 0));
}
int
event_base_loop(struct event_base *base, int flags)
{
/*evsel为base中操作IO复用的结构,下面封装了下面几个函数,编译时指定I/O复用后,无论是epoll还是kequeue等,都要实现这几个方法
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 *);
*/
const struct eventop *evsel = base->evsel;
struct timeval tv;
struct timeval *tv_p;
int res, done, retval = 0;
//防止多线程重入--start
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
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;
//防止多线程重入--end
//time cache置零
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;
}
/*时间校正,如5点添加了事件,而后用户改动了时间到2点,则表明时间出了问题,将时间小根堆 里的全部时间减3*/
timeout_correct(base, &tv);
tv_p = &tv;
if (!N_ACTIVE_CALLBACKS(base) && !(flags & EVLOOP_NONBLOCK)) {
timeout_next(base, &tv_p);
} else {
/*
有已经激活的事件或者延迟回调没执行则清除时间缓存退出
*/
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;
}
/* last wait time置为time cache,cache没有则获取系统时间 */
gettime(base, &base->event_tv);
//清除time cache
clear_time_cache(base);
//IO复用如epoll_wait执行一次
res = evsel->dispatch(base, tv_p);
if (res == -1) {
event_debug(("%s: dispatch returned unsuccessfully.",
__func__));
retval = -1;
goto done;
}
//更新cache,设为当前时间
update_time_cache(base);
//查找小根堆,超时时间的事件清除并加入激活时间队列
//event_active_nolock(ev, EV_TIMEOUT, 1);
timeout_process(base);
//event_process_active执行激活列表activequeues[priority]中事件的回调
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能管理信号事件的关键
/*
struct evsig_info {
// 用来监视下面ev_signal_pair[1]的事件
struct event ev_signal;
/*设置了socketpair,且在 signal.c :373中定义了
evsig_handler{
...
signal(sig, evsig_handler);
msg = sig;
send(evsig_base_fd, (char*)&msg, 1, 0);
errno = save_errno;
...
}
posix风格的signal函数使得当接收到信号sig时,调用本函数将sig(int类型)发送至evsig_base_fd( = base->sig.ev_signal_pair[0]),从而激活socketpair[1]的可读事件从而达到将signal加入事件循环的目的
*/
evutil_socket_t ev_signal_pair[2];
//True iff we've added the ev_signal event yet.
int ev_signal_added;
//Count of the number of signals we're currently watching.
int ev_n_signals_added;
/* Array of previous signal handler objects before Libevent started
* messing with them. Used to restore old signal handlers. */
#ifdef _EVENT_HAVE_SIGACTION
struct sigaction **sh_old;
#else
ev_sighandler_t **sh_old;
#endif
int sh_old_max;
};
*/
- 时间缓存 time_cache
while(!done){
…
}
此循环每次开始都会检查done变量,如果有事件激活则进入下方的event_process_active,done会置1,循环结束;若没事件激活则一直循环,循环中,每次判断进入event_process_active之前会更新time_cache,则下次进入循环就一直使用该时间作为当前时间,不必每次都调用gettimeofday(glibc 函数,不是系统调用)
参考浅谈时间函数gettimeofday的成本