pynexj
pynexj

Reputation: 20688

TCP socket: Can read() still fail with EINTR when select() indicates there are data available?

I'm using select() for non-blocking read() from TCP socket. When select() indicates there are data for reading I'm not sure if I still need to deal with EINTR after read().

Upvotes: 2

Views: 477

Answers (2)

Myst
Myst

Reputation: 19221

They way I understand the documentation (I didn't read through the kernel's code, so I may be wrong), the answer is: Yes.

If an interrupt occurs during the kernel's read operation (when the kernel is copying data from the socket's buffer to the user's memory and updating the socket's state), the operation is canceled and the read function will return -1 (with errno set to EINTR).

The fact that the socket is non-blocking only minimizes the "window" but it doesn't prevent this condition from taking place.

Also, even if this were not the case, I would recommend that you assume that EINTR is possible. As long as the documentation doesn't state that an EINTR error is invalid for non-blocking file descriptors, future updates to the kernel's implementation might invoke this error as they see fit.

Also, consider that even though the read operation feels atomic to the application, the kernel is juggling a number of internal structures (the socket's read buffer alone has a number of elements that need to be updated after the memory was copied). For this reason, the internal structure has locking / synchronizing mechanisms. Even though the socket is non-blocking, there's still a window of time where the call could be interrupted.

Upvotes: 2

David Schwartz
David Schwartz

Reputation: 182761

Yes, absolutely. The select function is a status reporting function that reports the status of something at some time in-between when you called select and when you noticed its return value. It comes with absolutely no future guarantees whatsoever, period.

This is a very common misconception. But thinking that select ensures a future operation will provide some particular result is as misguided as thinking that checking that there is free space on a disk means a future write won't fail. The implementation is permitted to fail a write with insufficient free space, in its judgement, even if you think there's enough free space. And the space can fill between finding the space and trying to use it.

The same is true with select. There is no rule that the implementation must somehow remember that it gave you a hit on select and have that affect the implementation of a subsequent read. People have made this assumption many times and gotten bitten by it horribly. Do not assume that just because you can't think of any way it can fail, that means it can't fail.

For example, no rule prohibits an implementation from doing the following:

  1. A packet is received.
  2. It's valid TCP data, so select returns ready to read. A read issued at this instant would have returned the data.
  3. Before the implementation can ACK the data, the network interface's write queue gets full.
  4. Since the implementation sees it can't send an ACK right now due to the full queue it simply opts to discard the packet and force the other end to retransmit
  5. A subsequent read operation blocks since there is no data to read.

If you think some standard prohibits it, please cite the standard. A read after a select hit can fail for any reason a read before a select hit could fail. The select function never gives future guarantees.

Upvotes: 6

Related Questions