[PATCH] prevent retries on fclose/fflush after write errors

Denys Vlasenko vda.linux at googlemail.com
Mon Mar 12 00:50:27 UTC 2012


On Sunday 11 March 2012 18:10, Rich Felker wrote:
> On Sun, Mar 11, 2012 at 04:12:19PM +0100, Denys Vlasenko wrote:
> > On Sunday 11 March 2012 14:46, Denys Vlasenko wrote:
> > > I propose the following patch.
> > > Only compile tested by me, care to run-test?
> > 
> > A more correct (I hope) version:
> 
> I'm curious why this is such a big patch introducing new functions and
> struct members. Couldn't it be just a one-line change in the function
> that writes out the buffers (i.e. do the buffer-voiding as soon as the
> error is hit rather than testing for it later)?

EINTR and EAGAIN should not result in output buffers being dropped.
You need to remember the error code for this.

> Perhaps I'm missing 
> something about uclibc's design that makes this not work well, but
> it's how my implementation in musl has always done it and I could
> switch to the bad glibc behavior just by changing one line...

How about this simpler one?


--- a/libc/stdio/_WRITE.c
+++ b/libc/stdio/_WRITE.c
@@ -58,13 +58,29 @@ size_t attribute_hidden __stdio_WRITE(register FILE *stream,
 			todo -= rv;
 			buf += rv;
 		} else
-#ifdef __UCLIBC_MJN3_ONLY__
-#warning EINTR?
-#endif
-/* 		if (errno != EINTR) */
-		{
-			__STDIO_STREAM_SET_ERROR(stream);
 
+		__STDIO_STREAM_SET_ERROR(stream);
+
+		/* We buffer data on "transient" errors, but discard it
+		 * on "hard" ones. Example of a hard error:
+		 *
+		 * close(fileno(stdout));
+		 * printf("Hi there 1\n"); // EBADF
+		 * dup2(good_fd, fileno(stdout));
+		 * printf("Hi there 2\n"); // buffers new data
+		 *
+		 * This program should not print "Hi there 1" to good_fd.
+		 * The rationale is that the caller of writing operation
+		 * should check for error and act on it.
+		 * If he didn't, then future users of the stream
+		 * have no idea what to do.
+		 * It's least confusing to at least not burden them with
+		 * some hidden buffered crap in the buffer.
+		 */
+ 		if (errno == EINTR
+		 || errno == EAGAIN
+		 /* do we have other "soft" errors? */
+		) {
 #ifdef __STDIO_BUFFERS
 			stodo = __STDIO_STREAM_BUFFER_SIZE(stream);
 			if (stodo != 0) {


More information about the uClibc mailing list