Clearing O_NONBLOCK from a pipe may lose data

Eric Blake
Sat Feb 21 12:03:00 GMT 2015

On 02/20/2015 01:21 PM, Lasse Collin wrote:
> For example, if xz is modified to leave O_NONBLOCK enabled on stdout,
>     ( xz -dc smallfile.xz ; cat bigfile ) | ( sleep 1 ; wc -c )
> will make cat print
>     cat: write error: Resource temporarily unavailable
> on GNU/Linux and most of bigfile won't be seen by wc. However, on
> Cygwin the above works because the modifications to the file status
> flags in xz aren't seen by cat. That is, stdout in cat is in blocking
> mode even though xz left it in non-blocking mode.

That's a bug in cygwin, although fixing it may be difficult.  In POSIX
terminology, the blocking flag of an open file description is shared
among all the file descriptors visiting that file description, whether
the extra file descriptors were created by dup() or by fork(); and it is
one of the few bits of information where a child can affect the state
visible in the parent.  But if Windows doesn't share blocking status of
multiple handles visiting the same resource, then I'm not sure how we
can emulate it.

[various side notes: Another such bit of information shared between
processes is the file offset of a shared seekable file description, and
Windows DOES support that.  On the other hand, things like the cloexec
flag are associated with a file descriptor [fcntl F_GETFD] rather than a
file description [fcntl F_GETFL], and so are NOT shared across dup() or
fork().  Also, note that two consecutive calls to open() with the same
parameters produces two separate file descriptions (the two file
descriptors do not share state); it is only dup() or fork() that can
create two file descriptors sharing a file description.

Where it gets really weird is with flock() vs. fcntl(F_SETLK)/lockf()
locking: flock() is per-description, but fcntl() and lockf() are
per-inode, which means a second locker visiting a distinct open() can
wipe out the lock of the first description - making lockf() very painful
to use; but flock() lacks byte ranges, making it also unideal.  The
Linux kernel is pioneering a new lock, and POSIX is considering
standardizing it, called fcntl(F_OFD_SETLK) which has all the benefits
of per-description locking (the best of flock) and range locking (the
best of lockf) - eventually, Cygwin should probably implement that as
well.  We already have quite the hacks in place to get flock/lockf
coordination from child back to parent, which would be the sort of code
to borrow from if we have to figure out how to get nonblocking status
propagated in the same direction.

hmm - my side notes took more space than my real response - is that a
good thing?]

> 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.

Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 604 bytes
Desc: OpenPGP digital signature
URL: <>

More information about the Cygwin mailing list