libevent支持io事件,timeout事件,signal事件,这篇文件将分析libevent是如何组织signal事件,以及如何实现signal事件响应的。

1.  sigmap

类似于io事件,event_base有另外一个hash表sigmap用于存储signal事件,hash表使用signal number做数组索引,同一个signal number的不同事件使用双向链表连接(使用struct event结构中的ev_. ev_signal. ev_signal_next成员来构造这个链表)。使用到的数据结构有struct event_signal_map与struct evmap_signal,定义如下:

/* Used to map signal numbers to a list of events.  If EVMAP_USE_HT is not
defined, this structure is also used as event_io_map, which maps fds to a
list of events.
*/
struct event_signal_map {
/* An array of evmap_io * or of evmap_signal *; empty entries are
* set to NULL. */
void **entries;
/* The number of entries available in entries */
int nentries;
};
/* An entry for an evmap_signal list: notes all the events that want to know
when a signal triggers. */
struct evmap_signal {
struct event_dlist events;
};

event_base中的成员sigmap即是struct event_signal_map结构的实例。entries指向一个动态分配的指针数组,数组长度为nentries;数组成员是一个指向动态分配的evmap_sinal结构的指针。sigmap的结构大致可以用图1-1表示,

图1-1 sigmap存储结构

2.  signal后端

signal事件的后端与io事件的后端不同,它们的操作基本不相同,libevent在源文件signal.c中实现signal事件的后端操作,并在event_base中使用成员struct eventop *evsigsel专门指向signal事件的后端操作,未复用指向io后端的evsel指针,signal后端使用到的信息保存在struct evsig_info sig成员中。

struct evsig_info的定义如下,这里主要介绍ev_signal与ev_signal_pair[2]这两个成员。

/* Data structure for the default signal-handling implementation in signal.c
*/
struct evsig_info {
/* Event watching ev_signal_pair[1] */
struct event ev_signal;
/* Socketpair used to send notifications from the signal handler */
evutil_socket_t ev_signal_pair[];
/* 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
/* Size of sh_old. */
int sh_old_max;
};
  • ev_signal_pair[2]是两个文件描述符,通常使用pipe函数创建。
  • ev_signal是一个专职事件(内部事件),监听ev_signal_pair[0]上的读事件,它作为一个io事件被加入到event_base中,并将优先级设置为0,以便一旦该事件发生,它的回调函数能被优先执行。

在signal后端中,每一个被注册了事件的signal都会使用sigaction函数将signal handler修改为统一的函数static void __cdecl evsig_handler(int sig),这个函数的作用就是向ev_signal_pair[1]中写触发的signal_number,激活事件ev_signal。函数定义如下(删除了跨平台代码):

static void __cdecl
evsig_handler(int sig)
{
int save_errno = errno;
ev_uint8_t msg; if (evsig_base == NULL) {
event_warnx(
"%s: received signal %d, but have no base configured",
__func__, sig);
return;
} /* Wake up our notification mechanism */
msg = sig;
{
int r = write(evsig_base_fd, (char*)&msg, );
(void)r; /* Suppress 'unused return value' and 'unused var' */
} errno = save_errno;
}

ev_signal的回调函数也是在signal.c源文件中定义,static void evsig_cb(evutil_socket_t fd, short what, void *arg),它的作用就是从ev_signal_pair[0]上读回被触发的signal number,并将sigmap上对应signal_number的所有event加入到event_base的待执行回调函数中。函数定义如下:

/* Callback for when the signal handler write a byte to our signaling socket */
static void
evsig_cb(evutil_socket_t fd, short what, void *arg)
{
static char signals[];
ev_ssize_t n;
int i;
int ncaught[NSIG];
struct event_base *base; base = arg;
memset(&ncaught, , sizeof(ncaught)); while () { n = read(fd, signals, sizeof(signals)); if (n == -) {
int err = evutil_socket_geterror(fd);
if (! EVUTIL_ERR_RW_RETRIABLE(err))
event_sock_err(, fd, "%s: recv", __func__);
break;
} else if (n == ) {
/* XXX warn? */
break;
}
for (i = ; i < n; ++i) {
ev_uint8_t sig = signals[i];
if (sig < NSIG)
ncaught[sig]++;
}
} EVBASE_ACQUIRE_LOCK(base, th_base_lock);
for (i = ; i < NSIG; ++i) {
if (ncaught[i])
evmap_signal_active_(base, i, ncaught[i]);//将signal number i 对应的事件加入到待执行回调函数链表中
}
EVBASE_RELEASE_LOCK(base, th_base_lock);
}

当signal发生时,evsig_handler会向ev_signal_pair[1]写数据(写入singal number),激活ev_signal事件,ev_signal事件的回调函数evsig_cb会从ev_signal_pair[0]上读到被触发的signal number,然后据此从event_base的sigmap中将对应的所有event的回调函数加入到待执行回调函数链表,这些回调函数将在event_base_loop中被执行,完成对signal事件的响应。

