signal(2)
faz parte da antiga API de sinais, que não é sempre conveniente usar, principalmente porque ...
The only portable use of signal() is to set a signal's disposition to
SIG_DFL
orSIG_IGN
. The semantics when usingsignal()
to establish a signal handler vary across systems (and POSIX.1 explicitly permits this variation); do not use it for this purpose.In the original UNIX systems, when a handler that was established using
signal()
was invoked by the delivery of a signal, the disposition of the signal would be reset toSIG_DFL
, and the system did not block delivery of further instances of the signal. System V also provides these semantics forsignal()
.On BSD, when a signal handler is invoked, the signal disposition is not reset, and further instances of the signal are blocked from being delivered while the handler is executing.
The situation on Linux is as follows:
- The kernel's
signal()
system call provides System V semantics.- By default, in glibc 2 and later, the
signal()
wrapper function [...] callssigaction(2)
using flags that supply BSD semantics.- On glibc 2 and later, if the
_BSD_SOURCE
feature test macro is not defined, thensignal()
provides System V semantics. (The default implicit definition of_BSD_SOURCE
is not provided if one invokesgcc(1)
in one of its standard modes (-std=xxx
or-ansi
) or... seesignal(2)
.
Em outras palavras, há uma miríade de casos em que um manipulador definido com signal
não será usado mais de uma vez: após um sinal, a função que você definiu será descartada e o manipulador será redefinido para o padrão , que, para SIGINT
, é para matar o processo.
Embora eu sugira que você leia a man page que acabei de citar, a melhor maneira de lidar com essa situação é provavelmente parar de usar signal
e mudar para sigaction
. A página man fornecerá todos os detalhes de que você precisa, mas aqui está um exemplo rápido:
void sighandler(int signum);
int main(void) {
struct sigaction sa;
sa.sa_handler = sighandler;
sigemptyset(&(sa.sa_mask));
sigaddset(&(sa.sa_mask), SIGINT);
sigaction(SIGINT, &sa, NULL);
int i;
for(i = 0; i < 5; i++) {
printf("Sleeping...\n");
sleep(5);
printf("Woke up!\n");
}
}
void sighandler(int signum) {
printf("Signal caught!\n");
}
Uma nota importante: como você já deve saber (daí seu loop "infinito" na sua função main
), os sinais irão interromper as chamadas do sistema (como aquelas sleep(3)
makes) recepção de sinal, se esse sinal é tratado pelo programa ou não. No meu exemplo acima, o programa irá imprimir Woke up! toda vez que você kill
ele sair da chamada de sono prematuramente. Se você der uma olhada na página do manual, verá que a chamada deve retornar o número de segundos restantes para dormir quando for interrompida.