rmaprath updated this revision to Diff 60017.
rmaprath added a comment.
Addressed comments from @mclow.lists.
http://reviews.llvm.org/D20328
Files:
CMakeLists.txt
include/__config
include/__config_site.in
include/__dynamic_threading
include/__threading_support
include/thread
lib/CMakeLists.txt
src/algorithm.cpp
src/memory.cpp
src/mutex.cpp
src/thread.cpp
test/CMakeLists.txt
test/libcxx/test/config.py
test/lit.site.cfg.in
test/std/thread/thread.condition/thread.condition.condvar/native_handle.pass.cpp
test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/native_handle.pass.cpp
test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/native_handle.pass.cpp
test/std/thread/thread.threads/thread.thread.class/thread.thread.member/native_handle.pass.cpp
test/std/thread/thread.threads/thread.thread.class/types.pass.cpp
test/support/external_threads.cpp
Index: test/support/external_threads.cpp
===================================================================
--- /dev/null
+++ test/support/external_threads.cpp
@@ -0,0 +1,340 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SUPPORT_EXTERNAL_THREADS
+#define SUPPORT_EXTERNAL_THREADS
+
+#include <__threading_support>
+
+// Only define these symbols if using the __dynamic_threading header
+#if defined(_LIBCPP_DYNAMIC_THREADING)
+
+#include <pthread.h>
+#include <stdlib.h>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+/* In the pthread-based (or statically-threaded) libc++ variant, pthread
+ primitives (like pthread_mutex_t) become part of the internal states of the
+ corresponding C++ constructs (e.g. C++ mutex class holds an internal
+ pthread_mutex_t object). In contrast, in the externally-threaded libc++
+ variant, C++ constructs hold (opaque) pointers to the underlying platform-
+ defined threading primitives. The following macros are used to convert the
+ opaque pointer types held within the C++ constructs and cast them as pointers
+ to the appropriate platform-defined thread primitive type (in this case,
+ pthread types again).
+*/
+#define AS_PTHREAD_MUTPTR(x) reinterpret_cast<pthread_mutex_t*>(x)
+#define AS_PTHREAD_CONDPTR(x) reinterpret_cast<pthread_cond_t*>(x)
+#define AS_PTHREAD_TPTR(x) reinterpret_cast<pthread_t*>(x)
+#define AS_PTHREAD_KPTR(x) reinterpret_cast<pthread_key_t*>(x)
+
+//-- Mutex --//
+
+/* This method is invoked from within the std::recursive_mutex constructor, as
+ such, it does not need to be thread-safe when initializing the *__m pointer.
+*/
+int __libcpp_recursive_mutex_init(__libcpp_mutex_t* __m)
+{
+ // Populate the internal opaque pointer *__m
+ pthread_mutex_t *mut = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t));
+ if (mut == nullptr)
+ return -1;
+ *__m = reinterpret_cast<__libcpp_mutex_t> (mut);
+
+ // Initialize the allocated pthread_mutex_t object as a recursive mutex
+ pthread_mutexattr_t attr;
+ int __ec = pthread_mutexattr_init(&attr);
+ if (__ec)
+ goto fail;
+
+ __ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ if (__ec)
+ {
+ pthread_mutexattr_destroy(&attr);
+ goto fail;
+ }
+
+ __ec = pthread_mutex_init(AS_PTHREAD_MUTPTR(*__m), &attr);
+ if (__ec)
+ {
+ pthread_mutexattr_destroy(&attr);
+ goto fail;
+ }
+
+ __ec = pthread_mutexattr_destroy(&attr);
+ if (__ec)
+ {
+ pthread_mutex_destroy(AS_PTHREAD_MUTPTR(*__m));
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ free(*__m);
+ return __ec;
+}
+
+/* C++11 standard requires mutex and condition_variable constructors to be
+ constexpr qualifying. This prohibits any prospects of calling a runtime
+ initialization routine from within mutex / condition_varialbe constructors.
+ For this reason, the external thread API must adopt an initialize-on-first-
+ use policy for mutexes and condition variables. With this strategy, we need
+ to be especially careful when initializing the internal opaque pointer *__m,
+ as multiple threads could attempt to lock the same mutex at once. In the
+ following routine, I've used a plain pthread mutex to make this initialization
+ thread-safe. It's also possible to use atomic compare-exchange builtins (where
+ available) to achieve the same goal.
+*/
+pthread_mutex_t mutex_init_access = PTHREAD_MUTEX_INITIALIZER;
+
+int mutex_safe_init(volatile __libcpp_mutex_t* __m) {
+ pthread_mutex_lock(&mutex_init_access);
+ if (*__m == nullptr) {
+ pthread_mutex_t *mut = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t));
+ if (mut == nullptr)
+ return -1;
+ if (pthread_mutex_init(mut, nullptr)) {
+ free(mut);
+ return -1;
+ }
+
+ *__m = reinterpret_cast<__libcpp_mutex_t> (mut);
+ }
+ pthread_mutex_unlock(&mutex_init_access);
+
+ return 0;
+}
+
+int __libcpp_mutex_lock(__libcpp_mutex_t* __m)
+{
+ // initialize-on-first-use
+ if (*__m == nullptr && mutex_safe_init(__m))
+ return -1;
+
+ return pthread_mutex_lock(AS_PTHREAD_MUTPTR(*__m));
+}
+
+int __libcpp_mutex_trylock(__libcpp_mutex_t* __m)
+{
+ // initialize-on-first-use
+ if (*__m == nullptr && mutex_safe_init(__m))
+ return -1;
+
+ return pthread_mutex_trylock(AS_PTHREAD_MUTPTR(*__m));
+}
+
+int __libcpp_mutex_unlock(__libcpp_mutex_t* __m)
+{
+ if (*__m == nullptr)
+ return 0;
+
+ return pthread_mutex_unlock(AS_PTHREAD_MUTPTR(*__m));
+}
+
+int __libcpp_mutex_destroy(__libcpp_mutex_t* __m) {
+ if (*__m == nullptr)
+ return 0;
+
+ int ec = pthread_mutex_destroy(AS_PTHREAD_MUTPTR(*__m));
+ free(*__m);
+ return ec;
+}
+
+//-- Condition variable --//
+
+int __libcpp_condvar_signal(__libcpp_condvar_t* __cv)
+{
+ if (*__cv == nullptr)
+ return 0;
+
+ return pthread_cond_signal(AS_PTHREAD_CONDPTR(*__cv));
+}
+
+int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv)
+{
+ if (*__cv == nullptr)
+ return 0;
+
+ return pthread_cond_broadcast(AS_PTHREAD_CONDPTR(*__cv));
+}
+
+// See comment for mutex_safe_init()
+pthread_mutex_t condvar_init_access = PTHREAD_MUTEX_INITIALIZER;
+
+int condvar_safe_init(__libcpp_condvar_t* __cv) {
+ pthread_mutex_lock(&condvar_init_access);
+ if (*__cv == nullptr) {
+ pthread_cond_t *cv = (pthread_cond_t*) malloc(sizeof(pthread_cond_t));
+ if (cv == nullptr)
+ return -1;
+ if (pthread_cond_init(cv, nullptr)) {
+ free(cv);
+ return -1;
+ }
+
+ *__cv = reinterpret_cast<__libcpp_condvar_t> (cv);
+ }
+ pthread_mutex_unlock(&condvar_init_access);
+
+ return 0;
+}
+
+int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m)
+{
+ // initialize-on-first-use
+ if (*__cv == nullptr && condvar_safe_init(__cv))
+ return -1;
+
+ return pthread_cond_wait(AS_PTHREAD_CONDPTR(*__cv), AS_PTHREAD_MUTPTR(*__m));
+}
+
+int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, timespec* __ts)
+{
+ // initialize-on-first-use
+ if (*__cv == nullptr && condvar_safe_init(__cv))
+ return -1;
+
+ return pthread_cond_timedwait(AS_PTHREAD_CONDPTR(*__cv), AS_PTHREAD_MUTPTR(*__m), __ts);
+}
+
+int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv)
+{
+ if (*__cv == nullptr)
+ return 0;
+
+ int ec = pthread_cond_destroy(AS_PTHREAD_CONDPTR(*__cv));
+ free(*__cv);
+ return ec;
+}
+
+//-- Thread --//
+
+bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2) {
+ return pthread_equal(t1, t2) != 0;
+}
+
+bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2) {
+ return t1 < t2;
+}
+
+/* This method is invoked from within the std::thread constructor, as such, it
+ does not need to be thread-safe when initializing the *__t pointer.
+*/
+int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg)
+{
+ pthread_t *td = (pthread_t*) malloc(sizeof(pthread_t));
+ if (td == nullptr)
+ return -1;
+
+ *__t = reinterpret_cast<__libcpp_thread_t>(td);
+
+ return pthread_create(AS_PTHREAD_TPTR(*__t), 0, __func, __arg);
+}
+
+__libcpp_thread_id __libcpp_thread_get_current_id()
+{
+ return static_cast<__libcpp_thread_id>(pthread_self());
+}
+
+__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t)
+{
+ if (*__t == 0)
+ return 0;
+
+ return static_cast<__libcpp_thread_id>(*AS_PTHREAD_TPTR(*__t));
+}
+
+int __libcpp_thread_join(__libcpp_thread_t* __t)
+{
+ // Must return non-zero if the internal state has already been invalidated
+ // This can happen for example, if std::thread::join() has been called
+ // before.
+ if (*__t == 0)
+ return -1;
+
+ // Must cleanup memory allocated in __libcpp_thread_create() here, as the
+ // library will set *__t to zero after this call.
+ int ec = pthread_join(*AS_PTHREAD_TPTR(*__t), 0);
+ free(*__t);
+ return ec;
+}
+
+int __libcpp_thread_detach(__libcpp_thread_t* __t)
+{
+ // Must return non-zero if the internal state has already been invalidated
+ // This can happen for example, if std::thread::detach() has been called
+ // before.
+ if (*__t == 0)
+ return -1;
+
+ // Must cleanup memory allocated in __libcpp_thread_create() here, as the
+ // library will set *__t to zero after this call.
+ int ec = pthread_detach(*AS_PTHREAD_TPTR(*__t));
+ free(*__t);
+ return ec;
+}
+
+void __libcpp_thread_yield()
+{
+ sched_yield();
+}
+
+void __libcpp_thread_finalize(__libcpp_thread_t* __t) {
+ // Cleanup memory allocated in __libcpp_thread_create()
+ if (*__t != 0)
+ free(*__t);
+}
+
+//-- TLS --//
+
+/* This method is invoked from within the std::__thread_specific_ptr
+ constructor, as such, it does not need to be thread-safe when initializing
+ the *__t pointer.
+*/
+int __libcpp_tl_create(__libcpp_tl_key* __key, void (*__at_exit)(void*))
+{
+ pthread_key_t *key = (pthread_key_t*) malloc(sizeof(pthread_key_t));
+ if (key == nullptr)
+ return -1;
+
+ *__key = reinterpret_cast<__libcpp_tl_key>(key);
+
+ return pthread_key_create(AS_PTHREAD_KPTR(*__key), __at_exit);
+}
+
+void* __libcpp_tl_get(__libcpp_tl_key __key)
+{
+ return pthread_getspecific(*AS_PTHREAD_KPTR(__key));
+}
+
+void __libcpp_tl_set(__libcpp_tl_key __key, void* __p)
+{
+ pthread_setspecific(*AS_PTHREAD_KPTR(__key), __p);
+}
+
+void __libcpp_tl_finalize(__libcpp_tl_key __key)
+{
+ // Only deallocate the memory allocated in __libcpp_tl_create. Do not
+ // call pthread_key_delete(__key). See comment for __thread_specific_ptr
+ // destructor.
+ if (__key != nullptr)
+ free(__key);
+}
+
+#undef AS_PTHREAD_MUTPTR
+#undef AS_PTHREAD_CONDPTR
+#undef AS_PTHREAD_TPTR
+#undef AS_PTHREAD_KPTR
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_DYNAMIC_THREADING
+
+#endif // SUPPORT_EXTERNAL_THREADS
Index: test/std/thread/thread.threads/thread.thread.class/types.pass.cpp
===================================================================
--- test/std/thread/thread.threads/thread.thread.class/types.pass.cpp
+++ test/std/thread/thread.threads/thread.thread.class/types.pass.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: libcpp-has-no-threads, libcpp-has-thread-api-external
// <thread>
Index: test/std/thread/thread.threads/thread.thread.class/thread.thread.member/native_handle.pass.cpp
===================================================================
--- test/std/thread/thread.threads/thread.thread.class/thread.thread.member/native_handle.pass.cpp
+++ test/std/thread/thread.threads/thread.thread.class/thread.thread.member/native_handle.pass.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: libcpp-has-no-threads, libcpp-has-thread-api-external
// <thread>
Index: test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/native_handle.pass.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/native_handle.pass.cpp
+++ test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/native_handle.pass.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: libcpp-has-no-threads, libcpp-has-thread-api-external
// <mutex>
Index: test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/native_handle.pass.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/native_handle.pass.cpp
+++ test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/native_handle.pass.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: libcpp-has-no-threads, libcpp-has-thread-api-external
// <mutex>
Index: test/std/thread/thread.condition/thread.condition.condvar/native_handle.pass.cpp
===================================================================
--- test/std/thread/thread.condition/thread.condition.condvar/native_handle.pass.cpp
+++ test/std/thread/thread.condition/thread.condition.condvar/native_handle.pass.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: libcpp-has-no-threads, libcpp-has-thread-api-external
// <condition_variable>
Index: test/lit.site.cfg.in
===================================================================
--- test/lit.site.cfg.in
+++ test/lit.site.cfg.in
@@ -23,6 +23,7 @@
config.llvm_unwinder = "@LIBCXXABI_USE_LLVM_UNWINDER@"
config.use_libatomic = "@LIBCXX_HAS_ATOMIC_LIB@"
config.libcxxabi_shared = "@LIBCXXABI_ENABLE_SHARED@"
+config.libcxx_external_thread_api = "@LIBCXX_HAS_EXTERNAL_THREAD_API@"
# Let the main config do the real work.
lit_config.load_config(config, "@LIBCXX_SOURCE_DIR@/test/lit.cfg")
Index: test/libcxx/test/config.py
===================================================================
--- test/libcxx/test/config.py
+++ test/libcxx/test/config.py
@@ -473,6 +473,10 @@
self.cxx.link_flags += [abs_path]
else:
self.cxx.link_flags += ['-lc++']
+ # This needs to come after -lc++ as we want its unresolved thread-api symbols
+ # to be picked up from this one.
+ if self.get_lit_bool('libcxx_external_thread_api', default=False):
+ self.cxx.link_flags += ['-lc++external_threading_support']
def configure_link_flags_abi_library(self):
cxx_abi = self.get_lit_conf('cxx_abi', 'libcxxabi')
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -18,6 +18,7 @@
pythonize_bool(LIBCXXABI_ENABLE_SHARED)
pythonize_bool(LIBCXXABI_USE_LLVM_UNWINDER)
pythonize_bool(LIBCXX_HAS_ATOMIC_LIB)
+pythonize_bool(LIBCXX_HAS_EXTERNAL_THREAD_API)
# The tests shouldn't link to any ABI library when it has been linked into
# libc++ statically or via a linker script.
@@ -48,10 +49,14 @@
set(experimental_dep cxx_experimental)
endif()
+if (LIBCXX_HAS_EXTERNAL_THREAD_API)
+ set(external_threading_support_dep cxx_external_threading_support)
+endif()
+
add_lit_testsuite(check-libcxx
"Running libcxx tests"
${CMAKE_CURRENT_BINARY_DIR}
- DEPENDS cxx ${experimental_dep})
+ DEPENDS cxx ${experimental_dep} ${external_threading_support_dep})
if (LIBCXX_GENERATE_COVERAGE)
include(CodeCoverage)
Index: src/thread.cpp
===================================================================
--- src/thread.cpp
+++ src/thread.cpp
@@ -39,6 +39,9 @@
thread::~thread()
{
+#if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
+ __libcpp_thread_finalize(&__t_);
+#endif
if (__t_ != 0)
terminate();
}
Index: src/mutex.cpp
===================================================================
--- src/mutex.cpp
+++ src/mutex.cpp
@@ -195,8 +195,23 @@
// keep in sync with: 7741191.
#ifndef _LIBCPP_HAS_NO_THREADS
+# if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
+static mutex mut;
+static condition_variable cv;
+# define LOCK_INIT() unique_lock<mutex> lk(mut);
+# define LOCK_LOCK() lk.lock();
+# define LOCK_UNLOCK() lk.unlock();
+# define CV_WAIT_LOCK() cv.wait(lk);
+# define CV_NOTIFY_ALL() cv.notify_all();
+# else
static __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER;
static __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER;
+# define LOCK_INIT() __libcpp_mutex_lock(&mut);
+# define LOCK_LOCK() __libcpp_mutex_lock(&mut);
+# define LOCK_UNLOCK() __libcpp_mutex_unlock(&mut);
+# define CV_WAIT_LOCK() __libcpp_condvar_wait(&cv, &mut);
+# define CV_NOTIFY_ALL() __libcpp_condvar_broadcast(&cv);
+# endif
#endif
/// NOTE: Changes to flag are done via relaxed atomic stores
@@ -225,9 +240,9 @@
#endif // _LIBCPP_NO_EXCEPTIONS
}
#else // !_LIBCPP_HAS_NO_THREADS
- __libcpp_mutex_lock(&mut);
+ LOCK_INIT()
while (flag == 1)
- __libcpp_condvar_wait(&cv, &mut);
+ CV_WAIT_LOCK()
if (flag == 0)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
@@ -235,26 +250,26 @@
{
#endif // _LIBCPP_NO_EXCEPTIONS
__libcpp_relaxed_store(&flag, 1ul);
- __libcpp_mutex_unlock(&mut);
+ LOCK_UNLOCK()
func(arg);
- __libcpp_mutex_lock(&mut);
+ LOCK_LOCK()
__libcpp_relaxed_store(&flag, ~0ul);
- __libcpp_mutex_unlock(&mut);
- __libcpp_condvar_broadcast(&cv);
+ LOCK_UNLOCK()
+ CV_NOTIFY_ALL()
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
- __libcpp_mutex_lock(&mut);
+ LOCK_LOCK()
__libcpp_relaxed_store(&flag, 0ul);
- __libcpp_mutex_unlock(&mut);
- __libcpp_condvar_broadcast(&cv);
+ LOCK_UNLOCK()
+ CV_NOTIFY_ALL()
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
}
else
- __libcpp_mutex_unlock(&mut);
+ LOCK_UNLOCK()
#endif // !_LIBCPP_HAS_NO_THREADS
}
Index: src/memory.cpp
===================================================================
--- src/memory.cpp
+++ src/memory.cpp
@@ -127,6 +127,9 @@
#if defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS)
static const std::size_t __sp_mut_count = 16;
+#if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
+static mutex mut_back_imp[__sp_mut_count];
+#else
static __libcpp_mutex_t mut_back_imp[__sp_mut_count] =
{
_LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
@@ -134,6 +137,7 @@
_LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
_LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER
};
+#endif
static mutex* mut_back = reinterpret_cast<std::mutex*>(mut_back_imp);
Index: src/algorithm.cpp
===================================================================
--- src/algorithm.cpp
+++ src/algorithm.cpp
@@ -48,14 +48,22 @@
template unsigned __sort5<__less<long double>&, long double*>(long double*, long double*, long double*, long double*, long double*, __less<long double>&);
#ifndef _LIBCPP_HAS_NO_THREADS
+# if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
+static mutex __rs_mut;
+# define LOCK_LOCK() __rs_mut.lock();
+# define LOCK_UNLOCK() __rs_mut.unlock();
+# else
static __libcpp_mutex_t __rs_mut = _LIBCPP_MUTEX_INITIALIZER;
+# define LOCK_LOCK() __libcpp_mutex_lock(&__rs_mut);
+# define LOCK_UNLOCK() __libcpp_mutex_unlock(&__rs_mut);
+# endif
#endif
unsigned __rs_default::__c_ = 0;
__rs_default::__rs_default()
{
#ifndef _LIBCPP_HAS_NO_THREADS
- __libcpp_mutex_lock(&__rs_mut);
+ LOCK_LOCK()
#endif
__c_ = 1;
}
@@ -69,7 +77,7 @@
{
#ifndef _LIBCPP_HAS_NO_THREADS
if (--__c_ == 0)
- __libcpp_mutex_unlock(&__rs_mut);
+ LOCK_UNLOCK()
#else
--__c_;
#endif
Index: lib/CMakeLists.txt
===================================================================
--- lib/CMakeLists.txt
+++ lib/CMakeLists.txt
@@ -155,6 +155,18 @@
)
endif()
+if (LIBCXX_HAS_EXTERNAL_THREAD_API)
+ file(GLOB LIBCXX_EXTERNAL_THREADING_SUPPORT_SOURCES ../test/support/external_threads.cpp)
+ add_library(cxx_external_threading_support STATIC ${LIBCXX_EXTERNAL_THREADING_SUPPORT_SOURCES})
+ target_link_libraries(cxx_external_threading_support cxx)
+
+ set_target_properties(cxx_external_threading_support
+ PROPERTIES
+ COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS}"
+ OUTPUT_NAME "c++external_threading_support"
+ )
+endif()
+
# Generate a linker script inplace of a libc++.so symlink. Rerun this command
# after cxx builds.
if (LIBCXX_ENABLE_ABI_LINKER_SCRIPT)
Index: include/thread
===================================================================
--- include/thread
+++ include/thread
@@ -188,6 +188,10 @@
// so this destructor is only invoked during program termination. Invoking
// pthread_key_delete(__key_) may prevent other threads from deleting their
// thread local data. For this reason we leak the key.
+
+#if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
+ __libcpp_tl_finalize(__key_);
+#endif
}
template <class _Tp>
Index: include/__threading_support
===================================================================
--- include/__threading_support
+++ include/__threading_support
@@ -24,10 +24,10 @@
#include <sched.h>
#endif
-_LIBCPP_BEGIN_NAMESPACE_STD
-
#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
+_LIBCPP_BEGIN_NAMESPACE_STD
+
// Mutex
#define _LIBCPP_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
typedef pthread_mutex_t __libcpp_mutex_t;
@@ -194,12 +194,26 @@
pthread_setspecific(__key, __p);
}
-#else // !_LIBCPP_HAS_THREAD_API_PTHREAD
+_LIBCPP_END_NAMESPACE_STD
+
+#elif defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
+/* !!!FOR LIBRARY IMPLEMENTORS ONLY!!! */
+# if !defined(__has_include) || __has_include(<__static_threading>)
+ /* For compiling libc++ against an external thread implementation.
+ This header should provide the definitions of various __libcpp_*
+ functions declared above. These functions should be defined as
+ _LIBCPP_ALWAYS_INLINE so that they are inlined into the library
+ code. */
+# include<__static_threading>
+# else
+ /* For compiling libc++ with an externalized (runtime) thread API. This
+ is the default when no __static_threading header is provided. */
+# include<__dynamic_threading>
+# endif
+#else
#error "No thread API selected."
#endif
-_LIBCPP_END_NAMESPACE_STD
-
#endif // _LIBCPP_HAS_NO_THREADS
#endif // _LIBCPP_THREADING_SUPPORT
Index: include/__dynamic_threading
===================================================================
--- /dev/null
+++ include/__dynamic_threading
@@ -0,0 +1,76 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_DYNAMIC_THREADING
+#define _LIBCPP_DYNAMIC_THREADING
+
+#include <__config>
+
+#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
+#pragma GCC system_header
+#endif
+
+#if !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
+# error "Only valid when _LIBCPP_HAS_THREAD_API_EXTERNAL is defined"
+#endif
+
+#include <time.h>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// Mutex
+#define _LIBCPP_MUTEX_INITIALIZER nullptr
+struct __libcpp_platform_mutex_t;
+typedef __libcpp_platform_mutex_t *__libcpp_mutex_t;
+
+int __libcpp_recursive_mutex_init(__libcpp_mutex_t* __m);
+int __libcpp_mutex_lock(__libcpp_mutex_t* __m);
+int __libcpp_mutex_trylock(__libcpp_mutex_t* __m);
+int __libcpp_mutex_unlock(__libcpp_mutex_t* __m);
+int __libcpp_mutex_destroy(__libcpp_mutex_t* __m);
+
+// Condition variable
+#define _LIBCPP_CONDVAR_INITIALIZER nullptr
+struct __libcpp_platform_condvar_t;
+typedef __libcpp_platform_condvar_t *__libcpp_condvar_t;
+
+int __libcpp_condvar_signal(__libcpp_condvar_t* __cv);
+int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv);
+int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m);
+int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, timespec* __ts);
+int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv);
+
+// Thread id
+typedef unsigned long __libcpp_thread_id;
+bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2);
+bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2);
+
+// Thread
+struct __libcpp_platform_thread_t;
+typedef __libcpp_platform_thread_t *__libcpp_thread_t;
+int __libcpp_thread_create(__libcpp_thread_t* __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* __t);
+int __libcpp_thread_join(__libcpp_thread_t* __t);
+int __libcpp_thread_detach(__libcpp_thread_t* __t);
+void __libcpp_thread_yield();
+void __libcpp_thread_finalize(__libcpp_thread_t* __t);
+
+// Thread local storage
+struct __libcpp_platform_tlskey_t;
+typedef __libcpp_platform_tlskey_t *__libcpp_tl_key;
+int __libcpp_tl_create(__libcpp_tl_key* __key, void (*__at_exit)(void*));
+void* __libcpp_tl_get(__libcpp_tl_key __key);
+void __libcpp_tl_set(__libcpp_tl_key __key, void* __p);
+void __libcpp_tl_finalize(__libcpp_tl_key __key);
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_DYNAMIC_THREADING
Index: include/__config_site.in
===================================================================
--- include/__config_site.in
+++ include/__config_site.in
@@ -20,5 +20,6 @@
#cmakedefine _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS
#cmakedefine _LIBCPP_HAS_MUSL_LIBC
#cmakedefine _LIBCPP_HAS_THREAD_API_PTHREAD
+#cmakedefine _LIBCPP_HAS_THREAD_API_EXTERNAL
#endif // _LIBCPP_CONFIG_SITE
Index: include/__config
===================================================================
--- include/__config
+++ include/__config
@@ -813,7 +813,9 @@
#endif
// Thread API
-#if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
+#if !defined(_LIBCPP_HAS_NO_THREADS) && \
+ !defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && \
+ !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
# if defined(__FreeBSD__) || \
defined(__NetBSD__) || \
defined(__linux__) || \
@@ -831,6 +833,11 @@
_LIBCPP_HAS_NO_THREADS is not defined.
#endif
+#if defined(_LIBCPP_HAS_NO_THREADS) && defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
+# error _LIBCPP_HAS_EXTERNAL_THREAD_API may not be defined when \
+ _LIBCPP_HAS_NO_THREADS is defined.
+#endif
+
#if defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK) && !defined(_LIBCPP_HAS_NO_THREADS)
# error _LIBCPP_HAS_NO_MONOTONIC_CLOCK may only be defined when \
_LIBCPP_HAS_NO_THREADS is defined.
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -126,7 +126,10 @@
"Build libc++ with support for a monotonic clock.
This option may only be set to OFF when LIBCXX_ENABLE_THREADS=OFF." ON)
option(LIBCXX_HAS_MUSL_LIBC "Build libc++ with support for the Musl C library" OFF)
-option(LIBCXX_HAS_PTHREAD_API "Ignore auto-detection and force use of pthread API" OFF)
+option(LIBCXX_HAS_PTHREAD_THREAD_API "Ignore auto-detection and force use of pthread API" OFF)
+option(LIBCXX_HAS_EXTERNAL_THREAD_API
+ "Build libc++ with an externalized threading API.
+ This option may only be set to ON when LIBCXX_ENABLE_THREADS=ON." OFF)
# Misc options ----------------------------------------------------------------
# FIXME: Turn -pedantic back ON. It is currently off because it warns
@@ -166,15 +169,20 @@
# Check option configurations
#===============================================================================
-# Ensure LIBCXX_ENABLE_MONOTONIC_CLOCK is set to ON only when
+# Ensure LIBCXX_ENABLE_MONOTONIC_CLOCK is always set to ON when
# LIBCXX_ENABLE_THREADS is on.
if(LIBCXX_ENABLE_THREADS AND NOT LIBCXX_ENABLE_MONOTONIC_CLOCK)
message(FATAL_ERROR "LIBCXX_ENABLE_MONOTONIC_CLOCK can only be set to OFF"
" when LIBCXX_ENABLE_THREADS is also set to OFF.")
endif()
-if(LIBCXX_HAS_PTHREAD_API AND NOT LIBCXX_ENABLE_THREADS)
- message(FATAL_ERROR "LIBCXX_HAS_PTHREAD_API can only be set to ON"
+if(LIBCXX_HAS_PTHREAD_THREAD_API AND NOT LIBCXX_ENABLE_THREADS)
+ message(FATAL_ERROR "LIBCXX_HAS_PTHREAD_THREAD_API can only be set to ON"
+ " when LIBCXX_ENABLE_THREADS is also set to ON.")
+endif()
+
+if(LIBCXX_HAS_EXTERNAL_THREAD_API AND NOT LIBCXX_ENABLE_THREADS)
+ message(FATAL_ERROR "LIBCXX_HAS_EXTERNAL_THREAD_API can only be set to ON"
" when LIBCXX_ENABLE_THREADS is also set to ON.")
endif()
@@ -394,7 +402,8 @@
config_define_if_not(LIBCXX_ENABLE_MONOTONIC_CLOCK _LIBCPP_HAS_NO_MONOTONIC_CLOCK)
config_define_if_not(LIBCXX_ENABLE_THREAD_UNSAFE_C_FUNCTIONS _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS)
-config_define_if(LIBCXX_HAS_PTHREAD_API _LIBCPP_HAS_THREAD_API_PTHREAD)
+config_define_if(LIBCXX_HAS_PTHREAD_THREAD_API _LIBCPP_HAS_THREAD_API_PTHREAD)
+config_define_if(LIBCXX_HAS_EXTERNAL_THREAD_API _LIBCPP_HAS_THREAD_API_EXTERNAL)
config_define_if(LIBCXX_HAS_MUSL_LIBC _LIBCPP_HAS_MUSL_LIBC)
if (LIBCXX_NEEDS_SITE_CONFIG)
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits