libevent源码分析(五)

libevent-1.4/sample/signal-test.c
event_add(&signal_int, NULL);
将 struct event signal_int添加到struct event_base* base,即注册号监听事件以及回调后添加到Reactor上。

int event_add(struct event *ev, const struct timeval *tv)
{
 struct event_base *base = ev->ev_base;
 const struct eventop *evsel = base->evsel;
 void *evbase = base->evbase;
 int res = 0;
  /*
  * prepare for timeout insertion further below, if we get a
  * failure on any step, we should not change any state.
  */
 if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
  if (min_heap_reserve(&base->timeheap,
   1 + min_heap_size(&base->timeheap)) == -1)
   return (-1);  /* ENOMEM == errno */
 }
  if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
     !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
  res = evsel->add(evbase, ev);
  if (res != -1)
   event_queue_insert(base, ev, EVLIST_INSERTED);
 }
 /* 
  * we should change the timout state only if the previous event
  * addition succeeded.
  */
 if (res != -1 && tv != NULL) {
  struct timeval now;
  /* 
   * we already reserved memory above for the case where we
   * are not replacing an exisiting timeout.
   */
  if (ev->ev_flags & EVLIST_TIMEOUT)
   event_queue_remove(base, ev, EVLIST_TIMEOUT);
    /* Check if it is active due to a timeout.  Rescheduling
   * this timeout before the callback can be executed
   * removes it from the active list. */
  if ((ev->ev_flags & EVLIST_ACTIVE) &&
      (ev->ev_res & EV_TIMEOUT)) {
   /* See if we are just active executing this
    * event in a loop
    */
   if (ev->ev_ncalls && ev->ev_pncalls) {
    /* Abort loop */
    *ev->ev_pncalls = 0;
   }
    event_queue_remove(base, ev, EVLIST_ACTIVE);
   }
   gettime(base, &now);
   evutil_timeradd(&now, tv, &ev->ev_timeout);
   event_queue_insert(base, ev, EVLIST_TIMEOUT);
  }
   return (res);
  }

注意到event_add管理了定时事件、信号以及普通事件,而且还是用了队列,整个结构还是很清楚的,需要关注的是
evsel->add(evbase, ev)——epoll_add(evbase, ev),在event_base_new已经调用了epoll_init进行一系列初始化,event_add基本上就是调用evsignal_add以及epoll_ctl系统调用。
evsignal_add——evsignal_set_handler(base, SIGINT, evsignal_handler),最终会进行信号相关的系统调用:

/* save previous handler and setup new handler */
#ifdef HAVE_SIGACTION
 memset(&sa, 0, sizeof(sa));
 sa.sa_handler = handler;
 sa.sa_flags |= SA_RESTART;
 sigfillset(&sa.sa_mask);
 if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
  event_warn("sigaction");
  free(sig->sh_old[evsignal]);
  sig->sh_old[evsignal] = NULL;
  return (-1);
 }
#else
 if ((sh = signal(evsignal, handler)) == SIG_ERR) {
  event_warn("signal");
  free(sig->sh_old[evsignal]);
  sig->sh_old[evsignal] = NULL;
  return (-1);
 }
 *sig->sh_old[evsignal] = sh;
#endif

有没有觉得sigaction以及signal很熟悉,这个就是signal的系统调用,至此,信号SIGINT的回调函数evsignal_handler就被注册了。
很显然,这不是使用
event_set(&signal_int, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb, &signal_int);设置的回调函数signal_cb,那么signal_cb怎么样才会被调用了呢?
看看evsignal_handler函数:

static void evsignal_handler(int sig)
{
  int save_errno = errno;
  if (evsignal_base == NULL) {
  	event_warn(
  	 "%s: received signal %d, but have no base configured",
 	  __func__, sig);
 	 return;
 	}
  evsignal_base->sig.evsigcaught[sig]++;
  evsignal_base->sig.evsignal_caught = 1;
  #ifndef HAVE_SIGACTION
 	signal(sig, evsignal_handler);
  #endif
 /* Wake up our notification mechanism */
 send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0);
 errno = save_errno;
}

其中关键部分在于
evsignal_base->sig.evsigcaught[sig]++;//sig=SIGINT
evsignal_base->sig.evsignal_caught = 1;
表明已经捕获到信号,使用以上信号计数以及标志,推迟处理回调函数signal_cb,在 event_base_dispatch(base)中处理,下节讲解,此时需要记住的是信号已经被捕获,并且有计数,关于计数的作用是不会遗漏相同的信号。
最后,可以看到使用了sockpair的写端ev_signal_pair[0],关于读端ev_signal_pair[1]的事件注册:
epoll_init——evsignal_init——
event_set(&base->sig.ev_signal,base->sig.ev_signal_pair [1],EV_READ|EV_PERSIST, evsignal_cb, &base->sig.ev_signal);

ev_signal_pair[1]被设置为监听读就绪事件,在event_base_dispatch(base)中监听到ev_signal_pair[1]读事件,从而唤醒event_base_dispatch中的监听loop,evsignal_cb回调函数的作用就是读取sockpair中的数据,并不做任何处理,避免一直触发读就绪事件。
唤醒event_base_dispatch中的监听loop后就会处理信号捕获标记和计数,从而执行原本注册的回调函数signal_cb。
分离信号捕获,集中处理回调函数,整个逻辑清晰简洁,这样的做法很值得借鉴。

猜你喜欢

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