处理EINTR(带goto?)

时间:2010-06-02 13:27:31

标签: c++ goto system-calls eintr

背景:这是this thread关于在C ++(Linux / GCC)中处理系统调用的EINTR的后续问题。无论我是否打算对我的应用程序进行概要分析,似乎我应该处理系统调用,将errno设置为EINTR作为特例。有关使用goto的{​​{3}},manymany意见。

我的问题:是系统调用设置errnoEINTR goto被视为名义上的情况?如果没有,那么您如何建议转换以下代码来处理EINTR

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

提前致谢!
干杯,
-Chris

更新:根据以下答案,我结束了编写以下宏:

#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 个答案:

答案 0 :(得分: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;
    }
}

答案 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意味着您的服务器已捕获到信号,并且在大多数情况下处理该信号非常重要。