sigaction函数
包含头文件<signal.h>
功能:sigaction函数用于改变进程接收到特定信号后的行为。
原型:
int sigaction(int signum,const struct sigaction *act,const struct sigaction *old);
参数
该函数的第一个参数为信号的值,可以为除SIGKILL及SIGSTOP外的任何一 个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)
第二个参数是指向结构sigaction的一个实例的指针,在结构 sigaction的实例中,指定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理
第三个参数oldact指向的对象用来保存原来对相应信号的处理,可指定oldact为NULL。
返回值:函数成功返回0,失败返回-1
signal(num., handle)
sigaction结构体
第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等
struct sigaction {
void (*sa_handler)(int); //信号处理程序 不接受额外数据
void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序 能接受额外数据,和sigqueue配合使用
sigset_t sa_mask; //
int sa_flags; //影响信号的行为 SA_SIGINFO表示能接受数据
void (*sa_restorer)(void); //废弃
};
注意1:回调函数句柄sa_handler、sa_sigaction只能任选其一。
注意2:The sigaction structure is defined as something like 思考如何测试?
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
#if 0
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */ 注意
int si_int; /* POSIX.1b signal */ 旧时设计
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count;
POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in
glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address
(since Linux 2.6.32) */
void *si_call_addr; /* Address of system call instruction
(since Linux 3.5) */
int si_syscall; /* Number of attempted system call
(since Linux 3.5) */
unsigned int si_arch; /* Architecture of attempted system call
(since Linux 3.5) */
}
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
//为某个信号设置捕捉函数
#if 1
//第一个回调函数的使用
void handler(int sig)
{
if (sig == SIGINT)
{
printf("handler recv a sig=%d\n", sig);
}
}
//第二个回调函数的使用,注意第二个结构体的成员
void handler2(int num, siginfo_t *info, void * p)
{
printf("handler 2 recv sig :%d\n", num);
}
void test()
{
struct sigaction act;
act.sa_handler = handler;
//act.sa_sigaction = handler2;//只能使用其中的一个
sigaction(SIGINT, &act, NULL);
for (;;)
{
sleep(1);
}
}
#endif
/*
信号捕捉特性:
1. 进程正常运行时,默认PCB中有一个信号屏蔽字,假定为☆,它决定了进程自动屏蔽哪些信号。
当注册了某个信号捕捉函数,捕捉到该信号以后,要调用该函数。
而该函数有可能执行很长时间,在这期间所屏蔽的信号不由☆来指定。而是用sa_mask来指定。
调用完信号处理函数,再恢复为☆
2. XXX信号捕捉函数执行期间,XXX信号自动被屏蔽。
3. 阻塞的常规信号不支持排队,产生多次只记录一次。(后32个实时信号支持排队)
*/
/*
测试sigaction结构体sa_mask参数的作用:
验证sa_mask在捕捉函数执行期间的屏蔽作用.
当执行SIGINT信号处理函数期间,多次收到SIGQUIT信号都将被屏蔽(阻塞)
SIGINT信号处理函数处理完,立刻解除对SIGQUIT信号的屏蔽,
由于没有捕捉该信号,将立刻执行该信号的默认动作,程序退出
*/
#if 1
void handler(int sig)
{
printf("recv a sig=%d 信号处理函数执行的时候,阻塞sa_mask中的信号\n", sig);
sleep(8);//模拟处理事件很长
}
void test()
{
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);//注意:sa_mask 仅在处理函数被调用期间屏蔽生效,是临时性设置。
sigaddset(&act.sa_mask, SIGQUIT);//将SIGQUIT加入到信号集sa_mask中,被阻塞(信号处理函数执行的过程中SIGQUIT被阻塞)。
//注意:SIGQUIT信号最终还会抵达
/*将SIGQUIT加入信号屏蔽集,这就导致,在调用信号处理函数期间
*不仅不响应SIGINT信号本身,还不响应SIGQUIT*/
act.sa_flags = 0;//表使用默认属性
if(sigaction(SIGINT, &act, NULL) < 0){//注册信号SIGINT捕捉函数
ERR_EXIT("sigaction error");
}
for (;;)
{
sleep(1);
}
}
/*
运行结果:
hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm02_sigaction
^\Quit (core dumped)
hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm02_sigaction
^Crecv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
^\Quit (core dumped)
hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm02_sigaction
^Crecv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
^C^\recv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
Quit (core dumped
*/
#endif
/*
验证在信号处理函数执行期间,该信号多次递送,那么只在处理函数之行结束后,处理一次。
*/
#if 0
void handler(int sig)
{
printf("recv a sig=%d 信号处理函数执行的时候,阻塞sa_mask中的信号\n", sig);
sleep(5);//模拟信号处理函数执行很长时间
printf("end of handler\n");
}
void test()
{
struct sigaction act, oldact;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);//不屏蔽任何信号
act.sa_flags = 0;
if(sigaction(SIGINT, &act, &oldact) < 0){//注册信号SIGINT捕捉函数
ERR_EXIT("sigaction error");
}
while(1);
}
/*
hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm02_sigaction
^Crecv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
^C^C^Cend of handler
recv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
end of handler
*/
#endif
/*
自动屏蔽本信号,调用完毕后屏蔽自动解除
*/
#if 1
void handler(int sig)
{
printf("recv a sig=%d 信号处理函数执行的时候,阻塞sa_mask中的信号\n", sig);
sleep(5);//模拟信号处理函数执行很长时间
printf("end of handler\n");
}
void test()
{
struct sigaction act, oldact;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);//不屏蔽任何信号
act.sa_flags = 0;
if(sigaction(SIGINT, &act, &oldact) < 0){//注册信号SIGINT捕捉函数
ERR_EXIT("sigaction error");
}
//pause();//是调用进程挂起,只有信号处理函数返回了,pause才返回
sleep(1);//也可以,保证cpu有机会去执行信号处理函数
if(sigaction(SIGINT, &oldact, NULL) < 0){//注册信号SIGINT捕捉函数
ERR_EXIT("sigaction error");
}
for (;;)
{
sleep(1);
}
}
/*
运行结果
hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm02_sigaction
^Crecv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
^C^C^C^C^C^C^C^C^Cend of handler
recv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
end of handler
^C
hzmct@U-64:/study/linuxtest/day02/02signal$
*/
#endif
int main(int argc, char *argv[])
{
test();
return 0;
}