This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[v3] Fix libstdc++/11378
- From: Paolo Carlini <pcarlini at unitus dot it>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 14 Jul 2003 20:27:12 +0200
- Subject: [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 );
}