This is the mail archive of the libstdc++@sourceware.cygnus.com mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

problem with flush on file streams



hi -

Continuing to test the new libstdc++, i've run into a problem with the
flush() method on file streams.  This is based on the current version
in cvs, using gcc 2.95.2 on a i686-pc-linux-gnu platform.

Consider the following program:

----------------------------------------------------
#include <iostream>

main ()
{
  cout << "a\n";
  cout.flush ();
  cerr << "b\n";
  cerr.flush ();
  cout << "c\n";
  cout.flush ();
}
----------------------------------------------------


Now, i understand that in the absence of any explicit flushes,
the ordering of output to different streams which go to the same
file is not guaranteed.  But, with the inclusion of the explicit
flushes above, i would expect this program to always produce output
in the order in which the calls are made in the program.

However, this is not the case.  When i run the program with no redirection,
i get the expected result:

$ ./test4
a
b
c

On the other hand, if i redirect stdout and stderr to a file, i get:

$ ./test4 >& x
$ cat x
a
c
b


which is not expected.

If i look in the debugger at what happens as a result of the cerr.flush()
call, i see in basic_filebuf::sync:

      virtual int 
      sync()
      {
	// Don't do anything about input sequences.
	bool __testput = _M_out_cur && _M_out_beg < _M_out_cur;
	if (__testput)
	  {
	    // Iff _M_mode is ios_base::out only, then need to set out
	    // pointers to the end of the current put sequence before
	    // we call _M_really_overflow, or else the stream will not be
	    // flushed. Back up, so overflow doesn't append extra characters.
	    this->_M_really_overflow();
	  }
	_M_last_overflowed = false;	
	return 0;
      }

that __testput is false, thus _M_really_overflow() does not get called.

I'm guessing that what happens is that after the `cerr << "b\n";', the
C++ streambuf is flushed to the libio layer, and it gets buffered there.
When flush() is called, we see that the C++ buffer is empty and thus
don't do anything, even though there is still data buffered at the 
layer below.

I tried to see what would happen if i called the libio sync()
unconditionally here:

1999-11-08  scott snyder  <snyder@fnal.gov>

	* bits/std_fstream.h (basic_filebuf::sync): Unconditionally call
	_M_file->sync().


--- std_fstream.h-orig	Sun Nov  7 20:42:39 1999
+++ std_fstream.h	Sun Nov  7 20:43:01 1999
@@ -170,6 +170,7 @@
 	    // flushed. Back up, so overflow doesn't append extra characters.
 	    this->_M_really_overflow();
 	  }
+        _M_file->sync ();
 	_M_last_overflowed = false;	
 	return 0;
       }

With this change, i get the expected output in both the redirected
and non-redirected cases.  But i don't really understand the 
libstdc++/libio interaction enough to be sure that this is a correct
fix.

thanks,
sss

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]