libevent-1.4/sample/singnal-test.c
接下来看看 event_base_dispatch(base);
这个函数是整个Reactor的核心,是一个loop.
函数定义:
int event_base_dispatch(struct event_base *event_base)
{
return (event_base_loop(event_base, 0));
}
event_base_dispatch调用event_base_loop:
int event_base_loop(struct event_base *base, int flags)
{
const struct eventop *evsel = base->evsel;
void *evbase = base->evbase;
struct timeval tv;
struct timeval *tv_p;
int res, done;
/* clear time cache */
base->tv_cache.tv_sec = 0;
if (base->sig.ev_signal_added)
evsignal_base = base;
done = 0;
while (!done) {
/* Terminate the loop if we have been asked to */
if (base->event_gotterm) {
base->event_gotterm = 0;
break;
}
if (base->event_break) {
base->event_break = 0;
break;
}
/* You cannot use this interface for multi-threaded apps */
while (event_gotsig) {
event_gotsig = 0;
if (event_sigcb) {
res = (*event_sigcb)();
if (res == -1) {
errno = EINTR;
return (-1);
}
}
}
timeout_correct(base, &tv);
tv_p = &tv;
if (!base->event_count_active && !(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)) {
event_debug(("%s: no events registered.", __func__));
return (1);
}
/* update last old time */
gettime(base, &base->event_tv);
/* clear time cache */
base->tv_cache.tv_sec = 0;
res = evsel->dispatch(base, evbase, tv_p);
if (res == -1)
return (-1);
gettime(base, &base->tv_cache);
timeout_process(base);
if (base->event_count_active) {
event_process_active(base);
if (!base->event_count_active && (flags & EVLOOP_ONCE))
done = 1;
} else if (flags & EVLOOP_NONBLOCK)
done = 1;
}
/* clear time cache */
base->tv_cache.tv_sec = 0;
event_debug(("%s: asked to terminate loop.", __func__));
return (0);
}
可以看到event_base_loop基本上就是一个while循环,不断的处理信号事件、定时事件以及监听事件,从程序流程来看,信号、定时以及监听事件分别独立处理。
通过注释也可以看到,信号事件的处理不能在多线程中使用,原因是使用了全局变量event_gotsig、event_sigcb,但其实我们注册的信号SIGINT函数不在此处处理,可以去看看event_add函数,也是就上篇文章l ibevent源码分析(五)。在上篇中曾说过当信号被捕获到时,信号响应函数向ev_signal_pair[0]写数据,从而导致ev_signal_pair[1]读事件就绪,从而唤醒event_base_dispatch中的监听loop,唤醒部分在代码
evsel->dispatch(base, evbase, tv_p)——epoll_dispatch
——epoll_wait(epollop->epfd, events, epollop->nevents, timeout)
epoll_wait系统调用就是监听的事件就绪以后会返回,是否阻塞取决于timeout的值,有定时事件时就超时,没有就阻塞。
可以看到epoll_wait返回后首先处理的就是信号,可以是唤醒的被正常注册的信号,也可以是被信号影响而直接返回。
sig.evsignal_caught信号捕获标志在
evsignal_process(base)函数中被清空,计数sig->evsigcaught[SIGINT]也被使用到了,信号事件被插入到激活队列
event_active(ev, EV_SIGNAL, ncalls)——event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);//base->event_count_active++;
返回event_base_loop函数看关于base->event_count_active部分的处理:
if (base->event_count_active) {
event_process_active(base);
if (!base->event_count_active && (flags & EVLOOP_ONCE))
done = 1;
}
在SIGINT事件插入激活列表时base->event_count_active++,所以会继续处理event_process_active(base):
static void
event_process_active(struct event_base *base)
{
struct event *ev;
struct event_list *activeq = NULL;
int i;
short ncalls;
for (i = 0; i < base->nactivequeues; ++i) {
if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
activeq = base->activequeues[i];
break;
}
}
for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
if (ev->ev_events & EV_PERSIST)
event_queue_remove(base, ev, EVLIST_ACTIVE);
else
event_del(ev);
/* Allows deletes to work */
ncalls = ev->ev_ncalls;
ev->ev_pncalls = &ncalls;
while (ncalls) {
ncalls--;
ev->ev_ncalls = ncalls;
(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
if (event_gotsig || base->event_break) {
ev->ev_pncalls = NULL;
return;
}
}
ev->ev_pncalls = NULL;
}
}
遍历激活队列,处理相应的事件回调函数。其中
ncalls就是在信号函数被处理时刻对应的计数sig->evsigcaught[SIGINT]的值,
ev来源于
for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq))
那么activeq又是来源于base->activequeues[i],看下函数流程,关于base->activequeues[i]部分:
event_base_dispatch(base);
event_base_loop(base, 0);
evsel->dispatch(base, base->evbase, tv_p)//没有定时事件,tv_p=NULL
epoll_dispatch(base, base->evbase, tv_p)
evsignal_process(base)
其中,在evsignal_process(base)中:
for (i = 1; i < NSIG; ++i) {
ncalls = sig->evsigcaught[i];
if (ncalls == 0)
continue;
sig->evsigcaught[i] -= ncalls;
for (ev = TAILQ_FIRST(&sig->evsigevents[i]);ev != NULL; ev = next_ev)
{
next_ev = TAILQ_NEXT(ev, ev_signal_next);
if (!(ev->ev_events & EV_PERSIST))
event_del(ev);
event_active(ev, EV_SIGNAL, ncalls);
}
}
sig->evsigevents[i])来源与
event_add(&signal_int, NULL);//signal-test.c
evsel->add(base->evsel, (&signal_int);
evsignal_add(&signal_int);
TAILQ_INSERT_TAIL(&sig->evsigevents[SIGINT], (&signal_int, ev_signal_next);
event_active——event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
case EVLIST_ACTIVE:
base->event_count_active++;
TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
ev,ev_active_next);
break;
整个都连起来了,很容易知道 for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq))中的ev直接指向signal_int,那么以下部分就很明白了:
(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
直接替换为
signal_cb((int)ev->ev_fd,ev->ev_res,ev->ev_arg)——signal_cb(SIGINT,EV_SIGNAL|EV_PERSIST, &signal_int)
至此,SIGINT的注册的信号事件回调函数开始执行。