处理 EINTR(使用 goto?)

发布于 2024-09-04 02:38:26 字数 1564 浏览 8 评论 0原文

背景:这是此帖子的后续问题,内容涉及在 C++ (Linux/GCC) 中处理系统调用的 EINTR。无论我是否打算分析我的应用程序,似乎我都应该处理系统调用,将 errno 设置为 EINTR 作为特殊情况。有很多许多许多关于使用goto<的意见/代码>。

我的问题:errno设置为EINTR的系统调用是否会导致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()" )

希望这对其他人有帮助!

Background: This is a follow-up question to this thread about handling EINTR for system calls in C++ (Linux/GCC). Regardless of whether or not I intend to profile my application, it seems like I should be handling system calls setting errno to EINTR as a special case. There are many, many, many opinions about the use of goto.

My question: is a system call setting errno to EINTR a case where goto is considered nominal? If not, then how would you suggest converting the following code to handle EINTR?

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

Thanks in advance!
Cheers,
-Chris

UPDATE: Based on the answers below, I wound up writing the following macro:

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

Which is used to transform my original snippet to this example:

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

Hope this helps someone else!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

旧情勿念 2024-09-11 02:38:26

据我所知,套接字系统调用无法返回并将 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;
    }
}

As far as I know the socket system call can't return with errno set to EINTR.
For other cases I use a loop:

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;
    }
}
国产ˉ祖宗 2024-09-11 02:38:26

我编写了一个 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 意味着您的服务器已捕获信号,并且大多数时候处理该信号很重要。

I programed an FTP server and I never had to use goto. I usually constructed interruptable system-calls like this:

    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 means your server has caught a signal, and it is most of the time important to handle that signal.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文