libevent中的信号处理
1、将信号转成I/O
采用socket pair方式,一个socket对,一个用于写,一个用于读,具体工作方式如下
linux环境下直接使用socketpair就可以,而在不支持socketpair情况就需要自己实现socket对,流程图为
libevent中是通过evutil_socketpair来实现的。
2、集成到event_base_loop事件循环中
创建socketpair后,将读socket注册到event_base实例中,当信号发生时,会将signo写入写socket,此时会触发读事件,然后调用signo对应的事件加入到激活事件链表中。
其处理框架为
3、信号初始化
其初始化代码为
int
evsig_init(struct event_base *base)
{/** Our signal handler is going to write to one end of the socket* pair to wake up our event loop. The event loop then scans for* signals that got delivered.*///创建socket对if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) {
#ifdef WIN32/* Make this nonfatal on win32, where sometimes peoplehave localhost firewalled. */event_sock_warn(-1, "%s: socketpair", __func__);
#elseevent_sock_err(1, -1, "%s: socketpair", __func__);
#endifreturn -1;}//设置socket对的FD_CLOEXEC标志evutil_make_socket_closeonexec(base->sig.ev_signal_pair[0]);evutil_make_socket_closeonexec(base->sig.ev_signal_pair[1]);base->sig.sh_old = NULL;base->sig.sh_old_max = 0;//设置非阻塞evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);evutil_make_socket_nonblocking(base->sig.ev_signal_pair[1]);//设置读socket的回调event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[1],EV_READ | EV_PERSIST, evsig_cb, base);base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;event_priority_set(&base->sig.ev_signal, 0);base->evsigsel = &evsigops;return 0;
}
4、注册
注册信号事件是通过event_add,在设置信号事件时,会将事件的ev_events包含EV_SIGNAL,所以在event_add_internal函数中会调用evmap_signal_add将事件添加到signo对应的事件链表中,同时会调用evsig_add来添加信号处理函数,其代码
static int
evsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
{struct evsig_info *sig = &base->sig;(void)p;EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);/* catch signals if they happen quickly */EVSIGBASE_LOCK();if (evsig_base != base && evsig_base_n_signals_added) {event_warnx("Added a signal to event base %p with signals ""already added to event_base %p. Only one can have ""signals at a time with the %s backend. The base with ""the most recently added signal or the most recent ""event_base_loop() call gets preference; do ""not rely on this behavior in future Libevent versions.",base, evsig_base, base->evsel->name);}evsig_base = base;evsig_base_n_signals_added = ++sig->ev_n_signals_added;evsig_base_fd = base->sig.ev_signal_pair[0];EVSIGBASE_UNLOCK();event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal));if (_evsig_set_handler(base, (int)evsignal, evsig_handler) == -1) { //设置信号处理函数goto err;}if (!sig->ev_signal_added) { //读socket是否注册到event_base中,如果没有,就注册到event_base中if (event_add(&sig->ev_signal, NULL))goto err;sig->ev_signal_added = 1;}return (0);err:EVSIGBASE_LOCK();--evsig_base_n_signals_added;--sig->ev_n_signals_added;EVSIGBASE_UNLOCK();return (-1);
}
在介绍之前,先说明evsig_info结构体
struct evsig_info {/* Event watching ev_signal_pair[1] */struct event ev_signal; //socketpair的读socket事件/* Socketpair used to send notifications from the signal handler */evutil_socket_t ev_signal_pair[2];//socketpair/* True iff we've added the ev_signal event yet. */int ev_signal_added; //读socket事件添加标志/* 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_SIGACTIONstruct sigaction **sh_old; //先前的信息处理函数
#elseev_sighandler_t **sh_old;
#endif/* Size of sh_old. */int sh_old_max;//先前的最大信号值
};
信号处理函数是通过_evsig_set_handler来实现的
int
_evsig_set_handler(struct event_base *base,int evsignal, void (__cdecl *handler)(int))
{
#ifdef _EVENT_HAVE_SIGACTIONstruct sigaction sa;
#elseev_sighandler_t sh;
#endifstruct evsig_info *sig = &base->sig;void *p;/** resize saved signal handler array up to the highest signal number.* a dynamic array is used to keep footprint on the low side.*/if (evsignal >= sig->sh_old_max) { //添加的信号值大于先前的最大信号值,就重新分配先前的信号处理函数指针数组int new_max = evsignal + 1;event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",__func__, evsignal, sig->sh_old_max));p = mm_realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));if (p == NULL) {event_warn("realloc");return (-1);}memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));sig->sh_old_max = new_max;sig->sh_old = p;}/* allocate space for previous handler out of dynamic array */sig->sh_old[evsignal] = mm_malloc(sizeof *sig->sh_old[evsignal]);if (sig->sh_old[evsignal] == NULL) {event_warn("malloc");return (-1);}/* save previous handler and setup new handler *///注册新的信号处理函数,同时将先前的信号处理函数保存在sh_old数组中
#ifdef _EVENT_HAVE_SIGACTIONmemset(&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");mm_free(sig->sh_old[evsignal]);sig->sh_old[evsignal] = NULL;return (-1);}
#elseif ((sh = signal(evsignal, handler)) == SIG_ERR) { event_warn("signal");mm_free(sig->sh_old[evsignal]);sig->sh_old[evsignal] = NULL;return (-1);}*sig->sh_old[evsignal] = sh;
#endifreturn (0);
}
所有的信号处理函数都是evsig_handler,将信号值写入写socket中,触发event_base中事件循环的读事件
static void __cdecl
evsig_handler(int sig)
{int save_errno = errno;
#ifdef WIN32int socket_errno = EVUTIL_SOCKET_ERROR();
#endifev_uint8_t msg;if (evsig_base == NULL) {event_warnx("%s: received signal %d, but have no base configured",__func__, sig);return;}#ifndef _EVENT_HAVE_SIGACTIONsignal(sig, evsig_handler);
#endif/* Wake up our notification mechanism */msg = sig;send(evsig_base_fd, (char*)&msg, 1, 0); //发送信号值errno = save_errno;
#ifdef WIN32EVUTIL_SET_SOCKET_ERROR(socket_errno);
#endif
}
5、事件触发
读事件触发后,调用evsig_cb,接收信号值,统计信号触发次数,读取信号对应的回调,添加到激活链表中
static void
evsig_cb(evutil_socket_t fd, short what, void *arg)
{static char signals[1024];ev_ssize_t n;int i;int ncaught[NSIG];struct event_base *base;base = arg;memset(&ncaught, 0, sizeof(ncaught));while (1) {n = recv(fd, signals, sizeof(signals), 0); //接收信号值if (n == -1) {int err = evutil_socket_geterror(fd);if (! EVUTIL_ERR_RW_RETRIABLE(err))event_sock_err(1, fd, "%s: recv", __func__);break;} else if (n == 0) {/* XXX warn? */break;}//统计信号触发次数for (i = 0; i < n; ++i) {ev_uint8_t sig = signals[i];if (sig < NSIG)ncaught[sig]++;}}EVBASE_ACQUIRE_LOCK(base, th_base_lock);//将事件添加到激活链表中for (i = 0; i < NSIG; ++i) {if (ncaught[i])evmap_signal_active(base, i, ncaught[i]);}EVBASE_RELEASE_LOCK(base, th_base_lock);
}
libevent中的信号处理相关推荐
- morlet包络检波matlab,布里渊光纤传感系统中的信号处理的研究
布里渊光纤传感系统中的信号处理的研究2012年5月 TP247崔琳 毕卫红2012年5月 光学工程 TheResearchingonSignalProcessingMethodsofBrillouin ...
- libevent中的bufferevent
bufferevent是libevent中处理网络事件很重要也是比较复杂的一个模块,其中包含一个读事件,一个写事件,两个缓冲区(读和写).读写水位.三个回调(读.写.出错)和函数指针组成的操作集.目前 ...
- libevent中的缓冲区(一)
libevent中的缓冲区定义为evbuffer,主要在文件evbuffer-internal.h文件中,定义如下 struct evbuffer {/** The first chain in ...
- libevent中的基本数据结构
libevent中文件queue.h文件包含5种数据结构:单链表,双向链表,队列,尾队列,环形队列.在处理I/O和signal中的事件时,用的就是尾队列,下面就介绍这几种数据结构 1.单链表 链表 ...
- libevent中事件的添加与删除
前面介绍了libevent中的hash表,在添加事件时,具体是如何操作的呢?事件操作主要是在evmap.c文件中,包含了io事件,signal事件的操作.在事件操作时,分两种情况,一种是利用ha ...
- libevent中的时间及相关的管理
libevent中的时间及相关的管理 在介绍时间之前,先说明几个与时间相关的函数及其用法 1.基础 1.1 clock_gettime(精度比较高,ns级) #include <time.h&g ...
- libevent中的hash表
libevent中的hash表的代码在ht-internal文件中,在添加io事件,signal事件时,底层是在操作 event_io_map和event_signal_map 1. hash的 ...
- 在libevent中使用线程池
一 线程的初始化 1线程对象 在进行事件驱动时,每个线程需建立自己的事件根基.由于libevent未提供线程之间通信的方式,我们采用管道来进行线程的通信.同时为方便主线程分配线程,我们还需保留各个线程 ...
- 如何在Python中加速信号处理
如何在Python中加速信号处理 This post is the eighth installment of the series of articles on the RAPIDS ecosyst ...
最新文章
- SAP WM MIGO移动类型311转库过账后WM层面产生了Posting Change Notice?
- 神策数据荣登 2020 IDC 中国 Fintech 50 强榜单
- 《深入理解C++11:C++ 11新特性解析与应用》——导读
- 除了工商银行,目前中国还有那些宇宙级别的企业?
- 51nod-猴猴吃香蕉【dp】
- pat1111-1120
- MySQL百万级/千万级数据存储解决方案
- C#LeetCode刷题-双指针
- wps序号打乱重新排序_WPS中Excel怎么自动排序
- 有重复组合公式及其证明方法
- html的3d旋转木马插件,js 3D旋转木马特效插件
- 硬件工程师成长之路(2)——电路设计
- 实时渲染3D动画创作大赛
- Chrome 添加自定义搜索引擎
- SuperMap三维专题之3dsMax数据——对接篇
- 【高并发编程】再谈同步、异步、阻塞、非阻塞
- 嵌入式设备的发展—应对复杂的开发设计挑战
- 华为擎云G540笔记本怎么U盘重装电脑系统详细教学
- Linux命令(13)——实时监控进程、监控网络
- 考研政治与专业课总结(持续更新)
热门文章
- 《玩转.NET Micro Framework 移植-基于STM32F10x处理器》--微软中国.NET Micro Framework项目组工程师所作之序...
- 利用LSM实现更安全的linux
- linux扩充消息队列,Linux关于消息队列的使用分享
- python打开一个不存在的文件时-python判断文件是否存在,不存在就创建一个的实例...
- python是一种通用编程语言-想自学一种编程语言,各种编程语言都有什么区别?...
- python中turtle画酷炫图案-酷炫的动态可视化交互大屏,用Excel就能做!
- python 自动化-Python 接口自动化测试
- python电脑下载有问题-Python 解决火狐浏览器不弹出下载框直接下载的问题
- python简单代码画图-Python竟能画这么漂亮的花,帅呆了(代码分享)
- python安装numpy-Python使用pip安装Numpy模块