37 changes: 12 additions & 25 deletions libstdc++-v3/include/std/stop_token
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,14 @@
#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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)
{
Expand All @@ -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.
Expand Down Expand Up @@ -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();
Expand Down
266 changes: 9 additions & 257 deletions libstdc++-v3/include/std/thread
Original file line number Diff line number Diff line change
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
1 change: 1 addition & 0 deletions libstdc++-v3/src/c++11/thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down