Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -11,6 +11,10 @@ #ifndef _LIBCPP_CONFIG #define _LIBCPP_CONFIG +#if !_WIN32 +#include +#endif + #if !defined(_MSC_VER) || defined(__clang__) #pragma GCC system_header #endif @@ -119,6 +123,12 @@ # endif #endif // !defined(_LIBCPP_LITTLE_ENDIAN) || !defined(_LIBCPP_BIG_ENDIAN) +#if !defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_POSIX_THREADS) || _POSIX_THREADS <= 0) +# error suggests that your system doesn't have PTHREADS... \ + If you'd like to build libcxx for a single threaded system, \ + please use -D_LIBCPP_SINGLE_THREADED +#endif + #ifdef _WIN32 // only really useful for a DLL Index: include/__mutex_base =================================================================== --- include/__mutex_base +++ include/__mutex_base @@ -22,6 +22,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD +#ifndef _LIBCPP_HAS_NO_THREADS + class _LIBCPP_TYPE_VIS mutex { pthread_mutex_t __m_; @@ -315,6 +317,7 @@ void __do_timed_wait(unique_lock& __lk, chrono::time_point) _NOEXCEPT; }; +#endif // !_LIBCPP_HAS_NO_THREADS template inline _LIBCPP_INLINE_VISIBILITY @@ -332,6 +335,7 @@ return __r; } +#ifndef _LIBCPP_HAS_NO_THREADS template void condition_variable::wait(unique_lock& __lk, _Predicate __pred) @@ -396,6 +400,8 @@ _VSTD::move(__pred)); } +#endif // !_LIBCPP_HAS_NO_THREADS + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___MUTEX_BASE Index: include/atomic =================================================================== --- include/atomic +++ include/atomic @@ -533,6 +533,10 @@ #pragma GCC system_header #endif +#ifdef _LIBCPP_HAS_NO_THREADS +#error is not supported on this single threaded system +#else // !_LIBCPP_HAS_NO_THREADS + _LIBCPP_BEGIN_NAMESPACE_STD #if !__has_feature(cxx_atomic) && _GNUC_VER < 407 @@ -1779,4 +1783,6 @@ _LIBCPP_END_NAMESPACE_STD +#endif // !_LIBCPP_HAS_NO_THREADS + #endif // _LIBCPP_ATOMIC Index: include/condition_variable =================================================================== --- include/condition_variable +++ include/condition_variable @@ -115,6 +115,8 @@ #pragma GCC system_header #endif +#ifndef _LIBCPP_HAS_NO_THREADS + _LIBCPP_BEGIN_NAMESPACE_STD class _LIBCPP_TYPE_VIS condition_variable_any @@ -253,4 +255,6 @@ _LIBCPP_END_NAMESPACE_STD +#endif // !_LIBCPP_HAS_NO_THREADS + #endif // _LIBCPP_CONDITION_VARIABLE Index: include/future =================================================================== --- include/future +++ include/future @@ -374,6 +374,10 @@ #pragma GCC system_header #endif +#ifndef _LIBCPP_HAS_NO_THREADS +#error is not supported on this single threaded system +#else // !_LIBCPP_HAS_NO_THREADS + _LIBCPP_BEGIN_NAMESPACE_STD //enum class future_errc @@ -2612,4 +2616,6 @@ _LIBCPP_END_NAMESPACE_STD +#endif // !_LIBCPP_HAS_NO_THREADS + #endif // _LIBCPP_FUTURE Index: include/memory =================================================================== --- include/memory +++ include/memory @@ -610,7 +610,7 @@ #include #endif -#if __has_feature(cxx_atomic) +#if __has_feature(cxx_atomic) && !defined(_LIBCPP_HAS_NO_THREADS) # include #endif @@ -5262,7 +5262,7 @@ basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, shared_ptr<_Yp> const& __p); -#if __has_feature(cxx_atomic) +#if __has_feature(cxx_atomic) && !defined(_LIBCPP_HAS_NO_THREADS) class _LIBCPP_TYPE_VIS __sp_mut { @@ -5388,7 +5388,7 @@ return atomic_compare_exchange_weak(__p, __v, __w); } -#endif // __has_feature(cxx_atomic) +#endif // __has_feature(cxx_atomic) && !defined(_LIBCPP_HAS_NO_THREADS) //enum class struct _LIBCPP_TYPE_VIS pointer_safety Index: include/mutex =================================================================== --- include/mutex +++ include/mutex @@ -187,6 +187,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD +#ifndef _LIBCPP_HAS_NO_THREADS + class _LIBCPP_TYPE_VIS recursive_mutex { pthread_mutex_t __m_; @@ -425,6 +427,8 @@ #endif // _LIBCPP_HAS_NO_VARIADICS +#endif // !_LIBCPP_HAS_NO_THREADS + struct _LIBCPP_TYPE_VIS_ONLY once_flag; #ifndef _LIBCPP_HAS_NO_VARIADICS Index: include/shared_mutex =================================================================== --- include/shared_mutex +++ include/shared_mutex @@ -112,6 +112,10 @@ #pragma GCC system_header #endif +#ifdef _LIBCPP_HAS_NO_THREADS +#error is not supported on this single threaded system +#else // !_LIBCPP_HAS_NO_THREADS + _LIBCPP_BEGIN_NAMESPACE_STD class _LIBCPP_TYPE_VIS shared_timed_mutex @@ -414,6 +418,8 @@ _LIBCPP_END_NAMESPACE_STD +#endif // !_LIBCPP_HAS_NO_THREADS + #endif // _LIBCPP_STD_VER > 11 #endif // _LIBCPP_SHARED_MUTEX Index: include/thread =================================================================== --- include/thread +++ include/thread @@ -106,6 +106,10 @@ #define __STDCPP_THREADS__ __cplusplus +#ifdef _LIBCPP_HAS_NO_THREADS +#error is not supported on this single threaded system +#else // !_LIBCPP_HAS_NO_THREADS + _LIBCPP_BEGIN_NAMESPACE_STD template @@ -455,4 +459,6 @@ _LIBCPP_END_NAMESPACE_STD +#endif // !_LIBCPP_HAS_NO_THREADS + #endif // _LIBCPP_THREAD Index: src/algorithm.cpp =================================================================== --- src/algorithm.cpp +++ src/algorithm.cpp @@ -47,12 +47,16 @@ template unsigned __sort5<__less&, long double*>(long double*, long double*, long double*, long double*, long double*, __less&); +#ifndef _LIBCPP_HAS_NO_THREADS static pthread_mutex_t __rs_mut = PTHREAD_MUTEX_INITIALIZER; +#endif unsigned __rs_default::__c_ = 0; __rs_default::__rs_default() { +#ifndef _LIBCPP_HAS_NO_THREADS pthread_mutex_lock(&__rs_mut); +#endif __c_ = 1; } @@ -63,8 +67,12 @@ __rs_default::~__rs_default() { +#ifndef _LIBCPP_HAS_NO_THREADS if (--__c_ == 0) pthread_mutex_unlock(&__rs_mut); +#else + --__c_; +#endif } __rs_default::result_type Index: src/condition_variable.cpp =================================================================== --- src/condition_variable.cpp +++ src/condition_variable.cpp @@ -7,11 +7,16 @@ // //===----------------------------------------------------------------------===// +#include "__config" + +#ifndef _LIBCPP_HAS_NO_THREADS + #include "condition_variable" #include "thread" #include "system_error" #include "cassert" + _LIBCPP_BEGIN_NAMESPACE_STD condition_variable::~condition_variable() @@ -79,3 +84,6 @@ } _LIBCPP_END_NAMESPACE_STD + +#endif // !_LIBCPP_HAS_NO_THREADS + Index: src/debug.cpp =================================================================== --- src/debug.cpp +++ src/debug.cpp @@ -35,6 +35,7 @@ namespace { +#ifndef _LIBCPP_HAS_NO_THREADS typedef mutex mutex_type; typedef lock_guard WLock; typedef lock_guard RLock; @@ -45,6 +46,7 @@ static mutex_type m; return m; } +#endif // !_LIBCPP_HAS_NO_THREADS } // unnamed namespace @@ -108,7 +110,9 @@ void* __libcpp_db::__find_c_from_i(void* __i) const { +#ifndef _LIBCPP_HAS_NO_THREADS RLock _(mut()); +#endif __i_node* i = __find_iterator(__i); _LIBCPP_ASSERT(i != nullptr, "iterator not found in debug database."); return i->__c_ != nullptr ? i->__c_->__c_ : nullptr; @@ -117,7 +121,9 @@ void __libcpp_db::__insert_ic(void* __i, const void* __c) { +#ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); +#endif if (__cbeg_ == __cend_) return; size_t hc = hash()(__c) % static_cast(__cend_ - __cbeg_); @@ -138,7 +144,9 @@ __c_node* __libcpp_db::__insert_c(void* __c) { +#ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); +#endif if (__csz_ + 1 > static_cast(__cend_ - __cbeg_)) { size_t nc = __next_prime(2*static_cast(__cend_ - __cbeg_) + 1); @@ -184,7 +192,9 @@ void __libcpp_db::__erase_i(void* __i) { +#ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); +#endif if (__ibeg_ != __iend_) { size_t hi = hash()(__i) % static_cast(__iend_ - __ibeg_); @@ -215,7 +225,9 @@ void __libcpp_db::__invalidate_all(void* __c) { +#ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); +#endif if (__cend_ != __cbeg_) { size_t hc = hash()(__c) % static_cast(__cend_ - __cbeg_); @@ -239,17 +251,23 @@ __c_node* __libcpp_db::__find_c_and_lock(void* __c) const { +#ifndef _LIBCPP_HAS_NO_THREADS mut().lock(); +#endif if (__cend_ == __cbeg_) { +#ifndef _LIBCPP_HAS_NO_THREADS mut().unlock(); +#endif return nullptr; } size_t hc = hash()(__c) % static_cast(__cend_ - __cbeg_); __c_node* p = __cbeg_[hc]; if (p == nullptr) { +#ifndef _LIBCPP_HAS_NO_THREADS mut().unlock(); +#endif return nullptr; } while (p->__c_ != __c) @@ -257,7 +275,9 @@ p = p->__next_; if (p == nullptr) { +#ifndef _LIBCPP_HAS_NO_THREADS mut().unlock(); +#endif return nullptr; } } @@ -281,13 +301,17 @@ void __libcpp_db::unlock() const { +#ifndef _LIBCPP_HAS_NO_THREADS mut().unlock(); +#endif } void __libcpp_db::__erase_c(void* __c) { +#ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); +#endif if (__cend_ != __cbeg_) { size_t hc = hash()(__c) % static_cast(__cend_ - __cbeg_); @@ -322,7 +346,9 @@ void __libcpp_db::__iterator_copy(void* __i, const void* __i0) { +#ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); +#endif __i_node* i = __find_iterator(__i); __i_node* i0 = __find_iterator(__i0); __c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr; @@ -348,7 +374,9 @@ bool __libcpp_db::__dereferenceable(const void* __i) const { +#ifndef _LIBCPP_HAS_NO_THREADS RLock _(mut()); +#endif __i_node* i = __find_iterator(__i); return i != nullptr && i->__c_ != nullptr && i->__c_->__dereferenceable(__i); } @@ -356,7 +384,9 @@ bool __libcpp_db::__decrementable(const void* __i) const { +#ifndef _LIBCPP_HAS_NO_THREADS RLock _(mut()); +#endif __i_node* i = __find_iterator(__i); return i != nullptr && i->__c_ != nullptr && i->__c_->__decrementable(__i); } @@ -364,7 +394,9 @@ bool __libcpp_db::__addable(const void* __i, ptrdiff_t __n) const { +#ifndef _LIBCPP_HAS_NO_THREADS RLock _(mut()); +#endif __i_node* i = __find_iterator(__i); return i != nullptr && i->__c_ != nullptr && i->__c_->__addable(__i, __n); } @@ -372,7 +404,9 @@ bool __libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const { +#ifndef _LIBCPP_HAS_NO_THREADS RLock _(mut()); +#endif __i_node* i = __find_iterator(__i); return i != nullptr && i->__c_ != nullptr && i->__c_->__subscriptable(__i, __n); } @@ -380,7 +414,9 @@ bool __libcpp_db::__less_than_comparable(const void* __i, const void* __j) const { +#ifndef _LIBCPP_HAS_NO_THREADS RLock _(mut()); +#endif __i_node* i = __find_iterator(__i); __i_node* j = __find_iterator(__j); __c_node* ci = i != nullptr ? i->__c_ : nullptr; @@ -391,7 +427,9 @@ void __libcpp_db::swap(void* c1, void* c2) { +#ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); +#endif size_t hc = hash()(c1) % static_cast(__cend_ - __cbeg_); __c_node* p1 = __cbeg_[hc]; _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap A"); @@ -420,7 +458,9 @@ void __libcpp_db::__insert_i(void* __i) { +#ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); +#endif __insert_iterator(__i); } Index: src/future.cpp =================================================================== --- src/future.cpp +++ src/future.cpp @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +#include "__config" + +#ifndef _LIBCPP_HAS_NO_THREADS + #include "future" #include "string" @@ -298,3 +302,7 @@ } _LIBCPP_END_NAMESPACE_STD + +#endif // !_LIBCPP_HAS_NO_THREADS + + Index: src/memory.cpp =================================================================== --- src/memory.cpp +++ src/memory.cpp @@ -9,8 +9,10 @@ #define _LIBCPP_BUILDING_MEMORY #include "memory" +#ifndef _LIBCPP_HAS_NO_THREADS #include "mutex" #include "thread" +#endif _LIBCPP_BEGIN_NAMESPACE_STD @@ -119,7 +121,7 @@ #endif // _LIBCPP_NO_RTTI -#if __has_feature(cxx_atomic) +#if __has_feature(cxx_atomic) && !_LIBCPP_HAS_NO_THREADS static const std::size_t __sp_mut_count = 16; static pthread_mutex_t mut_back_imp[__sp_mut_count] = @@ -172,7 +174,7 @@ return muts[hash()(p) & (__sp_mut_count-1)]; } -#endif // __has_feature(cxx_atomic) +#endif // __has_feature(cxx_atomic) && !_LIBCPP_HAS_NO_THREADS void declare_reachable(void*) Index: src/mutex.cpp =================================================================== --- src/mutex.cpp +++ src/mutex.cpp @@ -14,6 +14,7 @@ #include "cassert" _LIBCPP_BEGIN_NAMESPACE_STD +#ifndef _LIBCPP_HAS_NO_THREADS const defer_lock_t defer_lock = {}; const try_to_lock_t try_to_lock = {}; @@ -206,18 +207,42 @@ } } +#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 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); @@ -248,6 +273,8 @@ } else pthread_mutex_unlock(&mut); +#endif // !_LIBCPP_HAS_NO_THREADS + } _LIBCPP_END_NAMESPACE_STD Index: src/shared_mutex.cpp =================================================================== --- src/shared_mutex.cpp +++ src/shared_mutex.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +#include "__config" +#ifndef _LIBCPP_HAS_NO_THREADS + #define _LIBCPP_BUILDING_SHARED_MUTEX #include "shared_mutex" @@ -99,3 +102,7 @@ _LIBCPP_END_NAMESPACE_STD + +#endif // !_LIBCPP_HAS_NO_THREADS + + Index: src/thread.cpp =================================================================== --- src/thread.cpp +++ src/thread.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +#include "__config" +#ifndef _LIBCPP_HAS_NO_THREADS + #include "thread" #include "exception" #include "vector" @@ -225,3 +228,5 @@ } _LIBCPP_END_NAMESPACE_STD + +#endif // !_LIBCPP_HAS_NO_THREADS