EAGAIN 对常规文件的阻塞读取系统调用

EAGAIN on a blocking read system call on regular file

所以,这是一个我有时看到但无法找出原因的奇怪案例。

我们有一个从常规文件读取的 C 程序。还有其他进程写入同一个文件。该应用程序基于这样一个事实,即写入在 Linux 中是原子的,写入大小最大为 4096 字节。

文件未使用非阻塞标志打开,因此我的假设是读取会阻塞。

但有时在启动过程中,我们会在 errno 中看到“资源暂时不可用”错误设置。大小 return 由 read != -1 编辑,但部分读取大小。

错误消息类似于:

 2018-08-07T06:40:52.991141Z, Invalid message size, log_s.bin, fd 670, Resource temporarily unavailable, read size 285, expected size 525

我的问题是:

  1. 为什么我们在阻止文件读取时得到 EAGAIN

  2. 为什么return值不是-1?

  3. 这仅在启动的初始时间发生。此后它工作正常。哪些极端情况会让我们陷入这种情况?

Why are we getting EAGAIN on blocking file read ?

你不是(见下文)。

Why is the return value not -1 ?

因为操作没有失败

如果对 read() 的调用失败,errno 的值 具有合理的值。当且仅当返回 -1 时,对 read() 的调用失败。

来自Linux man-page for read()

RETURN VALUE

On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested;

[...]

On error, -1 is returned, and errno is set appropriately.

read() 的常见模式是

char buffer[BUFFER_MAX];
char * p = buffer;
size_t to_read = ... /* not larger then BUFFER_MAX! */

while (to_read > 0)
{
  ssize_t result = read(..., p, to_read);
  if (-1 == result)
  {
    if (EAGAIN == errno || EWOULDBLOCK == errno)
    {
      continue;
    }

    if (EINTR == errno)
    {
      continue; /* or break depending on application design. */
    }

    perror("read() failed");

    exit(EXIT_FAILURE);
  }
  else if (0 < result)
  {
    to_read -= (size_t) result;
    p += (size_t) result;
  }
  else if (0 == result) /* end of file  /  connection shut down for reading */
  {
    break;
  }
  else
  {
    fprintf(stderr, "read() returned the unexpected value of %zd. You probably hit a (kernel) bug ... :-/\n", result);

    exit(EXIT_FAILURE);
  }
}

If (0 < to_read)
{
  fprintf(stderr, "Encountered early end of stream. %zu bytes not read.\n", to_read);
}