在处理SIGTSTP信号时需要清楚一些细节问题
1)如果SIGTSTP被捕获了,那么就不会执行默认的停止进程的动作。
2)如果在SIGTSTP信号处理函数中,生成一个SIGSTOP信号来解决问题(1),由于SIGSTOP信号是无法被捕获、阻塞和忽略的,因此能确保立即停止进程。但是如果使用wait或waitpid返回的状态来判断是哪个信号导致了子进程停止。显示是SIGSTOP,而不是SIGTSTP
为了解决上面的问题,最好是在SIGTSTP的信号处理函数中再生成一个SIGTSTP信号来停止进程。
步骤如下:
1)在处理函数中将SIGTSTP的处理方式修改为SIG_DEF
2)生成新的SIGTSTP信号,raise(SIGTSTP)
3) 由于在信号SIGTSTP处理函数中,新的SIGTSTP是被阻塞的,所以第2步产生的SIGTSTP信号将被阻塞,所以这里要调用sigpromask函数将SIGTSTP信号从阻塞改为非阻塞。此时第2步生成的信号就可以执行了,并且按照默认的方式挂起进程。
4)在后面的某个时刻,当进程接收到SIGCONT信号恢复时。这时候,SIGTSTP的信号处理函数继续执行。
5)调用sigprocmask信号来阻塞SIGTSTP信号,以便在执行完(6)之后,(7)之前又收到一个SIGTSTP信号,导致提前进入信号处理函数。
6)在信号处理函数返回前,重新注册一个SIGTSTP的信号处理函数来处理下一个SIGTSTP信号。
7)信号处理函数返回,pause()退出,打印Main后,主函数继续停留在pause函数上。
-
gwwu@hz-dev2.wgw.com:~/test/signal>more handling_SIGSTP.c
-
#include <unistd.h>
-
#include <signal.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <errno.h>
-
-
static void tstpHandler(int sig)
-
{
-
sigset_t tstpMask,prevMask;
-
int saveErrno;
-
struct sigaction sa;
-
-
saveErrno = errno;
-
-
printf("Caught SIGTSTP\n");
-
/*1)在处理函数中将SIGTSTP的处理方式修改为SIG_DEF*/
-
if(signal(SIGTSTP,SIG_DFL) == SIG_ERR) {
-
printf("signal error\n");
-
return;
-
}
-
printf("before raise\n");
-
raise(SIGTSTP);/*2)生成新的SIGTSTP信号,raise(SIGTSTP)*/
-
printf("after raise\n");
-
sigemptyset(&tstpMask);
-
sigaddset(&tstpMask,SIGTSTP);
-
printf("wjx.....\n");
-
/*/*3) 由于在信号SIGTSTP处理函数中,新的SIGTSTP是被阻塞的,所以第2步产生的SIGTSTP信号将被阻塞,所以这里要调用sigpromask函数将SIGTSTP信号从阻塞改为非阻塞。此时第2步生成的信号就可以执行了,并且按照默认的方式挂起进程。*/
*/
-
if(sigprocmask(SIG_UNBLOCK,&tstpMask,&prevMask) == -1) {
-
printf("sigprocmask error\n");
-
return;
-
}
-
printf("is SIGTSTP in prevMask: %s\n",sigismember(&prevMask,SIGTSTP)?"yes":"no");
-
printf("is SIGINT in prevMask: %s\n",sigismember(&prevMask,SIGINT)?"yes":"no");
-
printf("wgw.....\n");
-
-
/*4)在后面的某个时刻,当进程接收到SIGCONT信号恢复时。这时候,SIGTSTP的信号处理函数继续执行。*/
-
/*5)调用sigprocmask信号来阻塞SIGTSTP信号,以便在执行完(6)之后,(7)之前又收到一个SIGTSTP信号,导致提前进入信号处理函数。*/
-
if(sigprocmask(SIG_SETMASK,&prevMask,NULL) == -1) {
-
printf("sigprocmask error\n");
-
return;
-
}
-
printf("tyx.....\n");
-
/*6)在信号处理函数返回前,重新注册一个SIGTSTP的信号处理函数来处理下一个SIGTSTP信号。*/
-
sigemptyset(&sa.sa_mask);
-
sa.sa_flags = SA_RESTART;
-
sa.sa_handler = tstpHandler;
-
if(sigaction(SIGTSTP,&sa,NULL) == -1) {
-
printf("sigaction error\n");
-
return;
-
}
-
-
printf("exiting tstpHandler\n");
-
errno = saveErrno;
-
}
-
-
int main(int argc, char *argv[])
-
{
-
struct sigaction sa;
-
-
if(sigaction(SIGTSTP,NULL,&sa) == -1) {
-
printf("sigaction error\n");
-
return -1;
-
}
-
if(sa.sa_handler != SIG_IGN) {
-
sigemptyset(&sa.sa_mask);
-
sa.sa_flags = SA_RESTART;
-
sa.sa_handler = tstpHandler;
-
if(sigaction(SIGTSTP,&sa,NULL) == -1) {
-
printf("sigaction error\n");
-
return -1;
-
}
-
}
-
for(;;) {
-
pause();
-
printf("Main\n");
-
}
-
}
编译运行:
-
gwwu@hz-dev2.wgw.com:~/test/signal>gcc -g handling_SIGSTP.c -o handling_SIGSTP
-
gwwu@hz-dev2.wgw.com:~/test/signal>./handling_SIGSTP
-
^ZCaught SIGTSTP ----------------------CONTROL+Z
-
before raise
-
after raise
-
wjx.....
-
-
[1]+ Stopped ./handling_SIGSTP
-
gwwu@hz-dev2.wgw.com:~/test/signal>fg
-
./handling_SIGSTP
-
is SIGTSTP in prevMask: yes
-
is SIGINT in prevMask: no
-
wgw.....
-
tyx.....
-
exiting tstpHandler
-
Main
-
^ZCaught SIGTSTP ------------------CONTROL+Z
-
before raise
-
after raise
-
wjx.....
-
-
[1]+ Stopped ./handling_SIGSTP
-
gwwu@hz-dev2.wgw.com:~/test/signal>fg
-
./handling_SIGSTP
-
is SIGTSTP in prevMask: yes
-
is SIGINT in prevMask: no
-
wgw.....
-
tyx.....
-
exiting tstpHandler
-
Main
-
^C -----------------CONTROL+C
-
gwwu@hz-dev2.wgw.com:~/test/signal>
阅读(6260) | 评论(0) | 转发(0) |