diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index 9b5bb23..c9a253e 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -1947,6 +1947,21 @@ GLIBCXX_3.4.23 { _ZNSsC[12]ERKSs[jmy]RKSaIcE; _ZNSbIwSt11char_traitsIwESaIwEEC[12]ERKS2_mRKS1_; + # __gnu_debug::_Safe_sequence_base + _ZN11__gnu_debug19_Safe_sequence_base18_M_detach_singularEm; + _ZN11__gnu_debug19_Safe_sequence_base22_M_revalidate_singularEm; + _ZN11__gnu_debug19_Safe_sequence_base12_M_get_mutexEm; + _ZN11__gnu_debug19_Safe_sequence_base7_M_swapERS0_m; + + # __gnu_debug::_Safe_iterator_base + _ZN11__gnu_debug19_Safe_iterator_base9_M_attachEPNS_19_Safe_sequence_baseEbm; + _ZN11__gnu_debug19_Safe_iterator_base9_M_detachEm; + + # __gnu_debug::_Safe_unordered_container_base and _Safe_local_iterator_base + _ZN11__gnu_debug30_Safe_unordered_container_base7_M_swapERS0_m; + _ZN11__gnu_debug25_Safe_local_iterator_base9_M_attachEPNS_19_Safe_sequence_baseEbm; + _ZN11__gnu_debug25_Safe_local_iterator_base9_M_detachEm; + } GLIBCXX_3.4.22; # Symbols in the support library (libsupc++) have their own tag. diff --git a/libstdc++-v3/include/debug/bitset b/libstdc++-v3/include/debug/bitset index 55d3281..024cc18 100644 --- a/libstdc++-v3/include/debug/bitset +++ b/libstdc++-v3/include/debug/bitset @@ -56,6 +56,10 @@ namespace __debug #if __cplusplus >= 201103L typedef typename _Base::reference reference; #else + static std::size_t + _S_alignment() + { return _Lowest_power_of_two<__alignof(bitset)>::__val; } + // bit reference: class reference : private _Base::reference @@ -66,22 +70,24 @@ namespace __debug friend class bitset; reference(); - reference(const _Base_ref& __base, - bitset* __seq __attribute__((__unused__))) _GLIBCXX_NOEXCEPT + reference(const _Base_ref& __base, bitset* __seq) _GLIBCXX_NOEXCEPT : _Base_ref(__base) - , _Safe_iterator_base(__seq, false) + , _Safe_iterator_base(__seq, false, _S_alignment()) { } public: reference(const reference& __x) _GLIBCXX_NOEXCEPT : _Base_ref(__x) - , _Safe_iterator_base(__x, false) + , _Safe_iterator_base(__x, false, _S_alignment()) { } + ~reference() + { this->_M_detach(_S_alignment()); } + reference& operator=(bool __x) _GLIBCXX_NOEXCEPT { - _GLIBCXX_DEBUG_VERIFY(! this->_M_singular(), + _GLIBCXX_DEBUG_VERIFY(!this->_M_singular(), _M_message(__gnu_debug::__msg_bad_bitset_write) ._M_iterator(*this)); *static_cast<_Base_ref*>(this) = __x; @@ -91,10 +97,10 @@ namespace __debug reference& operator=(const reference& __x) _GLIBCXX_NOEXCEPT { - _GLIBCXX_DEBUG_VERIFY(! __x._M_singular(), + _GLIBCXX_DEBUG_VERIFY(!__x._M_singular(), _M_message(__gnu_debug::__msg_bad_bitset_read) ._M_iterator(__x)); - _GLIBCXX_DEBUG_VERIFY(! this->_M_singular(), + _GLIBCXX_DEBUG_VERIFY(!this->_M_singular(), _M_message(__gnu_debug::__msg_bad_bitset_write) ._M_iterator(*this)); *static_cast<_Base_ref*>(this) = __x; @@ -104,7 +110,7 @@ namespace __debug bool operator~() const _GLIBCXX_NOEXCEPT { - _GLIBCXX_DEBUG_VERIFY(! this->_M_singular(), + _GLIBCXX_DEBUG_VERIFY(!this->_M_singular(), _M_message(__gnu_debug::__msg_bad_bitset_read) ._M_iterator(*this)); return ~(*static_cast(this)); @@ -112,7 +118,7 @@ namespace __debug operator bool() const _GLIBCXX_NOEXCEPT { - _GLIBCXX_DEBUG_VERIFY(! this->_M_singular(), + _GLIBCXX_DEBUG_VERIFY(!this->_M_singular(), _M_message(__gnu_debug::__msg_bad_bitset_read) ._M_iterator(*this)); return *static_cast(this); @@ -121,7 +127,7 @@ namespace __debug reference& flip() _GLIBCXX_NOEXCEPT { - _GLIBCXX_DEBUG_VERIFY(! this->_M_singular(), + _GLIBCXX_DEBUG_VERIFY(!this->_M_singular(), _M_message(__gnu_debug::__msg_bad_bitset_flip) ._M_iterator(*this)); _Base_ref::flip(); diff --git a/libstdc++-v3/include/debug/safe_base.h b/libstdc++-v3/include/debug/safe_base.h index aad9c52..7c3e4a0 100644 --- a/libstdc++-v3/include/debug/safe_base.h +++ b/libstdc++-v3/include/debug/safe_base.h @@ -49,6 +49,8 @@ namespace __gnu_debug */ class _Safe_iterator_base { + friend class _Safe_sequence_base; + public: /** The sequence this iterator references; may be NULL to indicate a singular iterator. */ @@ -84,31 +86,34 @@ namespace __gnu_debug * singular. Otherwise, the iterator will reference @p __seq and * be nonsingular. */ - _Safe_iterator_base(const _Safe_sequence_base* __seq, bool __constant) + _Safe_iterator_base(const _Safe_sequence_base* __seq, bool __constant, + std::size_t __alignment) : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0) - { this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant); } + { + this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant, + __alignment); + } /** Initializes the iterator to reference the same sequence that @p __x does. @p __constant is true if this is a constant iterator, and false if it is mutable. */ - _Safe_iterator_base(const _Safe_iterator_base& __x, bool __constant) + _Safe_iterator_base(const _Safe_iterator_base& __x, bool __constant, + std::size_t __alignment) : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0) - { this->_M_attach(__x._M_sequence, __constant); } - - ~_Safe_iterator_base() { this->_M_detach(); } + { this->_M_attach(__x._M_sequence, __constant, __alignment); } /** For use in _Safe_iterator. */ __gnu_cxx::__mutex& - _M_get_mutex() throw (); + _M_get_mutex(std::size_t __alignment) throw (); - public: /** Attaches this iterator to the given sequence, detaching it * from whatever sequence it was attached to originally. If the * new sequence is the NULL pointer, the iterator is left * unattached. */ void - _M_attach(_Safe_sequence_base* __seq, bool __constant); + _M_attach(_Safe_sequence_base* __seq, bool __constant, + std::size_t __alignment); /** Likewise, but not thread-safe. */ void @@ -118,12 +123,13 @@ namespace __gnu_debug * if any. */ void - _M_detach(); + _M_detach(std::size_t __alignment); /** Likewise, but not thread-safe. */ void _M_detach_single() throw (); + public: /** Determines if we are attached to the given sequence. */ bool _M_attached_to(const _Safe_sequence_base* __seq) const @@ -157,6 +163,17 @@ namespace __gnu_debug if (_M_next) _M_next->_M_prior = _M_prior; } + + private: + /** Methods kept for abi compatibility */ + __gnu_cxx::__mutex& + _M_get_mutex() throw (); + + void + _M_attach(_Safe_sequence_base* __seq, bool __constant); + + void + _M_detach(); }; /** Iterators that derive from _Safe_iterator_base can be determined singular @@ -174,6 +191,18 @@ namespace __gnu_debug const _Safe_iterator_base* __last) { return __first->_M_can_compare(*__last); } + // Compute power of 2 not greater than __n. + template + struct _Lowest_power_of_two + { + static const size_t __val + = _Lowest_power_of_two< (__n >> 1) >::__val + 1; + }; + + template<> + struct _Lowest_power_of_two<1> + { static const size_t __val = 1; }; + /** * @brief Base class that supports tracking of iterators that * reference a sequence. @@ -193,6 +222,8 @@ namespace __gnu_debug */ class _Safe_sequence_base { + friend class _Safe_iterator_base; + public: /// The list of mutable iterators that reference this container _Safe_iterator_base* _M_iterators; @@ -212,6 +243,8 @@ namespace __gnu_debug #if __cplusplus >= 201103L _Safe_sequence_base(const _Safe_sequence_base&) noexcept : _Safe_sequence_base() { } + _Safe_sequence_base(_Safe_sequence_base&&) noexcept + : _Safe_sequence_base() { } #endif /** Notify all iterators that reference this sequence that the @@ -228,7 +261,7 @@ namespace __gnu_debug * i->_M_version == _M_version. */ void - _M_detach_singular(); + _M_detach_singular(std::size_t __alignment); /** Revalidates all attached singular iterators. This method may * be used to validate iterators that were invalidated before @@ -236,7 +269,7 @@ namespace __gnu_debug * valid again). */ void - _M_revalidate_singular(); + _M_revalidate_singular(std::size_t __alignment); /** Swap this sequence with the given sequence. This operation * also swaps ownership of the iterators, so that when the @@ -244,21 +277,35 @@ namespace __gnu_debug * one container now reference the other container. */ void - _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT; + _M_swap(_Safe_sequence_base& __x, + std::size_t __alignment) _GLIBCXX_USE_NOEXCEPT; /** For use in _Safe_sequence. */ __gnu_cxx::__mutex& + _M_get_mutex(std::size_t __alignment) throw (); + + __gnu_cxx::__mutex& _M_get_mutex() throw (); - public: /** Invalidates all iterators. */ void _M_invalidate_all() const { if (++_M_version == 0) _M_version = 1; } + private: + void + _M_detach_singular_single(); + + void + _M_revalidate_singular_single(); + + void + _M_attach(_Safe_sequence_base* __seq, bool __constant); + /** Attach an iterator to this sequence. */ void - _M_attach(_Safe_iterator_base* __it, bool __constant); + _M_attach(_Safe_iterator_base* __it, bool __constant, + std::size_t __alignment); /** Likewise but not thread safe. */ void @@ -266,12 +313,33 @@ namespace __gnu_debug /** Detach an iterator from this sequence */ void - _M_detach(_Safe_iterator_base* __it); + _M_detach(_Safe_iterator_base* __it, std::size_t __alignment); /** Likewise but not thread safe. */ void _M_detach_single(_Safe_iterator_base* __it) throw (); + + /** Methods kept for abi compatibility */ + void + _M_detach_singular(); + + void + _M_revalidate_singular(); + + void + _M_attach(_Safe_iterator_base* __it, bool __constant); + + void + _M_detach(_Safe_iterator_base* __it); + + void + _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT; }; + + inline __gnu_cxx::__mutex& + _Safe_iterator_base::_M_get_mutex(std::size_t __alignment) throw () + { return _M_sequence->_M_get_mutex(__alignment); } + } // namespace __gnu_debug #endif diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h index c95d36c..865d34e 100644 --- a/libstdc++-v3/include/debug/safe_iterator.h +++ b/libstdc++-v3/include/debug/safe_iterator.h @@ -107,6 +107,10 @@ namespace __gnu_debug : _Iter_base(__i) { _M_attach_single(__seq); } + __gnu_cxx::__mutex& + _M_get_mutex() throw () + { return _Safe_base::_M_get_mutex(_Sequence::_S_alignment()); } + public: typedef _Iterator iterator_type; typedef typename _Traits::iterator_category iterator_category; @@ -127,7 +131,8 @@ namespace __gnu_debug */ _Safe_iterator(const _Iterator& __i, const _Safe_sequence_base* __seq) _GLIBCXX_NOEXCEPT - : _Iter_base(__i), _Safe_base(__seq, _M_constant()) + : _Iter_base(__i), + _Safe_base(__seq, _M_constant(), _Sequence::_S_alignment()) { _GLIBCXX_DEBUG_VERIFY(!this->_M_singular(), _M_message(__msg_init_singular) @@ -192,6 +197,9 @@ namespace __gnu_debug _M_attach(__x._M_sequence); } + ~_Safe_iterator() + { _M_detach(); } + /** * @brief Copy assignment. */ @@ -295,7 +303,7 @@ namespace __gnu_debug _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(), _M_message(__msg_bad_inc) ._M_iterator(*this, "this")); - __gnu_cxx::__scoped_lock(this->_M_get_mutex()); + __gnu_cxx::__scoped_lock __l(this->_M_get_mutex()); ++base(); return *this; } @@ -411,10 +419,18 @@ namespace __gnu_debug */ operator _Iterator() const _GLIBCXX_NOEXCEPT { return *this; } + /** Detach iterator from its sequence. */ + void + _M_detach() + { _Safe_base::_M_detach(_Sequence::_S_alignment()); } + /** Attach iterator to the given sequence. */ void _M_attach(_Safe_sequence_base* __seq) - { _Safe_base::_M_attach(__seq, _M_constant()); } + { + _Safe_base::_M_attach(__seq, _M_constant(), + _Sequence::_S_alignment()); + } /** Likewise, but not thread-safe. */ void diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc b/libstdc++-v3/include/debug/safe_iterator.tcc index e8e1b00..0ae7fd1 100644 --- a/libstdc++-v3/include/debug/safe_iterator.tcc +++ b/libstdc++-v3/include/debug/safe_iterator.tcc @@ -93,4 +93,3 @@ namespace __gnu_debug } // namespace __gnu_debug #endif - diff --git a/libstdc++-v3/include/debug/safe_local_iterator.h b/libstdc++-v3/include/debug/safe_local_iterator.h index e9ac74e..55d1279 100644 --- a/libstdc++-v3/include/debug/safe_local_iterator.h +++ b/libstdc++-v3/include/debug/safe_local_iterator.h @@ -44,15 +44,15 @@ namespace __gnu_debug * attaching/detaching the iterator from sequences, and querying * the iterator's state. */ - template + template class _Safe_local_iterator : private _Iterator , public _Safe_local_iterator_base { typedef _Iterator _Iter_base; typedef _Safe_local_iterator_base _Safe_base; - typedef typename _Sequence::const_local_iterator _Const_local_iterator; - typedef typename _Sequence::size_type size_type; + typedef typename _Container::const_local_iterator _Const_local_iterator; + typedef typename _Container::size_type size_type; /// Determine if this is a constant iterator. bool @@ -72,6 +72,10 @@ namespace __gnu_debug : _Iter_base(__i) { _M_attach_single(__cont); } + __gnu_cxx::__mutex& + _M_get_mutex() throw () + { return _Safe_base::_M_get_mutex(_Container::_S_alignment()); } + public: typedef _Iterator iterator_type; typedef typename _Traits::iterator_category iterator_category; @@ -92,7 +96,8 @@ namespace __gnu_debug */ _Safe_local_iterator(const _Iterator& __i, const _Safe_sequence_base* __cont) - : _Iter_base(__i), _Safe_base(__cont, _M_constant()) + : _Iter_base(__i), + _Safe_base(__cont, _M_constant(), _Container::_S_alignment()) { _GLIBCXX_DEBUG_VERIFY(!this->_M_singular(), _M_message(__msg_init_singular) @@ -142,8 +147,8 @@ namespace __gnu_debug const _Safe_local_iterator<_MutableIterator, typename __gnu_cxx::__enable_if::__value, - _Sequence>::__type>& __x) + typename _Container::local_iterator::iterator_type>::__value, + _Container>::__type>& __x) : _Iter_base(__x.base()) { // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -156,6 +161,9 @@ namespace __gnu_debug _M_attach(__x._M_sequence); } + ~_Safe_local_iterator() + { _M_detach(); } + /** * @brief Copy assignment. */ @@ -299,15 +307,23 @@ namespace __gnu_debug */ operator _Iterator() const { return *this; } + /** Detach iterator. */ + void + _M_detach() + { _Safe_base::_M_detach(_Container::_S_alignment()); } + /** Attach iterator to the given sequence. */ void - _M_attach(_Safe_sequence_base* __seq) - { _Safe_base::_M_attach(__seq, _M_constant()); } + _M_attach(_Safe_sequence_base* __cont) + { + _Safe_base::_M_attach(__cont, _M_constant(), + _Container::_S_alignment()); + } /** Likewise, but not thread-safe. */ void - _M_attach_single(_Safe_sequence_base* __seq) - { _Safe_base::_M_attach_single(__seq, _M_constant()); } + _M_attach_single(_Safe_sequence_base* __cont) + { _Safe_base::_M_attach_single(__cont, _M_constant()); } /// Is the iterator dereferenceable? bool @@ -329,10 +345,10 @@ namespace __gnu_debug typename __gnu_cxx::__conditional_type::__value, - const _Sequence*, - _Sequence*>::__type + const _Container*, + _Container*>::__type _M_get_sequence() const - { return static_cast<_Sequence*>(_M_sequence); } + { return static_cast<_Container*>(_M_sequence); } /// Is this iterator equal to the sequence's begin(bucket) iterator? bool _M_is_begin() const @@ -346,14 +362,14 @@ namespace __gnu_debug template bool _M_in_same_bucket(const _Safe_local_iterator<_Other, - _Sequence>& __other) const + _Container>& __other) const { return bucket() == __other.bucket(); } }; - template + template inline bool - operator==(const _Safe_local_iterator<_IteratorL, _Sequence>& __lhs, - const _Safe_local_iterator<_IteratorR, _Sequence>& __rhs) + operator==(const _Safe_local_iterator<_IteratorL, _Container>& __lhs, + const _Safe_local_iterator<_IteratorR, _Container>& __rhs) { _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(), _M_message(__msg_iter_compare_bad) @@ -370,10 +386,10 @@ namespace __gnu_debug return __lhs.base() == __rhs.base(); } - template + template inline bool - operator==(const _Safe_local_iterator<_Iterator, _Sequence>& __lhs, - const _Safe_local_iterator<_Iterator, _Sequence>& __rhs) + operator==(const _Safe_local_iterator<_Iterator, _Container>& __lhs, + const _Safe_local_iterator<_Iterator, _Container>& __rhs) { _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(), _M_message(__msg_iter_compare_bad) @@ -390,10 +406,10 @@ namespace __gnu_debug return __lhs.base() == __rhs.base(); } - template + template inline bool - operator!=(const _Safe_local_iterator<_IteratorL, _Sequence>& __lhs, - const _Safe_local_iterator<_IteratorR, _Sequence>& __rhs) + operator!=(const _Safe_local_iterator<_IteratorL, _Container>& __lhs, + const _Safe_local_iterator<_IteratorR, _Container>& __rhs) { _GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(), _M_message(__msg_iter_compare_bad) @@ -410,10 +426,10 @@ namespace __gnu_debug return __lhs.base() != __rhs.base(); } - template + template inline bool - operator!=(const _Safe_local_iterator<_Iterator, _Sequence>& __lhs, - const _Safe_local_iterator<_Iterator, _Sequence>& __rhs) + operator!=(const _Safe_local_iterator<_Iterator, _Container>& __lhs, + const _Safe_local_iterator<_Iterator, _Container>& __rhs) { _GLIBCXX_DEBUG_VERIFY(!__lhs._M_singular() && !__rhs._M_singular(), _M_message(__msg_iter_compare_bad) @@ -431,33 +447,33 @@ namespace __gnu_debug } /** Safe local iterators know if they are dereferenceable. */ - template + template inline bool __check_dereferenceable(const _Safe_local_iterator<_Iterator, - _Sequence>& __x) + _Container>& __x) { return __x._M_dereferenceable(); } /** Safe local iterators know how to check if they form a valid range. */ - template + template inline bool - __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>& __first, - const _Safe_local_iterator<_Iterator, _Sequence>& __last, + __valid_range(const _Safe_local_iterator<_Iterator, _Container>& __first, + const _Safe_local_iterator<_Iterator, _Container>& __last, typename _Distance_traits<_Iterator>::__type& __dist) { return __first._M_valid_range(__last, __dist); } /* Safe local iterators know their bucket. */ - template + template inline bool - __same_bucket(const _Safe_local_iterator<_Iterator, _Sequence>& __first, - const _Safe_local_iterator<_Iterator, _Sequence>& __last) + __same_bucket(const _Safe_local_iterator<_Iterator, _Container>& __first, + const _Safe_local_iterator<_Iterator, _Container>& __last) { return __first._M_in_same_bucket(__last); } /** Safe local iterators need a special method to get distance between each other. */ - template + template inline typename _Distance_traits<_Iterator>::__type - __get_distance(const _Safe_local_iterator<_Iterator, _Sequence>& __first, - const _Safe_local_iterator<_Iterator, _Sequence>& __last, + __get_distance(const _Safe_local_iterator<_Iterator, _Container>& __first, + const _Safe_local_iterator<_Iterator, _Container>& __last, std::input_iterator_tag) { if (__first.base() == __last.base()) @@ -496,10 +512,10 @@ namespace __gnu_debug return { 1, __dp_equality }; } - template + template inline typename _Distance_traits<_Iterator>::__type __get_distance_from_begin( - const _Safe_local_iterator<_Iterator, _Sequence>& __it) + const _Safe_local_iterator<_Iterator, _Container>& __it) { if (__it._M_is_begin()) return { 0, __dp_exact }; @@ -511,10 +527,10 @@ namespace __gnu_debug return { 1, __dp_equality }; } - template + template inline typename _Distance_traits<_Iterator>::__type __get_distance_to_end( - const _Safe_local_iterator<_Iterator, _Sequence>& __it) + const _Safe_local_iterator<_Iterator, _Container>& __it) { if (__it._M_is_begin()) return @@ -527,23 +543,23 @@ namespace __gnu_debug } #if __cplusplus < 201103L - template - struct _Unsafe_type<_Safe_local_iterator<_Iterator, _Sequence> > + template + struct _Unsafe_type<_Safe_local_iterator<_Iterator, _Container> > { typedef _Iterator _Type; }; #endif - template + template inline _Iterator - __unsafe(const _Safe_local_iterator<_Iterator, _Sequence>& __it) + __unsafe(const _Safe_local_iterator<_Iterator, _Container>& __it) { return __it.base(); } // Conversion to an unordered container safe local iterator. - template - inline _Safe_local_iterator<_Iterator, _Sequence> - __safe(const _Safe_local_iterator<_Iterator, _Sequence>& __safe_it, + template + inline _Safe_local_iterator<_Iterator, _Container> + __safe(const _Safe_local_iterator<_Iterator, _Container>& __safe_it, _Iterator __it) { - return _Safe_local_iterator<_Iterator, _Sequence>(__it, + return _Safe_local_iterator<_Iterator, _Container>(__it, __safe_it._M_get_sequence()); } diff --git a/libstdc++-v3/include/debug/safe_sequence.h b/libstdc++-v3/include/debug/safe_sequence.h index e12b6f1..73e6ec7 100644 --- a/libstdc++-v3/include/debug/safe_sequence.h +++ b/libstdc++-v3/include/debug/safe_sequence.h @@ -107,6 +107,8 @@ namespace __gnu_debug template class _Safe_sequence : public _Safe_sequence_base { + typedef _Safe_sequence_base _Base; + public: /** Invalidates all iterators @c x that reference this sequence, are not singular, and for which @c __pred(x) returns @c @@ -123,6 +125,36 @@ namespace __gnu_debug template void _M_transfer_from_if(_Safe_sequence& __from, _Predicate __pred); + + static _GLIBCXX_CONSTEXPR std::size_t + _S_alignment() _GLIBCXX_NOEXCEPT + { return _Lowest_power_of_two<__alignof(_Sequence)>::__val; } + + protected: +#if __cplusplus >= 201103L + _Safe_sequence() = default; + _Safe_sequence(const _Safe_sequence&) = default; + + // Move constructor swap iterators. + _Safe_sequence(_Safe_sequence&& __seq) + { _M_swap(__seq); } +#endif + + __gnu_cxx::__mutex& + _M_get_mutex() throw () + { return _Base::_M_get_mutex(_S_alignment()); } + + void + _M_detach_singular() + { _Base::_M_detach_singular(_S_alignment()); } + + void + _M_revalidate_singular() + { _Base::_M_revalidate_singular(_S_alignment()); } + + void + _M_swap(_Safe_sequence& __x) _GLIBCXX_USE_NOEXCEPT + { _Base::_M_swap(__x, _S_alignment()); } }; /// Like _Safe_sequence but with a special _M_invalidate_all implementation diff --git a/libstdc++-v3/include/debug/safe_unordered_base.h b/libstdc++-v3/include/debug/safe_unordered_base.h index 82a42eb..3d3bab6 100644 --- a/libstdc++-v3/include/debug/safe_unordered_base.h +++ b/libstdc++-v3/include/debug/safe_unordered_base.h @@ -61,17 +61,19 @@ namespace __gnu_debug * singular. Otherwise, the iterator will reference @p __seq and * be nonsingular. */ - _Safe_local_iterator_base(const _Safe_sequence_base* __seq, bool __constant) - { this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant); } + _Safe_local_iterator_base(const _Safe_sequence_base* __seq, + bool __constant, std::size_t __alignment) + { + this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), + __constant, __alignment); + } /** Initializes the iterator to reference the same container that @p __x does. @p __constant is true if this is a constant iterator, and false if it is mutable. */ _Safe_local_iterator_base(const _Safe_local_iterator_base& __x, - bool __constant) - { this->_M_attach(__x._M_sequence, __constant); } - - ~_Safe_local_iterator_base() { this->_M_detach(); } + bool __constant, std::size_t __alignment) + { this->_M_attach(__x._M_sequence, __constant, __alignment); } _Safe_unordered_container_base* _M_get_container() const noexcept; @@ -82,18 +84,30 @@ namespace __gnu_debug * new container is the NULL pointer, the iterator is left * unattached. */ - void _M_attach(_Safe_sequence_base* __seq, bool __constant); + void + _M_attach(_Safe_sequence_base* __seq, bool __constant, + std::size_t __alignment); /** Likewise, but not thread-safe. */ - void _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw (); + void + _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw (); /** Detach the iterator for whatever container it is attached to, * if any. */ - void _M_detach(); + void + _M_detach(std::size_t __alignment); /** Likewise, but not thread-safe. */ - void _M_detach_single() throw (); + void + _M_detach_single() throw (); + + private: + void + _M_attach(_Safe_sequence_base* __seq, bool __constant); + + void + _M_detach(); }; /** @@ -116,7 +130,9 @@ namespace __gnu_debug */ class _Safe_unordered_container_base : public _Safe_sequence_base { + friend class _Safe_local_iterator_base; typedef _Safe_sequence_base _Base; + public: /// The list of mutable local iterators that reference this container _Safe_iterator_base* _M_local_iterators; @@ -135,12 +151,6 @@ namespace __gnu_debug noexcept : _Safe_unordered_container_base() { } - // When moved unordered containers iterators are swapped. - _Safe_unordered_container_base(_Safe_unordered_container_base&& __x) - noexcept - : _Safe_unordered_container_base() - { this->_M_swap(__x); } - /** Notify all iterators that reference this container that the container is being destroyed. */ ~_Safe_unordered_container_base() noexcept @@ -156,11 +166,19 @@ namespace __gnu_debug * one container now reference the other container. */ void + _M_swap(_Safe_unordered_container_base& __x, + std::size_t __alignment) noexcept; + + private: + void _M_swap(_Safe_unordered_container_base& __x) noexcept; - public: /** Attach an iterator to this container. */ void + _M_attach_local(_Safe_iterator_base* __it, bool __constant, + std::size_t __alignment); + + void _M_attach_local(_Safe_iterator_base* __it, bool __constant); /** Likewise but not thread safe. */ @@ -169,6 +187,9 @@ namespace __gnu_debug /** Detach an iterator from this container */ void + _M_detach_local(_Safe_iterator_base* __it, std::size_t __alignment); + + void _M_detach_local(_Safe_iterator_base* __it); /** Likewise but not thread safe. */ diff --git a/libstdc++-v3/include/debug/safe_unordered_container.h b/libstdc++-v3/include/debug/safe_unordered_container.h index 4c4a138..a15677a 100644 --- a/libstdc++-v3/include/debug/safe_unordered_container.h +++ b/libstdc++-v3/include/debug/safe_unordered_container.h @@ -58,11 +58,34 @@ namespace __gnu_debug class _Safe_unordered_container : public _Safe_unordered_container_base { private: + typedef _Safe_unordered_container_base _Base; + _Container& _M_cont() noexcept { return *static_cast<_Container*>(this); } + public: + static constexpr std::size_t + _S_alignment() noexcept + { return _Lowest_power_of_two::__val; } + protected: + _Safe_unordered_container() = default; + _Safe_unordered_container(const _Safe_unordered_container&) = default; + + // Move constructor swap iterators. + _Safe_unordered_container(_Safe_unordered_container&& __x) noexcept + : _Base(std::move(__x)) + { _M_swap(__x); } + + __gnu_cxx::__mutex& + _M_get_mutex() throw () + { return _Base::_M_get_mutex(_S_alignment()); } + + void + _M_swap(_Safe_unordered_container& __x) noexcept + { _Base::_M_swap(__x, _S_alignment()); } + void _M_invalidate_locals() { diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc index ed0417a..769904e 100644 --- a/libstdc++-v3/src/c++11/debug.cc +++ b/libstdc++-v3/src/c++11/debug.cc @@ -33,9 +33,10 @@ #include #include +#include // for std::isspace #include // for std::min -#include // for _Hash_impl +#include // for _Hash_impl and std::function #include // for __cxa_demangle @@ -46,15 +47,30 @@ namespace /** Returns different instances of __mutex depending on the passed address * in order to limit contention without breaking current library binary * compatibility. */ + const size_t mask = 0xf; + __gnu_cxx::__mutex& - get_safe_base_mutex(void* __address) + get_mutex(size_t index) { - 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]; } + __gnu_cxx::__mutex& + get_safe_base_mutex(void* address) + { + const size_t index = _Hash_impl::hash(address) & mask; + return get_mutex(index); + } + + __gnu_cxx::__mutex& + get_safe_base_mutex(void* address, std::size_t alignment) + { + const size_t index + = (reinterpret_cast(address) >> alignment) & mask; + return get_mutex(index); + } + void swap_its(__gnu_debug::_Safe_sequence_base& __lhs, __gnu_debug::_Safe_iterator_base*& __lhs_its, @@ -70,8 +86,8 @@ namespace } void - swap_seq(__gnu_debug::_Safe_sequence_base& __lhs, - __gnu_debug::_Safe_sequence_base& __rhs) + swap_seq_single(__gnu_debug::_Safe_sequence_base& __lhs, + __gnu_debug::_Safe_sequence_base& __rhs) { swap(__lhs._M_version, __rhs._M_version); swap_its(__lhs, __lhs._M_iterators, @@ -81,10 +97,41 @@ namespace } void - swap_ucont(__gnu_debug::_Safe_unordered_container_base& __lhs, - __gnu_debug::_Safe_unordered_container_base& __rhs) + lock_and_run(__gnu_cxx::__mutex& lhs_mutex, + __gnu_cxx::__mutex& rhs_mutex, + std::function action) + { + // We need to lock both sequences to run action. + if (&lhs_mutex == &rhs_mutex) + { + __gnu_cxx::__scoped_lock sentry(lhs_mutex); + action(); + } + else + { + __gnu_cxx::__scoped_lock sentry1(&lhs_mutex < &rhs_mutex + ? lhs_mutex : rhs_mutex); + __gnu_cxx::__scoped_lock sentry2(&lhs_mutex < &rhs_mutex + ? rhs_mutex : lhs_mutex); + action(); + } + } + + void + swap_seq(__gnu_cxx::__mutex& lhs_mutex, + __gnu_debug::_Safe_sequence_base& lhs, + __gnu_cxx::__mutex& rhs_mutex, + __gnu_debug::_Safe_sequence_base& rhs) { - swap_seq(__lhs, __rhs); + lock_and_run(lhs_mutex, rhs_mutex, + [&lhs, &rhs]() { swap_seq_single(lhs, rhs); }); + } + + void + swap_ucont_single(__gnu_debug::_Safe_unordered_container_base& __lhs, + __gnu_debug::_Safe_unordered_container_base& __rhs) + { + swap_seq_single(__lhs, __rhs); swap_its(__lhs, __lhs._M_local_iterators, __rhs, __rhs._M_local_iterators); swap_its(__lhs, __lhs._M_const_local_iterators, @@ -92,6 +139,16 @@ namespace } void + swap_ucont(__gnu_cxx::__mutex& lhs_mutex, + __gnu_debug::_Safe_unordered_container_base& lhs, + __gnu_cxx::__mutex& rhs_mutex, + __gnu_debug::_Safe_unordered_container_base& rhs) + { + lock_and_run(lhs_mutex, rhs_mutex, + [&lhs, &rhs]() { swap_ucont_single(lhs, rhs); }); + } + + void detach_all(__gnu_debug::_Safe_iterator_base* __iter) { for (; __iter;) @@ -201,7 +258,8 @@ namespace __gnu_debug _Safe_sequence_base:: _M_detach_all() { - __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); + // No need to lock as current instance is being destroyed. + // __gnu_cxx::__scoped_lock sentry(_M_get_mutex(alignment)); detach_all(_M_iterators); _M_iterators = 0; @@ -214,6 +272,21 @@ namespace __gnu_debug _M_detach_singular() { __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); + _M_detach_singular_single(); + } + + void + _Safe_sequence_base:: + _M_detach_singular(size_t alignment) + { + __gnu_cxx::__scoped_lock sentry(_M_get_mutex(alignment)); + _M_detach_singular_single(); + } + + void + _Safe_sequence_base:: + _M_detach_singular_single() + { for (_Safe_iterator_base* __iter = _M_iterators; __iter;) { _Safe_iterator_base* __old = __iter; @@ -236,6 +309,21 @@ namespace __gnu_debug _M_revalidate_singular() { __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); + _M_revalidate_singular_single(); + } + + void + _Safe_sequence_base:: + _M_revalidate_singular(std::size_t alignment) + { + __gnu_cxx::__scoped_lock sentry(_M_get_mutex(alignment)); + _M_revalidate_singular_single(); + } + + void + _Safe_sequence_base:: + _M_revalidate_singular_single() + { for (_Safe_iterator_base* __iter = _M_iterators; __iter; __iter = __iter->_M_next) __iter->_M_version = _M_version; @@ -249,23 +337,22 @@ namespace __gnu_debug _Safe_sequence_base:: _M_swap(_Safe_sequence_base& __x) noexcept { - // We need to lock both sequences to swap + // We need to lock both containers 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); - } + __mutex& __this_mutex = _M_get_mutex(); + __mutex& __x_mutex = __x._M_get_mutex(); + swap_seq(__this_mutex, *this, __x_mutex, __x); + } + + void + _Safe_sequence_base:: + _M_swap(_Safe_sequence_base& __x, std::size_t alignment) noexcept + { + // We need to lock both containers to swap + using namespace __gnu_cxx; + __mutex& __this_mutex = _M_get_mutex(alignment); + __mutex& __x_mutex = __x._M_get_mutex(alignment); + swap_seq(__this_mutex, *this, __x_mutex, __x); } __gnu_cxx::__mutex& @@ -273,6 +360,11 @@ namespace __gnu_debug _M_get_mutex() throw () { return get_safe_base_mutex(this); } + __gnu_cxx::__mutex& + _Safe_sequence_base:: + _M_get_mutex(std::size_t alignment) throw () + { return get_safe_base_mutex(this, alignment); } + void _Safe_sequence_base:: _M_attach(_Safe_iterator_base* __it, bool __constant) @@ -283,6 +375,14 @@ namespace __gnu_debug void _Safe_sequence_base:: + _M_attach(_Safe_iterator_base* __it, bool __constant, std::size_t alignment) + { + __gnu_cxx::__scoped_lock sentry(_M_get_mutex(alignment)); + _M_attach_single(__it, __constant); + } + + void + _Safe_sequence_base:: _M_attach_single(_Safe_iterator_base* __it, bool __constant) throw () { _Safe_iterator_base*& __its = @@ -304,6 +404,15 @@ namespace __gnu_debug void _Safe_sequence_base:: + _M_detach(_Safe_iterator_base* __it, std::size_t alignment) + { + // Remove __it from this sequence's list + __gnu_cxx::__scoped_lock sentry(_M_get_mutex(alignment)); + _M_detach_single(__it); + } + + void + _Safe_sequence_base:: _M_detach_single(_Safe_iterator_base* __it) throw () { // Remove __it from this sequence's list @@ -331,6 +440,21 @@ namespace __gnu_debug void _Safe_iterator_base:: + _M_attach(_Safe_sequence_base* __seq, bool __constant, std::size_t alignment) + { + _M_detach(alignment); + + // 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, alignment); + } + } + + void + _Safe_iterator_base:: _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw () { _M_detach_single(); @@ -356,6 +480,16 @@ namespace __gnu_debug void _Safe_iterator_base:: + _M_detach(std::size_t alignment) + { + if (_M_sequence) + _M_sequence->_M_detach(this, alignment); + + _M_reset(); + } + + void + _Safe_iterator_base:: _M_detach_single() throw () { if (_M_sequence) @@ -389,8 +523,8 @@ namespace __gnu_debug __gnu_cxx::__mutex& _Safe_iterator_base:: - _M_get_mutex() throw () - { return get_safe_base_mutex(_M_sequence); } + _M_get_mutex() throw() + { return _M_sequence->_M_get_mutex(); } _Safe_unordered_container_base* _Safe_local_iterator_base:: @@ -414,6 +548,21 @@ namespace __gnu_debug void _Safe_local_iterator_base:: + _M_attach(_Safe_sequence_base* __cont, bool __constant, std::size_t alignment) + { + _M_detach(alignment); + + // Attach to the new container (if there is one) + if (__cont) + { + _M_sequence = __cont; + _M_version = _M_sequence->_M_version; + _M_get_container()->_M_attach_local(this, __constant, alignment); + } + } + + void + _Safe_local_iterator_base:: _M_attach_single(_Safe_sequence_base* __cont, bool __constant) throw () { _M_detach_single(); @@ -439,6 +588,16 @@ namespace __gnu_debug void _Safe_local_iterator_base:: + _M_detach(std::size_t alignment) + { + if (_M_sequence) + _M_get_container()->_M_detach_local(this, alignment); + + _M_reset(); + } + + void + _Safe_local_iterator_base:: _M_detach_single() throw () { if (_M_sequence) @@ -451,7 +610,8 @@ namespace __gnu_debug _Safe_unordered_container_base:: _M_detach_all() { - __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); + // No need to lock as current instance is being destroyed. + // __gnu_cxx::__scoped_lock sentry(_M_get_mutex(alignment)); detach_all(_M_iterators); _M_iterators = 0; @@ -471,21 +631,20 @@ namespace __gnu_debug { // We need to lock both containers 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_ucont(*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_ucont(*this, __x); - } + __mutex& __this_mutex = _M_get_mutex(); + __mutex& __x_mutex = __x._M_get_mutex(); + swap_ucont(__this_mutex, *this, __x_mutex, __x); + } + + void + _Safe_unordered_container_base:: + _M_swap(_Safe_unordered_container_base& __x, std::size_t alignment) noexcept + { + // We need to lock both containers to swap + using namespace __gnu_cxx; + __mutex& __this_mutex = _M_get_mutex(alignment); + __mutex& __x_mutex = __x._M_get_mutex(alignment); + swap_ucont(__this_mutex, *this, __x_mutex, __x); } void @@ -498,6 +657,15 @@ namespace __gnu_debug void _Safe_unordered_container_base:: + _M_attach_local(_Safe_iterator_base* __it, bool __constant, + std::size_t alignment) + { + __gnu_cxx::__scoped_lock sentry(_M_get_mutex(alignment)); + _M_attach_local_single(__it, __constant); + } + + void + _Safe_unordered_container_base:: _M_attach_local_single(_Safe_iterator_base* __it, bool __constant) throw () { _Safe_iterator_base*& __its = @@ -519,6 +687,15 @@ namespace __gnu_debug void _Safe_unordered_container_base:: + _M_detach_local(_Safe_iterator_base* __it, std::size_t alignment) + { + // Remove __it from this container's list + __gnu_cxx::__scoped_lock sentry(_M_get_mutex(alignment)); + _M_detach_local_single(__it); + } + + void + _Safe_unordered_container_base:: _M_detach_local_single(_Safe_iterator_base* __it) throw () { // Remove __it from this container's list diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc new file mode 100644 index 0000000..b043548 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc @@ -0,0 +1,40 @@ +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . +// + +#include + +#include + + +class container : public __gnu_debug::_Safe_sequence +{ +public: + __gnu_cxx::__mutex& + get_mutex() + { return this->_M_get_mutex(); } +}; + +int +main() +{ + container conts[16]; + + for (int i = 1; i != 16; ++i) + VERIFY( &conts[i - 1].get_mutex() != &conts[i].get_mutex() ); +} +