#include <cctype>
#include <cstdio>
#include <cstdlib>
+#include <functional>
using namespace std;
namespace
{
+ /** Returns different instances of __mutex depending on the passed address
+ * in order to limit contention without breaking current library binary
+ * compatibility. */
__gnu_cxx::__mutex&
- get_safe_base_mutex()
+ get_safe_base_mutex(void* __address)
{
- static __gnu_cxx::__mutex safe_base_mutex;
- return safe_base_mutex;
+ const size_t mask = 0xf;
+ static __gnu_cxx::__mutex safe_base_mutex[mask + 1];
+ const size_t index = _Hash_impl::hash(__address) & mask;
+ return safe_base_mutex[index];
+ }
+
+ void
+ swap_seq(__gnu_debug::_Safe_sequence_base& __lhs,
+ __gnu_debug::_Safe_sequence_base& __rhs)
+ {
+ swap(__lhs._M_iterators, __rhs._M_iterators);
+ swap(__lhs._M_const_iterators, __rhs._M_const_iterators);
+ swap(__lhs._M_version, __rhs._M_version);
+ __gnu_debug::_Safe_iterator_base* __iter;
+ for (__iter = __rhs._M_iterators; __iter; __iter = __iter->_M_next)
+ __iter->_M_sequence = &__rhs;
+ for (__iter = __lhs._M_iterators; __iter; __iter = __iter->_M_next)
+ __iter->_M_sequence = &__lhs;
+ for (__iter = __rhs._M_const_iterators; __iter; __iter = __iter->_M_next)
+ __iter->_M_sequence = &__rhs;
+ for (__iter = __lhs._M_const_iterators; __iter; __iter = __iter->_M_next)
+ __iter->_M_sequence = &__lhs;
}
} // anonymous namespace
{
_Safe_iterator_base* __old = __iter;
__iter = __iter->_M_next;
- __old->_M_detach_single();
+ __old->_M_reset();
}
+ _M_iterators = 0;
for (_Safe_iterator_base* __iter2 = _M_const_iterators; __iter2;)
{
_Safe_iterator_base* __old = __iter2;
__iter2 = __iter2->_M_next;
- __old->_M_detach_single();
+ __old->_M_reset();
}
+ _M_const_iterators = 0;
}
void
_Safe_sequence_base::
_M_swap(_Safe_sequence_base& __x)
{
- __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
- swap(_M_iterators, __x._M_iterators);
- swap(_M_const_iterators, __x._M_const_iterators);
- swap(_M_version, __x._M_version);
- _Safe_iterator_base* __iter;
- for (__iter = _M_iterators; __iter; __iter = __iter->_M_next)
- __iter->_M_sequence = this;
- for (__iter = __x._M_iterators; __iter; __iter = __iter->_M_next)
- __iter->_M_sequence = &__x;
- for (__iter = _M_const_iterators; __iter; __iter = __iter->_M_next)
- __iter->_M_sequence = this;
- for (__iter = __x._M_const_iterators; __iter; __iter = __iter->_M_next)
- __iter->_M_sequence = &__x;
+ // We need to lock both sequences to swap
+ using namespace __gnu_cxx;
+ __mutex *__this_mutex = &_M_get_mutex();
+ __mutex *__x_mutex = &__x._M_get_mutex();
+ if (__this_mutex == __x_mutex)
+ {
+ __scoped_lock __lock(*__this_mutex);
+ swap_seq(*this, __x);
+ }
+ else
+ {
+ __scoped_lock __l1(__this_mutex < __x_mutex
+ ? *__this_mutex : *__x_mutex);
+ __scoped_lock __l2(__this_mutex < __x_mutex
+ ? *__x_mutex : *__this_mutex);
+ swap_seq(*this, __x);
+ }
}
__gnu_cxx::__mutex&
_Safe_sequence_base::
_M_get_mutex() throw ()
- { return get_safe_base_mutex(); }
+ { return get_safe_base_mutex(this); }
+
+ void
+ _Safe_sequence_base::
+ _M_attach(_Safe_iterator_base* __it, bool __constant)
+ {
+ __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
+ _M_attach_single(__it, __constant);
+ }
+
+ void
+ _Safe_sequence_base::
+ _M_attach_single(_Safe_iterator_base* __it, bool __constant) throw ()
+ {
+ _Safe_iterator_base*& __its =
+ __constant ? _M_const_iterators : _M_iterators;
+ __it->_M_next = __its;
+ if (__it->_M_next)
+ __it->_M_next->_M_prior = __it;
+ __its = __it;
+ }
+
+ void
+ _Safe_sequence_base::
+ _M_detach(_Safe_iterator_base* __it)
+ {
+ // Remove __it from this sequence's list
+ __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
+ _M_detach_single(__it);
+ }
+
+ void
+ _Safe_sequence_base::
+ _M_detach_single(_Safe_iterator_base* __it) throw ()
+ {
+ // Remove __it from this sequence's list
+ if (__it->_M_prior)
+ __it->_M_prior->_M_next = __it->_M_next;
+ if (__it->_M_next)
+ __it->_M_next->_M_prior = __it->_M_prior;
+
+ if (_M_const_iterators == __it)
+ _M_const_iterators = __it->_M_next;
+ if (_M_iterators == __it)
+ _M_iterators = __it->_M_next;
+ }
void
_Safe_iterator_base::
_M_attach(_Safe_sequence_base* __seq, bool __constant)
{
- __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
- _M_attach_single(__seq, __constant);
+ _M_detach();
+
+ // Attach to the new sequence (if there is one)
+ if (__seq)
+ {
+ _M_sequence = __seq;
+ _M_version = _M_sequence->_M_version;
+ _M_sequence->_M_attach(this, __constant);
+ }
}
void
{
_M_sequence = __seq;
_M_version = _M_sequence->_M_version;
- _M_prior = 0;
- if (__constant)
- {
- _M_next = _M_sequence->_M_const_iterators;
- if (_M_next)
- _M_next->_M_prior = this;
- _M_sequence->_M_const_iterators = this;
- }
- else
- {
- _M_next = _M_sequence->_M_iterators;
- if (_M_next)
- _M_next->_M_prior = this;
- _M_sequence->_M_iterators = this;
- }
+ _M_sequence->_M_attach_single(this, __constant);
}
}
_Safe_iterator_base::
_M_detach()
{
- __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
- _M_detach_single();
+ if (_M_sequence)
+ {
+ _M_sequence->_M_detach(this);
+ }
+
+ _M_reset();
}
void
{
if (_M_sequence)
{
- // Remove us from this sequence's list
- if (_M_prior)
- _M_prior->_M_next = _M_next;
- if (_M_next)
- _M_next->_M_prior = _M_prior;
-
- if (_M_sequence->_M_const_iterators == this)
- _M_sequence->_M_const_iterators = _M_next;
- if (_M_sequence->_M_iterators == this)
- _M_sequence->_M_iterators = _M_next;
+ _M_sequence->_M_detach_single(this);
}
+ _M_reset();
+ }
+
+ void
+ _Safe_iterator_base::
+ _M_reset() throw ()
+ {
_M_sequence = 0;
_M_version = 0;
_M_prior = 0;
__gnu_cxx::__mutex&
_Safe_iterator_base::
_M_get_mutex() throw ()
- { return get_safe_base_mutex(); }
+ { return get_safe_base_mutex(_M_sequence); }
void
_Error_formatter::_Parameter::