2009-11-04 28 views
5

我的用戶空間模塊接收EINTR信號,後不知何故有時應用。如何處理EINTR(系統調用被中斷)

我什麼記錄使用Strace:

time(NULL)        = 1257343042 
time(NULL)        = 1257343042 
rt_sigreturn(0xbff07be4)    = -1 EINTR (Interrupted system call) 
--- SIGALRM (Alarm clock) @ 0 (0) --- 
time(NULL)        = 1257343042 
futex(0xb7cea80c, 0x80 /* FUTEX_??? */, 2) = ? ERESTARTSYS (To be restarted) 
--- SIGUSR1 (User defined signal 1) @ 0 (0) --- 
sigreturn()        = ? (mask now [ALRM]) 
futex(0xb7cea80c, 0x80 /* FUTEX_??? */, 2) = ? ERESTARTSYS (To be restarted) 
--- SIGWINCH (Window changed) @ 0 (0) --- 
futex(0xb7cea80c, 0x80 /* FUTEX_??? */, 2) = ? ERESTARTSYS (To be restarted) 
--- SIGTERM (Terminated) @ 0 (0) --- 
time(NULL)        = 1257343443 
time(NULL)        = 1257343443 
futex(0xb7cea80c, 0x80 /* FUTEX_??? */, 2) = ? ERESTARTSYS (To be restarted) 
--- SIGWINCH (Window changed) @ 0 (0) --- 
futex(0xb7cea80c, 0x80 /* FUTEX_??? */, 2 

我能趕上EINTR信號,我怎麼能重複來電關注諸如寫入,讀取或選擇?即使我使用第三方庫處理系統調用,如何確定發生了這個EINTR?

爲什麼我的應用程序接收到EINTR(:我發了SIGUSR1通常的處理方式,請參閱strace轉儲)之後被完全阻塞?爲什麼futex()將ERESTARTSYS返回給用戶空間?

感謝

+3

討論EINTR不是信號但在一個系統調用信號中斷的錯誤數返回。 – 2009-11-04 15:06:22

+0

使用'gstack'或'gdb'獲取堆棧跟蹤,找出程序當前停滯的地方。 – mark4o 2009-11-04 16:08:01

回答

17

這就要求寫(或其他阻塞操作)的代碼必須知道EINTR的。如果在阻塞操作期間發生信號,則操作將(a)返回部分完成,或(b)返回失敗,不執行任何操作,並將errno設置爲EINTR。

因此,對於全或失敗,從而中斷後重試寫操作時,你會做這樣的事情:

while(size > 0) { 
    int written = write(filedes, buf, size); 
    if (written == -1) { 
     if (errno == EINTR) continue; 
     return -1; 
    } 
    buf += written; 
    size -= written; 
} 
return 0; // success 

或爲東西有點更好的表現,這將重試EINTR,寫儘可能多因爲它可以,並報告有多少失敗的寫操作(使主叫方可以決定是否以及如何繼續其失敗不是由信號中斷等原因部分寫入):

int total = 0; 
while(size > 0) { 
    int written = write(filedes, buf, size); 
    if (written == -1) { 
     if (errno == EINTR) continue; 
     return (total == 0) ? -1 : total; 
    } 
    buf += written; 
    total += written; 
    size -= written; 
} 
return total; // bytes written 

GNU具有非標雖然我可能感興趣的TEMP_FAILURE_RETRY宏當我想要它們時,永遠無法找到它的文檔。包括現在。

+1

謝謝,我發現的Docu於宏在http://www.gnu.org/s/libc/manual/html_node/Interrupted-Primitives.html 你瞭解一下futex的鎖定()函數? – Maus 2009-11-04 15:11:05

+1

不知道ERESTARTSYS。我認爲這是一個內部實現細節 - 你可以在跟蹤中看到它,但不應該看到它返回給用戶代碼,因爲用戶模式系統代碼應該重試返回它的調用,否則將其轉換爲EINTR 。但我可能是錯的,我最後剃上週六,因此沒有像完整的Linux怪胎憑據;-) – 2009-11-04 15:16:17

+2

futex的事情是建立更高層次的東西就像一個信號燈Linux特有的「輕等待」鎖定框架和互斥體。見futex(7)。 – 2009-11-04 15:21:29