1、内核如何实现信号的捕捉:
(1)如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为信号捕捉。
(2)范例:
用户程序注册了SIGQUIT信号的处理函数sighandler。当前正在执行main函数,这时发生中断或异常切换到内核态。在中断处理完毕后要返回用户态的main函数之前检查到有信号SIGQUIT递达。内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler函数,sighandler和main函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是两个独立的控制流程。sighandler函数返回后自动执行特殊的系统调用sigreturn再次进入内核态。如果没有新的信号要递达,这次再返回用户态就是恢复main函数的上下文继续执行了。
(3)捕捉信号流程:
2、信号捕捉函数:
(1)signal函数:
注册一个信号捕捉函数:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
该函数由ANSI定义,由于历史原因在不同版本的Unix和不同版本的Linux中可能有不同的行为。因此应该尽量避免使用它,取而代之使用sigaction函数。
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<errno.h>
#include<stdlib.h>
void do_sig(int a)
{
printf("Hi,SIGINT,how do you do!\n");
}
int main()
{ if(signal(SIGINT,do_sig)==SIG_ERR)
{
perror("signal");
exit(1);
}
while(1)
{
printf("---------------\n");
sleep(1);
}
return 0;
}
//每当捕捉到SIGINT信号就调用do_sig函数处理信号;
还可以使用以下方式捕捉信号:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<errno.h>
#include<stdlib.h>
typedef void (*sighandler_t)(int);
void catchsigint(int signo)
{
printf(" handle signal!\n");
}
int main()
{
sighandler_t handler;
handler=signal(4,catchsigint);
if(handler==SIG_ERR)
{
perror("signal\n");
exit(1);
}
while(1)
{
printf("running...\n");
sleep(1);
}
return 0;
}
(2)sigaction函数:
修改信号处理动作(通常在Linux用其来注册一个信号的捕捉函数)
#include<signal.h>
int sigaction(int signum,const struct sigaction* act,struct sigaction* oldact);
//成功返回0; 失败返回-1;
act: 传入参数,新的处理方式。
oldact: 传出参数,旧的处理方式。
struct sigaction结构体
struct sigaction{
void (*sa_handler)(int);
void (*sa_sigaction)(int,siginfo_t*,void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
sa_restorer:该元素是过时的,不应该使用,POSIX.1标准将不指定该元素。
sa_sigaction: 当 sa_flags被指定为SA_SIGINFO标志时,使用该信号处理程序。
sa_handler:指定信号捕捉后的处理函数名(即自定义函数)。也可赋值为SIG_IGN表忽略或SIG_DFL表执行默认动作。
sa_mask:调用信号处理函数时,所要屏蔽的信号集合(信号屏蔽字)。仅在处理函数被调用期间屏蔽生效,是临时性设置。
sa_flags:通常设置为0,表使用默认属性。
使用范例:
/*当执行SIGINT信号处理函数期间
*多次收到SIGQUIT信号都将被屏蔽(阻塞)
*SIGINT信号处理函数处理完,立刻解除对
*SIGQUIT信号的屏蔽,由于没有捕捉该信号,
*将立刻执行该信号的默认动作,程序退出
*/
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
void sig_int(int signo)
{
printf("catch signal SIGINT\n");
sleep(10);
printf("----wait 10 secons\n");
}
int main()
{
struct sigaction act;
act.sa_handler=sig_int;
act.sa_flags=0;
sigemptyset(&act.sa_mask); //初始化信号集,所有位置0,即不屏蔽任何信号
sigaddset(&act.sa_mask,SIGQUIT); //设置屏蔽字,屏蔽SIGQUIT信号
sigaction(SIGINT,&act,NULL);
printf("---------------wait signal\n");
while(1); //等待接收信号
return 0;
}