[libc++][NFC] Granularise <thread> header
authorHui <hui.xie0621@gmail.com>
Wed, 31 May 2023 09:49:56 +0000 (10:49 +0100)
committerHui <hui.xie0621@gmail.com>
Sat, 17 Jun 2023 11:28:52 +0000 (12:28 +0100)
- This was to make implementing jthread easier and requested in https://reviews.llvm.org/D151559

Differential Revision: https://reviews.llvm.org/D151792

26 files changed:
libcxx/include/CMakeLists.txt
libcxx/include/__stop_token/stop_state.h
libcxx/include/__thread/formatter.h [new file with mode: 0644]
libcxx/include/__thread/this_thread.h [new file with mode: 0644]
libcxx/include/__thread/thread.h [new file with mode: 0644]
libcxx/include/future
libcxx/include/module.modulemap.in
libcxx/include/thread
libcxx/src/atomic.cpp
libcxx/src/thread.cpp
libcxx/test/libcxx/transitive_includes/cxx03.csv
libcxx/test/libcxx/transitive_includes/cxx11.csv
libcxx/test/libcxx/transitive_includes/cxx14.csv
libcxx/test/libcxx/transitive_includes/cxx17.csv
libcxx/test/libcxx/transitive_includes/cxx20.csv
libcxx/test/libcxx/transitive_includes/cxx23.csv
libcxx/test/libcxx/transitive_includes/cxx26.csv
libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex_duration.pass.cpp
libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex_time_point.pass.cpp
libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/try_lock_for.pass.cpp
libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/try_lock_shared_for.pass.cpp
libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/try_lock_shared_until.pass.cpp
libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/try_lock_until.pass.cpp
libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/enabled_hashes.pass.cpp
libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/types.compile.pass.cpp
libcxx/utils/data/ignore_format.txt

