Expand Up
@@ -37,26 +37,18 @@
#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 )
{
Expand All
@@ -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
Expand Down
Expand Up
@@ -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
Expand All
@@ -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)
Expand All
@@ -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)
Expand All
@@ -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:
Expand Down