对于在 EINTR 上重试的系统调用的包装器,重试多少次才有意义?

问题描述 投票:0回答:1

通常像

write(2)
read(2)
close(2)
等系统调用会因被具有
errno
EINTR
的信号中断而失败(假设终端窗口的大小已更改并且收到了
SIGWINCH
) ,这是一个暂时性错误,应该重试,代码通常使用这些系统调用的包装器,在
EINTR
(通常是
EAGAIN
ENOBUFS
)上重试。

但是有可能陷入理论情况,即由于接收不间断信号,或者因为系统调用被仅返回

EINTR
的系统调用的自定义实现拦截,代码继续在
EINTR
上无限循环.

在这种情况下,在库代码中,重试系统调用多少次才有意义?

c unix posix system-calls errno
1个回答
0
投票

对于在 EINTR 上重试的系统调用的包装器,重试多少次才有意义?

从零到无穷多。

Glibc 标准库已在全球数十亿台设备中使用。调用

printf("Hello world\n");
最终会出现在
_IO_new_file_write
函数中,如下所示,来自 https://github.com/bminor/glibc/blob/5aa2f79691ca6a40a59dfd4a2d6f7baff6917eb7/libio/fileops.c#L1176 :

ssize_t
_IO_new_file_write (FILE *f, const void *data, ssize_t n)
{
  ssize_t to_do = n;
  while (to_do > 0)
    {
      ssize_t count = (__builtin_expect (f->_flags2
                                         & _IO_FLAGS2_NOTCANCEL, 0)
               ? __write_nocancel (f->_fileno, data, to_do)
               : __write (f->_fileno, data, to_do));
      if (count < 0)
    {
      f->_flags |= _IO_ERR_SEEN;
      break;
    }
      to_do -= count;
      data = (void *) ((char *) data + count);
    }
  n -= to_do;
  if (f->_offset >= 0)
    f->_offset += n;
  return n;
}

尽你所能,

while (to_do > 0)
该函数将无限次循环,直到数据被写入,忽略任何
EINTR
信号,甚至不检查任何信号。

因为世界上几乎每一个 Linux 设备都使用这个软件,所以可以肯定地说无限多次循环是完全没问题的。

如果您愿意,可以循环 40 次或 100 次。没关系。

© www.soinside.com 2019 - 2024. All rights reserved.