index 3815662..a8e4011 100644 (file)
@@ -673,7 +673,10 @@ set(files
   __system_error/error_code.h
   __system_error/error_condition.h
   __system_error/system_error.h
+  __thread/formatter.h
   __thread/poll_with_backoff.h
+  __thread/this_thread.h
+  __thread/thread.h
   __thread/timed_backoff_policy.h
   __threading_support
   __tree
index d880286..95d563c 100644 (file)
@@ -15,6 +15,7 @@
 #include <__stop_token/atomic_unique_lock.h>
 #include <__stop_token/intrusive_list_view.h>
 #include <atomic>
+#include <cstdint>
 #include <thread>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__thread/formatter.h b/libcxx/include/__thread/formatter.h
new file mode 100644 (file)
index 0000000..97cd23c
--- /dev/null
@@ -0,0 +1,76 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___THREAD_FORMATTER_H
+#define _LIBCPP___THREAD_FORMATTER_H
+
+#include <__concepts/arithmetic.h>
+#include <__config>
+#include <__format/concepts.h>
+#include <__format/format_parse_context.h>
+#include <__format/formatter.h>
+#include <__format/formatter_integral.h>
+#include <__format/parser_std_format_spec.h>
+#include <__threading_support>
+#include <__type_traits/conditional.h>
+#include <__type_traits/is_pointer.h>
+#include <__type_traits/is_same.h>
+#include <cstdint>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 23
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <__fmt_char_type _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<__thread_id, _CharT> {
+  public:
+    template <class _ParseContext>
+    _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
+        return __parser_.__parse(__ctx, __format_spec::__fields_fill_align_width);
+    }
+
+    template <class _FormatContext>
+    _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(__thread_id __id, _FormatContext& __ctx) const {
+        // In __threading_support __libcpp_thread_id is either a
+        // unsigned long long or a pthread_t.
+        //
+        // The type of pthread_t is left unspecified in POSIX so it can be any
+        // type. The most logical types are an integral or pointer.
+        // On Linux systems pthread_t is an unsigned long long.
+        // On Apple systems pthread_t is a pointer type.
+        //
+        // Note the output should match what the stream operator does. Since
+        // the ostream operator has been shipped years before this formatter
+        // was added to the Standard, this formatter does what the stream
+        // operator does. This may require platform specific changes.
+
+        using _Tp = decltype(__get_underlying_id(__id));
+        using _Cp = conditional_t<integral<_Tp>, _Tp, conditional_t<is_pointer_v<_Tp>, uintptr_t, void>>;
+        static_assert(!is_same_v<_Cp, void>, "unsupported thread::id type, please file a bug report");
+
+        __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
+        if constexpr (is_pointer_v<_Tp>) {
+          __specs.__std_.__alternate_form_ = true;
+          __specs.__std_.__type_           = __format_spec::__type::__hexadecimal_lower_case;
+        }
+        return __formatter::__format_integer(reinterpret_cast<_Cp>(__get_underlying_id(__id)), __ctx, __specs);
+    }
+
+    __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__right};
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 23
+
+#endif // _LIBCPP___THREAD_FORMATTER_H
diff --git a/libcxx/include/__thread/this_thread.h b/libcxx/include/__thread/this_thread.h
new file mode 100644 (file)
index 0000000..b79065e
--- /dev/null
@@ -0,0 +1,87 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___THREAD_THIS_THREAD_H
+#define _LIBCPP___THREAD_THIS_THREAD_H
+
+#include <__chrono/steady_clock.h>
+#include <__chrono/time_point.h>
+#include <__condition_variable/condition_variable.h>
+#include <__config>
+#include <__mutex/mutex.h>
+#include <__mutex/unique_lock.h>
+#include <__threading_support>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace this_thread
+{
+
+_LIBCPP_EXPORTED_FROM_ABI void sleep_for(const chrono::nanoseconds& __ns);
+
+template <class _Rep, class _Period>
+_LIBCPP_HIDE_FROM_ABI void
+sleep_for(const chrono::duration<_Rep, _Period>& __d)
+{
+    if (__d > chrono::duration<_Rep, _Period>::zero())
+    {
+        // The standard guarantees a 64bit signed integer resolution for nanoseconds,
+        // so use INT64_MAX / 1e9 as cut-off point. Use a constant to avoid <climits>
+        // and issues with long double folding on PowerPC with GCC.
+        _LIBCPP_CONSTEXPR chrono::duration<long double> __max =
+            chrono::duration<long double>(9223372036.0L);
+        chrono::nanoseconds __ns;
+        if (__d < __max)
+        {
+            __ns = chrono::duration_cast<chrono::nanoseconds>(__d);
+            if (__ns < __d)
+                ++__ns;
+        }
+        else
+            __ns = chrono::nanoseconds::max();
+        this_thread::sleep_for(__ns);
+    }
+}
+
+template <class _Clock, class _Duration>
+_LIBCPP_HIDE_FROM_ABI void
+sleep_until(const chrono::time_point<_Clock, _Duration>& __t)
+{
+    mutex __mut;
+    condition_variable __cv;
+    unique_lock<mutex> __lk(__mut);
+    while (_Clock::now() < __t)
+        __cv.wait_until(__lk, __t);
+}
+
+template <class _Duration>
+inline _LIBCPP_INLINE_VISIBILITY
+void
+sleep_until(const chrono::time_point<chrono::steady_clock, _Duration>& __t)
+{
+    this_thread::sleep_for(__t - chrono::steady_clock::now());
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void yield() _NOEXCEPT {__libcpp_thread_yield();}
+
+} // namespace this_thread
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___THREAD_THIS_THREAD_H
diff --git a/libcxx/include/__thread/thread.h b/libcxx/include/__thread/thread.h
new file mode 100644 (file)
index 0000000..88b4ede
--- /dev/null
@@ -0,0 +1,269 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___THREAD_THREAD_H
+#define _LIBCPP___THREAD_THREAD_H
+
+#include <__condition_variable/condition_variable.h>
+#include <__config>
+#include <__exception/terminate.h>
+#include <__functional/hash.h>
+#include <__functional/unary_function.h>
+#include <__memory/unique_ptr.h>
+#include <__mutex/mutex.h>
+#include <__system_error/system_error.h>
+#include <__threading_support>
+#include <__utility/forward.h>
+#include <tuple>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Tp> class __thread_specific_ptr;
+class _LIBCPP_EXPORTED_FROM_ABI __thread_struct;
+class _LIBCPP_HIDDEN __thread_struct_imp;
+class __assoc_sub_state;
+
+_LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data();
+
+class _LIBCPP_EXPORTED_FROM_ABI __thread_struct
+{
+    __thread_struct_imp* __p_;
+
+    __thread_struct(const __thread_struct&);
+    __thread_struct& operator=(const __thread_struct&);
+public:
+    __thread_struct();
+    ~__thread_struct();
+
+    void notify_all_at_thread_exit(condition_variable*, mutex*);
+    void __make_ready_at_thread_exit(__assoc_sub_state*);
+};
+
+template <class _Tp>
+class __thread_specific_ptr
+{
+    __libcpp_tls_key __key_;
+
+     // Only __thread_local_data() may construct a __thread_specific_ptr
+     // and only with _Tp == __thread_struct.
+    static_assert((is_same<_Tp, __thread_struct>::value), "");
+    __thread_specific_ptr();
+    friend _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data();
+
+    __thread_specific_ptr(const __thread_specific_ptr&);
+    __thread_specific_ptr& operator=(const __thread_specific_ptr&);
+
+    _LIBCPP_HIDDEN static void _LIBCPP_TLS_DESTRUCTOR_CC __at_thread_exit(void*);
+
+public:
+    typedef _Tp* pointer;
+
+    ~__thread_specific_ptr();
+
+    _LIBCPP_INLINE_VISIBILITY
+    pointer get() const {return static_cast<_Tp*>(__libcpp_tls_get(__key_));}
+    _LIBCPP_INLINE_VISIBILITY
+    pointer operator*() const {return *get();}
+    _LIBCPP_INLINE_VISIBILITY
+    pointer operator->() const {return get();}
+    void set_pointer(pointer __p);
+};
+
+template <class _Tp>
+void _LIBCPP_TLS_DESTRUCTOR_CC
+__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
+{
+    delete static_cast<pointer>(__p);
+}
+
+template <class _Tp>
+__thread_specific_ptr<_Tp>::__thread_specific_ptr()
+{
+  int __ec =
+      __libcpp_tls_create(&__key_, &__thread_specific_ptr::__at_thread_exit);
+  if (__ec)
+    __throw_system_error(__ec, "__thread_specific_ptr construction failed");
+}
+
+template <class _Tp>
+__thread_specific_ptr<_Tp>::~__thread_specific_ptr()
+{
+    // __thread_specific_ptr is only created with a static storage duration
+    // so this destructor is only invoked during program termination. Invoking
+    // pthread_key_delete(__key_) may prevent other threads from deleting their
+    // thread local data. For this reason we leak the key.
+}
+
+template <class _Tp>
+void
+__thread_specific_ptr<_Tp>::set_pointer(pointer __p)
+{
+    _LIBCPP_ASSERT(get() == nullptr,
+                   "Attempting to overwrite thread local data");
+    std::__libcpp_tls_set(__key_, __p);
+}
+
+template<>
+struct _LIBCPP_TEMPLATE_VIS hash<__thread_id>
+    : public __unary_function<__thread_id, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(__thread_id __v) const _NOEXCEPT
+    {
+        return hash<__libcpp_thread_id>()(__v.__id_);
+    }
+};
+
+template<class _CharT, class _Traits>
+_LIBCPP_INLINE_VISIBILITY
+basic_ostream<_CharT, _Traits>&
+operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id)
+{return __os << __id.__id_;}
+
+class _LIBCPP_EXPORTED_FROM_ABI thread
+{
+    __libcpp_thread_t __t_;
+
+    thread(const thread&);
+    thread& operator=(const thread&);
+public:
+    typedef __thread_id id;
+    typedef __libcpp_thread_t native_handle_type;
+
+    _LIBCPP_INLINE_VISIBILITY
+    thread() _NOEXCEPT : __t_(_LIBCPP_NULL_THREAD) {}
+#ifndef _LIBCPP_CXX03_LANG
+    template <class _Fp, class ..._Args,
+              class = __enable_if_t<!is_same<__remove_cvref_t<_Fp>, thread>::value> >
+        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
+        explicit thread(_Fp&& __f, _Args&&... __args);
+#else  // _LIBCPP_CXX03_LANG
+    template <class _Fp>
+    _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
+    explicit thread(_Fp __f);
+#endif
+    ~thread();
+
+    _LIBCPP_INLINE_VISIBILITY
+    thread(thread&& __t) _NOEXCEPT : __t_(__t.__t_) {
+        __t.__t_ = _LIBCPP_NULL_THREAD;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    thread& operator=(thread&& __t) _NOEXCEPT {
+        if (!__libcpp_thread_isnull(&__t_))
+            terminate();
+        __t_ = __t.__t_;
+        __t.__t_ = _LIBCPP_NULL_THREAD;
+        return *this;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    void swap(thread& __t) _NOEXCEPT {_VSTD::swap(__t_, __t.__t_);}
+
+    _LIBCPP_INLINE_VISIBILITY
+    bool joinable() const _NOEXCEPT {return !__libcpp_thread_isnull(&__t_);}
+    void join();
+    void detach();
+    _LIBCPP_INLINE_VISIBILITY
+    id get_id() const _NOEXCEPT {return __libcpp_thread_get_id(&__t_);}
+    _LIBCPP_INLINE_VISIBILITY
+    native_handle_type native_handle() _NOEXCEPT {return __t_;}
+
+    static unsigned hardware_concurrency() _NOEXCEPT;
+};
+
+#ifndef _LIBCPP_CXX03_LANG
+
+template <class _TSp, class _Fp, class ..._Args, size_t ..._Indices>
+inline _LIBCPP_INLINE_VISIBILITY
+void
+__thread_execute(tuple<_TSp, _Fp, _Args...>& __t, __tuple_indices<_Indices...>)
+{
+    _VSTD::__invoke(_VSTD::move(_VSTD::get<1>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
+}
+
+template <class _Fp>
+_LIBCPP_INLINE_VISIBILITY
+void* __thread_proxy(void* __vp)
+{
+    // _Fp = tuple< unique_ptr<__thread_struct>, Functor, Args...>
+    unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
+    __thread_local_data().set_pointer(_VSTD::get<0>(*__p.get()).release());
+    typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 2>::type _Index;
+    _VSTD::__thread_execute(*__p.get(), _Index());
+    return nullptr;
+}
+
+template <class _Fp, class ..._Args,
+          class
+         >
+thread::thread(_Fp&& __f, _Args&&... __args)
+{
+    typedef unique_ptr<__thread_struct> _TSPtr;
+    _TSPtr __tsp(new __thread_struct);
+    typedef tuple<_TSPtr, __decay_t<_Fp>, __decay_t<_Args>...> _Gp;
+    unique_ptr<_Gp> __p(
+            new _Gp(_VSTD::move(__tsp),
+                    _VSTD::forward<_Fp>(__f),
+                    _VSTD::forward<_Args>(__args)...));
+    int __ec = _VSTD::__libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get());
+    if (__ec == 0)
+        __p.release();
+    else
+        __throw_system_error(__ec, "thread constructor failed");
+}
+
+#else  // _LIBCPP_CXX03_LANG
+
+template <class _Fp>
+struct __thread_invoke_pair {
+    // This type is used to pass memory for thread local storage and a functor
+    // to a newly created thread because std::pair doesn't work with
+    // std::unique_ptr in C++03.
+    _LIBCPP_HIDE_FROM_ABI __thread_invoke_pair(_Fp& __f) : __tsp_(new __thread_struct), __fn_(__f) {}
+    unique_ptr<__thread_struct> __tsp_;
+    _Fp __fn_;
+};
+
+template <class _Fp>
+_LIBCPP_HIDE_FROM_ABI void* __thread_proxy_cxx03(void* __vp)
+{
+    unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
+    __thread_local_data().set_pointer(__p->__tsp_.release());
+    (__p->__fn_)();
+    return nullptr;
+}
+
+template <class _Fp>
+thread::thread(_Fp __f)
+{
+
+    typedef __thread_invoke_pair<_Fp> _InvokePair;
+    typedef unique_ptr<_InvokePair> _PairPtr;
+    _PairPtr __pp(new _InvokePair(__f));
+    int __ec = _VSTD::__libcpp_thread_create(&__t_, &__thread_proxy_cxx03<_InvokePair>, __pp.get());
+    if (__ec == 0)
+        __pp.release();
+    else
+        __throw_system_error(__ec, "thread constructor failed");
+}
+
+#endif // _LIBCPP_CXX03_LANG
+
+inline _LIBCPP_INLINE_VISIBILITY
+void swap(thread& __x, thread& __y) _NOEXCEPT {__x.swap(__y);}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___THREAD_THREAD_H
index d2d33e5..ca3b5fd 100644 (file)
@@ -367,6 +367,7 @@ template <class R, class Alloc> struct uses_allocator<packaged_task<R>, Alloc>;
 #include <__chrono/time_point.h>
 #include <__config>
 #include <__exception/exception_ptr.h>
+#include <__memory/addressof.h>
 #include <__memory/allocator.h>
 #include <__memory/allocator_arg_t.h>
 #include <__memory/allocator_destructor.h>
index 3a524ec..cdfb0e9 100644 (file)
@@ -1532,7 +1532,10 @@ module std [system] {
     export *
 
     module __thread {
+      module formatter            { private header "__thread/formatter.h" }
       module poll_with_backoff    { private header "__thread/poll_with_backoff.h" }
+      module this_thread          { private header "__thread/this_thread.h" }
+      module thread               { private header "__thread/thread.h" }
       module timed_backoff_policy { private header "__thread/timed_backoff_policy.h" }
     }
   }
index 8a905b7..4ddcf3e 100644 (file)
@@ -88,32 +88,11 @@ void sleep_for(const chrono::duration<Rep, Period>& rel_time);
 
 #include <__assert> // all public C++ headers provide the assertion handler
 #include <__availability>
-#include <__chrono/steady_clock.h>
-#include <__chrono/time_point.h>
-#include <__concepts/arithmetic.h>
-#include <__condition_variable/condition_variable.h>
 #include <__config>
-#include <__exception/terminate.h>
-#include <__format/concepts.h>
-#include <__format/format_parse_context.h>
-#include <__format/formatter.h>
-#include <__format/formatter_integral.h>
-#include <__format/parser_std_format_spec.h>
-#include <__functional/hash.h>
-#include <__functional/unary_function.h>
-#include <__memory/addressof.h>
-#include <__memory/unique_ptr.h>
-#include <__mutex/mutex.h>
-#include <__mutex/unique_lock.h>
-#include <__system_error/system_error.h>
-#include <__thread/poll_with_backoff.h>
-#include <__thread/timed_backoff_policy.h>
+#include <__thread/formatter.h>
+#include <__thread/this_thread.h>
+#include <__thread/thread.h>
 #include <__threading_support>
-#include <__utility/forward.h>
-#include <cstddef>
-#include <cstdint>
-#include <iosfwd>
-#include <tuple>
 #include <version>
 
 // standard-mandated includes
@@ -125,347 +104,16 @@ void sleep_for(const chrono::duration<Rep, Period>& rel_time);
 #  pragma GCC system_header
 #endif
 
-_LIBCPP_PUSH_MACROS
-#include <__undef_macros>
-
 #ifdef _LIBCPP_HAS_NO_THREADS
 # error "<thread> is not supported since libc++ has been configured without support for threads."
 #endif
 
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-template <class _Tp> class __thread_specific_ptr;
-class _LIBCPP_EXPORTED_FROM_ABI __thread_struct;
-class _LIBCPP_HIDDEN __thread_struct_imp;
-class __assoc_sub_state;
-
-_LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data();
-
-class _LIBCPP_EXPORTED_FROM_ABI __thread_struct
-{
-    __thread_struct_imp* __p_;
-
-    __thread_struct(const __thread_struct&);
-    __thread_struct& operator=(const __thread_struct&);
-public:
-    __thread_struct();
-    ~__thread_struct();
-
-    void notify_all_at_thread_exit(condition_variable*, mutex*);
-    void __make_ready_at_thread_exit(__assoc_sub_state*);
-};
-
-template <class _Tp>
-class __thread_specific_ptr
-{
-    __libcpp_tls_key __key_;
-
-     // Only __thread_local_data() may construct a __thread_specific_ptr
-     // and only with _Tp == __thread_struct.
-    static_assert((is_same<_Tp, __thread_struct>::value), "");
-    __thread_specific_ptr();
-    friend _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data();
-
-    __thread_specific_ptr(const __thread_specific_ptr&);
-    __thread_specific_ptr& operator=(const __thread_specific_ptr&);
-
-    _LIBCPP_HIDDEN static void _LIBCPP_TLS_DESTRUCTOR_CC __at_thread_exit(void*);
-
-public:
-    typedef _Tp* pointer;
-
-    ~__thread_specific_ptr();
-
-    _LIBCPP_INLINE_VISIBILITY
-    pointer get() const {return static_cast<_Tp*>(__libcpp_tls_get(__key_));}
-    _LIBCPP_INLINE_VISIBILITY
-    pointer operator*() const {return *get();}
-    _LIBCPP_INLINE_VISIBILITY
-    pointer operator->() const {return get();}
-    void set_pointer(pointer __p);
-};
-
-template <class _Tp>
-void _LIBCPP_TLS_DESTRUCTOR_CC
-__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
-{
-    delete static_cast<pointer>(__p);
-}
-
-template <class _Tp>
-__thread_specific_ptr<_Tp>::__thread_specific_ptr()
-{
-  int __ec =
-      __libcpp_tls_create(&__key_, &__thread_specific_ptr::__at_thread_exit);
-  if (__ec)
-    __throw_system_error(__ec, "__thread_specific_ptr construction failed");
-}
-
-template <class _Tp>
-__thread_specific_ptr<_Tp>::~__thread_specific_ptr()
-{
-    // __thread_specific_ptr is only created with a static storage duration
-    // so this destructor is only invoked during program termination. Invoking
-    // pthread_key_delete(__key_) may prevent other threads from deleting their
-    // thread local data. For this reason we leak the key.
-}
-
-template <class _Tp>
-void
-__thread_specific_ptr<_Tp>::set_pointer(pointer __p)
-{
-    _LIBCPP_ASSERT(get() == nullptr,
-                   "Attempting to overwrite thread local data");
-    std::__libcpp_tls_set(__key_, __p);
-}
-
-template<>
-struct _LIBCPP_TEMPLATE_VIS hash<__thread_id>
-    : public __unary_function<__thread_id, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(__thread_id __v) const _NOEXCEPT
-    {
-        return hash<__libcpp_thread_id>()(__v.__id_);
-    }
-};
-
-template<class _CharT, class _Traits>
-_LIBCPP_INLINE_VISIBILITY
-basic_ostream<_CharT, _Traits>&
-operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id)
-{return __os << __id.__id_;}
-
-#if _LIBCPP_STD_VER >= 23
-template <__fmt_char_type _CharT>
-struct _LIBCPP_TEMPLATE_VIS formatter<__thread_id, _CharT> {
-  public:
-    template <class _ParseContext>
-    _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
-        return __parser_.__parse(__ctx, __format_spec::__fields_fill_align_width);
-    }
-
-    template <class _FormatContext>
-    _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(__thread_id __id, _FormatContext& __ctx) const {
-        // In __threading_support __libcpp_thread_id is either a
-        // unsigned long long or a pthread_t.
-        //
-        // The type of pthread_t is left unspecified in POSIX so it can be any
-        // type. The most logical types are an integral or pointer.
-        // On Linux systems pthread_t is an unsigned long long.
-        // On Apple systems pthread_t is a pointer type.
-        //
-        // Note the output should match what the stream operator does. Since
-        // the ostream operator has been shipped years before this formatter
-        // was added to the Standard, this formatter does what the stream
-        // operator does. This may require platform specific changes.
-
-        using _Tp = decltype(__get_underlying_id(__id));
-        using _Cp = conditional_t<integral<_Tp>, _Tp, conditional_t<is_pointer_v<_Tp>, uintptr_t, void>>;
-        static_assert(!is_same_v<_Cp, void>, "unsupported thread::id type, please file a bug report");
-
-        __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
-        if constexpr (is_pointer_v<_Tp>) {
-          __specs.__std_.__alternate_form_ = true;
-          __specs.__std_.__type_           = __format_spec::__type::__hexadecimal_lower_case;
-        }
-        return __formatter::__format_integer(reinterpret_cast<_Cp>(__get_underlying_id(__id)), __ctx, __specs);
-    }
-
-    __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__right};
-};
-#endif // _LIBCPP_STD_VER >= 23
-
-class _LIBCPP_EXPORTED_FROM_ABI thread
-{
-    __libcpp_thread_t __t_;
-
-    thread(const thread&);
-    thread& operator=(const thread&);
-public:
-    typedef __thread_id id;
-    typedef __libcpp_thread_t native_handle_type;
-
-    _LIBCPP_INLINE_VISIBILITY
-    thread() _NOEXCEPT : __t_(_LIBCPP_NULL_THREAD) {}
-#ifndef _LIBCPP_CXX03_LANG
-    template <class _Fp, class ..._Args,
-              class = __enable_if_t<!is_same<__remove_cvref_t<_Fp>, thread>::value> >
-        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
-        explicit thread(_Fp&& __f, _Args&&... __args);
-#else  // _LIBCPP_CXX03_LANG
-    template <class _Fp>
-    _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
-    explicit thread(_Fp __f);
+#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES)
+#  include <cstddef>
+#  include <ctime>
+#  include <iosfwd>
+#  include <ratio>
 #endif
-    ~thread();
-
-    _LIBCPP_INLINE_VISIBILITY
-    thread(thread&& __t) _NOEXCEPT : __t_(__t.__t_) {
-        __t.__t_ = _LIBCPP_NULL_THREAD;
-    }
-
-    _LIBCPP_INLINE_VISIBILITY
-    thread& operator=(thread&& __t) _NOEXCEPT {
-        if (!__libcpp_thread_isnull(&__t_))
-            terminate();
-        __t_ = __t.__t_;
-        __t.__t_ = _LIBCPP_NULL_THREAD;
-        return *this;
-    }
-
-    _LIBCPP_INLINE_VISIBILITY
-    void swap(thread& __t) _NOEXCEPT {_VSTD::swap(__t_, __t.__t_);}
-
-    _LIBCPP_INLINE_VISIBILITY
-    bool joinable() const _NOEXCEPT {return !__libcpp_thread_isnull(&__t_);}
-    void join();
-    void detach();
-    _LIBCPP_INLINE_VISIBILITY
-    id get_id() const _NOEXCEPT {return __libcpp_thread_get_id(&__t_);}
-    _LIBCPP_INLINE_VISIBILITY
-    native_handle_type native_handle() _NOEXCEPT {return __t_;}
-
-    static unsigned hardware_concurrency() _NOEXCEPT;
-};
-
-#ifndef _LIBCPP_CXX03_LANG
-
-template <class _TSp, class _Fp, class ..._Args, size_t ..._Indices>
-inline _LIBCPP_INLINE_VISIBILITY
-void
-__thread_execute(tuple<_TSp, _Fp, _Args...>& __t, __tuple_indices<_Indices...>)
-{
-    _VSTD::__invoke(_VSTD::move(_VSTD::get<1>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
-}
-
-template <class _Fp>
-_LIBCPP_INLINE_VISIBILITY
-void* __thread_proxy(void* __vp)
-{
-    // _Fp = tuple< unique_ptr<__thread_struct>, Functor, Args...>
-    unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
-    __thread_local_data().set_pointer(_VSTD::get<0>(*__p.get()).release());
-    typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 2>::type _Index;
-    _VSTD::__thread_execute(*__p.get(), _Index());
-    return nullptr;
-}
-
-template <class _Fp, class ..._Args,
-          class
-         >
-thread::thread(_Fp&& __f, _Args&&... __args)
-{
-    typedef unique_ptr<__thread_struct> _TSPtr;
-    _TSPtr __tsp(new __thread_struct);
-    typedef tuple<_TSPtr, __decay_t<_Fp>, __decay_t<_Args>...> _Gp;
-    unique_ptr<_Gp> __p(
-            new _Gp(_VSTD::move(__tsp),
-                    _VSTD::forward<_Fp>(__f),
-                    _VSTD::forward<_Args>(__args)...));
-    int __ec = _VSTD::__libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get());
-    if (__ec == 0)
-        __p.release();
-    else
-        __throw_system_error(__ec, "thread constructor failed");
-}
-
-#else  // _LIBCPP_CXX03_LANG
-
-template <class _Fp>
-struct __thread_invoke_pair {
-    // This type is used to pass memory for thread local storage and a functor
-    // to a newly created thread because std::pair doesn't work with
-    // std::unique_ptr in C++03.
-    _LIBCPP_HIDE_FROM_ABI __thread_invoke_pair(_Fp& __f) : __tsp_(new __thread_struct), __fn_(__f) {}
-    unique_ptr<__thread_struct> __tsp_;
-    _Fp __fn_;
-};
-
-template <class _Fp>
-_LIBCPP_HIDE_FROM_ABI void* __thread_proxy_cxx03(void* __vp)
-{
-    unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
-    __thread_local_data().set_pointer(__p->__tsp_.release());
-    (__p->__fn_)();
-    return nullptr;
-}
-
-template <class _Fp>
-thread::thread(_Fp __f)
-{
-
-    typedef __thread_invoke_pair<_Fp> _InvokePair;
-    typedef unique_ptr<_InvokePair> _PairPtr;
-    _PairPtr __pp(new _InvokePair(__f));
-    int __ec = _VSTD::__libcpp_thread_create(&__t_, &__thread_proxy_cxx03<_InvokePair>, __pp.get());
-    if (__ec == 0)
-        __pp.release();
-    else
-        __throw_system_error(__ec, "thread constructor failed");
-}
-
-#endif // _LIBCPP_CXX03_LANG
-
-inline _LIBCPP_INLINE_VISIBILITY
-void swap(thread& __x, thread& __y) _NOEXCEPT {__x.swap(__y);}
-
-namespace this_thread
-{
-
-_LIBCPP_EXPORTED_FROM_ABI void sleep_for(const chrono::nanoseconds& __ns);
-
-template <class _Rep, class _Period>
-_LIBCPP_HIDE_FROM_ABI void
-sleep_for(const chrono::duration<_Rep, _Period>& __d)
-{
-    if (__d > chrono::duration<_Rep, _Period>::zero())
-    {
-        // The standard guarantees a 64bit signed integer resolution for nanoseconds,
-        // so use INT64_MAX / 1e9 as cut-off point. Use a constant to avoid <climits>
-        // and issues with long double folding on PowerPC with GCC.
-        _LIBCPP_CONSTEXPR chrono::duration<long double> __max =
-            chrono::duration<long double>(9223372036.0L);
-        chrono::nanoseconds __ns;
-        if (__d < __max)
-        {
-            __ns = chrono::duration_cast<chrono::nanoseconds>(__d);
-            if (__ns < __d)
-                ++__ns;
-        }
-        else
-            __ns = chrono::nanoseconds::max();
-        this_thread::sleep_for(__ns);
-    }
-}
-
-template <class _Clock, class _Duration>
-_LIBCPP_HIDE_FROM_ABI void
-sleep_until(const chrono::time_point<_Clock, _Duration>& __t)
-{
-    mutex __mut;
-    condition_variable __cv;
-    unique_lock<mutex> __lk(__mut);
-    while (_Clock::now() < __t)
-        __cv.wait_until(__lk, __t);
-}
-
-template <class _Duration>
-inline _LIBCPP_INLINE_VISIBILITY
-void
-sleep_until(const chrono::time_point<chrono::steady_clock, _Duration>& __t)
-{
-    this_thread::sleep_for(__t - chrono::steady_clock::now());
-}
-
-inline _LIBCPP_INLINE_VISIBILITY
-void yield() _NOEXCEPT {__libcpp_thread_yield();}
-
-} // namespace this_thread
-
-_LIBCPP_END_NAMESPACE_STD
-
-_LIBCPP_POP_MACROS
 
 #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 17
 #  include <chrono>
@@ -476,6 +124,7 @@ _LIBCPP_POP_MACROS
 #  include <functional>
 #  include <new>
 #  include <system_error>
+#  include <type_traits>
 #endif
 
 #endif // _LIBCPP_THREAD
index 9a34210..4e63a72 100644 (file)
@@ -9,6 +9,7 @@
 #include <__config>
 #ifndef _LIBCPP_HAS_NO_THREADS
 
+#include <__thread/timed_backoff_policy.h>
 #include <atomic>
 #include <climits>
 #include <functional>
index ec4f65f..184b5ae 100644 (file)
@@ -10,6 +10,8 @@
 
 #ifndef _LIBCPP_HAS_NO_THREADS
 
+#include <__thread/poll_with_backoff.h>
+#include <__thread/timed_backoff_policy.h>
 #include <exception>
 #include <future>
 #include <limits>
index 21dd51c..8fa6a83 100644 (file)
@@ -785,6 +785,7 @@ stdexcept exception
 stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
+stop_token cstdint
 stop_token limits
 stop_token thread
 stop_token version
index 15044a9..f306a3e 100644 (file)
@@ -786,6 +786,7 @@ stdexcept exception
 stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
+stop_token cstdint
 stop_token limits
 stop_token thread
 stop_token version
index d2bd00a..3e982c2 100644 (file)
@@ -788,6 +788,7 @@ stdexcept exception
 stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
+stop_token cstdint
 stop_token limits
 stop_token thread
 stop_token version
index d2bd00a..3e982c2 100644 (file)
@@ -788,6 +788,7 @@ stdexcept exception
 stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
+stop_token cstdint
 stop_token limits
 stop_token thread
 stop_token version
index 2120eee..613819a 100644 (file)
@@ -794,6 +794,7 @@ stdexcept exception
 stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
+stop_token cstdint
 stop_token limits
 stop_token thread
 stop_token version
index 2efadb0..812bf3b 100644 (file)
@@ -538,6 +538,7 @@ stack version
 stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
+stop_token cstdint
 stop_token limits
 stop_token thread
 stop_token version
@@ -587,6 +588,7 @@ thread cstddef
 thread cstdint
 thread cstdlib
 thread ctime
+thread initializer_list
 thread iosfwd
 thread limits
 thread locale
index 2efadb0..812bf3b 100644 (file)
@@ -538,6 +538,7 @@ stack version
 stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
+stop_token cstdint
 stop_token limits
 stop_token thread
 stop_token version
@@ -587,6 +588,7 @@ thread cstddef
 thread cstdint
 thread cstdlib
 thread ctime
+thread initializer_list
 thread iosfwd
 thread limits
 thread locale
index 7e6760b..2281cc2 100644 (file)
@@ -621,8 +621,11 @@ libcxx/include/__support/win32/locale_win32.h
 libcxx/include/__support/xlocale/__nop_locale_mgmt.h
 libcxx/include/__system_error/errc.h
 libcxx/include/thread
+libcxx/include/__thread/formatter.h
 libcxx/include/__threading_support
 libcxx/include/__thread/poll_with_backoff.h
+libcxx/include/__thread/this_thread.h
+libcxx/include/__thread/thread.h
 libcxx/include/__thread/timed_backoff_policy.h
 libcxx/include/__tree
 libcxx/include/tuple