Index: include/__mutex_base =================================================================== --- include/__mutex_base +++ include/__mutex_base @@ -14,7 +14,10 @@ #include <__config> #include #include -#include + +#ifndef _WIN32 +#include +#endif #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -24,31 +27,7 @@ #ifndef _LIBCPP_HAS_NO_THREADS -class _LIBCPP_TYPE_VIS mutex -{ - pthread_mutex_t __m_; - -public: - _LIBCPP_INLINE_VISIBILITY -#ifndef _LIBCPP_HAS_NO_CONSTEXPR - constexpr mutex() _NOEXCEPT : __m_(PTHREAD_MUTEX_INITIALIZER) {} -#else - mutex() _NOEXCEPT {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;} -#endif - ~mutex(); - -private: - mutex(const mutex&);// = delete; - mutex& operator=(const mutex&);// = delete; - -public: - void lock(); - bool try_lock() _NOEXCEPT; - void unlock() _NOEXCEPT; - - typedef pthread_mutex_t* native_handle_type; - _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;} -}; +using __libcxx_support::mutex; struct _LIBCPP_TYPE_VIS defer_lock_t {}; struct _LIBCPP_TYPE_VIS try_to_lock_t {}; @@ -264,26 +243,23 @@ }; _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status) -class _LIBCPP_TYPE_VIS condition_variable +class _LIBCPP_TYPE_VIS condition_variable : private __libcxx_support::condition_variable { - pthread_cond_t __cv_; + typedef __libcxx_support::condition_variable base; public: _LIBCPP_INLINE_VISIBILITY -#ifndef _LIBCPP_HAS_NO_CONSTEXPR - constexpr condition_variable() : __cv_(PTHREAD_COND_INITIALIZER) {} -#else - condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;} -#endif - ~condition_variable(); + condition_variable() {} private: condition_variable(const condition_variable&); // = delete; condition_variable& operator=(const condition_variable&); // = delete; public: - void notify_one() _NOEXCEPT; - void notify_all() _NOEXCEPT; - + typedef base::native_handle_type native_handle_type; + using base::notify_one; + using base::notify_all; + using base::native_handle; + void wait(unique_lock& __lk) _NOEXCEPT; template void wait(unique_lock& __lk, _Predicate __pred); @@ -310,8 +286,6 @@ const chrono::duration<_Rep, _Period>& __d, _Predicate __pred); - typedef pthread_cond_t* native_handle_type; - _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;} private: void __do_timed_wait(unique_lock& __lk, Index: include/mutex =================================================================== --- include/mutex +++ include/mutex @@ -179,7 +179,10 @@ #ifndef _LIBCPP_HAS_NO_VARIADICS #include #endif -#include +#ifndef _WIN32 +#include +#include +#endif #include <__undef_min_max> @@ -191,27 +194,7 @@ #ifndef _LIBCPP_HAS_NO_THREADS -class _LIBCPP_TYPE_VIS recursive_mutex -{ - pthread_mutex_t __m_; - -public: - recursive_mutex(); - ~recursive_mutex(); - -private: - recursive_mutex(const recursive_mutex&); // = delete; - recursive_mutex& operator=(const recursive_mutex&); // = delete; - -public: - void lock(); - bool try_lock() _NOEXCEPT; - void unlock() _NOEXCEPT; - - typedef pthread_mutex_t* native_handle_type; - _LIBCPP_INLINE_VISIBILITY - native_handle_type native_handle() {return &__m_;} -}; +using __libcxx_support::recursive_mutex; class _LIBCPP_TYPE_VIS timed_mutex { @@ -257,10 +240,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_; + __libcxx_support::__thread_id __id_; public: recursive_timed_mutex(); ~recursive_timed_mutex(); @@ -286,9 +269,9 @@ recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { using namespace chrono; - pthread_t __id = pthread_self(); + __libcxx_support::__thread_id __id = __libcxx_support::get_id(); unique_lock lk(__m_); - if (pthread_equal(__id, __id_)) + if (__id == __id_) { if (__count_ == numeric_limits::max()) return false; @@ -360,7 +343,7 @@ break; } } - sched_yield(); + __libcxx_support::yield(); { unique_lock<_L1> __u1(__l1); if (__l0.try_lock()) @@ -369,7 +352,7 @@ break; } } - sched_yield(); + __libcxx_support::yield(); } } @@ -394,7 +377,7 @@ } } ++__i; - sched_yield(); + __libcxx_support::yield(); break; case 1: { @@ -410,7 +393,7 @@ __i = 0; else __i += 2; - sched_yield(); + __libcxx_support::yield(); break; default: __lock_first(__i - 2, __l2, __l3..., __l0, __l1); @@ -531,7 +514,7 @@ (*__p)(); } -_LIBCPP_FUNC_VIS void __call_once(volatile unsigned long&, void*, void(*)(void*)); +using __libcxx_support::__call_once; #ifndef _LIBCPP_HAS_NO_VARIADICS Index: include/support/pthread/mutex.hpp =================================================================== --- /dev/null +++ include/support/pthread/mutex.hpp @@ -0,0 +1,115 @@ +// -*- C++ -*- +//===---------------------- support/pthread/mutex.hpp ---------------------===// +// +// 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_HPP +#define _LIBCPP_SUPPORT_PTHREAD_MUTEX_HPP + +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __libcxx_support +{ + +#ifndef _LIBCPP_HAS_NO_THREADS + +class _LIBCPP_TYPE_VIS mutex +{ + pthread_mutex_t __m_; +public: + _LIBCPP_INLINE_VISIBILITY +#ifndef _LIBCPP_HAS_NO_CONSTEXPR + constexpr mutex() _NOEXCEPT : __m_(PTHREAD_MUTEX_INITIALIZER) {} +#else + mutex() _NOEXCEPT {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;} +#endif + ~mutex(); + +private: + mutex(const mutex&);// = delete; + mutex& operator=(const mutex&);// = delete; + +public: + void lock(); + bool try_lock() _NOEXCEPT; + void unlock() _NOEXCEPT; + + typedef pthread_mutex_t* native_handle_type; + _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;} +}; + + +class _LIBCPP_TYPE_VIS condition_variable +{ + pthread_cond_t __cv_; +public: + _LIBCPP_INLINE_VISIBILITY +#ifndef _LIBCPP_HAS_NO_CONSTEXPR + constexpr condition_variable() : __cv_(PTHREAD_COND_INITIALIZER) {} +#else + condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;} +#endif + ~condition_variable(); + +private: + condition_variable(const condition_variable&); // = delete; + condition_variable& operator=(const condition_variable&); // = delete; + +public: + void notify_one() _NOEXCEPT; + void notify_all() _NOEXCEPT; + + typedef pthread_cond_t* native_handle_type; + _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;} + +protected: + void __wait(pthread_mutex_t* __lk) _NOEXCEPT; + void __do_timed_wait(pthread_mutex_t* __lk, + _VSTD::chrono::time_point<_VSTD::chrono::system_clock, _VSTD::chrono::nanoseconds> __tp) _NOEXCEPT; +}; + + +class _LIBCPP_TYPE_VIS recursive_mutex +{ + pthread_mutex_t __m_; + +public: + recursive_mutex(); + ~recursive_mutex(); + +private: + recursive_mutex(const recursive_mutex&); // = delete; + recursive_mutex& operator=(const recursive_mutex&); // = delete; + +public: + void lock(); + bool try_lock() _NOEXCEPT; + void unlock() _NOEXCEPT; + + typedef pthread_mutex_t* native_handle_type; + _LIBCPP_INLINE_VISIBILITY + native_handle_type native_handle() {return &__m_;} +}; + + +_LIBCPP_FUNC_VIS void __call_once(volatile unsigned long&, void*, void(*)(void*)); + +#endif + +} // namespace __libcxx_support + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_SUPPORT_PTHREAD_MUTEX_HPP Index: include/support/pthread/thread.hpp =================================================================== --- /dev/null +++ include/support/pthread/thread.hpp @@ -0,0 +1,221 @@ +// -*- C++ -*- +//===---------------------- support/pthread/thread.hpp --------------------===// +// +// 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_HPP +#define _LIBCPP_SUPPORT_PTHREAD_THREAD_HPP + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +#include +#include +#include +#include + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __libcxx_support +{ + +template +class __thread_specific_ptr +{ + pthread_key_t __key_; + + __thread_specific_ptr(const __thread_specific_ptr&); + __thread_specific_ptr& operator=(const __thread_specific_ptr&); + + static void __at_thread_exit(void*); +public: + typedef _Tp* pointer; + + __thread_specific_ptr(); + ~__thread_specific_ptr(); + + _LIBCPP_INLINE_VISIBILITY + pointer get() const {return static_cast<_Tp*>(pthread_getspecific(__key_));} + _LIBCPP_INLINE_VISIBILITY + pointer operator*() const {return *get();} + _LIBCPP_INLINE_VISIBILITY + pointer operator->() const {return get();} + pointer release(); + void reset(pointer __p = nullptr); +}; + +template +void +__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) +{ + delete static_cast(__p); +} + +template +__thread_specific_ptr<_Tp>::__thread_specific_ptr() +{ + int __ec = pthread_key_create(&__key_, &__thread_specific_ptr::__at_thread_exit); +#ifndef _LIBCPP_NO_EXCEPTIONS + if (__ec) + throw system_error(error_code(__ec, system_category()), + "__thread_specific_ptr construction failed"); +#endif +} + +template +__thread_specific_ptr<_Tp>::~__thread_specific_ptr() +{ + pthread_key_delete(__key_); +} + +template +typename __thread_specific_ptr<_Tp>::pointer +__thread_specific_ptr<_Tp>::release() +{ + pointer __p = get(); + pthread_setspecific(__key_, 0); + return __p; +} + +template +void +__thread_specific_ptr<_Tp>::reset(pointer __p) +{ + pointer __p_old = get(); + pthread_setspecific(__key_, __p); + delete __p_old; +} + +class _LIBCPP_TYPE_VIS_ONLY __thread_id; + +inline _LIBCPP_INLINE_VISIBILITY __thread_id get_id() _NOEXCEPT; + +class _LIBCPP_TYPE_VIS_ONLY __thread_id +{ + // 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_; + +public: + _LIBCPP_INLINE_VISIBILITY + __thread_id() _NOEXCEPT : __id_(0) {} + + _LIBCPP_INLINE_VISIBILITY + void reset() { __id_ = 0; } + + friend _LIBCPP_INLINE_VISIBILITY + bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT + {return __x.__id_ == __y.__id_;} + 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_;} + friend _LIBCPP_INLINE_VISIBILITY + bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT + {return !(__y < __x);} + friend _LIBCPP_INLINE_VISIBILITY + bool operator> (__thread_id __x, __thread_id __y) _NOEXCEPT + {return __y < __x ;} + friend _LIBCPP_INLINE_VISIBILITY + bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT + {return !(__x < __y);} + + template + friend + _LIBCPP_INLINE_VISIBILITY + basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) + {return __os << __id.__id_;} + +private: + _LIBCPP_INLINE_VISIBILITY + __thread_id(pthread_t __id) : __id_(__id) {} + + friend __thread_id get_id() _NOEXCEPT; + friend class _LIBCPP_TYPE_VIS thread; + friend struct _LIBCPP_TYPE_VIS_ONLY hash<__thread_id>; +}; + +inline _LIBCPP_INLINE_VISIBILITY +__thread_id +get_id() _NOEXCEPT +{ + return pthread_self(); +} + + +inline _LIBCPP_INLINE_VISIBILITY +void yield() _NOEXCEPT +{ + sched_yield(); +} + +class _LIBCPP_TYPE_VIS thread +{ +protected: + pthread_t __t_; + + template + void start_thread(_Fp&& f, _Args&& __p); +public: + typedef __thread_id id; + typedef pthread_t native_handle_type; + + _LIBCPP_INLINE_VISIBILITY + thread() _NOEXCEPT : __t_(0) {} + + _LIBCPP_INLINE_VISIBILITY + bool joinable() const _NOEXCEPT {return __t_ != 0;} + void join(); + void detach(); + _LIBCPP_INLINE_VISIBILITY + id get_id() const _NOEXCEPT {return __t_;} + _LIBCPP_INLINE_VISIBILITY + native_handle_type native_handle() _NOEXCEPT {return __t_;} + +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + _LIBCPP_INLINE_VISIBILITY + thread(thread&& __t) _NOEXCEPT : __t_(__t.__t_) {__t.__t_ = 0;} + thread& operator=(thread&& __t) _NOEXCEPT; +#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES +}; + + + +template +void thread::start_thread(_Fp&& __f, _Args&& __p) +{ + int __ec = pthread_create(&__t_, 0, __f, __p.get()); + if (__ec == 0) + __p.release(); + else + __throw_system_error(__ec, "thread constructor failed"); +} + + + +} // __libcxx_support + +template<> +struct _LIBCPP_TYPE_VIS_ONLY hash<__libcxx_support::__thread_id> + : public unary_function<__libcxx_support::__thread_id, size_t> +{ + _LIBCPP_INLINE_VISIBILITY + size_t operator()(__libcxx_support::__thread_id __v) const + { + return hash()(__v.__id_); + } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_SUPPORT_PTHREAD_THREAD_HPP Index: include/thread =================================================================== --- include/thread +++ include/thread @@ -98,8 +98,6 @@ #ifndef _LIBCPP_HAS_NO_VARIADICS #include #endif -#include -#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -111,168 +109,35 @@ #error is not supported on this single threaded system #else // !_LIBCPP_HAS_NO_THREADS -_LIBCPP_BEGIN_NAMESPACE_STD - -template -class __thread_specific_ptr -{ - pthread_key_t __key_; - - __thread_specific_ptr(const __thread_specific_ptr&); - __thread_specific_ptr& operator=(const __thread_specific_ptr&); - - static void __at_thread_exit(void*); -public: - typedef _Tp* pointer; - - __thread_specific_ptr(); - ~__thread_specific_ptr(); +#ifndef _WIN32 +#include +#endif // _WIN32 - _LIBCPP_INLINE_VISIBILITY - pointer get() const {return static_cast<_Tp*>(pthread_getspecific(__key_));} - _LIBCPP_INLINE_VISIBILITY - pointer operator*() const {return *get();} - _LIBCPP_INLINE_VISIBILITY - pointer operator->() const {return get();} - pointer release(); - void reset(pointer __p = nullptr); -}; - -template -void -__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) -{ - delete static_cast(__p); -} - -template -__thread_specific_ptr<_Tp>::__thread_specific_ptr() -{ - int __ec = pthread_key_create(&__key_, &__thread_specific_ptr::__at_thread_exit); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (__ec) - throw system_error(error_code(__ec, system_category()), - "__thread_specific_ptr construction failed"); -#endif -} - -template -__thread_specific_ptr<_Tp>::~__thread_specific_ptr() -{ - pthread_key_delete(__key_); -} - -template -typename __thread_specific_ptr<_Tp>::pointer -__thread_specific_ptr<_Tp>::release() -{ - pointer __p = get(); - pthread_setspecific(__key_, 0); - return __p; -} - -template -void -__thread_specific_ptr<_Tp>::reset(pointer __p) -{ - pointer __p_old = get(); - pthread_setspecific(__key_, __p); - delete __p_old; -} +_LIBCPP_BEGIN_NAMESPACE_STD class _LIBCPP_TYPE_VIS thread; -class _LIBCPP_TYPE_VIS __thread_id; +using __libcxx_support::__thread_id; namespace this_thread { -_LIBCPP_INLINE_VISIBILITY __thread_id get_id() _NOEXCEPT; +using __libcxx_support::get_id; } // this_thread -template<> struct _LIBCPP_TYPE_VIS_ONLY hash<__thread_id>; - -class _LIBCPP_TYPE_VIS_ONLY __thread_id -{ - // 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_; - -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_;} - 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_;} - friend _LIBCPP_INLINE_VISIBILITY - bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT - {return !(__y < __x);} - friend _LIBCPP_INLINE_VISIBILITY - bool operator> (__thread_id __x, __thread_id __y) _NOEXCEPT - {return __y < __x ;} - friend _LIBCPP_INLINE_VISIBILITY - bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT - {return !(__x < __y);} - - template - friend - _LIBCPP_INLINE_VISIBILITY - basic_ostream<_CharT, _Traits>& - operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) - {return __os << __id.__id_;} - -private: - _LIBCPP_INLINE_VISIBILITY - __thread_id(pthread_t __id) : __id_(__id) {} - - friend __thread_id this_thread::get_id() _NOEXCEPT; - friend class _LIBCPP_TYPE_VIS thread; - friend struct _LIBCPP_TYPE_VIS_ONLY hash<__thread_id>; -}; - -template<> -struct _LIBCPP_TYPE_VIS_ONLY hash<__thread_id> - : public unary_function<__thread_id, size_t> -{ - _LIBCPP_INLINE_VISIBILITY - size_t operator()(__thread_id __v) const - { - return hash()(__v.__id_); - } -}; -namespace this_thread +class _LIBCPP_TYPE_VIS thread : private __libcxx_support::thread { - -inline _LIBCPP_INLINE_VISIBILITY -__thread_id -get_id() _NOEXCEPT -{ - return pthread_self(); -} - -} // this_thread - -class _LIBCPP_TYPE_VIS thread -{ - pthread_t __t_; - + typedef __libcxx_support::thread base; + thread(const thread&); thread& operator=(const thread&); public: typedef __thread_id id; - typedef pthread_t native_handle_type; + typedef __libcxx_support::thread::native_handle_type native_handle_type; _LIBCPP_INLINE_VISIBILITY - thread() _NOEXCEPT : __t_(0) {} + thread() _NOEXCEPT {} #ifndef _LIBCPP_HAS_NO_VARIADICS template & __thread_local_data(); +_LIBCPP_FUNC_VIS __libcxx_support::__thread_specific_ptr<__thread_struct>& __thread_local_data(); + +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + +inline _LIBCPP_INLINE_VISIBILITY +thread& +thread::operator=(thread&& __t) _NOEXCEPT +{ + if (__t_ != 0) + terminate(); + __t_ = __t.__t_; + __t.__t_ = 0; + return *this; +} + +#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES #ifndef _LIBCPP_HAS_NO_VARIADICS @@ -356,11 +233,7 @@ typedef tuple::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()); - if (__ec == 0) - __p.release(); - else - __throw_system_error(__ec, "thread constructor failed"); + this->start_thread(&__thread_proxy<_Gp>, _VSTD::move(__p)); } #else // _LIBCPP_HAS_NO_VARIADICS @@ -379,30 +252,11 @@ thread::thread(_Fp __f) { std::unique_ptr<_Fp> __p(new _Fp(__f)); - int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Fp>, __p.get()); - if (__ec == 0) - __p.release(); - else - __throw_system_error(__ec, "thread constructor failed"); + this->start_thread(&__thread_proxy<_Gp>, _VSTD::move(__p)); } #endif // _LIBCPP_HAS_NO_VARIADICS -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - -inline _LIBCPP_INLINE_VISIBILITY -thread& -thread::operator=(thread&& __t) _NOEXCEPT -{ - if (__t_ != 0) - terminate(); - __t_ = __t.__t_; - __t.__t_ = 0; - return *this; -} - -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES - inline _LIBCPP_INLINE_VISIBILITY void swap(thread& __x, thread& __y) _NOEXCEPT {__x.swap(__y);} @@ -453,9 +307,8 @@ sleep_for(__t - steady_clock::now()); } -inline _LIBCPP_INLINE_VISIBILITY -void yield() _NOEXCEPT {sched_yield();} - +using __libcxx_support::yield; + } // this_thread _LIBCPP_END_NAMESPACE_STD 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) Index: src/algorithm.cpp =================================================================== --- src/algorithm.cpp +++ src/algorithm.cpp @@ -48,14 +48,14 @@ 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; +static mutex __rs_mut; #endif unsigned __rs_default::__c_ = 0; __rs_default::__rs_default() { #ifndef _LIBCPP_HAS_NO_THREADS - pthread_mutex_lock(&__rs_mut); + __rs_mut.lock(); #endif __c_ = 1; } @@ -69,7 +69,7 @@ { #ifndef _LIBCPP_HAS_NO_THREADS if (--__c_ == 0) - pthread_mutex_unlock(&__rs_mut); + __rs_mut.unlock(); #else --__c_; #endif Index: src/condition_variable.cpp =================================================================== --- src/condition_variable.cpp +++ src/condition_variable.cpp @@ -18,62 +18,23 @@ _LIBCPP_BEGIN_NAMESPACE_STD -condition_variable::~condition_variable() -{ - pthread_cond_destroy(&__cv_); -} - -void -condition_variable::notify_one() _NOEXCEPT -{ - pthread_cond_signal(&__cv_); -} - -void -condition_variable::notify_all() _NOEXCEPT -{ - pthread_cond_broadcast(&__cv_); -} - void condition_variable::wait(unique_lock& 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()); - if (ec) - __throw_system_error(ec, "condition_variable wait failed"); + base::__wait(lk.mutex()->native_handle()); } void condition_variable::__do_timed_wait(unique_lock& lk, chrono::time_point 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(d); - typedef decltype(ts.tv_sec) ts_sec; - _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits::max(); - if (s.count() < ts_sec_max) - { - ts.tv_sec = static_cast(s.count()); - ts.tv_nsec = static_cast((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"); + base::__do_timed_wait(lk.mutex()->native_handle(), tp); } void Index: src/memory.cpp =================================================================== --- src/memory.cpp +++ src/memory.cpp @@ -127,15 +127,9 @@ #if __has_feature(cxx_atomic) && !defined(_LIBCPP_HAS_NO_THREADS) static const std::size_t __sp_mut_count = 16; -static pthread_mutex_t 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 -}; +static mutex mut_back_imp[__sp_mut_count]; -static mutex* mut_back = reinterpret_cast(mut_back_imp); +static mutex* mut_back = mut_back_imp; _LIBCPP_CONSTEXPR __sp_mut::__sp_mut(void* p) _NOEXCEPT : __lx(p) Index: src/mutex.cpp =================================================================== --- src/mutex.cpp +++ src/mutex.cpp @@ -21,92 +21,7 @@ const try_to_lock_t try_to_lock = {}; const adopt_lock_t adopt_lock = {}; -mutex::~mutex() -{ - pthread_mutex_destroy(&__m_); -} -void -mutex::lock() -{ - int ec = pthread_mutex_lock(&__m_); - if (ec) - __throw_system_error(ec, "mutex lock failed"); -} - -bool -mutex::try_lock() _NOEXCEPT -{ - return pthread_mutex_trylock(&__m_) == 0; -} - -void -mutex::unlock() _NOEXCEPT -{ - int ec = pthread_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"); -} - -recursive_mutex::~recursive_mutex() -{ - int e = pthread_mutex_destroy(&__m_); - (void)e; - assert(e == 0); -} - -void -recursive_mutex::lock() -{ - int ec = pthread_mutex_lock(&__m_); - if (ec) - __throw_system_error(ec, "recursive_mutex lock failed"); -} - -void -recursive_mutex::unlock() _NOEXCEPT -{ - int e = pthread_mutex_unlock(&__m_); - (void)e; - assert(e == 0); -} - -bool -recursive_mutex::try_lock() _NOEXCEPT -{ - return pthread_mutex_trylock(&__m_) == 0; -} // timed_mutex @@ -153,7 +68,7 @@ recursive_timed_mutex::recursive_timed_mutex() : __count_(0), - __id_(0) + __id_() { } @@ -165,9 +80,9 @@ void recursive_timed_mutex::lock() { - pthread_t id = pthread_self(); + __libcxx_support::__thread_id id = __libcxx_support::get_id(); unique_lock lk(__m_); - if (pthread_equal(id, __id_)) + if (id == __id_) { if (__count_ == numeric_limits::max()) __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached"); @@ -183,9 +98,9 @@ bool recursive_timed_mutex::try_lock() _NOEXCEPT { - pthread_t id = pthread_self(); + __libcxx_support::__thread_id id = __libcxx_support::get_id(); unique_lock lk(__m_, try_to_lock); - if (lk.owns_lock() && (__count_ == 0 || pthread_equal(id, __id_))) + if (lk.owns_lock() && (__count_ == 0 || (id == __id_))) { if (__count_ == numeric_limits::max()) return false; @@ -202,83 +117,14 @@ unique_lock lk(__m_); if (--__count_ == 0) { - __id_ = 0; + __id_.reset(); lk.unlock(); __cv_.notify_one(); } } -#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*)) -{ -#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_END_NAMESPACE_STD Index: src/support/pthread/condition_variable.cpp =================================================================== --- /dev/null +++ src/support/pthread/condition_variable.cpp @@ -0,0 +1,78 @@ +// -*- C++ -*- +//===--------------- support/pthread/condition_variable.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" +#ifndef _LIBCPP_HAS_NO_THREADS +#include +#include +#include + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __libcxx_support +{ + +condition_variable::~condition_variable() +{ + pthread_cond_destroy(&__cv_); +} + +void +condition_variable::notify_one() _NOEXCEPT +{ + pthread_cond_signal(&__cv_); +} + +void +condition_variable::notify_all() _NOEXCEPT +{ + pthread_cond_broadcast(&__cv_); +} + +void +condition_variable::__wait(pthread_mutex_t* lk) _NOEXCEPT +{ + int ec = pthread_cond_wait(&__cv_, lk); + if (ec) + __throw_system_error(ec, "condition_variable wait failed"); +} + +void +condition_variable::__do_timed_wait(pthread_mutex_t* lk, + _VSTD::chrono::time_point<_VSTD::chrono::system_clock, _VSTD::chrono::nanoseconds> tp) _NOEXCEPT +{ + using namespace _VSTD::chrono; + nanoseconds d = tp.time_since_epoch(); + if (d > nanoseconds(0x59682F000000E941)) + d = nanoseconds(0x59682F000000E941); + timespec ts; + seconds s = duration_cast(d); + typedef decltype(ts.tv_sec) ts_sec; + _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits::max(); + if (s.count() < ts_sec_max) + { + ts.tv_sec = static_cast(s.count()); + ts.tv_nsec = static_cast((d - s).count()); + } + else + { + ts.tv_sec = ts_sec_max; + ts.tv_nsec = giga::num - 1; + } + int ec = pthread_cond_timedwait(&__cv_, lk, &ts); + if (ec != 0 && ec != ETIMEDOUT) + __throw_system_error(ec, "condition_variable timed_wait failed"); +} + +} // namespace __libcxx_support + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_HAS_NO_THREADS Index: src/support/pthread/mutex.cpp =================================================================== --- /dev/null +++ src/support/pthread/mutex.cpp @@ -0,0 +1,184 @@ +// -*- C++ -*- +//===---------------------- support/pthread/mutex.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" +#ifndef _LIBCPP_HAS_NO_THREADS + +#include +#include +#include +#include "../atomic_support.h" + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __libcxx_support +{ + +mutex::~mutex() +{ + pthread_mutex_destroy(&__m_); +} + +void +mutex::lock() +{ + int ec = pthread_mutex_lock(&__m_); + if (ec) + __throw_system_error(ec, "mutex lock failed"); +} + +bool +mutex::try_lock() _NOEXCEPT +{ + return pthread_mutex_trylock(&__m_) == 0; +} + +void +mutex::unlock() _NOEXCEPT +{ + int ec = pthread_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"); +} + +recursive_mutex::~recursive_mutex() +{ + int e = pthread_mutex_destroy(&__m_); + (void)e; + assert(e == 0); +} + +void +recursive_mutex::lock() +{ + int ec = pthread_mutex_lock(&__m_); + if (ec) + __throw_system_error(ec, "recursive_mutex lock failed"); +} + +void +recursive_mutex::unlock() _NOEXCEPT +{ + int e = pthread_mutex_unlock(&__m_); + (void)e; + assert(e == 0); +} + +bool +recursive_mutex::try_lock() _NOEXCEPT +{ + return pthread_mutex_trylock(&__m_) == 0; +} + +// 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. + +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; +#endif // _LIBCPP_HAS_NO_THREADS + + +/// 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*)) +{ +#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 __libcxx_support + +_LIBCPP_END_NAMESPACE_STD 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" +#ifndef _LIBCPP_HAS_NO_THREADS + +#include + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __libcxx_support +{ + +void +thread::join() +{ + int ec = pthread_join(__t_, 0); +#ifndef _LIBCPP_NO_EXCEPTIONS + if (ec) + throw system_error(error_code(ec, system_category()), "thread::join failed"); +#else + (void)ec; +#endif // _LIBCPP_NO_EXCEPTIONS + __t_ = 0; +} + +void +thread::detach() +{ + int ec = EINVAL; + if (__t_ != 0) + { + ec = pthread_detach(__t_); + if (ec == 0) + __t_ = 0; + } +#ifndef _LIBCPP_NO_EXCEPTIONS + if (ec) + throw system_error(error_code(ec, system_category()), "thread::detach failed"); +#endif // _LIBCPP_NO_EXCEPTIONS +} + +} // namespace __libcxx_support + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_HAS_NO_THREADS Index: src/thread.cpp =================================================================== --- src/thread.cpp +++ src/thread.cpp @@ -38,34 +38,6 @@ terminate(); } -void -thread::join() -{ - int ec = pthread_join(__t_, 0); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (ec) - throw system_error(error_code(ec, system_category()), "thread::join failed"); -#else - (void)ec; -#endif // _LIBCPP_NO_EXCEPTIONS - __t_ = 0; -} - -void -thread::detach() -{ - int ec = EINVAL; - if (__t_ != 0) - { - ec = pthread_detach(__t_); - if (ec == 0) - __t_ = 0; - } -#ifndef _LIBCPP_NO_EXCEPTIONS - if (ec) - throw system_error(error_code(ec, system_category()), "thread::detach failed"); -#endif // _LIBCPP_NO_EXCEPTIONS -} unsigned thread::hardware_concurrency() _NOEXCEPT @@ -132,10 +104,10 @@ } // this_thread -__thread_specific_ptr<__thread_struct>& +__libcxx_support::__thread_specific_ptr<__thread_struct>& __thread_local_data() { - static __thread_specific_ptr<__thread_struct> __p; + static __libcxx_support::__thread_specific_ptr<__thread_struct> __p; return __p; }