This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[v3] Fix libstdc++/11378


Hi,

tested x86-linux.

Paolo.

//////////
2003-07-14  Paolo Carlini  <pcarlini@unitus.it>
	    Nathan C. Myers  <ncm-nospam@cantrip.org>

	PR libstdc++/11378
	* include/std/std_fstream.h (xsputn): Declare only.
	* include/bits/fstream.tcc (xsputn): Define, optimize for the
	always_noconv() case: when __n is sufficiently large flush 
	the buffer and issue a direct write, if possible combining the
	two with writev in __basic_file<>::xsputn_2.
	* config/io/basic_file_stdio.h (__basic_file<>::xsputn_2):
	New, declare.
	* config/io/basic_file_stdio.cc (__basic_file<>::xsputn_2):
	Define.
	* acinclude.m4 (GLIBCXX_CHECK_WRITE): New macro, checking for
	the availability of writev in <sys/uio.h>.
	* configure.in: Call here.
	* acconfig.h: Add undef for the corresponding symbol.
	* aclocal.m4: Regenerate.
	* configure: Regenerate.
	* config.h.in: Regenerate.
	* testsuite/27_io/basic_filebuf/setbuf/char/3.cc: Tweak.

	* include/std/std_fstream.h (sync): Constify a variable.
	
diff -urN libstdc++-v3-orig/acconfig.h libstdc++-v3/acconfig.h
--- libstdc++-v3-orig/acconfig.h	2003-07-05 06:05:18.000000000 +0200
+++ libstdc++-v3/acconfig.h	2003-07-11 19:37:09.000000000 +0200
@@ -144,6 +144,9 @@
 // Define if S_IFREG is available in <sys/stat.h>.
 #undef HAVE_S_IFREG
 
+// Define if writev is available in <sys/uio.h>.
+#undef HAVE_WRITEV
+
 // Define if LC_MESSAGES is available in <locale.h>.
 #undef HAVE_LC_MESSAGES
 
diff -urN libstdc++-v3-orig/acinclude.m4 libstdc++-v3/acinclude.m4
--- libstdc++-v3-orig/acinclude.m4	2003-07-11 18:27:48.000000000 +0200
+++ libstdc++-v3/acinclude.m4	2003-07-11 19:58:03.000000000 +0200
@@ -2162,6 +2162,23 @@
   fi
 ])
 
+dnl
+dnl Check whether writev is available in <sys/uio.h>.
+dnl
+
+AC_DEFUN(GLIBCXX_CHECK_WRITEV, [
+  AC_CACHE_VAL(glibcxx_cv_WRITEV, [
+    AC_TRY_COMPILE([#include <sys/uio.h>],
+                [struct iovec iov[2]; writev(0, iov, 0); ],
+                [glibcxx_cv_WRITEV=yes],
+                [glibcxx_cv_WRITEV=no])
+  ])
+  if test x$glibcxx_cv_WRITEV = xyes; then
+    AC_DEFINE(HAVE_WRITEV)
+  fi
+])
+
+
 # Check whether LC_MESSAGES is available in <locale.h>.
 # Ulrich Drepper <drepper@cygnus.com>, 1995.
 #
diff -urN libstdc++-v3-orig/config/io/basic_file_stdio.cc libstdc++-v3/config/io/basic_file_stdio.cc
--- libstdc++-v3-orig/config/io/basic_file_stdio.cc	2003-07-05 06:05:30.000000000 +0200
+++ libstdc++-v3/config/io/basic_file_stdio.cc	2003-07-12 01:23:46.000000000 +0200
@@ -50,6 +50,10 @@
 #include <poll.h>
 #endif
 
+#ifdef _GLIBCXX_HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
 #if defined(_GLIBCXX_HAVE_S_ISREG) || defined(_GLIBCXX_HAVE_S_IFREG)
 # include <sys/stat.h>
 # ifdef _GLIBCXX_HAVE_S_ISREG
@@ -225,6 +229,40 @@
     return __ret;
   }
 
+  streamsize 
+  __basic_file<char>::xsputn_2(const char* __s1, streamsize __n1,
+			       const char* __s2, streamsize __n2)
+  {
+    streamsize __ret = 0;
+#ifdef _GLIBCXX_HAVE_WRITEV
+    struct iovec __iov[2];
+    __iov[0].iov_base = const_cast<char*>(__s1);
+    __iov[0].iov_len = __n1;
+    __iov[1].iov_base = const_cast<char*>(__s2);
+    __iov[1].iov_len = __n2;
+
+    do
+      __ret = writev(this->fd(), __iov, 2);
+    while (__ret == -1L && errno == EINTR);
+#else
+    if (__n1)
+      do
+	__ret = write(this->fd(), __s1, __n1);
+      while (__ret == -1L && errno == EINTR);
+
+    if (__ret == __n1)
+      {
+	do
+	  __ret = write(this->fd(), __s2, __n2);
+	while (__ret == -1L && errno == EINTR);
+	
+	if (__ret != -1L)
+	  __ret += __n1;
+      }
+#endif
+    return __ret;
+  }
+
   streampos
   __basic_file<char>::seekoff(streamoff __off, ios_base::seekdir __way, 
 			      ios_base::openmode /*__mode*/)
