2010-06-02 64 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