espositofulvio updated the summary for this revision. espositofulvio updated this revision to Diff 34104. espositofulvio added a comment.
- Addressed possible ABI breaks - Reverted to not using a __config_file as @jroelofs has two separate patch for that Repository: rL LLVM http://reviews.llvm.org/D11781 Files: .gitignore CMakeLists.txt include/__config include/__mutex_base include/mutex include/support/condition_variable.h include/support/mutex.h include/support/pthread/condition_variable.h include/support/pthread/mutex.h include/support/pthread/thread.h include/support/thread.h include/thread lib/CMakeLists.txt src/algorithm.cpp src/condition_variable.cpp src/memory.cpp src/mutex.cpp src/support/pthread/condition_variable.cpp src/support/pthread/mutex.cpp src/support/pthread/thread.cpp src/thread.cpp
Index: src/thread.cpp =================================================================== --- src/thread.cpp +++ src/thread.cpp @@ -32,6 +32,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD +using namespace __libcpp_support; + thread::~thread() { if (__t_ != 0) @@ -41,7 +43,7 @@ void thread::join() { - int ec = pthread_join(__t_, 0); + int ec = __os_thread_join(__t_); #ifndef _LIBCPP_NO_EXCEPTIONS if (ec) throw system_error(error_code(ec, system_category()), "thread::join failed"); @@ -57,7 +59,7 @@ int ec = EINVAL; if (__t_ != 0) { - ec = pthread_detach(__t_); + ec = __os_thread_detach(__t_); if (ec == 0) __t_ = 0; } @@ -104,34 +106,12 @@ namespace this_thread { -void -sleep_for(const chrono::nanoseconds& ns) +void sleep_for(const chrono::nanoseconds& ns) { - using namespace chrono; - if (ns > nanoseconds::zero()) - { - seconds s = duration_cast<seconds>(ns); - timespec ts; - typedef decltype(ts.tv_sec) ts_sec; - _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max(); - if (s.count() < ts_sec_max) - { - ts.tv_sec = static_cast<ts_sec>(s.count()); - ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns-s).count()); - } - else - { - ts.tv_sec = ts_sec_max; - ts.tv_nsec = giga::num - 1; - } - - while (nanosleep(&ts, &ts) == -1 && errno == EINTR) - ; - } + __libcpp_support::__os_sleep_for(ns); } -} // this_thread - +} __thread_specific_ptr<__thread_struct>& __thread_local_data() { Index: src/support/pthread/thread.cpp =================================================================== --- /dev/null +++ src/support/pthread/thread.cpp @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===---------------------- support/pthread/thread.cpp --------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "__config" + +#include <ostream> +#include <chrono> +#define _LIBCPP_INCLUDE_THREAD_API +#include <support/pthread/thread.h> +#undef _LIBCPP_INCLUDE_THREAD_API + +_LIBCPP_BEGIN_NAMESPACE_STD +#ifndef _LIBCPP_HAS_NO_THREADS + +namespace __libcpp_support +{ + +void +__os_sleep_for(const chrono::nanoseconds& ns) +{ + using namespace chrono; + if (ns > nanoseconds::zero()) + { + seconds s = duration_cast<seconds>(ns); + timespec ts; + typedef decltype(ts.tv_sec) ts_sec; + _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max(); + if (s.count() < ts_sec_max) + { + ts.tv_sec = static_cast<ts_sec>(s.count()); + ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns-s).count()); + } + else + { + ts.tv_sec = ts_sec_max; + ts.tv_nsec = giga::num - 1; + } + + while (nanosleep(&ts, &ts) == -1 && errno == EINTR) + ; + } +} + +} //namespace __libcpp_support + +#endif // _LIBCPP_HAS_NO_THREADS +_LIBCPP_END_NAMESPACE_STD Index: src/support/pthread/mutex.cpp =================================================================== --- /dev/null +++ src/support/pthread/mutex.cpp @@ -0,0 +1,131 @@ +// -*- C++ -*- +//===---------------------- support/pthread/thread.cpp --------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "__config" + +#include <chrono> +#include <system_error> +#include "../../include/atomic_support.h" + +#define _LIBCPP_INCLUDE_THREAD_API +#include <support/pthread/mutex.h> +#undef _LIBCPP_INCLUDE_THREAD_API + +_LIBCPP_BEGIN_NAMESPACE_STD +#ifndef _LIBCPP_HAS_NO_THREADS + +namespace __libcpp_support +{ + +void __os_recursive_mutex_init(__os_mutex* __m) +{ + 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(__m, &attr); + if (ec) + { + pthread_mutexattr_destroy(&attr); + goto fail; + } + ec = pthread_mutexattr_destroy(&attr); + if (ec) + { + pthread_mutex_destroy(__m); + goto fail; + } + return; +fail: + __throw_system_error(ec, "recursive_mutex constructor failed"); +} + +#endif // _LIBCPP_HAS_NO_THREADS + +// If dispatch_once_f ever handles C++ exceptions, and if one can get to it +// without illegal macros (unexpected macros not beginning with _UpperCase or +// __lowercase), and if it stops spinning waiting threads, then call_once should +// call into dispatch_once_f instead of here. Relevant radar this code needs to +// keep in sync with: 7741191. + +#ifndef _LIBCPP_HAS_NO_THREADS +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; +#endif + +/// NOTE: Changes to flag are done via relaxed atomic stores +/// even though the accesses are protected by a mutex because threads +/// just entering 'call_once` concurrently read from flag. +void +__os_call_once(volatile unsigned long& flag, void* arg, void(*func)(void*)) +{ +#if defined(_LIBCPP_HAS_NO_THREADS) + if (flag == 0) + { +#ifndef _LIBCPP_NO_EXCEPTIONS + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + flag = 1; + func(arg); + flag = ~0ul; +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + flag = 0ul; + throw; + } +#endif // _LIBCPP_NO_EXCEPTIONS + } +#else // !_LIBCPP_HAS_NO_THREADS + pthread_mutex_lock(&mut); + while (flag == 1) + pthread_cond_wait(&cv, &mut); + if (flag == 0) + { +#ifndef _LIBCPP_NO_EXCEPTIONS + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + __libcpp_relaxed_store(&flag, 1ul); + pthread_mutex_unlock(&mut); + func(arg); + pthread_mutex_lock(&mut); + __libcpp_relaxed_store(&flag, ~0ul); + pthread_mutex_unlock(&mut); + pthread_cond_broadcast(&cv); +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + pthread_mutex_lock(&mut); + __libcpp_relaxed_store(&flag, 0ul); + pthread_mutex_unlock(&mut); + pthread_cond_broadcast(&cv); + throw; + } +#endif // _LIBCPP_NO_EXCEPTIONS + } + else + pthread_mutex_unlock(&mut); +#endif // !_LIBCPP_HAS_NO_THREADS + +} + +} //namespace __libcpp_support + +_LIBCPP_END_NAMESPACE_STD Index: src/support/pthread/condition_variable.cpp =================================================================== --- /dev/null +++ src/support/pthread/condition_variable.cpp @@ -0,0 +1,55 @@ +// -*- C++ -*- +//===---------------------- support/pthread/thread.cpp --------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "__config" + +#include <chrono> +#include "system_error" +#define _LIBCPP_INCLUDE_THREAD_API +#include <support/pthread/condition_variable.h> +#undef _LIBCPP_INCLUDE_THREAD_API + +_LIBCPP_BEGIN_NAMESPACE_STD +#ifndef _LIBCPP_HAS_NO_THREADS + +namespace __libcpp_support +{ + +void __os_cond_var_timed_wait(__os_cond_var* cv, + __os_mutex* m, + chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp) +{ + using namespace chrono; + nanoseconds d = tp.time_since_epoch(); + if (d > nanoseconds(0x59682F000000E941)) + d = nanoseconds(0x59682F000000E941); + timespec ts; + seconds s = duration_cast<seconds>(d); + typedef decltype(ts.tv_sec) ts_sec; + _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max(); + if (s.count() < ts_sec_max) + { + ts.tv_sec = static_cast<ts_sec>(s.count()); + ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((d - s).count()); + } + else + { + ts.tv_sec = ts_sec_max; + ts.tv_nsec = giga::num - 1; + } + int ec = pthread_cond_timedwait(cv, m, &ts); + if (ec != 0 && ec != ETIMEDOUT) + __throw_system_error(ec, "condition_variable timed_wait failed"); +} + +} //namespace __libcpp_support + +#endif // _LIBCPP_HAS_NO_THREADS +_LIBCPP_END_NAMESPACE_STD Index: src/mutex.cpp =================================================================== --- src/mutex.cpp +++ src/mutex.cpp @@ -12,100 +12,78 @@ #include "limits" #include "system_error" #include "cassert" -#include "include/atomic_support.h" +#include "support/thread.h" _LIBCPP_BEGIN_NAMESPACE_STD #ifndef _LIBCPP_HAS_NO_THREADS const defer_lock_t defer_lock = {}; const try_to_lock_t try_to_lock = {}; const adopt_lock_t adopt_lock = {}; +using namespace __libcpp_support; + mutex::~mutex() { - pthread_mutex_destroy(&__m_); + __os_mutex_destroy(&__m_); } void mutex::lock() { - int ec = pthread_mutex_lock(&__m_); + int ec = __os_mutex_lock(&__m_); if (ec) __throw_system_error(ec, "mutex lock failed"); } bool mutex::try_lock() _NOEXCEPT { - return pthread_mutex_trylock(&__m_) == 0; + return __os_mutex_trylock(&__m_) == 0; } void mutex::unlock() _NOEXCEPT { - int ec = pthread_mutex_unlock(&__m_); + int ec = __os_mutex_unlock(&__m_); (void)ec; assert(ec == 0); } // recursive_mutex recursive_mutex::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(&__m_, &attr); - if (ec) - { - pthread_mutexattr_destroy(&attr); - goto fail; - } - ec = pthread_mutexattr_destroy(&attr); - if (ec) - { - pthread_mutex_destroy(&__m_); - goto fail; - } - return; -fail: - __throw_system_error(ec, "recursive_mutex constructor failed"); + __os_recursive_mutex_init(&__m_); } recursive_mutex::~recursive_mutex() { - int e = pthread_mutex_destroy(&__m_); + int e = __os_recursive_mutex_destroy(&__m_); (void)e; assert(e == 0); } void recursive_mutex::lock() { - int ec = pthread_mutex_lock(&__m_); + int ec = __os_recursive_mutex_lock(&__m_); if (ec) __throw_system_error(ec, "recursive_mutex lock failed"); } void recursive_mutex::unlock() _NOEXCEPT { - int e = pthread_mutex_unlock(&__m_); + int e = __os_recursive_mutex_unlock(&__m_); (void)e; assert(e == 0); } bool recursive_mutex::try_lock() _NOEXCEPT { - return pthread_mutex_trylock(&__m_) == 0; + return __os_recursive_mutex_trylock(&__m_) == 0; } // timed_mutex @@ -165,9 +143,9 @@ void recursive_timed_mutex::lock() { - pthread_t id = pthread_self(); + __os_thread_id id = __os_get_current_thread_id(); unique_lock<mutex> lk(__m_); - if (pthread_equal(id, __id_)) + if (__os_thread_id_compare(id, __id_) == 0) { if (__count_ == numeric_limits<size_t>::max()) __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached"); @@ -183,9 +161,9 @@ bool recursive_timed_mutex::try_lock() _NOEXCEPT { - pthread_t id = pthread_self(); + __os_thread_id id = __os_get_current_thread_id(); unique_lock<mutex> lk(__m_, try_to_lock); - if (lk.owns_lock() && (__count_ == 0 || pthread_equal(id, __id_))) + if (lk.owns_lock() && (__count_ == 0 || __os_thread_id_compare(id, __id_) == 0)) { if (__count_ == numeric_limits<size_t>::max()) return false; @@ -210,75 +188,9 @@ #endif // !_LIBCPP_HAS_NO_THREADS -// If dispatch_once_f ever handles C++ exceptions, and if one can get to it -// without illegal macros (unexpected macros not beginning with _UpperCase or -// __lowercase), and if it stops spinning waiting threads, then call_once should -// call into dispatch_once_f instead of here. Relevant radar this code needs to -// keep in sync with: 7741191. - -#ifndef _LIBCPP_HAS_NO_THREADS -static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; -#endif - -/// NOTE: Changes to flag are done via relaxed atomic stores -/// even though the accesses are protected by a mutex because threads -/// just entering 'call_once` concurrently read from flag. -void -__call_once(volatile unsigned long& flag, void* arg, void(*func)(void*)) +void __call_once(volatile unsigned long& flag, void* arg, void(*func)(void*)) { -#if defined(_LIBCPP_HAS_NO_THREADS) - if (flag == 0) - { -#ifndef _LIBCPP_NO_EXCEPTIONS - try - { -#endif // _LIBCPP_NO_EXCEPTIONS - flag = 1; - func(arg); - flag = ~0ul; -#ifndef _LIBCPP_NO_EXCEPTIONS - } - catch (...) - { - flag = 0ul; - throw; - } -#endif // _LIBCPP_NO_EXCEPTIONS - } -#else // !_LIBCPP_HAS_NO_THREADS - pthread_mutex_lock(&mut); - while (flag == 1) - pthread_cond_wait(&cv, &mut); - if (flag == 0) - { -#ifndef _LIBCPP_NO_EXCEPTIONS - try - { -#endif // _LIBCPP_NO_EXCEPTIONS - __libcpp_relaxed_store(&flag, 1ul); - pthread_mutex_unlock(&mut); - func(arg); - pthread_mutex_lock(&mut); - __libcpp_relaxed_store(&flag, ~0ul); - pthread_mutex_unlock(&mut); - pthread_cond_broadcast(&cv); -#ifndef _LIBCPP_NO_EXCEPTIONS - } - catch (...) - { - pthread_mutex_lock(&mut); - __libcpp_relaxed_store(&flag, 0ul); - pthread_mutex_unlock(&mut); - pthread_cond_broadcast(&cv); - throw; - } -#endif // _LIBCPP_NO_EXCEPTIONS - } - else - pthread_mutex_unlock(&mut); -#endif // !_LIBCPP_HAS_NO_THREADS - + __libcpp_support::__os_call_once(flag, arg, func); } _LIBCPP_END_NAMESPACE_STD Index: src/memory.cpp =================================================================== --- src/memory.cpp +++ src/memory.cpp @@ -126,13 +126,14 @@ #if defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS) +using namespace __libcpp_support; static const std::size_t __sp_mut_count = 16; -static pthread_mutex_t mut_back_imp[__sp_mut_count] = +static __os_mutex mut_back_imp[__sp_mut_count] = { - PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, - PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, - PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, - PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER + __os_mutex_init, __os_mutex_init, __os_mutex_init, __os_mutex_init, + __os_mutex_init, __os_mutex_init, __os_mutex_init, __os_mutex_init, + __os_mutex_init, __os_mutex_init, __os_mutex_init, __os_mutex_init, + __os_mutex_init, __os_mutex_init, __os_mutex_init, __os_mutex_init }; static mutex* mut_back = reinterpret_cast<std::mutex*>(mut_back_imp); Index: src/condition_variable.cpp =================================================================== --- src/condition_variable.cpp +++ src/condition_variable.cpp @@ -18,62 +18,44 @@ _LIBCPP_BEGIN_NAMESPACE_STD +using namespace __libcpp_support; + condition_variable::~condition_variable() { - pthread_cond_destroy(&__cv_); + __os_cond_var_destroy(&__cv_); } void condition_variable::notify_one() _NOEXCEPT { - pthread_cond_signal(&__cv_); + __os_cond_var_notify_one(&__cv_); } void condition_variable::notify_all() _NOEXCEPT { - pthread_cond_broadcast(&__cv_); + __os_cond_var_notify_all(&__cv_); } void condition_variable::wait(unique_lock<mutex>& lk) _NOEXCEPT { if (!lk.owns_lock()) __throw_system_error(EPERM, "condition_variable::wait: mutex not locked"); - int ec = pthread_cond_wait(&__cv_, lk.mutex()->native_handle()); + int ec = __os_cond_var_wait(&__cv_, lk.mutex()->native_handle()); if (ec) __throw_system_error(ec, "condition_variable wait failed"); } void condition_variable::__do_timed_wait(unique_lock<mutex>& lk, chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp) _NOEXCEPT { - using namespace chrono; if (!lk.owns_lock()) __throw_system_error(EPERM, "condition_variable::timed wait: mutex not locked"); - nanoseconds d = tp.time_since_epoch(); - if (d > nanoseconds(0x59682F000000E941)) - d = nanoseconds(0x59682F000000E941); - timespec ts; - seconds s = duration_cast<seconds>(d); - typedef decltype(ts.tv_sec) ts_sec; - _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max(); - if (s.count() < ts_sec_max) - { - ts.tv_sec = static_cast<ts_sec>(s.count()); - ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((d - s).count()); - } - else - { - ts.tv_sec = ts_sec_max; - ts.tv_nsec = giga::num - 1; - } - int ec = pthread_cond_timedwait(&__cv_, lk.mutex()->native_handle(), &ts); - if (ec != 0 && ec != ETIMEDOUT) - __throw_system_error(ec, "condition_variable timed_wait failed"); + __os_cond_var_timed_wait(&__cv_, lk.mutex()->native_handle(), tp); } void Index: src/algorithm.cpp =================================================================== --- src/algorithm.cpp +++ src/algorithm.cpp @@ -47,15 +47,16 @@ template unsigned __sort5<__less<long double>&, long double*>(long double*, long double*, long double*, long double*, long double*, __less<long double>&); +using namespace __libcpp_support; #ifndef _LIBCPP_HAS_NO_THREADS -static pthread_mutex_t __rs_mut = PTHREAD_MUTEX_INITIALIZER; +static __os_mutex __rs_mut = __os_mutex_init; #endif unsigned __rs_default::__c_ = 0; __rs_default::__rs_default() { #ifndef _LIBCPP_HAS_NO_THREADS - pthread_mutex_lock(&__rs_mut); + __os_mutex_lock(&__rs_mut); #endif __c_ = 1; } @@ -69,7 +70,7 @@ { #ifndef _LIBCPP_HAS_NO_THREADS if (--__c_ == 0) - pthread_mutex_unlock(&__rs_mut); + __os_mutex_unlock(&__rs_mut); #else --__c_; #endif Index: lib/CMakeLists.txt =================================================================== --- lib/CMakeLists.txt +++ lib/CMakeLists.txt @@ -8,6 +8,9 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS") file(GLOB LIBCXX_SOLARIS_SOURCES ../src/support/solaris/*.c) list(APPEND LIBCXX_SOURCES ${LIBCXX_SOLARIS_SOURCES}) +elseif(UNIX) + file(GLOB LIBCXX_PTHREAD_SOURCES ../src/support/pthread/*.cpp) + list(APPEND LIBCXX_SOURCES ${LIBCXX_PTHREAD_SOURCES}) endif() # Add all the headers to the project for IDEs. @@ -17,6 +20,9 @@ file( GLOB LIBCXX_WIN32_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../include/support/win32/*.h) list(APPEND LIBCXX_HEADERS ${LIBCXX_WIN32_HEADERS}) endif() +if(XCODE) + file(GLOB_RECURSE LIBCXX_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../include/support/pthread/*) + endif() # Force them all into the headers dir on MSVC, otherwise they end up at # project scope because they don't have extensions. if (MSVC_IDE) @@ -67,7 +73,7 @@ add_library_flags("${LIBCXX_SANITIZER_LIBRARY}") add_link_flags("-Wl,-rpath,${LIBDIR}") endif() -endif() +endif() # Generate library list. add_library_flags_if(LIBCXX_HAS_PTHREAD_LIB pthread) Index: include/thread =================================================================== --- include/thread +++ include/thread @@ -98,8 +98,7 @@ #ifndef _LIBCPP_HAS_NO_VARIADICS #include <tuple> #endif -#include <pthread.h> -#include <sched.h> +#include <support/thread.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -137,7 +136,7 @@ template <class _Tp> class __thread_specific_ptr { - pthread_key_t __key_; + __libcpp_support::__os_tl_key __key_; // Only __thread_local_data() may construct a __thread_specific_ptr // and only with _Tp == __thread_struct. @@ -155,7 +154,7 @@ ~__thread_specific_ptr(); _LIBCPP_INLINE_VISIBILITY - pointer get() const {return static_cast<_Tp*>(pthread_getspecific(__key_));} + pointer get() const {return static_cast<_Tp*>(__libcpp_support::__os_tl_get(__key_));} _LIBCPP_INLINE_VISIBILITY pointer operator*() const {return *get();} _LIBCPP_INLINE_VISIBILITY @@ -174,7 +173,9 @@ template <class _Tp> __thread_specific_ptr<_Tp>::__thread_specific_ptr() { - int __ec = pthread_key_create(&__key_, &__thread_specific_ptr::__at_thread_exit); + int __ec = __libcpp_support::__os_tl_create( + &__key_, + &__thread_specific_ptr::__at_thread_exit); #ifndef _LIBCPP_NO_EXCEPTIONS if (__ec) throw system_error(error_code(__ec, system_category()), @@ -196,16 +197,16 @@ __thread_specific_ptr<_Tp>::release() { pointer __p = get(); - pthread_setspecific(__key_, 0); + __libcpp_support::__os_tl_set(__key_, 0); return __p; } template <class _Tp> void __thread_specific_ptr<_Tp>::reset(pointer __p) { pointer __p_old = get(); - pthread_setspecific(__key_, __p); + __libcpp_support::__os_tl_set(__key_, __p); delete __p_old; } @@ -226,21 +227,21 @@ // FIXME: pthread_t is a pointer on Darwin but a long on Linux. // NULL is the no-thread value on Darwin. Someone needs to check // on other platforms. We assume 0 works everywhere for now. - pthread_t __id_; + __libcpp_support::__os_thread_id __id_; public: _LIBCPP_INLINE_VISIBILITY __thread_id() _NOEXCEPT : __id_(0) {} friend _LIBCPP_INLINE_VISIBILITY bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT - {return __x.__id_ == __y.__id_;} + {return __libcpp_support::__os_thread_id_compare(__x.__id_, __y.__id_) == 0;} friend _LIBCPP_INLINE_VISIBILITY bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT {return !(__x == __y);} friend _LIBCPP_INLINE_VISIBILITY bool operator< (__thread_id __x, __thread_id __y) _NOEXCEPT - {return __x.__id_ < __y.__id_;} + {return __libcpp_support::__os_thread_id_compare(__x.__id_, __y.__id_) < 0;} friend _LIBCPP_INLINE_VISIBILITY bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT {return !(__y < __x);} @@ -256,11 +257,11 @@ _LIBCPP_INLINE_VISIBILITY basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) - {return __os << __id.__id_;} + {return __libcpp_support::__os_write_to_ostream(__os, __id.__id_);} private: _LIBCPP_INLINE_VISIBILITY - __thread_id(pthread_t __id) : __id_(__id) {} + __thread_id(__libcpp_support::__os_thread_id __id) : __id_(__id) {} friend __thread_id this_thread::get_id() _NOEXCEPT; friend class _LIBCPP_TYPE_VIS thread; @@ -274,7 +275,7 @@ _LIBCPP_INLINE_VISIBILITY size_t operator()(__thread_id __v) const { - return hash<pthread_t>()(__v.__id_); + return hash<__libcpp_support::__os_thread_id>()(__v.__id_); } }; @@ -285,23 +286,24 @@ __thread_id get_id() _NOEXCEPT { - return pthread_self(); + return __libcpp_support::__os_get_current_thread_id(); } } // this_thread class _LIBCPP_TYPE_VIS thread { - pthread_t __t_; + typedef __libcpp_support::__os_thread __thread_type; + __thread_type __t_; thread(const thread&); thread& operator=(const thread&); public: typedef __thread_id id; - typedef pthread_t native_handle_type; + typedef __thread_type native_handle_type; _LIBCPP_INLINE_VISIBILITY - thread() _NOEXCEPT : __t_(0) {} + thread() _NOEXCEPT : __t_(__libcpp_support::__os_thread_init) {} #ifndef _LIBCPP_HAS_NO_VARIADICS template <class _Fp, class ..._Args, class = typename enable_if @@ -329,7 +331,7 @@ void join(); void detach(); _LIBCPP_INLINE_VISIBILITY - id get_id() const _NOEXCEPT {return __t_;} + id get_id() const _NOEXCEPT {return __libcpp_support::__os_get_thread_id(__t_);} _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() _NOEXCEPT {return __t_;} @@ -365,7 +367,7 @@ typedef tuple<typename decay<_Fp>::type, typename decay<_Args>::type...> _Gp; _VSTD::unique_ptr<_Gp> __p(new _Gp(__decay_copy(_VSTD::forward<_Fp>(__f)), __decay_copy(_VSTD::forward<_Args>(__args))...)); - int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Gp>, __p.get()); + int __ec = __libcpp_support::__os_create_thread(&__t_, &__thread_proxy<_Gp>, __p.get()); if (__ec == 0) __p.release(); else @@ -388,7 +390,7 @@ thread::thread(_Fp __f) { std::unique_ptr<_Fp> __p(new _Fp(__f)); - int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Fp>, __p.get()); + int __ec = __libcpp_support::__os_create_thread(&__t_, &__thread_proxy<_Gp>, __p.get()); if (__ec == 0) __p.release(); else @@ -463,7 +465,7 @@ } inline _LIBCPP_INLINE_VISIBILITY -void yield() _NOEXCEPT {sched_yield();} +void yield() _NOEXCEPT {__libcpp_support::__os_yield();} } // this_thread Index: include/support/thread.h =================================================================== --- /dev/null +++ include/support/thread.h @@ -0,0 +1,27 @@ +// -*- 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_SUPPORT_THREAD_H +#define _LIBCPP_SUPPORT_THREAD_H + +#ifndef _LIBCPP_HAS_NO_THREADS + +#define _LIBCPP_INCLUDE_THREAD_API + +#if _LIBCPP_THREAD_API == _LIBCPP_PTHREAD +# include <support/pthread/thread.h> +#else +# error "No thread API found" +#endif // _LIBCPP_THREAD_API == _LIBCPP_PTHREAD +#undef _LIBCPP_INCLUDE_THREAD_API + +#endif // _LIBCPP_HAS_NO_THREADS + +#endif // _LIBCPP_SUPPORT_THREAD_H Index: include/support/pthread/thread.h =================================================================== --- /dev/null +++ include/support/pthread/thread.h @@ -0,0 +1,121 @@ +// -*- 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_SUPPORT_PTHREAD_THREAD_H +#define _LIBCPP_SUPPORT_PTHREAD_THREAD_H + +#ifndef _LIBCPP_INCLUDE_THREAD_API +# error "This header can't be included directly" +#endif // _LIBCPP_INCLUDE_THREAD_API + +#include <pthread.h> +#include <sched.h> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __libcpp_support +{ + +// thread local +typedef pthread_key_t __os_tl_key; + +template<class _Func> +inline _LIBCPP_INLINE_VISIBILITY +int __os_tl_create(__os_tl_key* __key, _Func&& __at_exit) +{ + return pthread_key_create(__key, __at_exit); +} + +inline _LIBCPP_INLINE_VISIBILITY +void __os_tl_destroy(__os_tl_key __key) +{ + pthread_key_delete(__key); +} + +inline _LIBCPP_INLINE_VISIBILITY +void* __os_tl_get(__os_tl_key __key) +{ + return pthread_getspecific(__key); +} + +inline _LIBCPP_INLINE_VISIBILITY +void __os_tl_set(__os_tl_key __key, void* __p) +{ + pthread_setspecific(__key, __p); +} + +// thread id +typedef pthread_t __os_thread_id; + +inline _LIBCPP_INLINE_VISIBILITY +int __os_thread_id_compare( __os_thread_id t1, __os_thread_id t2) +{ + bool res = pthread_equal(t1, t2); + return res != 0 ? 0 : (t1 < t2 ? -1 : 1); +} + +template<class _CharT, class _Traits> +inline _LIBCPP_INLINE_VISIBILITY +basic_ostream<_CharT, _Traits>& +__os_write_to_ostream(basic_ostream<_CharT, _Traits>& __os, __os_thread_id __id) +{ + return __os << __id; +} + +inline _LIBCPP_INLINE_VISIBILITY +__os_thread_id __os_get_current_thread_id() +{ + return pthread_self(); +} + + +// thread +typedef pthread_t __os_thread; +_LIBCPP_CONSTEXPR pthread_t __os_thread_init = 0; + +template<class _Func, class _Arg> +inline _LIBCPP_INLINE_VISIBILITY +int __os_create_thread(__os_thread* __t, _Func&& __f, _Arg&& __arg) +{ + return pthread_create(__t, 0, __f, __arg); +} + +inline _LIBCPP_INLINE_VISIBILITY +__os_thread_id __os_get_thread_id(__os_thread __t) +{ + return __t; +} + +inline _LIBCPP_INLINE_VISIBILITY +int __os_thread_join(__os_thread t) +{ + return pthread_join(t, 0); +} + +inline _LIBCPP_INLINE_VISIBILITY +int __os_thread_detach(__os_thread t) +{ + return pthread_detach(t); +} + +inline _LIBCPP_INLINE_VISIBILITY +void __os_yield() +{ + sched_yield(); +} + +_LIBCPP_FUNC_VIS void __os_sleep_for(const chrono::nanoseconds& ns); + +} // namespace __libcpp_support + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_SUPPORT_PTHREAD_THREAD_H + Index: include/support/pthread/mutex.h =================================================================== --- /dev/null +++ include/support/pthread/mutex.h @@ -0,0 +1,93 @@ +// -*- 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_SUPPORT_PTHREAD_MUTEX_H +#define _LIBCPP_SUPPORT_PTHREAD_MUTEX_H + +#ifndef _LIBCPP_INCLUDE_THREAD_API +# error "This header can't be included directly" +#endif // _LIBCPP_INCLUDE_THREAD_API + +#include <pthread.h> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __libcpp_support +{ + +// mutex +typedef pthread_mutex_t __os_mutex; +_LIBCPP_CONSTEXPR pthread_mutex_t __os_mutex_init = PTHREAD_MUTEX_INITIALIZER; + +inline _LIBCPP_INLINE_VISIBILITY +int __os_mutex_lock(__os_mutex* __m) +{ + return pthread_mutex_lock(__m); +} + +inline _LIBCPP_INLINE_VISIBILITY +int __os_mutex_trylock(__os_mutex* __m) +{ + return pthread_mutex_trylock(__m); +} + +inline _LIBCPP_INLINE_VISIBILITY +int __os_mutex_unlock(__os_mutex* __m) +{ + return pthread_mutex_unlock(__m); +} + +inline _LIBCPP_INLINE_VISIBILITY +int __os_mutex_destroy(__os_mutex* __m) +{ + return pthread_mutex_destroy(__m); +} + +// pthread hides differences between recursive and non-recursive mutexes +// internally, other platform (e.g. Windows) might not, thus the following +// is like the above except for init +typedef pthread_mutex_t __os_recursive_mutex; + +_LIBCPP_FUNC_VIS +void __os_recursive_mutex_init(__os_mutex* __m); + +inline _LIBCPP_INLINE_VISIBILITY +int __os_recursive_mutex_lock(__os_mutex* __m) +{ + return pthread_mutex_lock(__m); +} + +inline _LIBCPP_INLINE_VISIBILITY +int __os_recursive_mutex_trylock(__os_mutex* __m) +{ + return pthread_mutex_trylock(__m); +} + +inline _LIBCPP_INLINE_VISIBILITY +int __os_recursive_mutex_unlock(__os_mutex* __m) +{ + return pthread_mutex_unlock(__m); +} + +inline _LIBCPP_INLINE_VISIBILITY +int __os_recursive_mutex_destroy(__os_mutex* __m) +{ + return pthread_mutex_destroy(__m); +} + +_LIBCPP_FUNC_VIS void __os_call_once(volatile unsigned long&, void*, void(*)(void*)); + + +} // namespace __libcpp_support + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_SUPPORT_PTHREAD_MUTEX_H + Index: include/support/pthread/condition_variable.h =================================================================== --- /dev/null +++ include/support/pthread/condition_variable.h @@ -0,0 +1,62 @@ +// -*- 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_SUPPORT_PTHREAD_CONDITION_VARIABLE_H +#define _LIBCPP_SUPPORT_PTHREAD_CONDITION_VARIABLE_H + +#ifndef _LIBCPP_INCLUDE_THREAD_API +# error "This header can't be included directly" +#endif // _LIBCPP_INCLUDE_THREAD_API + +#include <pthread.h> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __libcpp_support +{ + +typedef pthread_cond_t __os_cond_var; +typedef pthread_mutex_t __os_mutex; +_LIBCPP_CONSTEXPR pthread_cond_t __os_cond_var_init = PTHREAD_COND_INITIALIZER; + +inline _LIBCPP_INLINE_VISIBILITY +void __os_cond_var_destroy(__os_cond_var* __cv) +{ + pthread_cond_destroy(__cv); +} + +inline _LIBCPP_INLINE_VISIBILITY +void __os_cond_var_notify_one(__os_cond_var* __cv) +{ + pthread_cond_signal(__cv); +} + +inline _LIBCPP_INLINE_VISIBILITY +void __os_cond_var_notify_all(__os_cond_var* __cv) +{ + pthread_cond_broadcast(__cv); +} + +inline _LIBCPP_INLINE_VISIBILITY +int __os_cond_var_wait(__os_cond_var* __cv, __os_mutex* __m) +{ + return pthread_cond_wait(__cv, __m); +} + +_LIBCPP_FUNC_VIS +void __os_cond_var_timed_wait(__os_cond_var* __cv, + __os_mutex* __m, + chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp); + +} // namespace __libcpp_support + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_SUPPORT_PTHREAD_CONDITION_VARIABLE_H Index: include/support/mutex.h =================================================================== --- /dev/null +++ include/support/mutex.h @@ -0,0 +1,28 @@ +// -*- 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_SUPPORT_MUTEX_H +#define _LIBCPP_SUPPORT_MUTEX_H + +#ifndef _LIBCPP_HAS_NO_THREADS + +#define _LIBCPP_INCLUDE_THREAD_API + +#if _LIBCPP_THREAD_API == _LIBCPP_PTHREAD +# include <support/pthread/mutex.h> +#else +# error "No thread API found" +#endif // _LIBCPP_THREAD_API == _LIBCPP_PTHREAD + +#undef _LIBCPP_INCLUDE_THREAD_API + +#endif // _LIBCPP_HAS_NO_THREADS + +#endif // _LIBCPP_SUPPORT_MUTEX_H Index: include/support/condition_variable.h =================================================================== --- /dev/null +++ include/support/condition_variable.h @@ -0,0 +1,28 @@ +// -*- 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_SUPPORT_CONDITION_VARIABLE_H +#define _LIBCPP_SUPPORT_CONDITION_VARIABLE_H + +#ifndef _LIBCPP_HAS_NO_THREADS + +#define _LIBCPP_INCLUDE_THREAD_API + +#if _LIBCPP_THREAD_API == _LIBCPP_PTHREAD +# include <support/pthread/condition_variable.h> +#else +# error "No thread API found" +#endif // _LIBCPP_THREAD_API == _LIBCPP_PTHREAD + +#undef _LIBCPP_INCLUDE_THREAD_API + +#endif // _LIBCPP_HAS_NO_THREADS + +#endif // _LIBCPP_SUPPORT_CONDITION_VARIABLE_H Index: include/mutex =================================================================== --- include/mutex +++ include/mutex @@ -179,9 +179,7 @@ #ifndef _LIBCPP_HAS_NO_VARIADICS #include <tuple> #endif -#ifndef _LIBCPP_HAS_NO_THREADS -#include <sched.h> -#endif +#include <support/thread.h> #include <__undef_min_max> @@ -195,7 +193,8 @@ class _LIBCPP_TYPE_VIS recursive_mutex { - pthread_mutex_t __m_; + typedef __libcpp_support::__os_mutex __mutex_type; + __mutex_type __m_; public: recursive_mutex(); @@ -208,9 +207,9 @@ public: void lock(); bool try_lock() _NOEXCEPT; - void unlock() _NOEXCEPT; + void unlock() _NOEXCEPT; - typedef pthread_mutex_t* native_handle_type; + typedef __mutex_type* native_handle_type; _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;} }; @@ -259,10 +258,10 @@ class _LIBCPP_TYPE_VIS recursive_timed_mutex { - mutex __m_; - condition_variable __cv_; - size_t __count_; - pthread_t __id_; + mutex __m_; + condition_variable __cv_; + size_t __count_; + __libcpp_support::__os_thread_id __id_; public: recursive_timed_mutex(); ~recursive_timed_mutex(); @@ -288,9 +287,10 @@ recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { using namespace chrono; - pthread_t __id = pthread_self(); + using namespace __libcpp_support; + __os_thread_id __id = __os_get_current_thread_id(); unique_lock<mutex> lk(__m_); - if (pthread_equal(__id, __id_)) + if (__os_thread_id_compare(__id, __id_) == 0) { if (__count_ == numeric_limits<size_t>::max()) return false; @@ -362,16 +362,16 @@ break; } } - sched_yield(); + __libcpp_support::__os_yield(); { unique_lock<_L1> __u1(__l1); if (__l0.try_lock()) { __u1.release(); break; } } - sched_yield(); + __libcpp_support::__os_yield(); } } @@ -396,7 +396,7 @@ } } ++__i; - sched_yield(); + __libcpp_support::__os_yield(); break; case 1: { @@ -412,7 +412,7 @@ __i = 0; else __i += 2; - sched_yield(); + __libcpp_support::__os_yield(); break; default: __lock_first(__i - 2, __l2, __l3..., __l0, __l1); Index: include/__mutex_base =================================================================== --- include/__mutex_base +++ include/__mutex_base @@ -14,9 +14,8 @@ #include <__config> #include <chrono> #include <system_error> -#ifndef _LIBCPP_HAS_NO_THREADS -#include <pthread.h> -#endif +#include <support/mutex.h> +#include <support/condition_variable.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -28,14 +27,15 @@ class _LIBCPP_TYPE_VIS mutex { - pthread_mutex_t __m_; + typedef __libcpp_support::__os_mutex __mutex_type; + __mutex_type __m_; public: _LIBCPP_INLINE_VISIBILITY #ifndef _LIBCPP_HAS_NO_CONSTEXPR - constexpr mutex() _NOEXCEPT : __m_(PTHREAD_MUTEX_INITIALIZER) {} + constexpr mutex() _NOEXCEPT : __m_(__libcpp_support::__os_mutex_init) {} #else - mutex() _NOEXCEPT {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;} + mutex() _NOEXCEPT {__m_ = __libcpp_support::__os_mutex_init;} #endif ~mutex(); @@ -48,7 +48,7 @@ bool try_lock() _NOEXCEPT; void unlock() _NOEXCEPT; - typedef pthread_mutex_t* native_handle_type; + typedef __mutex_type* native_handle_type; _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;} }; @@ -268,13 +268,14 @@ class _LIBCPP_TYPE_VIS condition_variable { - pthread_cond_t __cv_; + typedef __libcpp_support::__os_cond_var __cond_var_type; + __cond_var_type __cv_; public: _LIBCPP_INLINE_VISIBILITY #ifndef _LIBCPP_HAS_NO_CONSTEXPR - constexpr condition_variable() : __cv_(PTHREAD_COND_INITIALIZER) {} + constexpr condition_variable() : __cv_(__libcpp_support::__os_cond_var_init) {} #else - condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;} + condition_variable() {__cv_ = __libcpp_support::__os_cond_var_init;} #endif ~condition_variable(); @@ -312,7 +313,7 @@ const chrono::duration<_Rep, _Period>& __d, _Predicate __pred); - typedef pthread_cond_t* native_handle_type; + typedef __cond_var_type* native_handle_type; _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;} private: Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -746,6 +746,20 @@ # define _LIBCPP_WEAK __attribute__((__weak__)) #endif +// Thread API +#ifndef _LIBCPP_HAS_NO_THREADS +# if defined(__FreeBSD__) || \ + defined(__NetBSD__) || \ + defined(__linux__) || \ + defined(__APPLE__) || \ + defined(__CloudABI__) +# define _LIBCPP_THREAD_API _LIBCPP_PTHREAD +# else +# error "No thread API" +# endif // _LIBCPP_THREAD_API +#endif // _LIBCPP_HAS_NO_THREADS + + #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 @@ -185,7 +185,7 @@ # Setup Compiler Flags #=============================================================================== -include(HandleLibCXXABI) # Steup the ABI library flags +include(HandleLibCXXABI) # Setup the ABI library flags # Include macros for adding and removing libc++ flags. include(HandleLibcxxFlags) Index: .gitignore =================================================================== --- .gitignore +++ .gitignore @@ -52,3 +52,4 @@ # PyBuilder target/ +
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits