[llvm-branch-commits] [libcxxabi] 9ac3e12 - Adding internal threading support for POSIX(OFF)
Zibi Sarbinowski via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Feb 3 13:51:37 PST 2022
Author: Zibi Sarbinowski
Date: 2022-02-03T15:51:14-06:00
New Revision: 9ac3e1238472a780592755b6ad9465b25353cc45
URL: https://github.com/llvm/llvm-project/commit/9ac3e1238472a780592755b6ad9465b25353cc45
DIFF: https://github.com/llvm/llvm-project/commit/9ac3e1238472a780592755b6ad9465b25353cc45.diff
LOG: Adding internal threading support for POSIX(OFF)
Added:
libcxx/src/include/internal_threading_support.h
Modified:
libcxx/include/__threading_support
libcxx/src/CMakeLists.txt
libcxx/src/debug.cpp
libcxx/src/locale.cpp
libcxx/src/memory.cpp
libcxx/src/random_shuffle.cpp
libcxxabi/src/cxa_exception_storage.cpp
libcxxabi/src/cxa_guard_impl.h
libcxxabi/src/fallback_malloc.cpp
libcxxabi/test/test_exception_storage.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/include/__threading_support b/libcxx/include/__threading_support
index bf85d5f5d9f05..9149e729dc0b8 100644
--- a/libcxx/include/__threading_support
+++ b/libcxx/include/__threading_support
@@ -252,7 +252,14 @@ int __libcpp_tls_set(__libcpp_tls_key __key, void *__p);
#if (!defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL))
-#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
+#if defined(_LIBCPP_HAS_THREAD_LIBRARY_OPTIONAL)
+// Empty - function definitions are provided by src/include/internal_threading_support.h
+#if !defined(_LIBCPP_BUILDING_LIBRARY)
+#error _LIBCPP_HAS_THREAD_LIBRARY_OPTIONAL is only intended to protect internal \
+ uses of __threading_support by libcxx.
+#endif
+
+#elif defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
_LIBCPP_HIDE_FROM_ABI inline
int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index 12dcdf9544055..093fb4c647d72 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -18,6 +18,7 @@ set(LIBCXX_SOURCES
include/apple_availability.h
include/atomic_support.h
include/config_elast.h
+ include/internal_threading_support.h
include/refstring.h
include/ryu/common.h
include/ryu/d2fixed.h
diff --git a/libcxx/src/debug.cpp b/libcxx/src/debug.cpp
index ae31c91d154f4..92ec8355438fa 100644
--- a/libcxx/src/debug.cpp
+++ b/libcxx/src/debug.cpp
@@ -14,7 +14,7 @@
#include "cstdio"
#include "__hash_table"
#ifndef _LIBCPP_HAS_NO_THREADS
-#include "mutex"
+#include "include/internal_threading_support.h"
#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
diff --git a/libcxx/src/include/internal_threading_support.h b/libcxx/src/include/internal_threading_support.h
new file mode 100644
index 0000000000000..16bcaccf142f1
--- /dev/null
+++ b/libcxx/src/include/internal_threading_support.h
@@ -0,0 +1,482 @@
+//===----------------------------------------------------------------------===////
+//
+// 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_INTERNAL_THREADING_SUPPORT_H
+#define _LIBCPP_INTERNAL_THREADING_SUPPORT_H
+
+/** internal_threading_support.h - Equivalent to __threading_support, but for internal uses that are
+ * not related to the C++11 Threading Library. These should all be within code that is compiled into
+ * the libcxx library rather than potentially #included by user code.
+ *
+ * See libcxx/docs/DesignDocs/InternalThreadSynchronization.rst for details.
+ *
+ * Any use of the C++11 Thread Support Library (e.g. std::mutex) without an underlying thread
+ * library available is user error, so we want files like mutex.cpp to use the definitions from
+ * __threading_support. For that reason, _LIBCPP_HAS_THREAD_LIBRARY_OPTIONAL needs to be defined
+ * here instead of in __config.
+ *
+ * Any platforms which cannot determine during compilation of libc++ the availability of a thread
+ * library such as pthreads should define `_LIBCPP_HAS_THREAD_LIBRARY_OPTIONAL` before
+ * <__threading_support> is #included, and provide definitions for
+ * `__libcpp_is_threading_api_enabled()` and `__libcpp_might_have_multiple_threads()`
+ */
+
+#if !defined(_LIBCPP_BUILDING_LIBRARY)
+# error internal_threading_support.h is only intended for internal use by libcxx
+#endif
+
+#ifdef _LIBCPP_THREADING_SUPPORT
+# error internal_threading_support.h must be included before <__threading_support>
+#endif
+
+#if defined(__MVS__)
+// Tell __threading_support not to provide function definitions, since we provide them here
+# define _LIBCPP_HAS_THREAD_LIBRARY_OPTIONAL
+#endif
+
+#include <__threading_support>
+
+#if defined(_LIBCPP_HAS_THREAD_LIBRARY_OPTIONAL) && !defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL)
+
+_LIBCPP_THREAD_ABI_VISIBILITY
+bool __libcpp_is_threading_api_enabled();
+
+_LIBCPP_THREAD_ABI_VISIBILITY
+bool __libcpp_might_have_multiple_threads();
+
+# if defined(__MVS__)
+# include "ceeedb.h"
+/// On z/OS some posix functions can be enabled/disabled at runtime.
+/// However, the enabled/disabled status should not change over the life of the process.
+bool __libcpp_is_threading_api_enabled() {
+ static bool __posix_on = __libcpp_ceeedb_posix();
+ return __posix_on;
+}
+bool __libcpp_might_have_multiple_threads() { return __libcpp_ceeedb_multithread(); }
+# endif
+
+//===----------------------------------------------------------------------===//
+// Definitions which would normally be provided by __threading_support
+//===----------------------------------------------------------------------===//
+
+# if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
+
+int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m) {
+ if (!__libcpp_is_threading_api_enabled())
+ return 0;
+
+ 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;
+}
+
+int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m) {
+ // See __libcpp_mutex_lock for an explaination of why this is safe
+ if (!__libcpp_might_have_multiple_threads())
+ return 0;
+ return pthread_mutex_lock(__m);
+}
+
+bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m) {
+ // See __libcpp_mutex_lock for an explaination of why this is safe
+ if (!__libcpp_might_have_multiple_threads())
+ return true;
+ return pthread_mutex_trylock(__m) == 0;
+}
+
+int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m) {
+ // See __libcpp_mutex_lock for an explaination of why this is safe
+ if (!__libcpp_might_have_multiple_threads())
+ return 0;
+ return pthread_mutex_unlock(__m);
+}
+
+int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t* __m) {
+ if (!__libcpp_is_threading_api_enabled())
+ return 0;
+ return pthread_mutex_destroy(__m);
+}
+
+int __libcpp_mutex_lock(__libcpp_mutex_t* __m) {
+ // All libcxx-internal locks are released before we run any code which could
+ // spawn a thread, so we can safely skip mutex acquisition when there's only
+ // one thread (even if the threading API is enabled).
+ if (!__libcpp_might_have_multiple_threads())
+ return 0;
+ return pthread_mutex_lock(__m);
+}
+
+bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) {
+ // See __libcpp_mutex_lock for an explaination of why this is safe
+ if (!__libcpp_might_have_multiple_threads())
+ return true;
+ return pthread_mutex_trylock(__m) == 0;
+}
+
+int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) {
+ // See __libcpp_mutex_lock for an explaination of why this is safe
+ if (!__libcpp_might_have_multiple_threads())
+ return 0;
+ return pthread_mutex_unlock(__m);
+}
+
+int __libcpp_mutex_destroy(__libcpp_mutex_t* __m) {
+ if (!__libcpp_is_threading_api_enabled())
+ return 0;
+ return pthread_mutex_destroy(__m);
+}
+
+// Condition Variable
+int __libcpp_condvar_signal(__libcpp_condvar_t* __cv) {
+ // If we're the only thread, there's no one to signal to, skip it
+ if (!__libcpp_might_have_multiple_threads())
+ return 0;
+ return pthread_cond_signal(__cv);
+}
+
+int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv) {
+ // If we're the only thread, there's no one to broadcast to, skip it
+ if (!__libcpp_might_have_multiple_threads())
+ return 0;
+ return pthread_cond_broadcast(__cv);
+}
+
+int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m) {
+ // If we're the only thread, there's no one to wake us up, so this is a deadlock
+ assert(__libcpp_might_have_multiple_threads());
+ return pthread_cond_wait(__cv, __m);
+}
+
+int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, __libcpp_timespec_t* __ts) {
+ if (!__libcpp_is_threading_api_enabled()) {
+ // With nobody to wake us up, this is equivalent to a sleep
+ // TODO: actually wait until __ts, and replace this with
+ // `if(!__libcpp_might_have_multiple_threads())`
+ return ETIMEDOUT;
+ }
+ return pthread_cond_timedwait(__cv, __m, __ts);
+}
+
+int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv) {
+ if (!__libcpp_is_threading_api_enabled())
+ return 0;
+ return pthread_cond_destroy(__cv);
+}
+
+// Execute once
+int __libcpp_execute_once(__libcpp_exec_once_flag* flag, void (*init_routine)()) {
+ if (!__libcpp_is_threading_api_enabled()) {
+ if (*flag == _LIBCPP_EXEC_ONCE_INITIALIZER) {
+ init_routine();
+ // TODO: In order for this to work when __libcpp_is_threading_api_enabled() can change during
+ // program execution, we have to write the same value pthread_once would.
+ // For glibc this seems to be 2, but it could vary.
+ *flag = 2;
+ }
+ return 0;
+ }
+
+ return pthread_once(flag, init_routine);
+}
+
+// Thread id
+// Returns non-zero if the thread ids are equal, otherwise 0
+bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2) { return t1 == t2; }
+
+// Returns non-zero if t1 < t2, otherwise 0
+bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2) { return t1 < t2; }
+
+// Thread
+bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) { return __libcpp_thread_get_id(__t) == 0; }
+
+int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
+ assert(__libcpp_is_threading_api_enabled());
+ return pthread_create(__t, nullptr, __func, __arg);
+}
+
+__libcpp_thread_id __libcpp_thread_get_current_id() {
+ assert(__libcpp_is_threading_api_enabled());
+ const __libcpp_thread_t thread = pthread_self();
+ return __libcpp_thread_get_id(&thread);
+}
+
+__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t) {
+# if defined(__MVS__)
+ return __t->__;
+# else
+ return *__t;
+# endif
+}
+
+int __libcpp_thread_join(__libcpp_thread_t* __t) {
+ assert(__libcpp_is_threading_api_enabled());
+ return pthread_join(*__t, nullptr);
+}
+
+int __libcpp_thread_detach(__libcpp_thread_t* __t) {
+ assert(__libcpp_is_threading_api_enabled());
+ return pthread_detach(*__t);
+}
+
+void __libcpp_thread_yield() {
+ if (!__libcpp_might_have_multiple_threads())
+ return;
+ sched_yield();
+}
+
+void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) {
+ assert(__libcpp_is_threading_api_enabled());
+ __libcpp_timespec_t __ts = __thread_detail::__convert_to_timespec(__ns);
+ while (nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
+ ;
+}
+
+// Thread local storage
+int __libcpp_tls_create(__libcpp_tls_key* __key, void (*__at_exit)(void*)) {
+ if (!__libcpp_is_threading_api_enabled())
+ return 0;
+ return pthread_key_create(__key, __at_exit);
+}
+
+void* __libcpp_tls_get(__libcpp_tls_key __key) {
+ // ugly and devious way of getting cxa_exception_storage to work, but necessary if we want to
+ // keep all the runtime-dependent threading changes contained within internal_threading_support.h
+ if (!__libcpp_is_threading_api_enabled()) {
+ static struct {
+ void* caughtExceptions;
+ unsigned int uncaughtExceptions;
+ } eh_globals;
+ return &eh_globals;
+ }
+ // TODO: this won't work if __libcpp_is_threading_api_enabled() can change during program
+ // execution, because we may have skipped pthread_key_create()
+ return pthread_getspecific(__key);
+}
+
+int __libcpp_tls_set(__libcpp_tls_key __key, void* __p) {
+ assert(__libcpp_is_threading_api_enabled());
+ return pthread_setspecific(__key, __p);
+}
+
+# elif defined(_LIBCPP_HAS_THREAD_API_C11)
+
+int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m) {
+ if (!__libcpp_is_threading_api_enabled())
+ return 0;
+
+ return mtx_init(__m, mtx_plain | mtx_recursive) == thrd_success ? 0 : EINVAL;
+}
+
+int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m) {
+ // See __libcpp_mutex_lock for an explaination of why this is safe
+ if (!__libcpp_might_have_multiple_threads())
+ return 0;
+ return mtx_lock(__m) == thrd_success ? 0 : EINVAL;
+}
+
+bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m) {
+ // See __libcpp_mutex_lock for an explaination of why this is safe
+ if (!__libcpp_might_have_multiple_threads())
+ return true;
+ return mtx_trylock(__m) == thrd_success;
+}
+
+int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m) {
+ // See __libcpp_mutex_lock for an explaination of why this is safe
+ if (!__libcpp_might_have_multiple_threads())
+ return 0;
+ return mtx_unlock(__m) == thrd_success ? 0 : EINVAL;
+}
+
+int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t* __m) {
+ if (!__libcpp_is_threading_api_enabled())
+ return 0;
+ mtx_destroy(__m);
+ return 0;
+}
+
+int __libcpp_mutex_lock(__libcpp_mutex_t* __m) {
+ // All libcxx-internal locks are released before we run any code which could
+ // spawn a thread, so we can safely skip mutex acquisition when there's only
+ // one thread (even if the threading API is enabled).
+ if (!__libcpp_might_have_multiple_threads())
+ return 0;
+ return mtx_lock(__m) == thrd_success ? 0 : EINVAL;
+}
+
+bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) {
+ // See __libcpp_mutex_lock for an explaination of why this is safe
+ if (!__libcpp_might_have_multiple_threads())
+ return true;
+ return mtx_trylock(__m) == thrd_success;
+}
+
+int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) {
+ // See __libcpp_mutex_lock for an explaination of why this is safe
+ if (!__libcpp_might_have_multiple_threads())
+ return 0;
+ return mtx_unlock(__m) == thrd_success ? 0 : EINVAL;
+}
+
+int __libcpp_mutex_destroy(__libcpp_mutex_t* __m) {
+ if (!__libcpp_is_threading_api_enabled())
+ return 0;
+ mtx_destroy(__m);
+ return 0;
+}
+
+// Condition Variable
+int __libcpp_condvar_signal(__libcpp_condvar_t* __cv) {
+ // If we're the only thread, there's no one to signal to, skip it
+ if (!__libcpp_might_have_multiple_threads())
+ return 0;
+ return cnd_signal(__cv) == thrd_success ? 0 : EINVAL;
+}
+
+int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv) {
+ // If we're the only thread, there's no one to broadcast to, skip it
+ if (!__libcpp_might_have_multiple_threads())
+ return 0;
+ return cnd_broadcast(__cv) == thrd_success ? 0 : EINVAL;
+}
+
+int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m) {
+ // If we're the only thread, there's no one to wake us up, so this is a deadlock
+ assert(__libcpp_might_have_multiple_threads());
+ return cnd_wait(__cv, __m) == thrd_success ? 0 : EINVAL;
+}
+
+int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, timespec* __ts) {
+ if (!__libcpp_is_threading_api_enabled()) {
+ // With nobody to wake us up, this is equivalent to a sleep
+ // TODO: actually wait until __ts, and replace this with
+ // `if(!__libcpp_might_have_multiple_threads())`
+ return ETIMEDOUT;
+ }
+ int __ec = cnd_timedwait(__cv, __m, __ts);
+ return __ec == thrd_timedout ? ETIMEDOUT : __ec;
+}
+
+int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv) {
+ if (!__libcpp_is_threading_api_enabled())
+ return 0;
+ cnd_destroy(__cv);
+ return 0;
+}
+
+// Execute once
+int __libcpp_execute_once(__libcpp_exec_once_flag* flag, void (*init_routine)(void)) {
+ if (!__libcpp_is_threading_api_enabled()) {
+ if (*flag == _LIBCPP_EXEC_ONCE_INITIALIZER) {
+ init_routine();
+ // TODO: In order for this to work when __libcpp_is_threading_api_enabled() can change during
+ // program execution, we have to write the same value ::call_once would.
+ // For glibc this seems to be 2, but it could vary.
+ *flag = 2;
+ }
+ return 0;
+ }
+
+ ::call_once(flag, init_routine);
+ return 0;
+}
+
+// Thread id
+// Returns non-zero if the thread ids are equal, otherwise 0
+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
+bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2) { return t1 < t2; }
+
+// Thread
+bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) { return __libcpp_thread_get_id(__t) == 0; }
+
+int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
+ assert(__libcpp_is_threading_api_enabled());
+ int __ec = thrd_create(__t, reinterpret_cast<thrd_start_t>(__func), __arg);
+ return __ec == thrd_nomem ? ENOMEM : __ec;
+}
+
+__libcpp_thread_id __libcpp_thread_get_current_id() {
+ assert(__libcpp_is_threading_api_enabled());
+ return thrd_current();
+}
+
+__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t) { return *__t; }
+
+int __libcpp_thread_join(__libcpp_thread_t* __t) {
+ assert(__libcpp_is_threading_api_enabled());
+ return thrd_join(*__t, nullptr) == thrd_success ? 0 : EINVAL;
+}
+
+int __libcpp_thread_detach(__libcpp_thread_t* __t) {
+ assert(__libcpp_is_threading_api_enabled());
+ return thrd_detach(*__t) == thrd_success ? 0 : EINVAL;
+}
+
+void __libcpp_thread_yield() {
+ if (!__libcpp_might_have_multiple_threads())
+ return;
+ thrd_yield();
+}
+
+void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) {
+ assert(__libcpp_is_threading_api_enabled());
+ __libcpp_timespec_t __ts = __thread_detail::__convert_to_timespec(__ns);
+ thrd_sleep(&__ts, nullptr);
+}
+
+// Thread local storage
+int __libcpp_tls_create(__libcpp_tls_key* __key, void (*__at_exit)(void*)) {
+ if (!__libcpp_is_threading_api_enabled())
+ return 0;
+ return tss_create(__key, __at_exit) == thrd_success ? 0 : EINVAL;
+}
+
+void* __libcpp_tls_get(__libcpp_tls_key __key) {
+ // ugly and devious way of getting cxa_exception_storage to work, but necessary if we want to
+ // keep all the runtime-dependent threading changes contained within internal_threading_support.h
+ if (!__libcpp_is_threading_api_enabled()) {
+ static struct {
+ void* caughtExceptions;
+ unsigned int uncaughtExceptions;
+ } eh_globals;
+ return &eh_globals;
+ }
+ // TODO: this won't work if __libcpp_is_threading_api_enabled() can change during program
+ // execution, because we may have skipped tss_create()
+ return tss_get(__key);
+}
+
+int __libcpp_tls_set(__libcpp_tls_key __key, void* __p) {
+ assert(__libcpp_is_threading_api_enabled());
+ return tss_set(__key, __p) == thrd_success ? 0 : EINVAL;
+}
+
+# endif
+
+#endif // _LIBCPP_HAS_THREAD_LIBRARY_OPTIONAL && !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL
+
+#endif // _LIBCPP_INTERNAL_THREADING_SUPPORT_H
diff --git a/libcxx/src/locale.cpp b/libcxx/src/locale.cpp
index 2234784769dd3..c614551aeb5bf 100644
--- a/libcxx/src/locale.cpp
+++ b/libcxx/src/locale.cpp
@@ -12,6 +12,8 @@
#define _LCONV_C99
#endif
+// This must come before any file that #includes <__threading_support>.
+#include "include/internal_threading_support.h"
#include "algorithm"
#include "clocale"
#include "codecvt"
diff --git a/libcxx/src/memory.cpp b/libcxx/src/memory.cpp
index 4c9bf9f073c88..68a3fc0d26c94 100644
--- a/libcxx/src/memory.cpp
+++ b/libcxx/src/memory.cpp
@@ -8,7 +8,7 @@
#include "memory"
#ifndef _LIBCPP_HAS_NO_THREADS
-# include "mutex"
+# include "include/internal_threading_support.h"
# include "thread"
# if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
# pragma comment(lib, "pthread")
diff --git a/libcxx/src/random_shuffle.cpp b/libcxx/src/random_shuffle.cpp
index df9b7d53c8475..bf17bb1d48cf2 100644
--- a/libcxx/src/random_shuffle.cpp
+++ b/libcxx/src/random_shuffle.cpp
@@ -9,7 +9,7 @@
#include "algorithm"
#include "random"
#ifndef _LIBCPP_HAS_NO_THREADS
-# include "mutex"
+# include "include/internal_threading_support.h"
# if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
# pragma comment(lib, "pthread")
# endif
diff --git a/libcxxabi/src/cxa_exception_storage.cpp b/libcxxabi/src/cxa_exception_storage.cpp
index 3a3233a1b9272..acf0ed6fa7464 100644
--- a/libcxxabi/src/cxa_exception_storage.cpp
+++ b/libcxxabi/src/cxa_exception_storage.cpp
@@ -12,8 +12,6 @@
#include "cxa_exception.h"
-#include <__threading_support>
-
#if defined(_LIBCXXABI_HAS_NO_THREADS)
namespace __cxxabiv1 {
@@ -92,6 +90,11 @@ extern "C" {
// to the Itanium ABI and is taken advantage of in several places in
// libc++abi.
__cxa_eh_globals *__cxa_get_globals_fast() {
+ // If threads are disabled at runtime, revert to single-threaded implementation.
+ if (!std::__libcpp_is_threading_api_enabled()) {
+ static __cxa_eh_globals eh_globals;
+ return &eh_globals;
+ }
// First time through, create the key.
if (0 != std::__libcpp_execute_once(&flag_, construct_))
abort_message("execute once failure in __cxa_get_globals_fast()");
diff --git a/libcxxabi/src/cxa_guard_impl.h b/libcxxabi/src/cxa_guard_impl.h
index 5a7cbfd5cdb9d..e487e2d464984 100644
--- a/libcxxabi/src/cxa_guard_impl.h
+++ b/libcxxabi/src/cxa_guard_impl.h
@@ -56,7 +56,7 @@
#include <limits.h>
#include <stdlib.h>
-#include <__threading_support>
+#include "include/internal_threading_support.h" // from libc++
#ifndef _LIBCXXABI_HAS_NO_THREADS
# if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
# pragma comment(lib, "pthread")
diff --git a/libcxxabi/src/fallback_malloc.cpp b/libcxxabi/src/fallback_malloc.cpp
index 7e356d9fe47ba..26a604f1685fa 100644
--- a/libcxxabi/src/fallback_malloc.cpp
+++ b/libcxxabi/src/fallback_malloc.cpp
@@ -8,7 +8,7 @@
#include "fallback_malloc.h"
-#include <__threading_support>
+#include "include/internal_threading_support.h" // from libc++
#ifndef _LIBCXXABI_HAS_NO_THREADS
#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
diff --git a/libcxxabi/test/test_exception_storage.pass.cpp b/libcxxabi/test/test_exception_storage.pass.cpp
index 934cc4b6a7cba..525bff599c870 100644
--- a/libcxxabi/test/test_exception_storage.pass.cpp
+++ b/libcxxabi/test/test_exception_storage.pass.cpp
@@ -42,7 +42,19 @@ std::__libcpp_thread_t threads [ NUMTHREADS ];
#endif
int main() {
-#ifndef _LIBCXXABI_HAS_NO_THREADS
+#ifdef _LIBCXXABI_HAS_NO_THREADS
+ size_t thread_globals;
+ thread_code(&thread_globals);
+ // Check that __cxa_get_globals() is not NULL.
+ return (thread_globals == 0) ? 1 : 0;
+#else // !_LIBCXXABI_HAS_NO_THREADS
+ // If threads are disabled at runtime, revert to single-threaded test.
+ if (!std::__libcpp_is_threading_api_enabled()) {
+ thread_code((void*)thread_globals);
+ // Check that __cxa_get_globals() is not NULL.
+ return (thread_globals[0] == 0) ? 1 : 0;
+ }
+
// Make the threads, let them run, and wait for them to finish
for ( int i = 0; i < NUMTHREADS; ++i )
std::__libcpp_thread_create ( threads + i, thread_code, (void *) (thread_globals + i));
@@ -65,10 +77,5 @@ int main() {
}
}
return retVal;
-#else // _LIBCXXABI_HAS_NO_THREADS
- size_t thread_globals;
- thread_code(&thread_globals);
- // Check that __cxa_get_globals() is not NULL.
- return (thread_globals == 0) ? 1 : 0;
#endif // !_LIBCXXABI_HAS_NO_THREADS
}
More information about the llvm-branch-commits
mailing list