summaryrefslogtreecommitdiff
path: root/libstdc++-v3/src
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2019-10-09 16:59:56 +0100
committerJonathan Wakely <redi@gcc.gnu.org>2019-10-09 16:59:56 +0100
commitcc386cf23346d7cf78493390c4fe1e3ca4f171e6 (patch)
treeaa639bd1f2716137d71ac6507663d9e968c549e5 /libstdc++-v3/src
parent4a8841c0413d52261a8d024577381582d07a866a (diff)
PR libstdc++/91057 set locale::id::_M_index atomically
If two threads see _M_index==0 concurrently they will both try to set it, potentially storing the facet at two different indices in the array. Either set the _M_index data member using an atomic compare-exchange operation or while holding a mutex. Also move the LONG_DOUBLE_COMPAT code into a separate function to remove the visual noise it creates. PR libstdc++/91057 * src/c++98/locale.cc (locale::id::_M_id()) [__GTHREADS]: Use atomic compare-exchange or double-checked lock to ensure only one thread sets the _M_index variable. [_GLIBCXX_LONG_DOUBLE_COMPAT]: Call find_ldbl_sync_facet to detect facets that share another facet's ID. [_GLIBCXX_LONG_DOUBLE_COMPAT] (find_ldbl_sync_facet): New function. From-SVN: r276762
Diffstat (limited to 'libstdc++-v3/src')
-rw-r--r--libstdc++-v3/src/c++98/locale.cc72
1 files changed, 54 insertions, 18 deletions
diff --git a/libstdc++-v3/src/c++98/locale.cc b/libstdc++-v3/src/c++98/locale.cc
index 8652f8559c2..1d00edc6f51 100644
--- a/libstdc++-v3/src/c++98/locale.cc
+++ b/libstdc++-v3/src/c++98/locale.cc
@@ -474,6 +474,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Definitions for static const data members of locale::id
_Atomic_word locale::id::_S_refcount; // init'd to 0 by linker
+ // XXX GLIBCXX_ABI Deprecated
+#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT
+namespace {
+ inline locale::id*
+ find_ldbl_sync_facet(locale::id* __idp)
+ {
+# define _GLIBCXX_SYNC_ID(facet, mangled) \
+ if (__idp == &::mangled) \
+ return &facet::id
+
+ _GLIBCXX_SYNC_ID (num_get<char>, _ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE);
+ _GLIBCXX_SYNC_ID (num_put<char>, _ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE);
+ _GLIBCXX_SYNC_ID (money_get<char>, _ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE);
+ _GLIBCXX_SYNC_ID (money_put<char>, _ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE);
+# ifdef _GLIBCXX_USE_WCHAR_T
+ _GLIBCXX_SYNC_ID (num_get<wchar_t>, _ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE);
+ _GLIBCXX_SYNC_ID (num_put<wchar_t>, _ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE);
+ _GLIBCXX_SYNC_ID (money_get<wchar_t>, _ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE);
+ _GLIBCXX_SYNC_ID (money_put<wchar_t>, _ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE);
+# endif
+ }
+} // namespace
+#endif
+
size_t
locale::id::_M_id() const throw()
{
@@ -481,26 +505,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
// XXX GLIBCXX_ABI Deprecated
#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT
- locale::id *f = 0;
-# define _GLIBCXX_SYNC_ID(facet, mangled) \
- if (this == &::mangled) \
- f = &facet::id
- _GLIBCXX_SYNC_ID (num_get<char>, _ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE);
- _GLIBCXX_SYNC_ID (num_put<char>, _ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE);
- _GLIBCXX_SYNC_ID (money_get<char>, _ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE);
- _GLIBCXX_SYNC_ID (money_put<char>, _ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE);
-# ifdef _GLIBCXX_USE_WCHAR_T
- _GLIBCXX_SYNC_ID (num_get<wchar_t>, _ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE);
- _GLIBCXX_SYNC_ID (num_put<wchar_t>, _ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE);
- _GLIBCXX_SYNC_ID (money_get<wchar_t>, _ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE);
- _GLIBCXX_SYNC_ID (money_put<wchar_t>, _ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE);
-# endif
- if (f)
- _M_index = 1 + f->_M_id();
+ if (locale::id* f = find_ldbl_sync_facet(this))
+ {
+ const size_t sync_id = f->_M_id();
+ _M_index = 1 + sync_id;
+ return sync_id;
+ }
+#endif
+
+#ifdef __GTHREADS
+ if (__gthread_active_p())
+ {
+ if (__atomic_always_lock_free(sizeof(_M_index), &_M_index))
+ {
+ const _Atomic_word next
+ = 1 + __gnu_cxx::__exchange_and_add(&_S_refcount, 1);
+ size_t expected = 0;
+ __atomic_compare_exchange_n(&_M_index, &expected, next,
+ /* weak = */ false,
+ /* success = */ __ATOMIC_ACQ_REL,
+ /* failure = */ __ATOMIC_ACQUIRE);
+ }
+ else
+ {
+ static __gnu_cxx::__mutex m;
+ __gnu_cxx::__scoped_lock l(m);
+ if (!_M_index)
+ _M_index = ++_S_refcount;
+ }
+ }
else
#endif
- _M_index = 1 + __gnu_cxx::__exchange_and_add_dispatch(&_S_refcount,
- 1);
+ _M_index = ++_S_refcount; // single-threaded case
}
return _M_index - 1;
}