On 27/11/20 17:46 +0000, Jonathan Wakely wrote:
On 20/11/20 16:30 -0800, Thomas Rodgers wrote:
From: Thomas Rodgers <trodg...@redhat.com>
Should include all discussion on and off list to date.
Most of the comments in
https://gcc.gnu.org/pipermail/gcc-patches/2020-November/558090.html
still apply to this version.
Adds <barrier>
libstdc++/ChangeLog:
* include/Makefile.am (std_headers): Add new header.
* include/Makefile.in: Regenerate.
* include/std/barrier: New file.
* include/std/version: Add __cpp_lib_barrier feature test macro.
* testsuite/30_thread/barrier/1.cc: New test.
* testsuite/30_thread/barrier/2.cc: Likewise.
* testsuite/30_thread/barrier/arrive_and_drop.cc: Likewise.
* testsuite/30_thread/barrier/arrive_and_wait.cc: Likewise.
* testsuite/30_thread/barrier/arrive.cc: Likewise.
* testsuite/30_thread/barrier/completion.cc: Likewise.
* testsuite/30_thread/barrier/max.cc: Likewise.
---
libstdc++-v3/include/Makefile.am | 1 +
libstdc++-v3/include/Makefile.in | 1 +
libstdc++-v3/include/std/barrier | 258 ++++++++++++++++++
libstdc++-v3/include/std/version | 3 +
.../testsuite/30_threads/barrier/1.cc | 27 ++
.../testsuite/30_threads/barrier/2.cc | 27 ++
.../testsuite/30_threads/barrier/arrive.cc | 51 ++++
.../30_threads/barrier/arrive_and_drop.cc | 49 ++++
.../30_threads/barrier/arrive_and_wait.cc | 51 ++++
.../30_threads/barrier/completion.cc | 54 ++++
.../testsuite/30_threads/barrier/max.cc | 44 +++
11 files changed, 566 insertions(+)
create mode 100644 libstdc++-v3/include/std/barrier
create mode 100644 libstdc++-v3/testsuite/30_threads/barrier/1.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/barrier/2.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/barrier/arrive.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/barrier/arrive_and_drop.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/barrier/arrive_and_wait.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/barrier/completion.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/barrier/max.cc
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index ca413b8fdfe..a20dd461fd1 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -30,6 +30,7 @@ std_headers = \
${std_srcdir}/any \
${std_srcdir}/array \
${std_srcdir}/atomic \
+ ${std_srcdir}/barrier \
${std_srcdir}/bit \
${std_srcdir}/bitset \
${std_srcdir}/charconv \
The new header should also be added to include/precompiled/stdc++.h
and doc/doxygen/user.cfg.in
diff --git a/libstdc++-v3/include/std/barrier b/libstdc++-v3/include/std/barrier
new file mode 100644
index 00000000000..a6cc6a058dd
--- /dev/null
+++ b/libstdc++-v3/include/std/barrier
@@ -0,0 +1,258 @@
+// <barrier> -*- 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// This implementation is based on libcxx/include/barrier
+//===-- barrier.h --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------===//
This file doesn't have the usual @file doxygen block.
+
+#ifndef _GLIBCXX_BARRIER
+#define _GLIBCXX_BARRIER 1
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#include <bits/c++config.h>
+
+#if defined(_GLIBCXX_HAS_GTHREADS)
This doesn't match the condition used in <bits/atomic_wait.h>. I've
added _GLIBCXX_HAVE_ATOMIC_WAIT so it could check that.
+#define __cpp_lib_barrier 201907L
+#include <bits/atomic_base.h>
+#include <bits/atomic_wait.h>
This is already included by <bits/atomic_base.h>
I suggest:
#if __cplusplus > 201703L
#include <bits/atomic_base.h>
#ifdef _GLIBCXX_HAVE_ATOMIC_WAIT
#include <bits/functional_hash.h>
...
#define __cpp_lib_barrier 201907L
We should only define the __cpp_lib macro after including all other
headers, otherwise we advertise to those headers that the feature
exists, but it hasn't been defined yet. Nothing is trying to use
barrier in the rest of the library yet, but that could change.
+#include <bits/functional_hash.h>
+
+#include <memory>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ struct __empty_completion
+ {
+ _GLIBCXX_ALWAYS_INLINE void
+ operator()() noexcept
+ { }
+ };
+
+/*
+
+The default implementation of __tree_barrier is a classic tree barrier.
+
+It looks different from literature pseudocode for two main reasons:
+ 1. Threads that call into std::barrier functions do not provide indices,
+ so a numbering step is added before the actual barrier algorithm,
+ appearing as an N+1 round to the N rounds of the tree barrier.
+ 2. A great deal of attention has been paid to avoid cache line thrashing
+ by flattening the tree structure into cache-line sized arrays, that
+ are indexed in an efficient way.
+
+*/
+
+ using __barrier_phase_t = uint8_t;
+
+ template<typename _CompletionF>
+ class __tree_barrier
+ {
+ struct alignas(64) /* naturally-align the heap state */ __state_t
+ {
+ struct
+ {
+ __atomic_base<__barrier_phase_t> __phase = { 0 };
+ } __tickets[64];
+ };
+
+ ptrdiff_t _M_expected;
+ unique_ptr<char[]> _M_state_allocation;
+ __state_t* _M_state;
+ __atomic_base<ptrdiff_t> _M_expected_adjustment;
+ _CompletionF _M_completion;
+
+ using __atomic_phase_ref_t = std::__atomic_ref<__barrier_phase_t>;
+ using __atomic_phase_const_ref_t = std::__atomic_ref<const
__barrier_phase_t>;
+ static constexpr size_t __phase_alignment =
+ __atomic_phase_ref_t::required_alignment;
+ alignas(__phase_alignment) __barrier_phase_t _M_phase;
+
+ static __gthread_t
+ _S_get_tid() noexcept
+ {
+#ifdef __GLIBC__
+ // For the GNU C library pthread_self() is usable without linking to
+ // libpthread.so but returns 0, so we cannot use it in single-threaded
+ // programs, because this_thread::get_id() != thread::id{} must be true.
+ // We know that pthread_t is an integral type in the GNU C library.
+ if (!__gthread_active_p())
+ return 1;
+#endif
+ return __gthread_self();
If you include <bits/std_thread.h> you can use this_thread::get_id()
here. That avoids needing to repeat the glibc-specific hack.
+ }
+
+ bool
+ _M_arrive(__barrier_phase_t __old_phase)
+ {
+ __barrier_phase_t const __half_step = __old_phase + 1,
+ __full_step = __old_phase + 2;
+ size_t __current_expected = _M_expected;
+ size_t __current = _Hash_impl::hash(_S_get_tid())
+ % ((_M_expected + 1) >> 1);
If we move std::hash<std::thread::id> into <bits/std_thread.h> then
you can just use that.
Done in r11-6227.
Tested powerpc64le-linux, committed to trunk.
commit 8cdca5f9c706af118390489efc94336f6214f515
Author: Jonathan Wakely <jwak...@redhat.com>
Date: Thu Dec 17 11:59:07 2020
libstdc++: Move std::hash<std::thread::id> to <bits/std_thread.h>
This makes the hash function available without including the whole of
<thread>, which is needed for <barrier>.
libstdc++-v3/ChangeLog:
* include/bits/std_thread.h (hash<thread::id>): Move here,
from ...
* include/std/thread (hash<thread::id>): ... here.
diff --git a/libstdc++-v3/include/bits/std_thread.h b/libstdc++-v3/include/bits/std_thread.h
index 24bd5fbd44e..4810d355695 100644
--- a/libstdc++-v3/include/bits/std_thread.h
+++ b/libstdc++-v3/include/bits/std_thread.h
@@ -38,6 +38,7 @@
#include <exception> // std::terminate
#include <iosfwd> // std::basic_ostream
#include <tuple> // std::tuple
+#include <bits/functional_hash.h> // std::hash
#include <bits/invoke.h> // std::__invoke
#include <bits/refwrap.h> // not required, but helpful to users
#include <bits/unique_ptr.h> // std::unique_ptr
@@ -288,6 +289,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// N.B. other comparison operators are defined in <thread>
+ // DR 889.
+ /// std::hash specialization for thread::id.
+ template<>
+ struct hash<thread::id>
+ : public __hash_base<size_t, thread::id>
+ {
+ size_t
+ operator()(const thread::id& __id) const noexcept
+ { return std::_Hash_impl::hash(__id._M_thread); }
+ };
+
namespace this_thread
{
/// this_thread::get_id
diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread
index 8d0ede2b6c2..10fb9e631be 100644
--- a/libstdc++-v3/include/std/thread
+++ b/libstdc++-v3/include/std/thread
@@ -43,7 +43,6 @@
#endif
#include <bits/std_thread.h> // std::thread, get_id, yield
-#include <bits/functional_hash.h> // std::hash
#ifdef _GLIBCXX_USE_NANOSLEEP
# include <cerrno> // errno, EINTR
@@ -94,17 +93,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return !(__x < __y); }
#endif // __cpp_lib_three_way_comparison
- // DR 889.
- /// std::hash specialization for thread::id.
- template<>
- struct hash<thread::id>
- : public __hash_base<size_t, thread::id>
- {
- size_t
- operator()(const thread::id& __id) const noexcept
- { return std::_Hash_impl::hash(__id._M_thread); }
- };
-
template<class _CharT, class _Traits>
inline basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id)