Testsed x86_64-pc-linux-gnu, committed to master.
Jonathan Wakely writes: > On 02/11/20 08:10 -0800, Thomas Rodgers wrote: >>From: Thomas Rodgers <trodg...@redhat.com> >> >>IGNORE the previous patch. >> >>Changes implementation to use a private __mutex type as discussed on >>IRC. >> >>libstdc++/ChangeLog: >> libstdc++-v3/doc/doxygen/user.cfg.in (INPUT): Add new header. >> libstdc++-v3/include/Makefile.am (std_headers): Add new header. >> libstdc++-v3/include/Makefile.in: Regenerate. >> libstdc++-v3/include/precompiled/stdc++.h: Include new header. >> (basic_streambuf): Befriend __detail::__streambuf_core_access. >> libstdc++-v3/include/std/syncstream: New header. >> libstdc++-v3/include/std/version: Add __cpp_lib_syncbuf: >> libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc: New test. >> libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc: Likewise. >> libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc: >> Likewise. >> libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc: >> Likewise. >> libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc: >> Likewise. >> libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc: Likewise. >> libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc: Likewise. >> libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc: >> Likewise. >> libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc: >> Likewise. >>--- >> libstdc++-v3/doc/doxygen/user.cfg.in | 1 + >> libstdc++-v3/include/Makefile.am | 1 + >> libstdc++-v3/include/Makefile.in | 1 + >> libstdc++-v3/include/precompiled/stdc++.h | 2 +- >> libstdc++-v3/include/std/syncstream | 333 ++++++++++++++++++ >> libstdc++-v3/include/std/version | 4 + >> .../testsuite/27_io/basic_syncbuf/1.cc | 28 ++ >> .../testsuite/27_io/basic_syncbuf/2.cc | 28 ++ >> .../27_io/basic_syncbuf/basic_ops/1.cc | 137 +++++++ >> .../27_io/basic_syncbuf/requirements/types.cc | 42 +++ >> .../27_io/basic_syncbuf/sync_ops/1.cc | 130 +++++++ >> .../testsuite/27_io/basic_syncstream/1.cc | 28 ++ >> .../testsuite/27_io/basic_syncstream/2.cc | 28 ++ >> .../27_io/basic_syncstream/basic_ops/1.cc | 134 +++++++ >> .../basic_syncstream/requirements/types.cc | 43 +++ >> 15 files changed, 939 insertions(+), 1 deletion(-) >> create mode 100644 libstdc++-v3/include/std/syncstream >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc >> create mode 100644 >> libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc >> create mode 100644 >> libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc >> create mode 100644 >> libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc >> >>diff --git a/libstdc++-v3/doc/doxygen/user.cfg.in >>b/libstdc++-v3/doc/doxygen/user.cfg.in >>index 9b49a15d31b..320f6dea688 100644 >>--- a/libstdc++-v3/doc/doxygen/user.cfg.in >>+++ b/libstdc++-v3/doc/doxygen/user.cfg.in >>@@ -897,6 +897,7 @@ INPUT = >>@srcdir@/doc/doxygen/doxygroups.cc \ >> include/streambuf \ >> include/string \ >> include/string_view \ >>+ include/syncstream \ >> include/system_error \ >> include/thread \ >> include/tuple \ >>diff --git a/libstdc++-v3/include/Makefile.am >>b/libstdc++-v3/include/Makefile.am >>index c90ac555e15..8652b921274 100644 >>--- a/libstdc++-v3/include/Makefile.am >>+++ b/libstdc++-v3/include/Makefile.am >>@@ -73,6 +73,7 @@ std_headers = \ >> ${std_srcdir}/shared_mutex \ >> ${std_srcdir}/span \ >> ${std_srcdir}/sstream \ >>+ ${std_srcdir}/syncstream \ >> ${std_srcdir}/stack \ >> ${std_srcdir}/stdexcept \ >> ${std_srcdir}/stop_token \ >>diff --git a/libstdc++-v3/include/precompiled/stdc++.h >>b/libstdc++-v3/include/precompiled/stdc++.h >>index 7518a98c25a..8899c323a28 100644 >>--- a/libstdc++-v3/include/precompiled/stdc++.h >>+++ b/libstdc++-v3/include/precompiled/stdc++.h >>@@ -141,6 +141,6 @@ >> #include <ranges> >> #include <span> >> #include <stop_token> >>-// #include <syncstream> >>+#include <syncstream> >> #include <version> >> #endif >>diff --git a/libstdc++-v3/include/std/syncstream >>b/libstdc++-v3/include/std/syncstream >>new file mode 100644 >>index 00000000000..ff96ca6cf59 >>--- /dev/null >>+++ b/libstdc++-v3/include/std/syncstream >>@@ -0,0 +1,333 @@ >>+// <syncstream> -*- C++ -*- >>+ >>+// Copyright (C) 2020 Free Software Foundation, Inc. >>+// >>+// This file is part of the GNU ISO C++ Library. This library is free >>+// software; you can redistribute it and/or modify it under the >>+// terms of the GNU General Public License as published by the >>+// Free Software Foundation; either version 3, or (at your option) >>+// any later version. >>+ >>+// This library is distributed in the hope that it will be useful, >>+// but WITHOUT ANY WARRANTY; without even the implied warranty of >>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >>+// GNU General Public License for more details. >>+ >>+// Under Section 7 of GPL version 3, you are granted additional >>+// permissions described in the GCC Runtime Library Exception, version >>+// 3.1, as published by the Free Software Foundation. >>+ >>+// You should have received a copy of the GNU General Public License and >>+// a copy of the GCC Runtime Library Exception along with this program; >>+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see >>+// <http://www.gnu.org/licenses/>. >>+ >>+/** @file include/syncstream >>+ * This is a Standard C++ Library header. >>+ */ >>+ >>+#ifndef _GLIBCXX_SYNCSTREAM >>+#define _GLIBCXX_SYNCSTREAM 1 >>+ >>+#if __cplusplus > 201703L >>+ >>+#include <bits/c++config.h> >>+#if _GLIBCXX_USE_CXX11_ABI >>+ >>+#define __cpp_lib_syncbuf 201803L >>+ >>+#pragma GCC system_header >>+ >>+#include <sstream> >>+ >>+#include <bits/alloc_traits.h> >>+#include <bits/allocator.h> >>+#include <bits/functexcept.h> >>+#include <bits/functional_hash.h> >>+ >>+#if _GLIBCXX_HAS_GTHREADS >>+# include <bits/std_mutex.h> >>+#endif >>+ >>+namespace std _GLIBCXX_VISIBILITY(default) >>+{ >>+_GLIBCXX_BEGIN_NAMESPACE_VERSION >>+ >>+ template<typename _CharT, typename _Traits = char_traits<_CharT>, >>+ typename _Alloc = allocator<_CharT>> >>+ class basic_syncbuf : public basic_streambuf<_CharT, _Traits> >>+ { >>+ public: >>+ using char_type = _CharT; >>+ using int_type = typename _Traits::int_type; >>+ using pos_type = typename _Traits::pos_type; >>+ using off_type = typename _Traits::off_type; >>+ using traits_type = _Traits; >>+ using allocator_type = _Alloc; >>+ using streambuf_type = basic_streambuf<_CharT, _Traits>; >>+ >>+ basic_syncbuf() >>+ : basic_syncbuf(nullptr, allocator_type{}) >>+ { } >>+ >>+ explicit >>+ basic_syncbuf(streambuf_type* __obuf) >>+ : basic_syncbuf(__obuf, allocator_type{}) >>+ { } >>+ >>+ basic_syncbuf(streambuf_type* __obuf, const allocator_type& __alloc) >>+ : _M_wrapped(__obuf) >>+ , _M_impl(__alloc) >>+ , _M_mtx(__obuf) >>+ { } >>+ >>+ basic_syncbuf(basic_syncbuf&& __other) >>+ : _M_wrapped(__other._M_wrapped) >>+ , _M_impl(std::move(__other._M_impl)) >>+ , _M_mtx(std::move(__other._M_mtx)) >>+ , _M_emit_on_sync(__other._M_emit_on_sync) >>+ , _M_needs_sync(__other._M_needs_sync) >>+ { >>+ __other._M_wrapped = nullptr; >>+ } >>+ >>+ ~basic_syncbuf() >>+ { >>+ __try >>+ { >>+ emit(); >>+ } >>+ __catch (...) >>+ { } >>+ } >>+ >>+ basic_syncbuf& operator=(basic_syncbuf&& __other) >>+ { >>+ if (std::__addressof(__other) != this) >>+ { >>+ emit(); >>+ >>+ _M_impl = std::move(__other._M_impl); >>+ _M_wrapped = __other._M_wrapped; __other._M_wrapped = nullptr; >>+ _M_mtx = std::move(__other._M_mtx); >>+ _M_emit_on_sync = __other._M_emit_on_sync; >>+ _M_needs_sync = __other._M_needs_sync; >>+ } >>+ return *this; >>+ } >>+ >>+ void >>+ swap(basic_syncbuf& __other) >>+ { >>+ if (std::__addressof(__other) != this) >>+ { >>+ std::swap(_M_impl, __other._M_impl); >>+ std::swap(_M_wrapped, __other._M_wrapped); >>+ std::swap(_M_mtx, __other._M_mtx); >>+ std::swap(_M_emit_on_sync, __other._M_emit_on_sync); >>+ std::swap(_M_needs_sync, __other._M_needs_sync); >>+ } >>+ } >>+ >>+ bool >>+ emit() >>+ { >>+ if (!_M_wrapped) >>+ return false; >>+ >>+ auto __s = _M_impl.view(); >>+ if (__s.empty()) >>+ return true; >>+ >>+ const lock_guard<__mutex> __l(_M_mtx); >>+ if (_M_wrapped->sputn(__s.data(), __s.size()) != __s.size()) >>+ return false; >>+ >>+ if (_M_needs_sync) >>+ { >>+ _M_needs_sync = false; >>+ if (_M_wrapped->pubsync() != 0) >>+ return false; >>+ } >>+ >>+ _M_impl.str(""); >>+ return true; >>+ } >>+ >>+ streambuf_type* >>+ get_wrapped() const noexcept >>+ { return _M_wrapped; } >>+ >>+ allocator_type get_allocator() const noexcept >>+ { return _M_impl.get_allocator(); } >>+ >>+ void >>+ set_emit_on_sync(bool __b) noexcept >>+ { _M_emit_on_sync = __b; } >>+ >>+ protected: >>+ int >>+ sync() override >>+ { >>+ auto __res = _M_impl.pubsync(); >>+ if (__res == 0) >>+ { >>+ _M_needs_sync = true; >>+ if (_M_emit_on_sync) >>+ return emit() ? 0 : -1; >>+ } >>+ return __res; >>+ } >>+ >>+ streamsize >>+ xsputn(const char_type* __s, streamsize __n) override >>+ { return _M_impl.sputn(__s, __n); } >>+ >>+ private: >>+ streambuf_type* _M_wrapped; >>+ >>+ using __impl_type = basic_stringbuf<char_type, traits_type, >>+ allocator_type>; >>+ __impl_type _M_impl; >>+ >>+ struct __mutex >>+ { >>+#if _GLIBCXX_HAS_GTHREADS >>+ mutex* _M_mtx; >>+ >>+ __mutex(void* __t) > > Make this 'explicit' please. > >>+ : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr) >>+ { } >>+ >>+ void >>+ swap(__mutex& __other) noexcept >>+ { std::swap(_M_mtx, __other._M_mtx); } >>+ >>+ void >>+ lock() >>+ { >>+ if (_M_mtx) >>+ _M_mtx->lock(); >>+ } >>+ >>+ void >>+ unlock() >>+ { >>+ if (_M_mtx) >>+ _M_mtx->unlock(); >>+ } >>+ >>+ // FIXME: This should be put in the .so >>+ static mutex& >>+ _S_get_mutex(void* __t) >>+ { >>+ const unsigned char __mask = 0xf; >>+ static mutex __m[__mask + 1]; >>+ >>+ auto __key = _Hash_impl::hash(__t) & __mask; >>+ return __m[__key]; >>+ } >>+#else >>+ __mutex(void*) > > And 'explicit' here too. > >>+ { } >>+ >>+ void >>+ swap(__mutex&&) noexcept > > This needs to be an lvalue reference, or it won't compile. > >>+ { } >>+ >>+ void >>+ lock() >>+ { } >>+ >>+ void >>+ unlock() >>+ { } > > All these completely empty functions can be put on one line: > > void unlock() { } > > There's no need for these no-op members take up so many lines. > >>+#endif >>+ __mutex(const __mutex&) = delete; >>+ __mutex& operator=(const __mutex&) = delete; > > These are redundant (the user-declared moves below cause the copies to > be deleted) but harmless. > >>+ >>+ __mutex(__mutex&&) = default; >>+ __mutex& operator=(__mutex&&) = default; >>+ }; >>+ __mutex _M_mtx; >>+ >>+ bool _M_emit_on_sync = false; >>+ bool _M_needs_sync = false; >>+ }; > > > OK for trunk, thanks.