6

If I call a POSIX function like read() that isn't part of the C++ standard library I have to worry about it being interrupted by a signal and handle an EINTR return value. If I call a C++ standard library function like fread() based on this documentation there is no mention of EINTR so it seems like the standard library hides this from the user. Is my understanding correct and does this hold for all C++ standard library functions?

Update: So what is still not clear from the responses is that is the conclusion that one can't write standard C++ that properly functions on every platform? I'm seeing people mention POSIX behavior that is not part of the standard so this is confusing.

Mike Sweeney
  • 1,896
  • 2
  • 18
  • 20

3 Answers3

3

If I call a POSIX function like read() that isn't part of the C++ standard library I have to worry about it being interrupted by a signal and handle an EINTR return value.

And that should not be an issue for your code because:

  1. read can fail, hence the return value and errno must be handled anyway.
  2. read can do a partial read, so that in blocking mode you have to call read in a loop. errno == EINTR is just another condition to retry the call in both blocking and non-blocking mode.
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
1

POSIX covers fread as well, which is good since the C and C++ standards say very little about signals to support more than just POSIX. It says, partially on the fgetc page, that fread may return early (possibly returning 0), set ferror, and set errno to EINTR. Of course, if a signal causes a short read, there is no way for the C library to detect that and it will simply call read again, so you can’t rely on responding to the signal in a timely fashion. Writing is analogous.

There are very few other operations in the C++ standard library that can produce EINTR; unfortunately, POSIX doesn’t cover C++, so there isn’t an established answer for things like sleep_for that aren’t in C.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • Where in the standard is this documented? If I look at the documentation I linked to where does it say that EINTR is possible? In other words is what you're suggesting platform/implementation dependent or required for standard code? – Mike Sweeney Jun 11 '19 at 13:07
  • @MikeSweeney: It’s on the `fgetc` page, to which `fread` defers for errors. This behavior is required for *POSIX* C implementations (and thus applies to C++ implementations that are built on them), but not other C (ir C++) systems. – Davis Herring Jun 11 '19 at 13:22
0

fread() was originally part of the C standard library, libc, defined in <stdio.h>. The C++ standard library makes the same fread() available through the C library wrapper <cstdio>.

read() has no such wrapper (perhaps because it would clash with istream's version) but you can still call it using the C library. You're correct that read() came from the POSIX specific extension <unistd.h> and is not part of the standard library, but it has since been implemented quite broadly and often distributed with libc.

You're also correct that read() will set errno on failure and one of those errors might be EINTR. And on the other hand when fread() fails, there is no way to find out what error occurred, so technically you're also correct that EINTR occurrences are hidden from the user in that case. Indeed, how fread() handles any platform specific details is up to the implementation. But it would be a stretch to say that this pattern applies to "all C++ standard library functions" - you'd really have to check case by case.

If you want to write "properly functioning" code that runs on every platform, then don't use the POSIX extensions. Stick to fread() and friends, and accept the fact that generalisation across platforms means you might not be able to get platform specific details like error numbers. Since the possible errors are platform specific, there's no generic way to know if you should try again.

More details on the differences between read() and fread() are here.

Heath Raftery
  • 3,643
  • 17
  • 34
  • I specifically said `read()` is not part of the "C++ standard library" and from what I know `fread()` is guaranteed to be available per the C++ standard via ``. My question was about whether when calling `fread()` one has to worry about possibly retrying it because of EINTR. I looked at my libc implementation of `fread` and it retries in the case of EINTR which is in contradiction to some answers here. – Mike Sweeney Jun 15 '19 at 03:57
  • Ah yes, so you did. Sorry I got wrapped up in an edit cycle. Have taken the incorrect assertion out. Hopefully it still answers your question - `fread()` doesn't guarantee anything, including whether EINTR exists or not. – Heath Raftery Jun 16 '19 at 01:12