![为什么strace和ltrace会导致EINTR发生?](https://linux22.com/image/139208/%E4%B8%BA%E4%BB%80%E4%B9%88strace%E5%92%8Cltrace%E4%BC%9A%E5%AF%BC%E8%87%B4EINTR%E5%8F%91%E7%94%9F%EF%BC%9F.png)
考虑这个程序:
#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;
}
当我单独运行该程序时,调整终端大小(从而生成 SIGWINCH)不会对其执行任何操作,并且它会继续等待标准输入上的输入。当我在 strace 或 ltrace 中运行它时,SIGWINCH 会导致 epoll_wait 出现 EINTR 错误。我对 EINTR 的理解是,只有当信号调用代码中的信号处理程序时才会生成它,但我没有注册它们中的任何一个。我认为 strace 或 ltrace 可能已经为我设置了一个,所以我尝试将其显式设置为 SIG_IGN,但这仍然没有阻止 EINTR。为什么会发生这种情况?
答案1
他们使用ptrace(2)
,其手册页注释
在被追踪时,每次发出信号时,被追踪者都会停止,即使信号被忽略。 (一个例外是
SIGKILL
,这具有其通常的效果。)跟踪器将在下次调用时收到通知waitpid(2)
(或相关的“等待”系统调用之一);该调用将返回一个状态值,其中包含指示被跟踪者停止原因的信息。当被跟踪者停止时,跟踪器可以使用各种 ptrace 请求来检查和修改被跟踪者。然后,跟踪器使被跟踪者继续,可以选择忽略传递的信号(或者甚至传递不同的信号)。
然后:
请注意,抑制信号仍会导致系统调用过早返回。在这种情况下,系统调用将重新启动:跟踪器将观察被跟踪者重新执行中断的系统调用(或
restart_syscall(2)
系统调用(用于一些使用不同机制重新启动的系统调用)如果跟踪器使用PTRACE_SYSCALL
。甚至系统调用(例如poll(2)
) 信号被抑制后,信号重新启动后不可重新启动;然而,存在内核错误,即使没有可观察到的信号注入到被跟踪者,也会导致某些系统调用失败并出现 EINTR。
默认情况下,SIGWINCH
被忽略,但听起来好像epoll
足够相似,以至于poll
调用EINTR
者可以看到(即使重新启动)。