Вопросы по отлову сигналов Unix - PullRequest
1 голос
/ 26 мая 2011

Следующий код ловит сигнал «SIGINT» только один раз, а затем прерывает (программа существует):

#include <signal.h>
#include <stdio.h>

void IntHandler(int value);

void CatchIntSignal()
{
    struct sigaction intAction;
    intAction.sa_handler = IntHandler;
    sigemptyset(&intAction.sa_mask);
    intAction.sa_flags = 0;
    //if to uncomment any of "0" or "SIG_IGN" - IntHandler will be never called:
    //intAction.sa_sigaction = 0/*SIG_IGN*/;
    if(sigaction(SIGINT, &intAction, NULL) != 0)
    {
        printf("sigaction() failed.\n");
    }
}

void IntHandler(int value)
{
    printf("IntHandler(%d)\n", value);
    //uncommenting this does not help:
    //CatchIntSignal();
}

int main()
{
    CatchIntSignal();
    getchar();
    return 0;
}

Как мне изменить этот код, чтобы сохранить выход из программы после перехвата SIGINT? Если установить intAction.sa_sigaction в 0 или в SIG_IGN - IntHandler никогда не будет вызываться - но почему? Какое неопределенное значение должно сказать системе, что «необходимо вызвать IntHandler»? Если я установлю некоторый обработчик на intAction.sa_sigaction - этот обработчик будет вызван (но IntHandler не будет). Как система узнает, что я установил что-то на intAction.sa_sigaction ?

Ответы [ 3 ]

4 голосов
/ 26 мая 2011

Ваша проблема в том, что sa_handler и sa_sigaction поля struct sigaction на самом деле одно и то же поле . Цитирование справочной страницы (OSX) для sigaction(2):

 struct  sigaction {
         union __sigaction_u __sigaction_u;  /* signal handler */
         sigset_t sa_mask;               /* signal mask to apply */
         int     sa_flags;               /* see signal options below */
 };

 union __sigaction_u {
         void    (*__sa_handler)(int);
         void    (*__sa_sigaction)(int, struct __siginfo *,
                        void *);
 };

 #define sa_handler      __sigaction_u.__sa_handler
 #define sa_sigaction    __sigaction_u.__sa_sigaction

Таким образом, ваше назначение sa_sigaction перезаписывает уже установленный вами обработчик. Вы должны просто установить sa_handler и оставить sa_sigaction в покое. Вот как CatchIntSignal следует читать:

void CatchIntSignal()
{
    struct sigaction intAction;
    intAction.sa_handler = IntHandler;
    sigemptyset(&intAction.sa_mask);
    intAction.sa_flags = SA_RESTART;
    if(sigaction(SIGINT, &intAction, NULL) != 0)
        printf("sigaction() failed: %s\n", strerror(errno));
}

(Вам может потребоваться добавить #include из string.h и errno.h, чтобы получить бит strerror(errno) для компиляции. Всегда включайте strerror(errno) в сообщения об ошибках, возникающие при сбое системных вызовов.)

(ИСПРАВЛЕНИЕ: добавлено SA_RESTART к флагам за ниндзя).

2 голосов
/ 26 мая 2011

Возможно, ваша проблема в том, что системный вызов прерван, поэтому getchar() возвращается, возможно, с EOF.И следующее, что делает программа, это выход ...

Итак, вы можете попробовать проверить, что возвращает getchar(), сбросить статус ошибки на stdin и снова вызвать getchar(), чтобы получить следующий сигнал.

0 голосов
/ 26 мая 2011

После того, как вы поймали сигнал прерывания и обработали свои коды перехвата, вам нужно вернуть обработку на SIG_DFL.

РЕДАКТИРОВАТЬ: игнорировать, пожалуйста. Это применимо только к старому unix-сигналу ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...