Signals

為什麼 strace 和 ltrace 會導致 EINTR 發生?

  • August 27, 2018

考慮這個程序:

#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)對它沒有任何作用,它一直在等待 stdin 上的輸入。當我在 strace 或 ltrace 中執行它時,SIGWINCH 會導致 epoll_wait 出現 EINTR 錯誤。我對 EINTR 的理解是,它僅在信號呼叫程式碼中的信號處理程序時生成,但我沒有註冊它們中的任何一個。我認為 strace 或 ltrace 可能已經為我設置了一個,所以我嘗試將其顯式設置為 SIG_IGN,但這仍然沒有阻止 EINTR。為什麼會這樣?

他們使用**ptrace(2)**,其手冊頁註釋

在被跟踪時,每次傳遞信號時被跟踪者都會停止,即使該信號被忽略。(一個例外是 SIGKILL,它具有通常的效果。)跟踪器將在其下一次呼叫**waitpid(2)**(或相關的“等待”系統呼叫之一)時得到通知;該呼叫將返回一個狀態值,其中包含指示被跟踪者停止原因的資訊。當 tracee 停止時,tracer 可以使用各種 ptrace 請求來檢查和修改 tracee。然後跟踪器使被跟踪者繼續,可選地忽略傳遞的信號(或者甚至傳遞不同的信號)。

然後:

請注意,抑制信號仍會導致系統呼叫過早返回。在這種情況下,系統呼叫將被重新啟動: restart_syscall(2) 如果跟踪器使用 PTRACE_SYSCALL. 即使是在 signal 後不可重新啟動的系統呼叫(例如**poll(2)**),在 signal 被抑制後也會重新啟動;然而,即使沒有可觀察的信號注入到 tracee ,核心錯誤也會導致某些系統呼叫失敗並出現 EINTR

預設情況下,**SIGWINCH**被忽略,但聽起來好像與呼叫者可見的足夠相似(即使重新啟動)epollpoll``EINTR

引用自:https://unix.stackexchange.com/questions/465193