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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to