mirror of
https://gcc.gnu.org/git/gcc.git
synced 2025-01-02 00:43:44 +08:00
PR libstdc++/91057 set locale:🆔:_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:🆔:_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
This commit is contained in:
parent
4a8841c041
commit
cc386cf233
@ -1,5 +1,13 @@
|
||||
2019-10-09 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
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.
|
||||
|
||||
PR libstdc++/78552
|
||||
* src/c++98/locale_init.cc (locale::classic()): Do not construct a new
|
||||
locale object for every call.
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user