sigsetjmp()和siglongjmp():调用sigsetjmp()并返回siglongjmp()时,屏蔽信号不一样

时间:2015-11-28 19:20:28

标签: c unix

根据手册页:

如果您想要移植保存和恢复信号模板,请使用sigsetjmp()siglongjmp()

sigsetjmp()setjmp()类似。如果且仅当savesigs非零时,进程的当前信号掩码将保存在env中并且        如果稍后使用此siglongjmp(3)执行env,则可以恢复。

但是在我的程序中,上述陈述不是真的,或者我遗漏了什么?调用sigsetjmpsiglongjmp返回时,屏蔽信号不同。我在整个代码中都写了一些评论来详细解释这个问题。我的问题是为什么会这样?

先谢谢

#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

1 个答案:

答案 0 :(得分:2)

这是因为您没有打印正确的信息。您只需打印action.sa_mask这是正确的行为,因为您通过从中删除SIGSEGV来更改它。

您想要的是打印通过sigprocmask提供的流程掩码,这是sigsetjmp / siglongjmp保存的值。

----- EDIT ----------------------------

来自sigprocmask手册(GNU):

  

当前被阻止的信号集合称为   信号掩码。每个进程都有自己的信号掩码。当你创建一个   新进程(请参阅创建进程),它继承了其父进程的掩码。   您可以通过修改来完全灵活地阻止或取消阻止信号   信号掩码。

此掩码是通过siglongjmp次呼叫恢复的掩码。

sigaction手册(GNU)关于sa_mask字段:

  

这指定了处理程序运行时要阻止的一组信号。   Blocking for Handler中解释了阻塞。注意信号   默认情况下,默认情况下会自动阻止它   处理程序启动;无论sa_mask中的值如何,都是如此。   如果您希望在其处理程序中不阻止该信号,则必须   在处理程序中编写代码以解锁它。

因此,使用sigaction不会修改进程掩码,但会在某些信号传递时执行处理程序时将其修改为