根据手册页:
如果您想要移植保存和恢复信号模板,请使用sigsetjmp()
和siglongjmp()
。
sigsetjmp()
与setjmp()
类似。如果且仅当savesigs
非零时,进程的当前信号掩码将保存在env
中并且
如果稍后使用此siglongjmp(3)
执行env
,则可以恢复。
但是在我的程序中,上述陈述不是真的,或者我遗漏了什么?调用sigsetjmp
和siglongjmp
返回时,屏蔽信号不同。我在整个代码中都写了一些评论来详细解释这个问题。我的问题是为什么会这样?
先谢谢
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
sigjmp_buf env;
static void handler(int signo)
{
printf("\ncatched signal: %d\n", signo);
siglongjmp(env,1);
}
int main(void)
{
struct sigaction action;
action.sa_flags = 0;
action.sa_handler = handler;
if( (sigemptyset(&action.sa_mask) == -1) || (sigaction(SIGINT, &action, NULL) == -1) )
{
perror("Failed to set!");
return 1;
}
printf("this is process %ld\n", (long)getpid());
//here I add the SIGSEGV to mask signals i.e action.sa_mask
sigaddset(&action.sa_mask,SIGSEGV);
sigaction(0, &action, NULL);
sigaction(0, 0 , &action);
printf("\nsigismember(&action.sa_mask, SIGSEGV)? 1 : 0 -> %d\n", sigismember(&action.sa_mask, SIGSEGV)? 1 : 0);
//and yes it is member of mask signals i.e action.sa_mask
if(sigsetjmp(env,1)) //"first time" it saves state of registers and mask signals and as return value is 0 it does not go inside
{
//when it comes here due to siglongjmp() the signal masks must be restored
printf("Return to main loop due to ^c\n");
//so again SIGSEGV must be member of mask signal i.e action.sa_mask as it was removed only after sigsetjmp was called
sigaction(0 , 0 , &action);
printf("sigismember(&action.sa_mask, SIGSEGV)? 1 : 0 -> %d\n", sigismember(&action.sa_mask, SIGSEGV)? 1 : 0);
//but it shows it is NOT member of mask signal i.e action.sa_mask. why???
}
//here I delete the SIGSEGV from mask signals i.e action.sa_mask
sigdelset(&action.sa_mask,SIGSEGV);
sigaction(0, &action, NULL);
sigaction(0, 0 , &action);
printf("\nsigismember(&action.sa_mask, SIGSEGV)? 1 : 0 -> %d\n\n", sigismember(&action.sa_mask, SIGSEGV)? 1 : 0);
for(;;);
}
输出:
majid@K53SC:~/Desktop$ ./a.out
this is process 6335
sigismember(&action.sa_mask, SIGSEGV)? 1 : 0 -> 1
sigismember(&action.sa_mask, SIGSEGV)? 1 : 0 -> 0
^C
catched signal: 2
Return to main loop due to ^c
sigismember(&action.sa_mask, SIGSEGV)? 1 : 0 -> 0
sigismember(&action.sa_mask, SIGSEGV)? 1 : 0 -> 0
^C
catched signal: 2
Return to main loop due to ^c
sigismember(&action.sa_mask, SIGSEGV)? 1 : 0 -> 0
sigismember(&action.sa_mask, SIGSEGV)? 1 : 0 -> 0
修改
我发布了一个正确的程序,以显示sigsetjmp()
和siglongjmp()
以及how the signal mask is restored
的概念,并根据Jean先生的回答输出BaptisteYuès已经在答案部分给出了它可能对其他人有所帮助:
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
sigjmp_buf env;
void handler(int signo)
{
printf("\nCaught signal: %s", strsignal(signo));
siglongjmp(env,1);
}
int main(void)
{
sigset_t pmask;
if( (sigemptyset(&pmask) == -1) || (signal(SIGINT, handler)== SIG_ERR) )
{
perror("Failed to set!");
return 1;
}
sigprocmask(SIG_SETMASK, &pmask, NULL); //set the process signal mask to pmask
sigprocmask(0, NULL, &pmask); //check the process mask in pmask
printf("\nsigismember(&pmask, SIGSEGV)? 1 : 0 -> %d", sigismember(&pmask, SIGSEGV)? 1 : 0);
if(sigsetjmp(env,1)!=0) //save process environment context and signal mask
printf("\nReturn from signal handler to main loop\nProcess signal mask is restored by siglongjmp()!\n");
else
printf("\nProcess signal mask is saved by sigsetjmp()!\n");
printf("\n**** This is process %ld ****", (long)getpid());
sigprocmask(0, NULL, &pmask); //ckeck the process mask to mask
printf("\nsigismember(&pmask, SIGSEGV)? 1 : 0 -> %d", sigismember(&pmask, SIGSEGV)? 1 : 0);
printf("\nChanging process signal mask");
sigaddset(&pmask,SIGSEGV);
sigprocmask(SIG_SETMASK, &pmask, NULL);
sigprocmask(0, NULL, &pmask); //ckeck the process mask to mask
printf("\nsigismember(&pmask, SIGSEGV)? 1 : 0 -> %d\n\n", sigismember(&pmask, SIGSEGV)? 1 : 0);
pause();
}
输出
majid@K53SC:~/Desktop$ gcc P45.c
majid@K53SC:~/Desktop$ ./a.out
sigismember(&pmask, SIGSEGV)? 1 : 0 -> 0
Process signal mask is saved by sigsetjmp()!
**** This is process 23099 ****
sigismember(&pmask, SIGSEGV)? 1 : 0 -> 0
Changing process signal mask
sigismember(&pmask, SIGSEGV)? 1 : 0 -> 1
^C
Caught signal: Interrupt
Return from signal handler to main loop
Process signal mask is restored by siglongjmp()!
**** This is process 23099 ****
sigismember(&pmask, SIGSEGV)? 1 : 0 -> 0
Changing process signal mask
sigismember(&pmask, SIGSEGV)? 1 : 0 -> 1
答案 0 :(得分:2)
这是因为您没有打印正确的信息。您只需打印action.sa_mask
这是正确的行为,因为您通过从中删除SIGSEGV
来更改它。
您想要的是打印通过sigprocmask
提供的流程掩码,这是sigsetjmp
/ siglongjmp
保存的值。
----- EDIT ----------------------------
来自sigprocmask
手册(GNU):
当前被阻止的信号集合称为 信号掩码。每个进程都有自己的信号掩码。当你创建一个 新进程(请参阅创建进程),它继承了其父进程的掩码。 您可以通过修改来完全灵活地阻止或取消阻止信号 信号掩码。
此掩码是通过siglongjmp
次呼叫恢复的掩码。
从sigaction
手册(GNU)关于sa_mask
字段:
这指定了处理程序运行时要阻止的一组信号。 Blocking for Handler中解释了阻塞。注意信号 默认情况下,默认情况下会自动阻止它 处理程序启动;无论sa_mask中的值如何,都是如此。 如果您希望在其处理程序中不阻止该信号,则必须 在处理程序中编写代码以解锁它。
因此,使用sigaction
不会修改进程掩码,但会在某些信号传递时执行处理程序时将其修改为。