From owner-freebsd-bugs@FreeBSD.ORG Sat Feb 11 08:32:16 2012 Return-Path: Delivered-To: freebsd-bugs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id EAB271065676 for ; Sat, 11 Feb 2012 08:32:16 +0000 (UTC) (envelope-from brde@optusnet.com.au) Received: from mail02.syd.optusnet.com.au (mail02.syd.optusnet.com.au [211.29.132.183]) by mx1.freebsd.org (Postfix) with ESMTP id 7B7348FC12 for ; Sat, 11 Feb 2012 08:32:16 +0000 (UTC) Received: from c211-30-171-136.carlnfd1.nsw.optusnet.com.au (c211-30-171-136.carlnfd1.nsw.optusnet.com.au [211.30.171.136]) by mail02.syd.optusnet.com.au (8.13.1/8.13.1) with ESMTP id q1B8WDEC028396 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Sat, 11 Feb 2012 19:32:14 +1100 Date: Sat, 11 Feb 2012 19:32:13 +1100 (EST) From: Bruce Evans X-X-Sender: bde@besplex.bde.org To: David Xu In-Reply-To: <201202110330.q1B3UF1V033278@freefall.freebsd.org> Message-ID: <20120211185842.Y2039@besplex.bde.org> References: <201202110330.q1B3UF1V033278@freefall.freebsd.org> MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed Cc: freebsd-bugs@freebsd.org Subject: Re: bin/164947: tee looses data when writing to non-blocking file descriptors X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 11 Feb 2012 08:32:17 -0000 On Sat, 11 Feb 2012, David Xu wrote: > [... excessive quoting removed] > >> Description: > > When tee(1) tries to write to a file descriptor that has been set to non-blocking mode the write(2) call may fail with EAGAIN. Instead of retrying the operation, tee will throw that chunk of data away. > so tee should also work with non-blocking read, your patch is incomplete. Not just for tee :-). Just about every filter utility starting with cat(1) doesn't even dream of EAGAIN. I once helped implement a stdio that retried unconditionally after EAGAIN. This isn't quite right, but it automatically fixes any utility that makes the mistake of using stdio for anything important, starting with filter utilities that make this mistake (fortunately, not cat(1) in FreeBSD). The stdio interface also doesn't even dream of EAGAIN. Unless stdio's internals know about it and retries automatically, it has to treat EAGAIN as a fatal error like EIO, and return an error and set ferror() on the stream, and it should set errno to EAGAIN. This is what FreeBSD stdio does (no retry). Applications can check for EAGAIN and retry, but this is not portable and applications that use stdio are probably doing it because they want to be portable and/or don't want to handle the details, so they are further from dreaming about EAGAIN that the average application. The correct behaviour for stdio is probably to retry conditionally depending on a flag set by ffcntl(3new) that defaults to on. You would clear the flag in the unusual case where you actual want to use non-blocking i/o and see EAGAIN. Stdio doesn't really support non- blocking i/o, but it might work. ffcntl() could also use ordinary fcntl() to clear O_NONBLOCK. The old stdio might have retried because the system didn't support fcntl(). But even with fcntl(), clearing O_NONBLOCK should be a separate option, since this action might have side effects on the file, so you shouldn't do it unless you know what the file is, and in particular you shouldn't do it in filters. Side effects are more common than they should be, since most implementations of fcntl(... O_NONBLOCK) are buggy. They tend to set O_NONBLOCK on the device (when the file is for a device) where they should set it only on the open file. Thus they affect other opens of the device. The old stdio also couldn't have used select() to avoid possibly spinning doing i/o's. Yet another ffcntl() flag could be used to control whether select()/poll()/kqueue is used. This would be even more unportable and device-dependent (for best results). Bruce