Date: Mon, 18 Aug 2014 11:26:40 +1000 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Pedro Giffuni <pfg@freebsd.org> Cc: svn-src-stable@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org, Andrey Chernov <ache@freebsd.org>, svn-src-stable-10@freebsd.org Subject: Re: svn commit: r270035 - stable/10/lib/libc/stdio Message-ID: <20140818102031.C948@besplex.bde.org> In-Reply-To: <53F0FE68.6080501@freebsd.org> References: <201408160129.s7G1TojV024013@svn.freebsd.org> <53F0F263.7040202@freebsd.org> <53F0FE68.6080501@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Sun, 17 Aug 2014, Pedro Giffuni wrote: > > On 08/17/14 13:20, Andrey Chernov wrote: >> On 16.08.2014 5:29, Pedro F. Giffuni wrote: >>> Author: pfg >>> Date: Sat Aug 16 01:29:49 2014 >>> New Revision: 270035 >>> URL: http://svnweb.freebsd.org/changeset/base/270035 >>> >>> Log: >>> MFC r268924: >>> Update fflush(3) to return success on a read-only stream. >>> This is done for compliance with SUSv3. The changes cause >>> no secondary effects in the gnulib tests (we pass them). >> ... >>> @@ -122,6 +123,12 @@ __sflush(FILE *fp) >>> for (; n > 0; n -= t, p += t) { >>> t = _swrite(fp, (char *)p, n); >>> if (t <= 0) { >>> + /* Reset _p and _w. */ >>> + if (p > fp->_p) /* Some was written. */ >>> + memmove(fp->_p, p, n); >>> + fp->_p += n; >>> + if ((fp->_flags & (__SLBF | __SNBF)) == 0) >>> + fp->_w -= n; >>> fp->_flags |= __SERR; >>> return (EOF); >>> } >>> >> The description is incomplete. This code also does internal stdio >> structure adjustment for partial write. >> > Oh yes, I forgot about that part. > > The story is that Apple only does this for EAGAIN but Bruce suggested it > should be done for other errors as well. > > TBH, I wasn't going to merge this change but it seemed consistent to have > all the changes that originated from Apple's libc together. The tests for it seem to be missing too. The other errors are mainly EINTR. stdio is almost unusable in the presence of EAGAIN or EINTR. Its philosophy is to treat these as normal errors push the error handling up to the caller, but this means that almost any stdio operation can fail in unexpected ways, and stdio provides no portable way to even classify these errors. Normally in BSD, EINTR rarely happens because at least read() and write() are restarted after interrupts and files with non-blocking i/o are rare. Both using SA_RESTART to stop syscalls being restarted and using O_NONBLOCK are at a lower level than stdio, so applications that use them are mostly on their own. But non-BSD programs have to deal with EINTR (especially POSIX ones where EINTR is not at a lower level than the system), an file descriptors with O_NONBLOCK can be produced by users and enforced on stdio by fdopen() (again in POSIX). POSIX does document EAGAIN and EINTR as extensions of C99 for stdio functions. Non-stdio is difficult to use in the absence of these errors. Signal handling in top(1) is still broken by restarting read(). It used to work in most cases using unsafe signal handling (clean up and exit in the SIGINT handler). It would work with no syscall restarting and safe signal handling (just set a flag in the syscall and check it in the main loop). But FreeBSD has syscall restarting and safe signal handling, so input waits unboundedly for a newline, EOF, or an actual error after receiving a SIGINT (EOF handling is broken too). It seems necessary for _any_ interactive program to turn off syscall restarting around _any_ syscall that might block unboundedly, and then handle the EINTRs that may occur from this. This is nontrivial and not done by most programs. top(1) is relatively easy to fix since it only has about place to change and this place doesn't use stdio. I know too much about this since I once broke a version of stdio to handle EAGAIN internally. Any handling prevents the application seeing the EAGAIN and handling it appropriately. Stdio has no way to know if the application wants to retry immediately, and there is no way to tell it what to do. Spinning retrying EAGAIN in stdio is just better than what an average application will do. Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20140818102031.C948>