2010-06-02 33 views
3

背景:這是關於在C++(Linux/GCC)中處理系統調用的EINTR的this thread的後續問題。無論我是否打算介紹我的應用程序,似乎我應該將系統調用設置爲errnoEINTR作爲特例。有many,many,many關於使用goto的意見。處理EINTR(帶goto?)

我的問題:是一個系統調用設置errnoEINTR其中goto被認爲是正常的情況下?如果沒有,那麼你會如何建議轉換下面的代碼來處理EINTR

if ((sock_fd = ::socket(domain, type, protocol)) < 0) { 
    throw SocketException("Socket::Socket() -> ::socket()", errno); 
} 

在此先感謝!
乾杯,
克里斯

UPDATE:基於下面的答案,我結束了寫下面的宏:

#define SOCK_SYSCALL_TRY(call,error)    \ 
    while ((call) < 0) {       \ 
    switch (errno) {       \ 
     case EINTR:         \ 
     continue;         \ 
     default:         \ 
     throw SocketException((error), errno); \ 
    }            \ 
    }            \ 

這是用我原來的片段轉換爲這個例子:

SOCK_SYSCALL_TRY(sock_fd = ::socket(domain, type, protocol), "Socket::Socket() -> ::socket()") 

希望這可以幫助別人!

+2

克里斯,得到這本書:http://www.unpbook.com - 你會很高興你做到了。源代碼在線http://www.unpbook.com/src.html - 請參閱此處瞭解如何處理EINTR的示例。 – 2010-06-02 13:34:33

+0

我從來沒有想過使用時/繼續 - 偉大的想法! – 2010-06-02 14:17:01

回答

4

據我所知,套接字系統調用不能返回與errno設置爲EINTR。 對於其他情況下,我使用一個循環:

while ((::connect(sock, (struct sockaddr *)&destAddress, sizeof(struct sockaddr))) == -1) { 
    if (errno == EINTR) { 
     LOGERROR("connect interrupted, retry"); 
     continue; 
    } else if (errno == EINPROGRESS) { 
     break; 
    } else { 
     LOGERROR("connect failed, errno: " << errno); 
     return -1; 
    } 
} 
2

我程序性的FTP服務器,我從來沒有使用goto。我通常建立可中斷的系統調用是這樣的:

while((ret = 
     splice_stream(data, NULL, file, &block_offset, 
      XFER_BLOCK_SIZE)) == -1) 
    { 
     switch(errno) 
     { 
     case EINTR: 
      if(server_handle_signal()) 
       return FTP_QUIT; 
      else 
       continue; 
      break; 
     case EPIPE: 
     case ECONNRESET: 
      return FTP_ABOR; 
     default: 
      log_fatal("Splice error: %m\n"); 
      return FTP_ERROR; 
     } 
    } 

EINTR意味着你的服務器已經趕上一個信號,它是大多數來處理信號的時間很重要。

+0

我不認爲你正在處理信號的權利。從系統調用返回-1和EINTR後,signal_handler已被異步調用。您需要處理signal_handler中的信號,或者使用signal_fd。 – WiSaGaN 2015-02-05 02:35:34