libevent源码分析三--signal事件响应
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事件响应的更多相关文章
- libevent源码分析二--timeout事件响应
libevent不仅支持io事件,同时还支持timeout事件与signal事件,这篇文件将分析libevent是如何组织timeout事件以及如何响应timeout事件. 1. min_heap ...
- libevent源码分析一--io事件响应
这篇文章将分析libevent如何组织io事件,如何捕捉事件的发生并进行相应的响应.这里不会详细分析event与event_base的细节,仅描述io事件如何存储与如何响应. 1. select l ...
- 【转】libevent源码分析
libevent源码分析 转自:http://www.cnblogs.com/hustcat/archive/2010/08/31/1814022.html 这两天没事,看了一下Memcached和l ...
- Libevent源码分析 (1) hello-world
Libevent源码分析 (1) hello-world ⑨月份接触了久闻大名的libevent,当时想读读源码,可是由于事情比较多一直没有时间,现在手头的东西基本告一段落了,我准备读读libeven ...
- 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入
使用react全家桶制作博客后台管理系统 前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...
- [Abp vNext 源码分析] - 13. 本地事件总线与分布式事件总线 (Rabbit MQ)
一.简要介绍 ABP vNext 封装了两种事件总线结构,第一种是 ABP vNext 自己实现的本地事件总线,这种事件总线无法跨项目发布和订阅.第二种则是分布式事件总线,ABP vNext 自己封装 ...
- tomcat源码分析(三)一次http请求的旅行-从Socket说起
p { margin-bottom: 0.25cm; line-height: 120% } tomcat源码分析(三)一次http请求的旅行 在http请求旅行之前,我们先来准备下我们所需要的工具. ...
- libevent源码分析
这两天没事,看了一下Memcached和libevent的源码,做个小总结. 1.入门 1.1.概述Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的网络 ...
- Django搭建及源码分析(三)---+uWSGI+nginx
每个框架或者应用都是为了解决某些问题才出现旦生的,没有一个事物是可以解决所有问题的.如果觉得某个框架或者应用使用很不方便,那么很有可能就是你没有将其使用到正确的地方,没有按开发者的设计初衷来使用它,当 ...
随机推荐
- vmvare ESXi使用
新建主机,选择系统,自定义配置,选择ios镜像,完成,打开电源,开启配置
- 关于api创建监控项,添加灵活调度的事件间隔
在api文档中没有明确说明,可以查询数据库,得到的是一个字符串,
- CCF 201812-3 CIDR合并
CCF 201812-3 CIDR合并 //100分 93ms #include<stdio.h>//CCF上stdio.h比cstdio快!!! #include<string.h ...
- https与http的区别?
https要比http更加安全一些,也就是说http协议是由ssl+http协议构建的可进行加密传输.身份验证的网络协议要比http协议安全 现在大多数的网站都逐渐用https://,因为安全问题太重 ...
- NIOBuffer 缓冲区
Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然Java NIO 中除此之外还有很多类和组件,但是,Channel,Buffer 和 Select ...
- Http的状态码及状态码的类型
Http的状态码以及根据这些状态码分成5种类型 statusCode/100 /* * Copyright 2002-2013 the original author or authors. * * ...
- Nexus Repository Manager OSS 3.x 安装配置
前言想要使用maven搭建项目,但是国内的网络环境可以想象,还有公司自己开发的jar包等问题,所以需要搭建一个maven的私服,这样便于管理. 找了一些教程,顺便记下来,当做笔记. 本文以Window ...
- MySQL的tmpdir临时文件说明及使用设置
晚上收到告警MySQL数据库服务器磁盘占满发现是,数据库在tmpdir写数据的文件占用过大 执行命令lsof -n | grep deleted印出所有针对已删除文件的读写操作,这类操作是无效的,也正 ...
- DB2数据库基础
一.DB2数据库安装教程 DB2安装教程:https://jingyan.baidu.com/article/e75057f2f59ef9ebc91a8905.html 二.DB2常用命令 1. 打开 ...
- 两行命令查看自己笔记本连接的wifi密码
打开cmd.exe窗口 第一行命令 netsh wlan show profiles 可以查看所有曾经连接过的wifi 第二命令 netsh wlan show profiles "vivo ...