Обработка сигналов в C

Я сделал следующую программу для изучения поведения SIG_SETMASK.

Следующая программа должна блокировать SIGINT сигнал прерывания до тех пор, пока функция func() не вызовет

     sigprocmask(SIG_SETMASK,&fOnemask,NULL);

где, поскольку fOnemask пуст, потому что до этого в sigset не хранились сигналы. Но как я звоню

     sigprocmask(SIG_SETMASK,&fTwoCmask,NULL);

внутри функции func2() перед возвратом, где fTwomask содержит предыдущий список сигналов, сделанный функцией func(), программа начинает получать сигналы, и программа прерывается при передаче SIGINT.

Почему это происходит?

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");
}

введите здесь описание изображения


person Alfred    schedule 06.01.2013    source источник
comment
Проблема с вашим образцом: он никогда не вызывает func. Пожалуйста, обновите код (постарайтесь сохранить отступ) на то, что воспроизводит вашу проблему. (Замена main вызовом func без форка работает как положено, sigint остается заблокированным.)   -  person Mat    schedule 06.01.2013
comment
Мат, когда sigprocmask() в func2() возвращает старый список сигналов в fTwomask, т.е. список, созданный функцией func().   -  person Alfred    schedule 06.01.2013
comment
Я не понимаю вашего комментария. Я повторю то, что сказал выше: код, который вы разместили, никогда не вызывает func или func2. Пожалуйста, опубликуйте точный код, с которым вы играете.   -  person Mat    schedule 06.01.2013
comment
Я обновил вопрос. Он был удален во время публикации кода   -  person Alfred    schedule 06.01.2013
comment
Обратите внимание, что последовательные вызовы sigemptyset() и sigfillset(), как и в func2(), являются избыточными; в контексте вызывать только sigfillset().   -  person Jonathan Leffler    schedule 06.01.2013
comment
Почему я запускаю ваш код, нет никаких проблем. Дочерний процесс игнорирует SIGINT до последней sigprocmask в func, как и ожидалось. Вы включили все соответствующие заголовки?   -  person Mat    schedule 06.01.2013
comment
@JonathanLeffler, если я добавлю сигнал в sigset_t obj в основную функцию, а затем вызову foo() из main. Затем я добавляю сигнал в другой объект sigset_t, локальный для foo(), например sigprocmask(SIG_SETMASK,&foomask,&oldmask). Когда я позвоню sigprocmask(SIG_SETMASK,&oldset,NULL), что сделает sigprocmask(SIG_SETMASK,&oldset,NULL)?   -  person Alfred    schedule 06.01.2013
comment
@Mat, в моем случае я отправляю CTRL+C с терминала, когда func2() печатает на экране. После прекращения печати функция func() ничего не печатает.   -  person Alfred    schedule 06.01.2013
comment
@Mat да, я добавил все заголовки, включая signal.h   -  person Alfred    schedule 06.01.2013


Ответы (1)


Родительский процесс прерывается SIGINT, потому что вы никогда не устанавливали обработку сигнала для SIGINT в родительском процессе, поэтому для него установлено значение SIG_DFL (вероятно, если вы не отключили обработку прерывания в оболочке, что довольно маловероятно), поэтому процесс завершается.

Ты прав; оболочки не умирают при отправке прерывания. Это потому, что оболочки тщательно следят за тем, чтобы их не убило прерывание.


Один из комментариев к основному вопросу:

Если я добавлю сигнал в объект sigset_t в функцию main, а затем вызову foo() из main. Затем я добавляю сигнал в другой объект sigset_t, локальный для foo(), например sigprocmask(SIG_SETMASK, &foomask, &oldmask). Когда я позвоню sigprocmask(SIG_SETMASK, &oldset, NULL), что сделает sigprocmask(SIG_SETMASK, &oldset, NULL)?

Ваш комментарий (вопрос) в лучшем случае сбивает с толку; комментарии - не лучший способ редактирования вопроса.

Насколько я понимаю, вы спрашиваете о:

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...
}

Это то, что было написано в комментарии, насколько я могу предположить. И поскольку oldset не был инициализирован, вы страдаете от GIGO (мусор на входе, мусор на выходе); никто не может сказать, что происходит, потому что поведение не определено.

Если вы имели в виду oldmask вместо oldset в вопросе, то foo() может выглядеть так:

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...
}

Затем второй sigprocmask() отменяет изменения, сделанные первым вызовом sigprocmask(). Помните, что параметр SIG_SETMASK означает «установить маску сигнала процесса точно в соответствии с маской во втором аргументе» (если только второй аргумент не равен нулю, в этом случае третий аргумент не должен быть нулевым, и не имеет значения, что находится в первом). аргумент, так как он становится вызовом узнать текущую маску без каких-либо изменений).

person Jonathan Leffler    schedule 06.01.2013
comment
как родитель может умереть, когда в данный момент работает дочерний процесс? - person Alfred; 06.01.2013
comment
Легко... очень легко. Подумайте о процессах демона; они создаются разветвлением ребенка и смертью родителя (скорее добровольно, чем невольно). - person Jonathan Leffler; 06.01.2013
comment
если я добавлю сигнал в sigset_t obj в основной функции, а затем вызову foo() из main. Затем я добавляю сигнал в другой объект sigset_t, локальный для foo(), например sigprocmask(SIG_SETMASK,&foomask,&oldmask). Когда я позвоню sigprocmask(SIG_SETMASK,&oldset,NULL), что сделает sigprocmask(SIG_SETMASK,&oldset,NULL)? - person Alfred; 06.01.2013
comment
Теперь я также блокирую SIGINT в основном, но он все равно не работает. - person Alfred; 06.01.2013
comment
Хорошо, теперь это очищается. Один вопрос, когда в sigprocmask нет третьего аргумента, а how есть SIG_SETMASK, блокирует ли он сигналы во втором аргументе маски сигналов. - person Alfred; 06.01.2013
comment
Если третий аргумент sigprocmask() равен NULL, то вы просто не узнать, какой была маска сигнала до того, как было установлено новое значение. Итак, да, если how равно SIG_SETMASK, то новая маска процесса устанавливается точно на набор сигналов, перечисленных во втором (set) аргументе. - person Jonathan Leffler; 06.01.2013
comment
@ Альфред, как родитель может умереть, когда в данный момент запущен дочерний процесс? -- что их остановит? - person Jim Balter; 07.01.2013