From 9ac3e1238472a780592755b6ad9465b25353cc45 Mon Sep 17 00:00:00 2001 From: Zibi Sarbinowski Date: Thu, 3 Feb 2022 15:51:14 -0600 Subject: [PATCH] Adding internal threading support for POSIX(OFF) --- libcxx/include/__threading_support | 9 +- libcxx/src/CMakeLists.txt | 1 + libcxx/src/debug.cpp | 2 +- .../src/include/internal_threading_support.h | 482 ++++++++++++++++++ libcxx/src/locale.cpp | 2 + libcxx/src/memory.cpp | 2 +- libcxx/src/random_shuffle.cpp | 2 +- libcxxabi/src/cxa_exception_storage.cpp | 7 +- libcxxabi/src/cxa_guard_impl.h | 2 +- libcxxabi/src/fallback_malloc.cpp | 2 +- .../test/test_exception_storage.pass.cpp | 19 +- 11 files changed, 516 insertions(+), 14 deletions(-) create mode 100644 libcxx/src/include/internal_threading_support.h 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(__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 #include -#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 }