Process

EINTR:它背後有什麼理由嗎?

  • November 24, 2021

閒聊作為背景

EINTR是所謂的可中斷系統呼叫可能返回的錯誤。如果在系統呼叫執行時出現信號,則不會忽略該信號。如果為它定義了一個未SA_RESTART設置的信號處理程序並且此處理程序處理該信號,則係統呼叫將返回EINTR錯誤程式碼。

ncurses附帶說明一下,我在 Python 中經常遇到這個錯誤。

問題

POSIX 標準規定的這種行為背後是否有理由?可以理解它可能無法恢復(取決於核心設計),但是,在核心級別不自動重新啟動它的理由是什麼?這是出於遺留還是技術原因?如果這是出於技術原因,那麼這些原因現在仍然有效嗎?如果這是出於遺留原因,那麼歷史是什麼?

在信號處理程序中很難做不平凡的事情,因為程序的其餘部分處於未知狀態。大多數信號處理程序只是設置一個標誌,稍後在程序的其他地方對其進行檢查和處理。

沒有自動重啟系統呼叫的原因:

想像一個應用程序通過阻塞和不間斷 recv()的系統呼叫從套接字接收數據。在我們的場景中,數據來得很慢,並且程序在該系統呼叫中駐留了很長時間。該程序有一個信號處理程序,用於SIGINT設置一個標誌(在別處評估),並SA_RESTART設置系統呼叫自動重新啟動。想像一下程序在recv()其中等待數據。但是沒有數據到達。系統呼叫阻塞。該程序現在擷取ctrl-c從使用者。系統呼叫被中斷並執行剛剛設置標誌的信號處理程序。然後recv()重新啟動,仍在等待數據。事件循環卡住了recv(),沒有機會評估標誌並優雅地退出程序。

SA_RESTART設置:

在上述場景中,當SA_RESTART未設置時,recv()將收到EINTR而不是重新啟動。系統呼叫退出,因此可以繼續。當然,程序應該(盡可能早地)檢查標誌(由信號處理程序設置)並進行清理或其他任何操作。

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