Clearing O_NONBLOCK from a pipe may lose data

Lasse Collin
Sun Feb 22 21:00:00 GMT 2015

(I have now subscribed to the list to get everyone's replies. Sorry for
breaking the message thread.)

Eric Blake wrote:
> On 02/20/2015 01:21 PM, Lasse Collin wrote:
> > The above Cygwin behavior would make it very easy to add a
> > workaround to xz for the pipe-data-loss problem: simply don't clear
> > O_NONBLOCK on stdout. However, I wonder if it is a bug in Cygwin
> > that the changes to file status flags aren't seen via other file
> > descriptors that refer to the same file description. If it is a
> > bug, then the workaround idea will cause trouble in the future when
> > the bug in Cygwin gets fixed.
> Yeah, the fact that cygwin is buggy with respect to POSIX may break
> any workaround you add if cygwin is later patched.

OK. I think I will keep stdout in blocking mode in xz on Cygwin for now.
The race condition in signal handling is a very minor issue compared to
data loss.

Thomas Wolff wrote:
> I see no strict requirement that the fcntl call removing O_NONBLOCK
> from a file descriptor should itself still be handled as nonblocking
> (it can well be argued that the flag is changed first and then the
> call is allowed to block) - and even if this were not proper it is
> certainly more acceptable than losing data.

I agree that it's better than losing data even though it has some

Blocking F_SETFL can cause a deadlock since it is valid to do this from
a single thread:

    1. Create a pipe in non-blocking mode.
    2. Write up to PIPE_BUF bytes to the pipe.
    3. Set pipe to blocking mode.
    4. Read from the pipe.

I don't know why a program would do that, so maybe it's not a problem
in practice. Even if it is a problem, a deadlock should be easier to
debug than silent data loss.

What should be done if the thread blocked in F_SETFL receives a signal?
Usually blocking syscalls can be interrupted by signals if SA_RESTART
isn't used. Looking at POSIX and Linux fcntl() man pages, the
possibility of EINTR is mentioned for specific commands and F_SETFL
isn't among them. It sounds likely that applications aren't prepared to
restart F_SETFL (at least xz isn't), and using EINTR would lead to data
loss, although it would no longer be silent data loss since it can be
detected from fcntl's return value. It's worth noting that the
interrupting signal doesn't necessarily come from a user; it may be e.g.
SIGALRM that was requested via alarm().

On the other hand, if the fcntl() call is restarted after a signal even
when SA_RESTART isn't used, a program may become unresponsive to
signals. Even then this sounds less bad than unexpected EINTR (assuming
that applications aren't prepared to restart F_SETFL).

Alternative idea: Would there be a significant downside if Cygwin
remembered if non-blocking mode was enabled at some point and close()
would use that flag instead of the current (non)blocking status to
determine if the background thread hack should be used?

Lasse Collin  |  IRC: Larhzu @ IRCnet & Freenode

Problem reports:
Unsubscribe info:

More information about the Cygwin mailing list