为什么strace和ltrace会导致EINTR发生?

为什么strace和ltrace会导致EINTR发生?

考虑这个程序:

#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者可以看到(即使重新启动)。

相关内容