libevent源码分析(六)

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的注册的信号事件回调函数开始执行。

猜你喜欢

转载自blog.csdn.net/weixin_38134600/article/details/82827235