-
Notifications
You must be signed in to change notification settings - Fork 12.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc++] Split the monolithic __threading_support header #79654
Conversation
@llvm/pr-subscribers-libcxxabi @llvm/pr-subscribers-libcxx Author: Louis Dionne (ldionne) ChangesThe <__threading_support> header is a huge beast and it's really difficult to navigate. I find myself struggling to find what I want every time I have to open it, and I've been considering splitting it up for years for that reason. This patch aims not to contain any functional change. The various implementations of the threading base are simply moved to separate headers and then the individual headers are simplified in mechanical ways. For example, we used to have redundant declarations of all the functions at the top of Finally, this patch adds documentation for the API we expect from any threading implementation. Patch is 56.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/79654.diff 34 Files Affected:
diff --git a/libcxx/docs/DesignDocs/ThreadingSupportAPI.rst b/libcxx/docs/DesignDocs/ThreadingSupportAPI.rst
index 752a9d4d770a1c..e7f3de54e6782a 100644
--- a/libcxx/docs/DesignDocs/ThreadingSupportAPI.rst
+++ b/libcxx/docs/DesignDocs/ThreadingSupportAPI.rst
@@ -14,9 +14,9 @@ These different models provide entirely different interfaces from each
other. To address this libc++ wraps the underlying threading API in a new and
consistent API, which it uses internally to implement threading primitives.
-The ``<__threading_support>`` header is where libc++ defines its internal
-threading interface. It contains forward declarations of the internal threading
-interface as well as definitions for the interface.
+The ``<__thread/support.h>`` header is where libc++ defines its internal
+threading interface. It documents the functions and declarations required
+to fullfil the internal threading interface.
External Threading API and the ``<__external_threading>`` header
================================================================
@@ -25,10 +25,10 @@ In order to support vendors with custom threading API's libc++ allows the
entire internal threading interface to be provided by an external,
vendor provided, header.
-When ``_LIBCPP_HAS_THREAD_API_EXTERNAL`` is defined the ``<__threading_support>``
+When ``_LIBCPP_HAS_THREAD_API_EXTERNAL`` is defined the ``<__thread/support.h>``
header simply forwards to the ``<__external_threading>`` header (which must exist).
It is expected that the ``<__external_threading>`` header provide the exact
-interface normally provided by ``<__threading_support>``.
+interface normally provided by ``<__thread/support.h>``.
External Threading Library
==========================
@@ -58,6 +58,10 @@ Threading Configuration Macros
This macro is defined when libc++ should use POSIX threads to implement the
internal threading API.
+**_LIBCPP_HAS_THREAD_API_C11**
+ This macro is defined when libc++ should use C11 threads to implement the
+ internal threading API.
+
**_LIBCPP_HAS_THREAD_API_WIN32**
This macro is defined when libc++ should use Win32 threads to implement the
internal threading API.
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index ed721d467e94f4..0bb23710cae849 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -688,10 +688,14 @@ set(files
__thread/id.h
__thread/jthread.h
__thread/poll_with_backoff.h
+ __thread/support.h
+ __thread/support/c11.h
+ __thread/support/external.h
+ __thread/support/pthread.h
+ __thread/support/windows.h
__thread/this_thread.h
__thread/thread.h
__thread/timed_backoff_policy.h
- __threading_support
__tree
__tuple/make_tuple_types.h
__tuple/pair_like.h
diff --git a/libcxx/include/__atomic/atomic_flag.h b/libcxx/include/__atomic/atomic_flag.h
index d76e5e45c01a02..a45a7183547726 100644
--- a/libcxx/include/__atomic/atomic_flag.h
+++ b/libcxx/include/__atomic/atomic_flag.h
@@ -15,7 +15,7 @@
#include <__atomic/memory_order.h>
#include <__chrono/duration.h>
#include <__config>
-#include <__threading_support>
+#include <__thread/support.h>
#include <cstdint>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__atomic/atomic_sync.h b/libcxx/include/__atomic/atomic_sync.h
index 3d20d6a8ce2514..93527958b2e1ce 100644
--- a/libcxx/include/__atomic/atomic_sync.h
+++ b/libcxx/include/__atomic/atomic_sync.h
@@ -17,7 +17,7 @@
#include <__config>
#include <__memory/addressof.h>
#include <__thread/poll_with_backoff.h>
-#include <__threading_support>
+#include <__thread/support.h>
#include <__type_traits/decay.h>
#include <cstring>
diff --git a/libcxx/include/__condition_variable/condition_variable.h b/libcxx/include/__condition_variable/condition_variable.h
index 4d8e590e29db7f..2b1a817e2dfee6 100644
--- a/libcxx/include/__condition_variable/condition_variable.h
+++ b/libcxx/include/__condition_variable/condition_variable.h
@@ -16,7 +16,7 @@
#include <__mutex/mutex.h>
#include <__mutex/unique_lock.h>
#include <__system_error/system_error.h>
-#include <__threading_support>
+#include <__thread/support.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_floating_point.h>
#include <__utility/move.h>
diff --git a/libcxx/include/__mutex/mutex.h b/libcxx/include/__mutex/mutex.h
index 4423abf62b8b78..ddc85cf5a00d51 100644
--- a/libcxx/include/__mutex/mutex.h
+++ b/libcxx/include/__mutex/mutex.h
@@ -10,7 +10,7 @@
#define _LIBCPP___MUTEX_MUTEX_H
#include <__config>
-#include <__threading_support>
+#include <__thread/support.h>
#include <__type_traits/is_nothrow_default_constructible.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__thread/formatter.h b/libcxx/include/__thread/formatter.h
index 0454864ce93990..9b54036dcab36b 100644
--- a/libcxx/include/__thread/formatter.h
+++ b/libcxx/include/__thread/formatter.h
@@ -43,7 +43,7 @@ struct _LIBCPP_TEMPLATE_VIS formatter<__thread_id, _CharT> {
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
+ // In __thread/support/pthread.h, __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
diff --git a/libcxx/include/__thread/id.h b/libcxx/include/__thread/id.h
index 83b1d8eceede3b..d5aef3f860ce27 100644
--- a/libcxx/include/__thread/id.h
+++ b/libcxx/include/__thread/id.h
@@ -14,7 +14,7 @@
#include <__config>
#include <__fwd/hash.h>
#include <__fwd/ostream.h>
-#include <__threading_support>
+#include <__thread/support.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
diff --git a/libcxx/include/__thread/jthread.h b/libcxx/include/__thread/jthread.h
index 2fbc8a36755e96..253e3a935d9b73 100644
--- a/libcxx/include/__thread/jthread.h
+++ b/libcxx/include/__thread/jthread.h
@@ -15,8 +15,8 @@
#include <__functional/invoke.h>
#include <__stop_token/stop_source.h>
#include <__stop_token/stop_token.h>
+#include <__thread/support.h>
#include <__thread/thread.h>
-#include <__threading_support>
#include <__type_traits/decay.h>
#include <__type_traits/is_constructible.h>
#include <__type_traits/is_same.h>
diff --git a/libcxx/include/__thread/support.h b/libcxx/include/__thread/support.h
new file mode 100644
index 00000000000000..b05ee892c5f0f6
--- /dev/null
+++ b/libcxx/include/__thread/support.h
@@ -0,0 +1,118 @@
+// -*- 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_SUPPORT_H
+#define _LIBCPP___THREAD_SUPPORT_H
+
+#include <__config>
+
+#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
+# pragma GCC system_header
+#endif
+
+/*
+
+//
+// The library supports multiple implementations of the basic threading functionality.
+// The following functionality must be provided by any implementation:
+//
+
+using __libcpp_timespec_t = ...;
+
+//
+// Mutex
+//
+using __libcpp_mutex_t = ...;
+#define _LIBCPP_MUTEX_INITIALIZER ...
+
+using __libcpp_recursive_mutex_t = ...;
+
+int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t*);
+_LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t*);
+_LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t*);
+_LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t*);
+int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t*);
+
+_LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_lock(__libcpp_mutex_t*);
+_LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool __libcpp_mutex_trylock(__libcpp_mutex_t*);
+_LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_unlock(__libcpp_mutex_t*);
+int __libcpp_mutex_destroy(__libcpp_mutex_t*);
+
+//
+// Condition Variable
+//
+using __libcpp_condvar_t = ...;
+#define _LIBCPP_CONDVAR_INITIALIZER ...
+
+int __libcpp_condvar_signal(__libcpp_condvar_t*);
+int __libcpp_condvar_broadcast(__libcpp_condvar_t*);
+int __libcpp_condvar_wait(__libcpp_condvar_t*, __libcpp_mutex_t*);
+int __libcpp_condvar_timedwait(__libcpp_condvar_t*, __libcpp_mutex_t*, __libcpp_timespec_t*);
+int __libcpp_condvar_destroy(__libcpp_condvar_t*);
+
+//
+// Execute once
+//
+using __libcpp_exec_once_flag = ...;
+#define _LIBCPP_EXEC_ONCE_INITIALIZER ...
+
+int __libcpp_execute_once(__libcpp_exec_once_flag*, void (*__init_routine)());
+
+//
+// Thread id
+//
+using __libcpp_thread_id = ...;
+
+bool __libcpp_thread_id_equal(__libcpp_thread_id, __libcpp_thread_id);
+bool __libcpp_thread_id_less(__libcpp_thread_id, __libcpp_thread_id);
+
+//
+// Thread
+//
+#define _LIBCPP_NULL_THREAD ...
+using __libcpp_thread_t = ...;
+
+bool __libcpp_thread_isnull(const __libcpp_thread_t*);
+int __libcpp_thread_create(__libcpp_thread_t*, void* (*__func)(void*), void* __arg);
+__libcpp_thread_id __libcpp_thread_get_current_id();
+__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t*);
+int __libcpp_thread_join(__libcpp_thread_t*);
+int __libcpp_thread_detach(__libcpp_thread_t*);
+void __libcpp_thread_yield();
+void __libcpp_thread_sleep_for(const chrono::nanoseconds&);
+
+//
+// Thread local storage
+//
+#define _LIBCPP_TLS_DESTRUCTOR_CC ...
+using __libcpp_tls_key = ...;
+
+int __libcpp_tls_create(__libcpp_tls_key*, void (*__at_exit)(void*));
+void* __libcpp_tls_get(__libcpp_tls_key);
+int __libcpp_tls_set(__libcpp_tls_key, void*);
+
+*/
+
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+
+# if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
+# include <__thread/support/external.h>
+# elif defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
+# include <__thread/support/pthread.h>
+# elif defined(_LIBCPP_HAS_THREAD_API_C11)
+# include <__thread/support/c11.h>
+# elif defined(_LIBCPP_HAS_THREAD_API_WIN32)
+# include <__thread/support/windows.h>
+# else
+# error "No threading API was selected"
+# endif
+
+#endif // !_LIBCPP_HAS_NO_THREADS
+
+#endif // _LIBCPP___THREAD_SUPPORT_H
diff --git a/libcxx/include/__thread/support/c11.h b/libcxx/include/__thread/support/c11.h
new file mode 100644
index 00000000000000..44515454d69581
--- /dev/null
+++ b/libcxx/include/__thread/support/c11.h
@@ -0,0 +1,190 @@
+// -*- 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_SUPPORT_C11_H
+#define _LIBCPP___THREAD_SUPPORT_C11_H
+
+#include <__chrono/convert_to_timespec.h>
+#include <__chrono/duration.h>
+#include <__config>
+#include <ctime>
+#include <threads.h>
+
+#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
+# pragma GCC system_header
+#endif
+
+typedef ::timespec __libcpp_timespec_t;
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+//
+// Mutex
+//
+typedef mtx_t __libcpp_mutex_t;
+// mtx_t is a struct so using {} for initialization is valid.
+#define _LIBCPP_MUTEX_INITIALIZER \
+ {}
+
+typedef mtx_t __libcpp_recursive_mutex_t;
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m) {
+ return mtx_init(__m, mtx_plain | mtx_recursive) == thrd_success ? 0 : EINVAL;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
+__libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m) {
+ return mtx_lock(__m) == thrd_success ? 0 : EINVAL;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool
+__libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m) {
+ return mtx_trylock(__m) == thrd_success;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
+__libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m) {
+ return mtx_unlock(__m) == thrd_success ? 0 : EINVAL;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t* __m) {
+ mtx_destroy(__m);
+ return 0;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_lock(__libcpp_mutex_t* __m) {
+ return mtx_lock(__m) == thrd_success ? 0 : EINVAL;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) {
+ return mtx_trylock(__m) == thrd_success;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) {
+ return mtx_unlock(__m) == thrd_success ? 0 : EINVAL;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_mutex_destroy(__libcpp_mutex_t* __m) {
+ mtx_destroy(__m);
+ return 0;
+}
+
+//
+// Condition Variable
+//
+typedef cnd_t __libcpp_condvar_t;
+// cnd_t is a struct so using {} for initialization is valid.
+#define _LIBCPP_CONDVAR_INITIALIZER \
+ {}
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_condvar_signal(__libcpp_condvar_t* __cv) {
+ return cnd_signal(__cv) == thrd_success ? 0 : EINVAL;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv) {
+ return cnd_broadcast(__cv) == thrd_success ? 0 : EINVAL;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
+__libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m) {
+ return cnd_wait(__cv, __m) == thrd_success ? 0 : EINVAL;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
+__libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, timespec* __ts) {
+ int __ec = cnd_timedwait(__cv, __m, __ts);
+ return __ec == thrd_timedout ? ETIMEDOUT : __ec;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv) {
+ cnd_destroy(__cv);
+ return 0;
+}
+
+//
+// Execute once
+//
+typedef ::once_flag __libcpp_exec_once_flag;
+#define _LIBCPP_EXEC_ONCE_INITIALIZER ONCE_FLAG_INIT
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_execute_once(__libcpp_exec_once_flag* flag, void (*init_routine)(void)) {
+ ::call_once(flag, init_routine);
+ return 0;
+}
+
+//
+// Thread id
+//
+typedef thrd_t __libcpp_thread_id;
+
+// Returns non-zero if the thread ids are equal, otherwise 0
+inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2) {
+ return thrd_equal(t1, t2) != 0;
+}
+
+// Returns non-zero if t1 < t2, otherwise 0
+inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2) {
+ return t1 < t2;
+}
+
+//
+// Thread
+//
+#define _LIBCPP_NULL_THREAD 0U
+
+typedef thrd_t __libcpp_thread_t;
+
+inline _LIBCPP_HIDE_FROM_ABI __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t) { return *__t; }
+
+inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) {
+ return __libcpp_thread_get_id(__t) == 0;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
+ int __ec = thrd_create(__t, reinterpret_cast<thrd_start_t>(__func), __arg);
+ return __ec == thrd_nomem ? ENOMEM : __ec;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI __libcpp_thread_id __libcpp_thread_get_current_id() { return thrd_current(); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_join(__libcpp_thread_t* __t) {
+ return thrd_join(*__t, nullptr) == thrd_success ? 0 : EINVAL;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_detach(__libcpp_thread_t* __t) {
+ return thrd_detach(*__t) == thrd_success ? 0 : EINVAL;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI void __libcpp_thread_yield() { thrd_yield(); }
+
+inline _LIBCPP_HIDE_FROM_ABI void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) {
+ __libcpp_timespec_t __ts = std::__convert_to_timespec<__libcpp_timespec_t>(__ns);
+ thrd_sleep(&__ts, nullptr);
+}
+
+//
+// Thread local storage
+//
+#define _LIBCPP_TLS_DESTRUCTOR_CC /* nothing */
+
+typedef tss_t __libcpp_tls_key;
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_tls_create(__libcpp_tls_key* __key, void (*__at_exit)(void*)) {
+ return tss_create(__key, __at_exit) == thrd_success ? 0 : EINVAL;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI void* __libcpp_tls_get(__libcpp_tls_key __key) { return tss_get(__key); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_tls_set(__libcpp_tls_key __key, void* __p) {
+ return tss_set(__key, __p) == thrd_success ? 0 : EINVAL;
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___THREAD_SUPPORT_C11_H
diff --git a/libcxx/include/__thread/support/external.h b/libcxx/include/__thread/support/external.h
new file mode 100644
index 00000000000000..d5e212491cfdbd
--- /dev/null
+++ b/libcxx/include/__thread/support/external.h
@@ -0,0 +1,21 @@
+// -*- 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_SUPPORT_EXTERNAL_H
+#define _LIBCPP___THREAD_SUPPORT_EXTERNAL_H
+
+#include <__config>
+
+#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
+# pragma GCC system_header
+#endif
+
+#include <__external_threading>
+
+#endif // _LIBCPP___THREAD_SUPPORT_EXTERNAL_H
diff --git a/libcxx/include/__thread/support/pthread.h b/libcxx/include/__thread/support/pthread.h
new file mode 100644
index 00000000000000..c129234433ac57
--- /dev/null
+++ b/libcxx/include/__thread/support/pthread.h
@@ -0,0 +1,219 @@
+// -*- 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_SUPPORT_PTHREAD_H
+#define _LIBCPP___THREAD_SUPPORT_PTHREAD_H
+
+#include <__availability>
+#include <__chrono/convert_to_timespec.h>
+#include <__chrono/duration.h>
+#include <__config>
+#include <__fwd/hash.h>
+#include <ctime>
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+
+#ifdef __MVS__
+# include <__support/ibm/nanosleep.h>
+#endif
+
+// Some platforms require <bits/atomic_wide_counter.h> in order for
+// PTHREAD_COND_INITIALIZER to be expanded. Normally that would come
+// in via <pthread.h>, but it's a non-modular header on those platforms,
+// so libc++'s <math.h> usually absorbs atomic_wide_counter.h into the
+// module with <math.h> and makes atomic_wide_counter.h invisible.
+// Include <math.h> here to work around that.
+#include <math.h>
+
+#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
+# pragma GCC system_header
+#endif
+
+typedef ::timespec __libcpp_timespec_t;
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+//
+// Mutex
+//
+typedef pthread_mutex_t __libcpp_mutex_t;
+#define _LIBCPP_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+
+typedef pthread_mutex_t __libcpp_recursive_mutex_t;
+
+inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m) {
+ pthread_mutexattr_t __attr;
+ int __ec = pthread_mutexattr_init(&__attr);
+ if (__ec)
+ return __ec;
+ __ec = pthread_mutexattr_settype(&__attr, PTHREAD_MUTEX_RECURSIVE);
+ if (__ec) {
+ pthread_mutexattr_destroy(&__attr);
+ return __ec;
+ }
+ __ec = pthread_mutex_init(__m, &__attr);
+ if (__ec) {
+ pthread_mutexattr_destroy(&__attr);
+ return __ec;
+ }
+ __ec = pthread_mutexattr_destroy(&__attr);
+ if (__ec) {
+ pthread_mutex_destroy(__m);
+ return __ec;
+ }
+ return 0;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSI...
[truncated]
|
The <__threading_support> header is a huge beast and it's really difficult to navigate. I find myself struggling to find what I want every time I have to open it, and I've been considering splitting it up for years for that reason. This patch aims not to contain any functional change. The various implementations of the threading base are simply moved to separate headers and then the individual headers are simplified in mechanical ways. For example, we used to have redundant declarations of all the functions at the top of `__threading_support`, and those are removed since they are not needed anymore. The various #ifdefs are also simplified and removed when they become unnecessary. Finally, this patch adds documentation for the API we expect from any threading implementation.
5ffc5af
to
7c2838a
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! This looks really nice. LGTM % nit.
# pragma GCC system_header | ||
#endif | ||
|
||
typedef ::timespec __libcpp_timespec_t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe refactor these to using
aliases in a follow-up patch?
#if !defined(_LIBCPP_HAS_NO_THREADS) | ||
|
||
# if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) | ||
# include <__thread/support/external.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just include the <__external_threading>
header directly? There doesn't seem to be much reason not to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am tempted to leave it as-is just cause the CI is passing and there are other changes I want to land on top. I can do a follow-up patch.
This requires updating libcxx and libcxxabi at the same time. Any opposition to replacing the includes in libcxxabi with
for a while, so that projects can keep rolling libcxxabi and libcxx independently? (We have an autoroller for libcxxabi that has been working without issues for years up to this change, and we have one for libcxx that's broken pretty frequently due to libcxx changes, including right now. It'd be nice if libcxxabi could keep rolling.) |
We can do that... but what I don't understand is how you build libc++abi. We require building libc++ and libc++abi at the same time, so how do you manage to roll both libraries independently? |
We don't use upstream's cmake files. We do build libc++ and libc++abi at the same time, but sometimes the revisions are off by a bit, since both are autoupdated independently. They're pulled in from two independent mirrors, one of llvm-project.git/libcxx, one of llvm-project.git/libcxxabi. Happy to go into as much detail as you want :) |
Would there be any appetite on your end to update both at the same time? I'm definitely willing to add the workaround temporarily to ease your internal process since the cost is low, however that's not something we'd want to do on a regular basis going forward. In fact, I want to write a RFC for merging the libc++ and libc++abi projects, which would require this work on your end regardless. |
See 372f7dd. I will remove the work-around by EOW -- is that fine? I would really appreciate if you folks could take this opportunity to ensure that libc++ and libc++abi are rolled as a unit, since your setup is not supported right now. We really value the project's relationship with Chrome so it makes sense to do a temporary workaround like this, but I'm sure you understand how it's not viable to accommodate similar requests coming from arbitrary downstreams. |
Unless absolutely necessary, no :) Updating LLVM can be a lot of work. The more parts of it we can ship independently, the better. libcxx is one of the harder parts to update, so I wouldn't want us to tie anything to it unless we want to. (We'd prefer to move in the opposite direction: We currently bundle the sanitizer runtimes with the compiler/linker package, and it'd be nice if they'd update separately for example. The sanitizer runtimes have been pretty stable the last few years though, so it's not a priority.)
Is it expensive to keep around for a bit longer? At the moment, updating libc++ is blocked on removing an is_pod somewhere in our codebase, but it's in a dependency that needs to roll in both my cherry-pick and a bunch of related things, and the new version of the dependency has some msan issues at the moment, etc. Fixing things in dependencies can take a while since we don't fully control them. (For example, https://crbug.com/1481891 – the |
That's fair, however libc++abi is an implementation detail of libc++. The fact that they're in separate directories with separate CMake files is, at this point, nothing more than a historical artifact. Those two really need to be in sync and I wouldn't be surprised if you hit other bugs at some point due to that. |
By coincidence, our libc++ roll blocker got resolved yesterday and we could roll in the 42 revisions that landed Jan 19 - 21 yesterday. And there were no new issues in the 49 revisions that landed Jan 23 - Feb 2, so we're now all caught up again and don't need this workaround any more. So end of week is actually good enough (barring reverts, but looks ok so far) – but it's hard to say in advance with changes in deps. Anyways, fine to undo 372f7dd from our end. I don't know if it's useful for anyone else out there. Thank you for putting it in, it made things easier :) |
(Workaround got reverted here: c5f68a7) |
After llvm/llvm-project#80282, `formatter_integral.h` includes not `locale` but `_locale` https://github.com/llvm/llvm-project/blame/aadaa00de76ed0c4987b97450dd638f63a385bed/libcxx/include/__format/formatter_integral.h#L35 and after several more include changes this causes https://github.com/llvm/llvm-project/blob/aadaa00de76ed0c4987b97450dd638f63a385bed/libcxx/include/__thread/support/pthread.h not to be included when https://github.com/emscripten-core/emscripten/blob/main/system/include/emscripten/val.h is included. `pthread.h` is where `pthread_t` is defined, which is used here: https://github.com/emscripten-core/emscripten/blob/fb14f6d9fc2b00fea36af0f5ca4e996f61520b8f/system/include/emscripten/val.h#L676 Until LLVM 18, the contents of https://github.com/llvm/llvm-project/blob/aadaa00de76ed0c4987b97450dd638f63a385bed/libcxx/include/__thread/support/pthread.h was in https://github.com/llvm/llvm-project/blob/3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff/libcxx/include/__threading_support, which was split off to several files in llvm/llvm-project#79654. This file was (transitively) included from `locale`. Anyway, this commit just adds `#include <pthread.h>` directly to `val.h`.
After llvm/llvm-project#80282, `formatter_integral.h` includes not `locale` but `_locale` https://github.com/llvm/llvm-project/blame/aadaa00de76ed0c4987b97450dd638f63a385bed/libcxx/include/__format/formatter_integral.h#L35 and after several more include changes this causes https://github.com/llvm/llvm-project/blob/aadaa00de76ed0c4987b97450dd638f63a385bed/libcxx/include/__thread/support/pthread.h not to be included when https://github.com/emscripten-core/emscripten/blob/main/system/include/emscripten/val.h is included. `pthread.h` is where `pthread_t` is defined, which is used here: https://github.com/emscripten-core/emscripten/blob/fb14f6d9fc2b00fea36af0f5ca4e996f61520b8f/system/include/emscripten/val.h#L676 Until LLVM 18, the contents of https://github.com/llvm/llvm-project/blob/aadaa00de76ed0c4987b97450dd638f63a385bed/libcxx/include/__thread/support/pthread.h was in https://github.com/llvm/llvm-project/blob/3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff/libcxx/include/__threading_support, which was split off to several files in llvm/llvm-project#79654. This file was (transitively) included from `locale`. Anyway, this commit just adds `#include <pthread.h>` directly to `val.h`.
The <__threading_support> header is a huge beast and it's really difficult to navigate. I find myself struggling to find what I want every time I have to open it, and I've been considering splitting it up for years for that reason.
This patch aims not to contain any functional change. The various implementations of the threading base are simply moved to separate headers and then the individual headers are simplified in mechanical ways. For example, we used to have redundant declarations of all the functions at the top of
__threading_support
, and those are removed since they are not needed anymore. The various #ifdefs are also simplified and removed when they become unnecessary.Finally, this patch adds documentation for the API we expect from any threading implementation.