
Considere este programa:
#include <stdio.h>
#include <sys/epoll.h>
int main(void) {
int epfd = epoll_create1(0);
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = 0;
epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &event);
epoll_wait(epfd, &event, 1, -1);
perror("epoll_wait");
return 0;
}
Quando executo este programa sozinho, redimensionar o terminal (gerando assim o SIGWINCH) não faz nada com ele e fica aguardando a entrada no stdin. Quando eu o executo dentro de strace ou ltrace, o SIGWINCH resulta em erro de epoll_wait com EINTR. Meu entendimento do EINTR é que ele só é gerado se um sinal chamar um manipulador de sinal no seu código, mas não tenho nenhum deles registrado. Achei que strace ou ltrace poderia estar definindo um para mim, então tentei defini-lo explicitamente como SIG_IGN, mas isso ainda não interrompeu o EINTR. Por que isso está acontecendo?
Responder1
Eles usamptrace(2)
, cuja página de manual comenta
Durante o rastreamento, o rastreamento irá parar cada vez que um sinal for entregue,mesmo se o sinal estiver sendo ignorado. (Uma exceção é
SIGKILL
, que tem seu efeito usual.) O rastreador será notificado em sua próxima chamada parawaitpid(2)
(ou uma das chamadas de sistema de "espera" relacionadas); essa chamada retornará um valor de status contendo informações que indicam a causa da parada no tracee. Enquanto o tracee está interrompido, o rastreador pode usar várias solicitações ptrace para inspecionar e modificar o tracee. O rastreador então faz com que o rastreador continue, ignorando opcionalmente o sinal entregue (ou até mesmo entregando um sinal diferente).
e depois:
Observe que um sinal suprimido ainda faz com que as chamadas do sistema retornem prematuramente. Neste caso, as chamadas do sistema serão reiniciadas: o rastreador observará o tracee para reexecutar a chamada do sistema interrompida (ou
restart_syscall(2)
chamada de sistema para algumas chamadas de sistema que usam um mecanismo diferente para reiniciar) se o rastreador usarPTRACE_SYSCALL
. Até mesmo chamadas de sistema (comopoll(2)
) que não podem ser reinicializados após o sinal ser reiniciado após o sinal ser suprimido;no entanto, existem bugs no kernel que fazem com que algumas chamadas do sistema falhem com o EINTR, mesmo que nenhum sinal observável seja injetado no tracee.
Por padrão,SIGWINCH
é ignorado, mas parece epoll
semelhante o suficiente para poll
que EINTR
fique visível para o chamador (mesmo com a reinicialização).