diff -urN libstdc++-v3-orig/config/io/basic_file_stdio.h libstdc++-v3/config/io/basic_file_stdio.h
--- libstdc++-v3-orig/config/io/basic_file_stdio.h	2003-07-05 06:05:30.000000000 +0200
+++ libstdc++-v3/config/io/basic_file_stdio.h	2003-07-11 20:09:57.000000000 +0200
@@ -97,6 +97,10 @@
       xsputn(const char* __s, streamsize __n);
 
       streamsize 
+      xsputn_2(const char* __s1, streamsize __n1,
+	       const char* __s2, streamsize __n2);
+
+      streamsize 
       xsgetn(char* __s, streamsize __n);
 
       streampos
diff -urN libstdc++-v3-orig/configure.in libstdc++-v3/configure.in
--- libstdc++-v3-orig/configure.in	2003-07-05 06:05:26.000000000 +0200
+++ libstdc++-v3/configure.in	2003-07-12 13:42:45.000000000 +0200
@@ -423,6 +423,10 @@
   GLIBCXX_CHECK_POLL
   GLIBCXX_CHECK_S_ISREG_OR_S_IFREG
 
+  # For xsputn_2().
+  AC_CHECK_HEADERS(sys/uio.h)
+  GLIBCXX_CHECK_WRITEV
+
   AC_LC_MESSAGES
 
   AC_TRY_COMPILE([
diff -urN libstdc++-v3-orig/include/bits/fstream.tcc libstdc++-v3/include/bits/fstream.tcc
--- libstdc++-v3-orig/include/bits/fstream.tcc	2003-07-05 06:05:34.000000000 +0200
+++ libstdc++-v3/include/bits/fstream.tcc	2003-07-12 11:10:57.000000000 +0200
@@ -438,6 +438,54 @@
       return __elen && __elen == __plen;
     }
 
+   template<typename _CharT, typename _Traits>
+     streamsize
+     basic_filebuf<_CharT, _Traits>::
+     xsputn(const _CharT* __s, streamsize __n)
+     { 
+       streamsize __ret = 0;
+      
+       // Optimization in the always_noconv() case, to be generalized in the
+       // future: when __n is sufficiently large we write directly instead of
+       // using the buffer.
+       const bool __testout = this->_M_mode & ios_base::out;
+       if (__testout && !_M_reading
+	   && __check_facet(_M_codecvt).always_noconv())
+	{
+	  // Measurement would reveal the best choice.
+	  const streamsize __chunk = 1ul << 10;
+	  streamsize __bufavail = this->epptr() - this->pptr();
+
+	  // Don't mistake 'uncommitted' mode buffered with unbuffered.
+	  if (!_M_writing && this->_M_buf_size > 1)
+	    __bufavail = this->_M_buf_size - 1;
+
+	  const streamsize __limit = std::min(__chunk, __bufavail);
+	  if (__n >= __limit)
+	    {
+	      const streamsize __buffill = this->pptr() - this->pbase();
+	      const char* __buf = reinterpret_cast<const char*>(this->pbase());
+	      __ret = _M_file.xsputn_2(__buf, __buffill,
+				       reinterpret_cast<const char*>(__s), __n);
+	      if (__ret == __buffill + __n)
+		{
+		  _M_set_buffer(0);
+		  _M_writing = true;
+		}
+	      if (__ret > __buffill)
+		__ret -= __buffill;
+	      else
+		__ret = 0;
+	    }
+	  else
+	    __ret = __streambuf_type::xsputn(__s, __n);
+	}
+       else
+	 __ret = __streambuf_type::xsputn(__s, __n);
+      
+       return __ret;
+    }
+
   template<typename _CharT, typename _Traits>
     typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 
     basic_filebuf<_CharT, _Traits>::
diff -urN libstdc++-v3-orig/include/std/std_fstream.h libstdc++-v3/include/std/std_fstream.h
--- libstdc++-v3-orig/include/std/std_fstream.h	2003-07-06 13:24:43.000000000 +0200
+++ libstdc++-v3/include/std/std_fstream.h	2003-07-11 19:42:49.000000000 +0200
@@ -365,7 +365,7 @@
 	// NB: _M_file.sync() will be called within.
 	if (this->pbase() < this->pptr())
 	  {
-	    int_type __tmp = this->overflow();
+	    const int_type __tmp = this->overflow();
 	    if (traits_type::eq_int_type(__tmp, traits_type::eof()))
 	      __ret = -1;
 	    else
@@ -407,8 +407,7 @@
 
       // [documentation is inherited]
       virtual streamsize
-      xsputn(const char_type* __s, streamsize __n)
-      { return __streambuf_type::xsputn(__s, __n); }
+      xsputn(const char_type* __s, streamsize __n);
 
       /**
        *  @if maint
diff -urN libstdc++-v3-orig/testsuite/27_io/basic_filebuf/setbuf/char/3.cc libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/3.cc
--- libstdc++-v3-orig/testsuite/27_io/basic_filebuf/setbuf/char/3.cc	2003-04-10 09:15:28.000000000 +0200
+++ libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/3.cc	2003-07-11 19:44:05.000000000 +0200
@@ -34,7 +34,9 @@
   filebuf fbuf01;
   fbuf01.open("tmp", ios_base::out);
 
-  fbuf01.pubsetbuf(buf, strlitsize);
+  // NB: +2 otherwise sputn is optimized to a direct write,
+  // bypassing the buffer.
+  fbuf01.pubsetbuf(buf, strlitsize + 2);
   fbuf01.sputn(strlit, strlitsize);
   VERIFY( std::strncmp(strlit, buf, strlitsize) == 0 );
 }

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