[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