diff --git a/libcxx/include/__locale b/libcxx/include/__locale --- a/libcxx/include/__locale +++ b/libcxx/include/__locale @@ -203,7 +203,8 @@ class _LIBCPP_TYPE_VIS locale::id { - once_flag __flag_; + // Reserve space for a once_flag to preserve ABI compatibility + once_flag __reserved; int32_t __id_; static int32_t __next_id; @@ -212,8 +213,6 @@ void operator=(const id&) = delete; id(const id&) = delete; -private: - void __init(); public: // only needed for tests long __get(); diff --git a/libcxx/src/locale.cpp b/libcxx/src/locale.cpp --- a/libcxx/src/locale.cpp +++ b/libcxx/src/locale.cpp @@ -12,6 +12,7 @@ #define _LCONV_C99 #endif +#include "__threading_support" #include "algorithm" #include "clocale" #include "codecvt" @@ -707,36 +708,29 @@ int32_t locale::id::__next_id = 0; -namespace -{ +#ifndef _LIBCPP_HAS_NO_THREADS +_LIBCPP_SAFE_STATIC static __libcpp_mutex_t __id_mut = _LIBCPP_MUTEX_INITIALIZER; +#endif -class __fake_bind -{ - locale::id* id_; - void (locale::id::* pmf_)(); -public: - __fake_bind(void (locale::id::* pmf)(), locale::id* id) - : id_(id), pmf_(pmf) {} +long locale::id::__get() { + // Before we do anything as expensive as acquire a mutex, check if __id_ has already been set + auto id_copy = __libcpp_atomic_load(&__id_, _AO_Relaxed); + if (id_copy != 0) + return id_copy - 1; - void operator()() const - { - (id_->*pmf_)(); - } -}; - -} - -long -locale::id::__get() -{ - call_once(__flag_, __fake_bind(&locale::id::__init, this)); - return __id_ - 1; -} +#ifndef _LIBCPP_HAS_NO_THREADS + __libcpp_mutex_lock(&__m_); +#endif + id_copy = __id_; + if (id_copy == 0) { + id_copy = ++__next_id; + __libcpp_relaxed_store(&__id_, id_copy); + } -void -locale::id::__init() -{ - __id_ = __libcpp_atomic_add(&__next_id, 1); +#ifndef _LIBCPP_HAS_NO_THREADS + __libcpp_mutex_unlock(&__m_); +#endif + return id_copy - 1; } // template <> class collate_byname