為什麼 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)對它沒有任何作用,它一直在等待 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
**被忽略,但聽起來好像與呼叫者可見的足夠相似(即使重新啟動)epoll
。poll``EINTR