Can read(2) return zero when not at EOF?

WilliamKF picture WilliamKF · Jun 19, 2010 · Viewed 12.9k times · Source

According to the man page for read(2), it only returns zero when EOF is reached.

However, It appears this is incorrect and that it may sometimes return zero, perhaps because the file is not ready to be read yet? Should I call select() to see if it is ready before reading a file from disk?

Note that nBytes is: 1,445,888

Some sample code:

fd_set readFdSet;
timeval timeOutTv;

timeOutTv.tv_sec = 0;
timeOutTv.tv_usec = 0;

// Let's see if we'll block on the read.
FD_ZERO(&readFdSet);
FD_SET(fd, &readFdSet);

int selectReturn = ::select(fd + 1, &readFdSet, NULL, NULL, &timeOutTv);

if (selectReturn == 0) {
  // There is still more to read.
  return false; // But return early.
} else if (selectReturn < 0) {
  clog << "Error: select failure: " << strerror(errno) << endl;
  abort();
} else {
  assert(FD_ISSET(fd, &readFdSet));

  try {
    const int bufferSizeAvailable = _bufferSize - _availableIn;

    if (_availableIn) {
      assert(_availableIn <= _bufferSize);

      memmove(_buffer, _buffer + bufferSizeAvailable, _availableIn);
    }

    ssize_t got = ::read(fd, _buffer + _availableIn, bufferSizeAvailable);

    clog << " available: " << bufferSizeAvailable << " availableIn: "
         << _availableIn << " bufferSize: " << _bufferSize << " got "
         << got << endl;

    return got == 0;
  } catch (Err &err) {
    err.append("During load from file.");
    throw;
  }
}

The output reads (when it fails with no data read):

available: 1445888 availableIn: 0 bufferSize: 1445888 got: 0

This is running on centos4 32 bit as a virtual machine using VMware Server 1.0.10. The file system being read is local to the virtual machine. The host machine is windows server 2008 32 bit.

The uname -a says:

Linux q-centos4x32 2.6.9-89.0.25.ELsmp #1 SMP Thu May 6 12:28:03 EDT 2010 i686 i686 i386 GNU/Linux

I notice that the link http://opengroup.org/onlinepubs/007908775/xsh/read.html given below states:

The value returned may be less than nbyte if the number of bytes left in the file is less than nbyte, if the read() request was interrupted by a signal...

If a read() is interrupted by a signal before it reads any data, it will return -1 with errno set to [EINTR].

If a read() is interrupted by a signal after it has successfully read some data, it will return the number of bytes read. 

So, perhaps I am getting a signal interrupting the read and thus the value returned is zero because of either a bug or it thinks zero bytes were read?

Answer

Nicholas Knight picture Nicholas Knight · Jun 19, 2010

After some research, there actually are some circumstances under which it will return 0 that you might not think of as being "EOF".

For the gritty details, see the POSIX definition for read(): http://opengroup.org/onlinepubs/007908775/xsh/read.html

Some notable ones are if you ask it to read 0 bytes -- double check that you're not accidentally passing 0 to it -- and reading past the end of the "written" portion of the file (you can actually seek past the end of the file, which "extends" the file with zeroes if you write there, but until you do, "EOF" is still at the end of the already-written portion).

My best guess is that you're getting into a timing problem somewhere. Some questions you need to ask are "How are these files being written?" and "Am I sure they're not zero-length when I try to read them?". For the second one, you could try running a stat() on the file before reading it to see what its current size is.