libevent在对文件描述符,套接字进行监控时直接放到event,这些event通过io多路复用函数进行监控,然而对应信号来说io复用函数却无能为力,为了解决问题,libevent采用统一事件源的方式,即将信号也表现成event的形式,用到了socketpair套接字对
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的做法是为
我觉得完全可以直接在内部使用sigaction/signal绑定信号值和用户的信号处理函数
但是既然libevent想要把所有东西都当成event来处理,就需要将信号转成event,把所有event都放到激活队列中一起处理
复习一下linux下的信号处理机制
UNIX系统信号机制最简单的接口是signal函数,函数原型为
#include
void (*signal(int signo, void (*func)(int)))(int);
signal的使用还是比较简单的
#include
#include
#include
#include
#include
#include
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
int sigaction(int signo, const struct sigaction *act,
struct sigaction *oact);
结构体struct sigaction如下
struct sigaction
{
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
void (*sa_sigaction)(int, siginfo_t *, void *);
}
通常使用sa_handler和sa_mask就可以满足需求了
#include
#include
#include
#include
#include
#include
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中的信号如果发生了会在当前信号处理函数完成后才送达当前进程