
考慮這個程序:
#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
可以看到(即使重新啟動)。