libstdc++: Move std::thread to a new header
authorJonathan Wakely <jwakely@redhat.com>
Thu, 19 Nov 2020 13:36:15 +0000 (13:36 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Thu, 19 Nov 2020 13:36:15 +0000 (13:36 +0000)
This makes it possible to use std::thread without including the whole of
<thread>. It also makes this_thread::get_id() and this_thread::yield()
available even when there is no gthreads support (e.g. when GCC is built
with --disable-threads or --enable-threads=single).

In order for the std::thread::id return type of this_thread::get_id() to
be defined, std:thread itself is defined unconditionally. However the
constructor that creates new threads is not defined for single-threaded
builds. The thread::join() and thread::detach() member functions are
defined inline for single-threaded builds and just throw an exception
(because we know the thread cannot be joinable if the constructor that
creates joinable threads doesn't exit).

The thread::hardware_concurrency() member function is also defined
inline and returns 0 (as suggested by the standard when the value "is
not computable or well-defined").

The main benefit for most targets is that other headers such as <future>
do not need to include the whole of <thread> just to be able to create a
std::thread. That avoids including <stop_token> and std::jthread where
not required. This is another partial fix for PR 92546.

This also means we can use this_thread::get_id() and this_thread::yield()
in <stop_token> instead of using the gthread functions directly. This
removes some preprocessor conditionals, simplifying the code.

libstdc++-v3/ChangeLog:

PR libstdc++/92546
* include/Makefile.am: Add new <bits/std_thread.h> header.
* include/Makefile.in: Regenerate.
* include/std/future: Include new header instead of <thread>.
* include/std/stop_token: Include new header instead of
<bits/gthr.h>.
(stop_token::_S_yield()): Use this_thread::yield().
(_Stop_state_t::_M_requester): Change type to std::thread::id.
(_Stop_state_t::_M_request_stop()): Use this_thread::get_id().
(_Stop_state_t::_M_remove_callback(_Stop_cb*)): Likewise.
Use __is_single_threaded() to decide whether to synchronize.
* include/std/thread (thread, operator==, this_thread::get_id)
(this_thread::yield): Move to new header.
(operator<=>, operator!=, operator<, operator<=, operator>)
(operator>=, hash<thread::id>, operator<<): Define even when
gthreads not available.
* src/c++11/thread.cc: Include <memory>.
* include/bits/std_thread.h: New file.
(thread, operator==, this_thread::get_id, this_thread::yield):
Define even when gthreads not available.
[!_GLIBCXX_HAS_GTHREADS] (thread::join, thread::detach)
(thread::hardware_concurrency): Define inline.

libstdc++-v3/include/Makefile.am
libstdc++-v3/include/Makefile.in
libstdc++-v3/include/bits/std_thread.h [new file with mode: 0644]
libstdc++-v3/include/std/future
libstdc++-v3/include/std/stop_token
libstdc++-v3/include/std/thread
libstdc++-v3/src/c++11/thread.cc

index 292d89da8ba7be0f639c6d34ae39a6d261f5afa5..7979f1c589d600981d532825daa724a969a7e649 100644 (file)
@@ -187,6 +187,7 @@ bits_headers = \
        ${bits_srcdir}/std_abs.h \
        ${bits_srcdir}/std_function.h \
        ${bits_srcdir}/std_mutex.h \
+       ${bits_srcdir}/std_thread.h \
        ${bits_srcdir}/stl_algo.h \
        ${bits_srcdir}/stl_algobase.h \
        ${bits_srcdir}/stl_bvector.h \
index fff444c69e866018fab729096ae58c3e990417bb..dfa72b95547c413dd8ffda33c0cce09a1de557b3 100644 (file)
@@ -533,6 +533,7 @@ bits_headers = \
        ${bits_srcdir}/std_abs.h \
        ${bits_srcdir}/std_function.h \
        ${bits_srcdir}/std_mutex.h \
+       ${bits_srcdir}/std_thread.h \
        ${bits_srcdir}/stl_algo.h \
        ${bits_srcdir}/stl_algobase.h \
        ${bits_srcdir}/stl_bvector.h \
diff --git a/libstdc++-v3/include/bits/std_thread.h b/libstdc++-v3/include/bits/std_thread.h
new file mode 100644 (file)
index 0000000..96c8d1b
--- /dev/null
@@ -0,0 +1,337 @@
+// std::thread declarations -*- C++ -*-
+
+// Copyright (C) 2008-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 bits/std_thread.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{thread}
+ */
+
+#ifndef _GLIBCXX_THREAD_H
+#define _GLIBCXX_THREAD_H 1
+
+#pragma GCC system_header
+
+#if __cplusplus >= 201103L
+#include <bits/c++config.h>
+
+#include <exception>           // std::terminate
+#include <iosfwd>              // std::basic_ostream
+#include <tuple>               // std::tuple
+#include <bits/invoke.h>       // std::__invoke
+#include <bits/refwrap.h>       // not required, but helpful to users
+#include <bits/unique_ptr.h>   // std::unique_ptr
+
+#ifdef _GLIBCXX_HAS_GTHREADS
+# include <bits/gthr.h>
+#else
+# include <errno.h>
+# include <bits/functexcept.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  /** @addtogroup threads
+   *  @{
+   */
+
+  /// thread
+  class thread
+  {
+  public:
+#ifdef _GLIBCXX_HAS_GTHREADS
+    // Abstract base class for types that wrap arbitrary functors to be
+    // invoked in the new thread of execution.
+    struct _State
+    {
+      virtual ~_State();
+      virtual void _M_run() = 0;
+    };
+    using _State_ptr = unique_ptr<_State>;
+
+    using native_handle_type = __gthread_t;
+#else
+    using native_handle_type = int;
+#endif
+
+    /// thread::id
+    class id
+    {
+      native_handle_type       _M_thread;
+
+    public:
+      id() noexcept : _M_thread() { }
+
+      explicit
+      id(native_handle_type __id) : _M_thread(__id) { }
+
+    private:
+      friend class thread;
+      friend struct hash<id>;
+
+      friend bool
+      operator==(id __x, id __y) noexcept;
+
+#if __cpp_lib_three_way_comparison
+      friend strong_ordering
+      operator<=>(id __x, id __y) noexcept;
+#else
+      friend bool
+      operator<(id __x, id __y) noexcept;
+#endif
+
+      template<class _CharT, class _Traits>
+       friend basic_ostream<_CharT, _Traits>&
+       operator<<(basic_ostream<_CharT, _Traits>& __out, id __id);
+    };
+
+  private:
+    id                         _M_id;
+
+    // _GLIBCXX_RESOLVE_LIB_DEFECTS
+    // 2097.  packaged_task constructors should be constrained
+    // 3039. Unnecessary decay in thread and packaged_task
+    template<typename _Tp>
+      using __not_same = __not_<is_same<__remove_cvref_t<_Tp>, thread>>;
+
+  public:
+    thread() noexcept = default;
+
+#ifdef _GLIBCXX_HAS_GTHREADS
+    template<typename _Callable, typename... _Args,
+            typename = _Require<__not_same<_Callable>>>
+      explicit
+      thread(_Callable&& __f, _Args&&... __args)
+      {
+       static_assert( __is_invocable<typename decay<_Callable>::type,
+                                     typename decay<_Args>::type...>::value,
+         "std::thread arguments must be invocable after conversion to rvalues"
+         );
+
+#ifdef GTHR_ACTIVE_PROXY
+       // Create a reference to pthread_create, not just the gthr weak symbol.
+       auto __depend = reinterpret_cast<void(*)()>(&pthread_create);
+#else
+       auto __depend = nullptr;
+#endif
+       using _Wrapper = _Call_wrapper<_Callable, _Args...>;
+       // Create a call wrapper with DECAY_COPY(__f) as its target object
+       // and DECAY_COPY(__args)... as its bound argument entities.
+       _M_start_thread(_State_ptr(new _State_impl<_Wrapper>(
+             std::forward<_Callable>(__f), std::forward<_Args>(__args)...)),
+           __depend);
+      }
+#endif // _GLIBCXX_HAS_GTHREADS
+
+    ~thread()
+    {
+      if (joinable())
+       std::terminate();
+    }
+
+    thread(const thread&) = delete;
+
+    thread(thread&& __t) noexcept
+    { swap(__t); }
+
+    thread& operator=(const thread&) = delete;
+
+    thread& operator=(thread&& __t) noexcept
+    {
+      if (joinable())
+       std::terminate();
+      swap(__t);
+      return *this;
+    }
+
+    void
+    swap(thread& __t) noexcept
+    { std::swap(_M_id, __t._M_id); }
+
+    bool
+    joinable() const noexcept
+    { return !(_M_id == id()); }
+
+    void
+    join();
+
+    void
+    detach();
+
+    id
+    get_id() const noexcept
+    { return _M_id; }
+
+    /** @pre thread is joinable
+     */
+    native_handle_type
+    native_handle()
+    { return _M_id._M_thread; }
+
+    // Returns a value that hints at the number of hardware thread contexts.
+    static unsigned int
+    hardware_concurrency() noexcept;
+
+#ifdef _GLIBCXX_HAS_GTHREADS
+  private:
+    template<typename _Callable>
+      struct _State_impl : public _State
+      {
+       _Callable               _M_func;
+
+       template<typename... _Args>
+         _State_impl(_Args&&... __args)
+         : _M_func{{std::forward<_Args>(__args)...}}
+         { }
+
+       void
+       _M_run() { _M_func(); }
+      };
+
+    void
+    _M_start_thread(_State_ptr, void (*)());
+
+#if _GLIBCXX_THREAD_ABI_COMPAT
+  public:
+    struct _Impl_base;
+    typedef shared_ptr<_Impl_base>     __shared_base_type;
+    struct _Impl_base
+    {
+      __shared_base_type       _M_this_ptr;
+      virtual ~_Impl_base() = default;
+      virtual void _M_run() = 0;
+    };
+
+  private:
+    void
+    _M_start_thread(__shared_base_type, void (*)());
+
+    void
+    _M_start_thread(__shared_base_type);
+#endif
+
+  private:
+    // A call wrapper that does INVOKE(forwarded tuple elements...)
+    template<typename _Tuple>
+      struct _Invoker
+      {
+       _Tuple _M_t;
+
+       template<typename>
+         struct __result;
+       template<typename _Fn, typename... _Args>
+         struct __result<tuple<_Fn, _Args...>>
+         : __invoke_result<_Fn, _Args...>
+         { };
+
+       template<size_t... _Ind>
+         typename __result<_Tuple>::type
+         _M_invoke(_Index_tuple<_Ind...>)
+         { return std::__invoke(std::get<_Ind>(std::move(_M_t))...); }
+
+       typename __result<_Tuple>::type
+       operator()()
+       {
+         using _Indices
+           = typename _Build_index_tuple<tuple_size<_Tuple>::value>::__type;
+         return _M_invoke(_Indices());
+       }
+      };
+
+  public:
+    template<typename... _Tp>
+      using _Call_wrapper = _Invoker<tuple<typename decay<_Tp>::type...>>;
+#endif // _GLIBCXX_HAS_GTHREADS
+  };
+
+#ifndef _GLIBCXX_HAS_GTHREADS
+  inline void thread::join() { std::__throw_system_error(EINVAL); }
+  inline void thread::detach() { std::__throw_system_error(EINVAL); }
+  inline unsigned int thread::hardware_concurrency() { return 0; }
+#endif
+
+  inline void
+  swap(thread& __x, thread& __y) noexcept
+  { __x.swap(__y); }
+
+  inline bool
+  operator==(thread::id __x, thread::id __y) noexcept
+  {
+    // pthread_equal is undefined if either thread ID is not valid, so we
+    // can't safely use __gthread_equal on default-constructed values (nor
+    // the non-zero value returned by this_thread::get_id() for
+    // single-threaded programs using GNU libc). Assume EqualityComparable.
+    return __x._M_thread == __y._M_thread;
+  }
+
+  // N.B. other comparison operators are defined in <thread>
+
+  namespace this_thread
+  {
+    /// this_thread::get_id
+    inline thread::id
+    get_id() noexcept
+    {
+#ifdef _GLIBCXX_HAS_GTHREADS
+
+#ifdef __GLIBC__
+      // For the GNU C library pthread_self() is usable without linking to
+      // libpthread, but prior to version 2.27 the version in libc returns 0,
+      // which breaks the invariant this_thread::get_id() != thread::id{}.
+      //
+      // We know that pthread_t is a scalar type in the GNU C library,
+      // so just use (__gthread_t)1 as the ID of the main (and only) thread.
+      //
+      // This uses __gthread_active_p not __gnu_cxx::__is_single_threaded
+      // because we don't want the thread::id of the main thread to change
+      // if additional threads are created later.
+      if (!__gthread_active_p())
+       return thread::id((__gthread_t)1);
+#endif
+
+      return thread::id(__gthread_self());
+#else
+      return thread::id(1);
+#endif
+    }
+
+    /// this_thread::yield
+    inline void
+    yield() noexcept
+    {
+#if defined _GLIBCXX_HAS_GTHREADS && defined _GLIBCXX_USE_SCHED_YIELD
+      __gthread_yield();
+#endif
+    }
+
+  } // namespace this_thread
+
+  /// @}
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // C++11
+
+#endif // _GLIBCXX_THREAD_H
index f7617cac8e932a2929bd24d3e2c4dffd8c88e5b1..77b6f930f00afc1b6a49c8e6ca1cdc90f270a2a4 100644 (file)
@@ -36,7 +36,6 @@
 #else
 
 #include <mutex>             // call_once
-#include <thread>
 #include <condition_variable> // __at_thread_exit_elt
 #include <system_error>
 #include <atomic>
@@ -46,6 +45,7 @@
 #include <bits/unique_ptr.h>
 #include <bits/shared_ptr.h>
 #include <bits/std_function.h>
+#include <bits/std_thread.h>
 #include <bits/uses_allocator.h>
 #include <ext/aligned_buffer.h>
 
index 7cd01c9713ee0351efbc7847818d291b5eaa478e..5b2d5a0427c7d75ee57795c71b02e337926f20cb 100644 (file)
 #if __cplusplus > 201703L
 
 #include <atomic>
+#include <bits/std_thread.h>
 
-#ifdef _GLIBCXX_HAS_GTHREADS
-# define __cpp_lib_jthread 201911L
-# include <bits/gthr.h>
-# if __has_include(<semaphore>)
-#  include <semaphore>
-# endif
+#if __has_include(<semaphore>)
+# include <semaphore>
 #endif
 
+#define __cpp_lib_jthread 201911L
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -105,9 +104,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
 #if defined __i386__ || defined __x86_64__
       __builtin_ia32_pause();
-#elif defined _GLIBCXX_HAS_GTHREADS && defined _GLIBCXX_USE_SCHED_YIELD
-      __gthread_yield();
 #endif
+      this_thread::yield();
     }
 
 #ifndef __cpp_lib_semaphore
@@ -162,18 +160,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       std::atomic<value_type> _M_owners{1};
       std::atomic<value_type> _M_value{_S_ssrc_counter_inc};
       _Stop_cb* _M_head = nullptr;
-      struct
-      {
-#ifdef _GLIBCXX_HAS_GTHREADS
-       __gthread_t _M_id;
-       void _M_set() { _M_id = __gthread_self(); }
-       bool _M_is_current_thread() const
-       { return __gthread_equal(_M_id, __gthread_self()); }
-#else
-       void _M_set() { }
-       constexpr bool _M_is_current_thread() const { return true; }
-#endif
-      } _M_requester;
+      std::thread::id _M_requester;
 
       _Stop_state_t() = default;
 
@@ -246,7 +233,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          }
        while (!_M_try_lock_and_stop(__old));
 
-       _M_requester._M_set();
+       _M_requester = this_thread::get_id();
 
        while (_M_head)
          {
@@ -273,10 +260,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            if (!__destroyed)
              {
                __cb->_M_destroyed = nullptr;
-#ifdef _GLIBCXX_HAS_GTHREADS
+
                // synchronize with destructor of stop_callback that owns *__cb
-               __cb->_M_done.release();
-#endif
+               if (!__gnu_cxx::__is_single_threaded())
+                 __cb->_M_done.release();
              }
 
            // Avoid relocking if we already know there are no more callbacks.
@@ -353,7 +340,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        // Despite appearances there is no data race on _M_requester. The only
        // write to it happens before the callback is removed from the list,
        // and removing it from the list happens before this read.
-       if (!_M_requester._M_is_current_thread())
+       if (!(_M_requester == this_thread::get_id()))
          {
            // Synchronize with completion of callback.
            __cb->_M_done.acquire();
index 080036e26097a8b11803ecd1c1521669e71746f8..6ea8a51c0cf88cfecf8dd7c7cefb9cd9cdba99c7 100644 (file)
 
 #include <chrono> // std::chrono::*
 
-#ifdef _GLIBCXX_USE_NANOSLEEP
-# include <cerrno>  // errno, EINTR
-# include <time.h>  // nanosleep
-#endif
-
-#if defined(_GLIBCXX_HAS_GTHREADS)
-#include <bits/gthr.h>
-
-#include <memory> // std::unique_ptr
-#include <tuple>  // std::tuple
-
 #if __cplusplus > 201703L
 # include <compare>    // std::strong_ordering
 # include <stop_token> // std::stop_source, std::stop_token, std::nostopstate
 #endif
 
+#include <bits/std_thread.h> // std::thread, get_id, yield
 #include <bits/functional_hash.h> // std::hash
-#include <bits/invoke.h>         // std::__invoke
 
-#endif // _GLIBCXX_HAS_GTHREADS
+#ifdef _GLIBCXX_USE_NANOSLEEP
+# include <cerrno>  // errno, EINTR
+# include <time.h>  // nanosleep
+#endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -70,221 +62,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    * @{
    */
 
-#if defined(_GLIBCXX_HAS_GTHREADS)
-  /// thread
-  class thread
-  {
-  public:
-    // Abstract base class for types that wrap arbitrary functors to be
-    // invoked in the new thread of execution.
-    struct _State
-    {
-      virtual ~_State();
-      virtual void _M_run() = 0;
-    };
-    using _State_ptr = unique_ptr<_State>;
-
-    typedef __gthread_t                        native_handle_type;
-
-    /// thread::id
-    class id
-    {
-      native_handle_type       _M_thread;
-
-    public:
-      id() noexcept : _M_thread() { }
-
-      explicit
-      id(native_handle_type __id) : _M_thread(__id) { }
-
-    private:
-      friend class thread;
-      friend struct hash<id>;
-
-      friend bool
-      operator==(id __x, id __y) noexcept;
-
-#if __cpp_lib_three_way_comparison
-      friend strong_ordering
-      operator<=>(id __x, id __y) noexcept;
-#else
-      friend bool
-      operator<(id __x, id __y) noexcept;
-#endif
-
-      template<class _CharT, class _Traits>
-       friend basic_ostream<_CharT, _Traits>&
-       operator<<(basic_ostream<_CharT, _Traits>& __out, id __id);
-    };
-
-  private:
-    id                         _M_id;
-
-    // _GLIBCXX_RESOLVE_LIB_DEFECTS
-    // 2097.  packaged_task constructors should be constrained
-    // 3039. Unnecessary decay in thread and packaged_task
-    template<typename _Tp>
-      using __not_same = __not_<is_same<__remove_cvref_t<_Tp>, thread>>;
-
-  public:
-    thread() noexcept = default;
-
-    template<typename _Callable, typename... _Args,
-            typename = _Require<__not_same<_Callable>>>
-      explicit
-      thread(_Callable&& __f, _Args&&... __args)
-      {
-       static_assert( __is_invocable<typename decay<_Callable>::type,
-                                     typename decay<_Args>::type...>::value,
-         "std::thread arguments must be invocable after conversion to rvalues"
-         );
-
-#ifdef GTHR_ACTIVE_PROXY
-       // Create a reference to pthread_create, not just the gthr weak symbol.
-       auto __depend = reinterpret_cast<void(*)()>(&pthread_create);
-#else
-       auto __depend = nullptr;
-#endif
-       using _Wrapper = _Call_wrapper<_Callable, _Args...>;
-       // Create a call wrapper with DECAY_COPY(__f) as its target object
-       // and DECAY_COPY(__args)... as its bound argument entities.
-       _M_start_thread(_State_ptr(new _State_impl<_Wrapper>(
-             std::forward<_Callable>(__f), std::forward<_Args>(__args)...)),
-           __depend);
-      }
-
-    ~thread()
-    {
-      if (joinable())
-       std::terminate();
-    }
-
-    thread(const thread&) = delete;
-
-    thread(thread&& __t) noexcept
-    { swap(__t); }
-
-    thread& operator=(const thread&) = delete;
-
-    thread& operator=(thread&& __t) noexcept
-    {
-      if (joinable())
-       std::terminate();
-      swap(__t);
-      return *this;
-    }
-
-    void
-    swap(thread& __t) noexcept
-    { std::swap(_M_id, __t._M_id); }
-
-    bool
-    joinable() const noexcept
-    { return !(_M_id == id()); }
-
-    void
-    join();
-
-    void
-    detach();
-
-    id
-    get_id() const noexcept
-    { return _M_id; }
-
-    /** @pre thread is joinable
-     */
-    native_handle_type
-    native_handle()
-    { return _M_id._M_thread; }
-
-    // Returns a value that hints at the number of hardware thread contexts.
-    static unsigned int
-    hardware_concurrency() noexcept;
-
-  private:
-    template<typename _Callable>
-      struct _State_impl : public _State
-      {
-       _Callable               _M_func;
-
-       template<typename... _Args>
-         _State_impl(_Args&&... __args)
-         : _M_func{{std::forward<_Args>(__args)...}}
-         { }
-
-       void
-       _M_run() { _M_func(); }
-      };
-
-    void
-    _M_start_thread(_State_ptr, void (*)());
-
-#if _GLIBCXX_THREAD_ABI_COMPAT
-  public:
-    struct _Impl_base;
-    typedef shared_ptr<_Impl_base>     __shared_base_type;
-    struct _Impl_base
-    {
-      __shared_base_type       _M_this_ptr;
-      virtual ~_Impl_base() = default;
-      virtual void _M_run() = 0;
-    };
-
-  private:
-    void
-    _M_start_thread(__shared_base_type, void (*)());
-
-    void
-    _M_start_thread(__shared_base_type);
-#endif
-
-  private:
-    // A call wrapper that does INVOKE(forwarded tuple elements...)
-    template<typename _Tuple>
-      struct _Invoker
-      {
-       _Tuple _M_t;
-
-       template<typename>
-         struct __result;
-       template<typename _Fn, typename... _Args>
-         struct __result<tuple<_Fn, _Args...>>
-         : __invoke_result<_Fn, _Args...>
-         { };
-
-       template<size_t... _Ind>
-         typename __result<_Tuple>::type
-         _M_invoke(_Index_tuple<_Ind...>)
-         { return std::__invoke(std::get<_Ind>(std::move(_M_t))...); }
-
-       typename __result<_Tuple>::type
-       operator()()
-       {
-         using _Indices
-           = typename _Build_index_tuple<tuple_size<_Tuple>::value>::__type;
-         return _M_invoke(_Indices());
-       }
-      };
-
-  public:
-    template<typename... _Tp>
-      using _Call_wrapper = _Invoker<tuple<typename decay<_Tp>::type...>>;
-  };
-
-  inline void
-  swap(thread& __x, thread& __y) noexcept
-  { __x.swap(__y); }
-
-  inline bool
-  operator==(thread::id __x, thread::id __y) noexcept
-  {
-    // pthread_equal is undefined if either thread ID is not valid, so we
-    // can't safely use __gthread_equal on default-constructed values (nor
-    // the non-zero value returned by this_thread::get_id() for
-    // single-threaded programs using GNU libc). Assume EqualityComparable.
-    return __x._M_thread == __y._M_thread;
-  }
+  // std::thread is defined in <bits/std_thread.h>
 
 #if __cpp_lib_three_way_comparison
   inline strong_ordering
@@ -336,7 +114,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       else
        return __out << __id._M_thread;
     }
-#endif // _GLIBCXX_HAS_GTHREADS
 
   /** @namespace std::this_thread
    *  @brief ISO C++ 2011 namespace for interacting with the current thread
@@ -345,36 +122,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    */
   namespace this_thread
   {
-#if defined _GLIBCXX_HAS_GTHREADS
-    /// get_id
-    inline thread::id
-    get_id() 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 thread::id(1);
-#endif
-      return thread::id(__gthread_self());
-    }
-#endif // _GLIBCXX_HAS_GTHREADS
-
-    /// yield
-    inline void
-    yield() noexcept
-    {
-#if defined _GLIBCXX_HAS_GTHREADS && defined _GLIBCXX_USE_SCHED_YIELD
-      __gthread_yield();
-#endif
-    }
-
     void
     __sleep_for(chrono::seconds, chrono::nanoseconds);
 
-    /// sleep_for
+    /// this_thread::sleep_for
     template<typename _Rep, typename _Period>
       inline void
       sleep_for(const chrono::duration<_Rep, _Period>& __rtime)
@@ -396,7 +147,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
       }
 
-    /// sleep_until
+    /// this_thread::sleep_until
     template<typename _Clock, typename _Duration>
       inline void
       sleep_until(const chrono::time_point<_Clock, _Duration>& __atime)
@@ -421,6 +172,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #ifdef __cpp_lib_jthread
 
+  /// A thread that can be requested to stop and automatically joined.
   class jthread
   {
   public:
index a4c87d816a58819775f83050ff9b37aecd3cd72a..e4dd1687a4b25f3106f1233d5af697b90461bf1d 100644 (file)
@@ -24,6 +24,7 @@
 
 
 #define _GLIBCXX_THREAD_ABI_COMPAT 1
+#include <memory> // include this first so <thread> can use shared_ptr
 #include <thread>
 #include <system_error>
 #include <cerrno>