libevent源码分析三--signal事件响应的更多相关文章

  1. libevent源码分析二--timeout事件响应

    libevent不仅支持io事件,同时还支持timeout事件与signal事件,这篇文件将分析libevent是如何组织timeout事件以及如何响应timeout事件. 1.  min_heap ...

  2. libevent源码分析一--io事件响应

    这篇文章将分析libevent如何组织io事件,如何捕捉事件的发生并进行相应的响应.这里不会详细分析event与event_base的细节,仅描述io事件如何存储与如何响应. 1.  select l ...

  3. 【转】libevent源码分析

    libevent源码分析 转自:http://www.cnblogs.com/hustcat/archive/2010/08/31/1814022.html 这两天没事,看了一下Memcached和l ...

  4. Libevent源码分析 (1) hello-world

    Libevent源码分析 (1) hello-world ⑨月份接触了久闻大名的libevent,当时想读读源码,可是由于事情比较多一直没有时间,现在手头的东西基本告一段落了,我准备读读libeven ...

  5. 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入

    使用react全家桶制作博客后台管理系统   前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...

  6. [Abp vNext 源码分析] - 13. 本地事件总线与分布式事件总线 (Rabbit MQ)

    一.简要介绍 ABP vNext 封装了两种事件总线结构,第一种是 ABP vNext 自己实现的本地事件总线,这种事件总线无法跨项目发布和订阅.第二种则是分布式事件总线,ABP vNext 自己封装 ...

  7. tomcat源码分析(三)一次http请求的旅行-从Socket说起

    p { margin-bottom: 0.25cm; line-height: 120% } tomcat源码分析(三)一次http请求的旅行 在http请求旅行之前,我们先来准备下我们所需要的工具. ...

  8. libevent源码分析

    这两天没事,看了一下Memcached和libevent的源码,做个小总结. 1.入门 1.1.概述Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的网络 ...

  9. Django搭建及源码分析(三)---+uWSGI+nginx

    每个框架或者应用都是为了解决某些问题才出现旦生的,没有一个事物是可以解决所有问题的.如果觉得某个框架或者应用使用很不方便,那么很有可能就是你没有将其使用到正确的地方,没有按开发者的设计初衷来使用它,当 ...

随机推荐

  1. Java算法考试笔记

    1.快速构建排列树: void BackTrace(int t){//排列树 if(t<N){//如果没有到叶子结点 for(int i=t;i<N;i++){ swap(x,t,i); ...

  2. 钠 GZY整理贪心

    目录 CF140C New Year Snowmen CF161B Discounts P1842 奶牛玩杂技 CF140C New Year Snowmen #include <bits/st ...

  3. 洛谷 P1879 [USACO06NOV]玉米田Corn Fields 题解

    P1879 [USACO06NOV]玉米田Corn Fields 题目描述 Farmer John has purchased a lush new rectangular pasture compo ...

  4. javaScript 迭代器

    for ...of 语句 "use strict"; var name = ['a','b','c']; var mark = [1, 2, 3]; for(var i of na ...

  5. linux驱动由浅入深系列:高通sensor架构实例分析之三(adsp上报数据详解、校准流程详解)【转】

    本文转载自:https://blog.csdn.net/radianceblau/article/details/76180915 本系列导航: linux驱动由浅入深系列:高通sensor架构实例分 ...

  6. Evolutionary approaches towards AI: past, present, and future

    Evolutionary approaches towards AI: past, present, and future 2019-10-06 07:28:13 This blog is from: ...

  7. TermKit的新一代Mac终端,在Ubuntu 11.04 轻松安装TermKit

    作为开发人员的必备工具,终端程序却一直没有什么大的变化,TermKit旨在改变这一切,作为下一代的命令行/终端程序,TermKit为我们提供了一个图形化的终端/命令行程序,它可以以可视化的方式展示终端 ...

  8. Java: 线程池(ThreadPoolExecutor)中的参数说明

    最近在看<阿里巴巴Android开发手册>,里面有这样几句话: [强制]新建线程时,必须通过线程池提供(AsyncTask 或者ThreadPoolExecutor或者其他形式自定义的线程 ...

  9. 部署一个fc网站需要注意的地方

    1. php环境 必须5.3 2. yum install nodejs 3. yum install v8-devel 3. 下载v8js php扩展, 版本是 v8js-0.1.3 tar -zx ...

  10. 解决 No IDEA annotations attached to the JDK 1.8和xml文件没有代码提示

    Android studio3.3 用着用着突然xml里没有代码联想了,忙着做其他的就没管,写xml的时候就硬写... 然后今天用着突然在class文件上方提示No IDEA annotations ...