Signals handling in C

2019-08-14 03:18发布

问题:

I made the following program for learning the behavior of SIG_SETMASK.

The following program is supposed to block SIGINT the interrupt signal until the func() function calls

     sigprocmask(SIG_SETMASK,&fOnemask,NULL);

where as fOnemask is empty cuz no signals were store in sigset before it. But as I call

     sigprocmask(SIG_SETMASK,&fTwoCmask,NULL);

inside func2() function before returning,where fTwomask contains previous signal list made by func() function, the program starts receiving signals and the program is interrupted when SIGINT is passed.

Why is this happening?

void func();
void func2();

int main()
{
    int childpid,child;
    childpid=fork();

    if(childpid==0)
    {
        func();
    }

    while(wait(NULL)>0);
    return 0;
}

void func()
{
    sigset_t sigmask,fOnemask;
    sigemptyset(&sigmask);
    sigaddset(&sigmask,SIGINT);
    sigprocmask(SIG_SETMASK,&sigmask,&fOnemask);

    func2();

    int i;
    for(i=0;i<10;i++)
    {
        sleep(1);
        printf("%d\n",i);
    }

    sigprocmask(SIG_SETMASK,&omask,NULL);
    printf("returning from func\n");

}

void func2()
{
    sigset_t sigmask,fTwomask;
    sigemptyset(&sigmask);
    sigfillset(&sigmask);
    sigprocmask(SIG_SETMASK,&sigmask,&fTwomask);

    int i;
    for(i=0;i<10;i++)
    {
        sleep(1);
        printf("%d\n",i);
    }

    sigprocmask(SIG_SETMASK,&fTwomask,NULL);
    printf("func2 ending\n");
}

回答1:

The parent process is interrupted by SIGINT because you never set any signal handling for SIGINT in the parent process, so it is set to SIG_DFL (probably, unless you've turned of interrupt handling in the shell, which is pretty unlikely), so the process terminates.

You're right; shells don't die when an interrupt is sent. That's because shells take great care to ensure that they aren't killed by an interrupt.


One of the comments to the main question is:

If I add a signal in sigset_t object in main function and then call foo() from main. I then add a signal in another sigset_t object local to foo() like sigprocmask(SIG_SETMASK, &foomask, &oldmask). When I call sigprocmask(SIG_SETMASK, &oldset, NULL), what will sigprocmask(SIG_SETMASK, &oldset, NULL) do?

Your comment (question) is confusing at best; comments are not the best way of editing the question.

As I understand it, you are asking about:

static void foo(void);

int main(void)
{
    sigset_t mainmask;
    sigemptyset(&mainmask);
    sigaddset(&mainmask, SIGINT);

    // No call to sigprocmask() here...

    foo();
    return(0);
}

static void foo(void)
{
    sigset_t foomask;
    sigset_t oldmask;
    sigset_t oldset;     // Uninitialized
    sigemptyset(&foomask);
    sigaddset(&foomask, SIGQUIT);  // Different signal
    if (sigprocmask(SIG_SETMASK, &foomask, &oldmask) != 0)
        ...process error...
    if (sigprocmask(SIG_SETMASK, &oldset, NULL) != 0)
        ...process error...
    ...other code, presumably...
}

This is what was written in the comment, as near as I can guess. And because oldset was uninitialized, you suffer from GIGO (garbage in, garbage out); no-one can say what happens because the behaviour is undefined.

If you meant oldmask instead of oldset in the question, then foo() might look like:

static void foo(void)
{
    sigset_t foomask;
    sigset_t oldmask;
    sigemptyset(&foomask);
    sigaddset(&foomask, SIGQUIT);  // Different signal
    if (sigprocmask(SIG_SETMASK, &foomask, &oldmask) != 0)
        ...process error...
    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
        ...process error...
    ...other code, presumably...
}

Then the second sigprocmask() undoes the changes made by the first call to sigprocmask(). Remember, the SIG_SETMASK option means 'set the process signal mask to exactly the mask in the second argument' (unless the second argument is null, in which case, the third argument should not be null and it doesn't matter what's in the first argument since it becomes a call to find out the current mask without changing anything).