為什麼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可以看到(即使重新啟動)。

相關內容