libevent源码学习-----统一事件源及信号绑定函数
2017-10-11 00:13
375 查看
libevent在对文件描述符,套接字进行监控时直接放到event,这些event通过io多路复用函数进行监控,然而对应信号来说io复用函数却无能为力,为了解决问题,libevent采用统一事件源的方式,即将信号也表现成event的形式,用到了socketpair套接字对
socketpair套接字对
套接字对也是通信方式的一种,在进程间通信时相比于管道和命名管道而言更简单,也更安全
linux下使用socketpair函数创建一对套接字,函数原型
创建的套接字对的每一端都可以进行读写,也就是sv[0]可以既作为读端也可以作为写端,sv[1]也是。
libevent中sv[1]为读端,sv[0]为写端。向sv[0]中写入数据时sv[1]会变为可读
对于信号的处理,其实用户可以自己使用sigaction注册信号处理函数然后自己提供回调函数,但是既然想要交给libevent处理,就说明用户只提供回调函数,其他什么都不管。
也可以在内部只调用sigaciton/signal注册信号处理函数,回调函数是用户提供的那个,这样也可以满足需求,但是既然统一事件源,就需要把信号也当成event处理。
libevent的做法是为
读端注册到base中,提供一个内部的回调函数,该步骤仅仅调用一次
信号值作为fd创建event,绑定内部回调函数,注册到base中
为信号绑定一个内部的信号处理函数,在信号处理函数中将发生的信号值写入套接字对的写端
此时读端变为可读,调用这个读端套接字绑定的回调函数
读端回调函数中读取信号值,将信号值对应的event添加到激活队列中
激活队列处理
我觉得完全可以直接在内部使用sigaction/signal绑定信号值和用户的信号处理函数
但是既然libevent想要把所有东西都当成event来处理,就需要将信号转成event,把所有event都放到激活队列中一起处理
复习一下linux下的信号处理机制
UNIX系统信号机制最简单的接口是signal函数,函数原型为
signo表示用户关心的信号类型,如终端信号,退出信号,SIGINT,SIGQUIT等
func可以是一个函数指针,也就是信号处理函数,当signno信号发生时,会调用这个函数。该函数有一个int类型参数,通常是信号值。也可以是常量SIG_IGN表示内核忽略该信号(SIGKILL和SIGSTOP不能被忽略),常量SIG_DFL表示执行系统默认的处理动作,通常是终止当前进程
返回值是指向在此之前的信号处理函数的指针
signal的使用还是比较简单的
程序首先注册信号处理函数,之后当中断发生后切换到内核态,在内核的中断处理程序执行完后返回用户态之前检测到有信号SIGINT发生,内核遍不恢复到main函数而是直接转到handler函数中,在执行完handler后由内核转到main函数中继续执行。main和handler是两个独立的存在
signal并不属于POSIX标准,在UNIX中使用sigaction函数作为signal的替代品,signaction函数的功能是检查或修改(或检查并修改)与制定信号相关联的处理动作,函数原型为
signno是要检测或修改其处理动作的信号编号,如SIGINT,SIGQUIT等
act为要修改的动作,本质上是信号处理函数
oact为以前的信号处理动作,不关心时可以设置为NULL
调用成功返回0,失败返回-1(linux的系统调用返回值大多是这样)
结构体struct sigaction如下
sa_handler和signal的第二个参数相同,表示信号处理函数,SIG_IGN表示忽略,SIG_DFL表示默认动作,参数为信号值
sa_mask是信号屏蔽字集,如果设置,那么在进行信号处理函数时,如果有在sa_mask中的信号到达,则不会通知进程,而是在信号处理函数执行完后才通知。默认情况下,如果程序正在执行信号处理函数,那么对于当前这个信号处理函数处理的信号不会再次送到进程。
内核维护着一个信号队列,如果当前有正在处理的信号处理函数,会把其他到达进程的信号放到这个队列中。若同一种信号多次发生,通常只会添加一次
sa_sigaction和sa_flags配合使用,与sa_handler相对应,通常使用sa_handler就不需要使用sa_sigaction,主要用于实时信号可以带信息,使用sa_handler时sa_flags设为0即可
通常使用sa_handler和sa_mask就可以满足需求了
先按ctrl+c发送中断信号,马上按ctrl+z发送终止信号,发现程序5秒后才终止,说明sa_mask中的信号如果发生了会在当前信号处理函数完成后才送达当前进程
socketpair套接字对
套接字对也是通信方式的一种,在进程间通信时相比于管道和命名管道而言更简单,也更安全
linux下使用socketpair函数创建一对套接字,函数原型
/* *@param d: 协议族,通常为AF_UNIX *@param type: 套接字类型,如SOCK_STREAM *@param protocol: 协议,0即可 *@param sv: 存放创建的两个套接字 */ int socketpair(int d, int type, int protocol, int sv[2]);
创建的套接字对的每一端都可以进行读写,也就是sv[0]可以既作为读端也可以作为写端,sv[1]也是。
libevent中sv[1]为读端,sv[0]为写端。向sv[0]中写入数据时sv[1]会变为可读
对于信号的处理,其实用户可以自己使用sigaction注册信号处理函数然后自己提供回调函数,但是既然想要交给libevent处理,就说明用户只提供回调函数,其他什么都不管。
也可以在内部只调用sigaciton/signal注册信号处理函数,回调函数是用户提供的那个,这样也可以满足需求,但是既然统一事件源,就需要把信号也当成event处理。
libevent的做法是为
读端注册到base中,提供一个内部的回调函数,该步骤仅仅调用一次
信号值作为fd创建event,绑定内部回调函数,注册到base中
为信号绑定一个内部的信号处理函数,在信号处理函数中将发生的信号值写入套接字对的写端
此时读端变为可读,调用这个读端套接字绑定的回调函数
读端回调函数中读取信号值,将信号值对应的event添加到激活队列中
激活队列处理
我觉得完全可以直接在内部使用sigaction/signal绑定信号值和用户的信号处理函数
但是既然libevent想要把所有东西都当成event来处理,就需要将信号转成event,把所有event都放到激活队列中一起处理
复习一下linux下的信号处理机制
UNIX系统信号机制最简单的接口是signal函数,函数原型为
#include <signal.h> void (*signal(int signo, void (*func)(int)))(int);
signo表示用户关心的信号类型,如终端信号,退出信号,SIGINT,SIGQUIT等
func可以是一个函数指针,也就是信号处理函数,当signno信号发生时,会调用这个函数。该函数有一个int类型参数,通常是信号值。也可以是常量SIG_IGN表示内核忽略该信号(SIGKILL和SIGSTOP不能被忽略),常量SIG_DFL表示执行系统默认的处理动作,通常是终止当前进程
返回值是指向在此之前的信号处理函数的指针
signal的使用还是比较简单的
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <sys/types.h> void handler(int signo); int main() { signal(SIGINT,handler); for(;;) pause(); return 0; } void handler(int signo) { printf("receive sig=%d\n", sig); }
程序首先注册信号处理函数,之后当中断发生后切换到内核态,在内核的中断处理程序执行完后返回用户态之前检测到有信号SIGINT发生,内核遍不恢复到main函数而是直接转到handler函数中,在执行完handler后由内核转到main函数中继续执行。main和handler是两个独立的存在
signal并不属于POSIX标准,在UNIX中使用sigaction函数作为signal的替代品,signaction函数的功能是检查或修改(或检查并修改)与制定信号相关联的处理动作,函数原型为
#include <signal.h> int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
signno是要检测或修改其处理动作的信号编号,如SIGINT,SIGQUIT等
act为要修改的动作,本质上是信号处理函数
oact为以前的信号处理动作,不关心时可以设置为NULL
调用成功返回0,失败返回-1(linux的系统调用返回值大多是这样)
结构体struct sigaction如下
struct sigaction { void (*sa_handler)(int); sigset_t sa_mask; int sa_flags; void (*sa_sigaction)(int, siginfo_t *, void *); }
sa_handler和signal的第二个参数相同,表示信号处理函数,SIG_IGN表示忽略,SIG_DFL表示默认动作,参数为信号值
sa_mask是信号屏蔽字集,如果设置,那么在进行信号处理函数时,如果有在sa_mask中的信号到达,则不会通知进程,而是在信号处理函数执行完后才通知。默认情况下,如果程序正在执行信号处理函数,那么对于当前这个信号处理函数处理的信号不会再次送到进程。
内核维护着一个信号队列,如果当前有正在处理的信号处理函数,会把其他到达进程的信号放到这个队列中。若同一种信号多次发生,通常只会添加一次
sa_sigaction和sa_flags配合使用,与sa_handler相对应,通常使用sa_handler就不需要使用sa_sigaction,主要用于实时信号可以带信息,使用sa_handler时sa_flags设为0即可
通常使用sa_handler和sa_mask就可以满足需求了
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <signal.h> #include <sys/types.h> void handler(int signo); int main() { struct sigaction act; act.sa_handler = handler; /* 清空信号屏蔽集 */ sigemptyset(&act.sa_mask); /* 在信号处理函数执行期间屏蔽SIGQUIT,执行完后送达当前进程 */ sigaddset(&act.sa_mask, SIGQUIT); act.sa_flags = 0; if(sigaction(SIGINT, &act, NULL) < 0) { perror("sigaction error"); exit(1); } for(;;) pause(); return 0; } void handler(int signo) { printf("receive sig=%d\n", signo); sleep(5); }
先按ctrl+c发送中断信号,马上按ctrl+z发送终止信号,发现程序5秒后才终止,说明sa_mask中的信号如果发生了会在当前信号处理函数完成后才送达当前进程
相关文章推荐
- PyQt4调用partial函数绑定多个信号到相同slot源码实例
- Vue学习之源码分析--从Vue.js源码角度再看数据绑定(三)
- jQuery1.3.2 源码学习-8 index 函数
- jquery源码学习笔记:自执行匿名函数剖析
- Python源码学习:Python函数浅析-有参函数
- libevent学习笔记--setvbuf()函数
- ZigBee学习之绑定表管理函数详解——ZStack API解读
- Libevent源码分析-----更多evbuffer操作函数
- libevent学习之四:VS2012编译libevent-2.1.8-stable源码 可调试
- Libevent源码分析-----与event相关的一些函数和操作
- libevent源码分析--event_init()函数
- jQuery1.3.2 源码学习-7 setArray,each 函数
- Libevent源码分析-----信号event的处理
- libevent源码学习-第一天
- Libevent源码分析-----通用类型和函数
- libevent学习之一:libevent源码的特点和结构
- 第67讲:Scala并发编程匿名Actor、消息传递、偏函数实战解析及其在Spark源码中的应用解析学习笔记
- libevent源码分析(7)--2.1.8--信号事件处理机制分析
- nginx 源码学习笔记(十九)—— nginx启动过程函数调用图