public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: "François Dumont" <frs.dumont@gmail.com>
To: "libstdc++@gcc.gnu.org" <libstdc++@gcc.gnu.org>,
	gcc-patches <gcc-patches@gcc.gnu.org>
Subject: debug container mutex association
Date: Tue, 13 Sep 2016 20:37:00 -0000	[thread overview]
Message-ID: <46b4f297-c0da-b0b0-03ef-bba019b97ec7@gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 4267 bytes --]

Hi

     When I proposed to change std::hash for pointers my plan was to use 
this approach for the debug containers. So here is the patch leveraging 
on this technique to avoid going through _Hash_impl to hash address and 
get mutex index from it. I think it is obious that new access is faster 
so I didn't wrote a performance test to demonstrate it.

     Drawback is new exported symbols.

     * include/debug/safe_base.h (_Lowest_power_of_two<>): New.
     (_Safe_sequence_base): Make _Safe_iterator_base friend.
     (_Safe_sequence_base::_M_detach_singular(size_t)): New.
     (_Safe_sequence_base::_M_revalidate_singular(size_t)): New.
     (_Safe_sequence_base::_M_swap(_Safe_sequence_base&, size_t)): New.
     (_Safe_sequence_base::_M_get_mutex(size_t)): New.
     (_Safe_iterator_base::_M_get_mutex(size_t)): New.
     (_Safe_iterator_base::_M_attach(_Safe_sequence_base*, bool, size_t)):
     New.
     (_Safe_iterator_base::_M_detach(size_t)): New.
     (_Safe_iterator_base(const _Safe_sequence_base*, bool)): Replace by...
     (_Safe_iterator_base(const _Safe_sequence_base*, bool, size_t)):
     ...this.
     (_Safe_iterator_base(const _Safe_iterator_base&, bool)): Replace by...
     (_Safe_iterator_base(const _Safe_iterator_base&, bool, size_t)):
     ...this.
     (~_Safe_iterator_base()): Delete.
     * include/debug/bitset (bitset::_S_alignment()): New.
     (bitset::reference::~reference()): New.
     (bitset::reference::reference(const _Base_ref&, bitset*)): Adapt.
     (bitset::reference::reference(const reference&)): Adapt.
     * include/debug/safe_iterator.h (_Safe_iterator::_M_get_mutex()): New.
     (_Safe_iterator::_Safe_iterator(const _Iterator&,
     const _Safe_sequence_base*)): Adapt.
     (_Safe_iterator::~_Safe_iterator()): New.
     (_Safe_iterator::_M_detach()): New.
     (_Safe_iterator::_M_attach(_Safe_sequence_base*)): Adapt.
     * include/debug/safe_iterator.tcc: Remove trailing line.
     * include/debug/safe_local_iterator.h (_Safe_local_iterator<>): Rename
     _Sequence template parameter into _Container.
     (_Safe_local_iterator::_M_get_mutex()): New.
     (_Safe_local_iterator::_Safe_local_iterator(const _Iterator&,
     const _Safe_sequence_base*)): Adapt.
     (_Safe_local_iterator::~_Safe_local_iterator()): New.
     (_Safe_local_iterator::_M_detach()): New.
     (_Safe_local_iterator::_M_attach(_Safe_sequence_base*)): Adapt.
     * include/debug/safe_sequence.h
     (_Safe_sequence::_S_alignment()): New.
     (_Safe_sequence::_Safe_sequence(_Safe_sequence&&)): New.
     (_Safe_sequence::_M_get_mutex()): New.
     (_Safe_sequence::_M_detach_singular()): New.
     (_Safe_sequence::_M_revalidate_singular()): New.
     (_Safe_sequence::_M_swap(_Safe_sequence&)): New.
     * include/debug/safe_unordered_base.h
     (_Safe_local_iterator_base(const _Safe_sequence_base*, bool)): Replace
     by...
     (_Safe_local_iterator_base(const _Safe_sequence_base*, bool, size_t)):
     ...this.
     (_Safe_local_iterator_base(const _Safe_local_iterator&, bool)): Replace
     by...
     (_Safe_local_iterator_base(const _Safe_local_iterator&, bool, size_t)):
     ...this.
     (_Safe_local_iterator_base::~_Safe_local_iterator_base()): Delete.
     (_Safe_local_iterator_base::_M_attach(_Safe_sequence_base*, bool,
     size_t)): New.
     (_Safe_local_iterator_base::_M_detach(size_t)): New.
(_Safe_unordered_container_base(_Safe_unordered_container_base&&)):
     Delete.
     (_Safe_unordered_container_base::_M_swap(
     _Safe_unordered_container_base&, size_t)): New.
(_Safe_unordered_container_base::_M_attach_local(_Safe_iterator_base*,
     bool, size_t)): New.
(_Safe_unordered_container_base::_M_detach_local(_Safe_iterator_base*,
     size_t)): New.
     * include/debug/safe_unordered_container.h
     (_Safe_unordered_container::_S_alignment()): New.
     (_Safe_unordered_container::_Safe_unordered_container(
     _Safe_unordered_container&&)): New.
     (_Safe_unordered_container::_M_get_mutex()): New.
(_Safe_unordered_container::_M_swap(_Safe_unordered_container&)): New.
     * src/c++11/debug.cc: Adapt.
     * testsuite/23_containers/vector/debug/mutex_association.cc: New.
     * config/abi/pre/gnu.ver: Add new symbols.

Tested under Linux x86_64.

François



[-- Attachment #2: debug_mutex.patch --]
[-- Type: text/x-patch, Size: 44407 bytes --]

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<const _Base_ref*>(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<const _Base_ref*>(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<size_t __n>
+    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<typename _Iterator, typename _Sequence>
+  template<typename _Iterator, typename _Container>
     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<std::__are_same<
 	      _MutableIterator,
-	      typename _Sequence::local_iterator::iterator_type>::__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<std::__are_same<_Const_local_iterator,
 						    _Safe_local_iterator>::__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<typename _Other>
 	bool
 	_M_in_same_bucket(const _Safe_local_iterator<_Other,
-						     _Sequence>& __other) const
+						     _Container>& __other) const
 	{ return bucket() == __other.bucket(); }
     };
 
-  template<typename _IteratorL, typename _IteratorR, typename _Sequence>
+  template<typename _IteratorL, typename _IteratorR, typename _Container>
     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<typename _Iterator, typename _Sequence>
+  template<typename _Iterator, typename _Container>
     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<typename _IteratorL, typename _IteratorR, typename _Sequence>
+  template<typename _IteratorL, typename _IteratorR, typename _Container>
     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<typename _Iterator, typename _Sequence>
+  template<typename _Iterator, typename _Container>
     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<typename _Iterator, typename _Sequence>
+  template<typename _Iterator, typename _Container>
     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<typename _Iterator, typename _Sequence>
+  template<typename _Iterator, typename _Container>
     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<typename _Iterator, typename _Sequence>
+  template<typename _Iterator, typename _Container>
     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<typename _Iterator, typename _Sequence>
+  template<typename _Iterator, typename _Container>
     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<typename _Iterator, typename _Sequence>
+  template<typename _Iterator, typename _Container>
     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<typename _Iterator, typename _Sequence>
+  template<typename _Iterator, typename _Container>
     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<typename _Iterator, typename _Sequence>
-    struct _Unsafe_type<_Safe_local_iterator<_Iterator, _Sequence> >
+  template<typename _Iterator, typename _Container>
+    struct _Unsafe_type<_Safe_local_iterator<_Iterator, _Container> >
     { typedef _Iterator _Type; };
 #endif
 
-  template<typename _Iterator, typename _Sequence>
+  template<typename _Iterator, typename _Container>
     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<typename _Iterator, typename _Sequence>
-    inline _Safe_local_iterator<_Iterator, _Sequence>
-    __safe(const _Safe_local_iterator<_Iterator, _Sequence>& __safe_it,
+  template<typename _Iterator, typename _Container>
+    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<typename _Sequence>
     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<typename _Predicate>
 	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<alignof(_Container)>::__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 <cassert>
 #include <cstdio>
+#include <cctype> // for std::isspace
 
 #include <algorithm> // for std::min
-#include <functional> // for _Hash_impl
+#include <functional> // for _Hash_impl and std::function
 
 #include <cxxabi.h> // 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<size_t>(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<void()> 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
+// <http://www.gnu.org/licenses/>.
+//
+
+#include <debug/vector>
+
+#include <testsuite_hooks.h>
+
+
+class container : public __gnu_debug::_Safe_sequence<container>
+{
+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() );
+}
+

             reply	other threads:[~2016-09-13 20:37 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-13 20:37 François Dumont [this message]
2016-09-14  9:01 ` Jonathan Wakely
2016-09-14 20:53   ` François Dumont
2016-09-15  9:15     ` Jonathan Wakely
2016-09-19 20:19       ` François Dumont
2016-09-20  8:58         ` Jonathan Wakely
2016-09-27 15:39           ` Jonathan Wakely
2016-09-27 21:14             ` François Dumont
2016-09-20  9:20         ` Jonathan Wakely
2016-09-26 11:55           ` Jonathan Wakely
2016-09-26 12:23         ` Andreas Schwab
2016-09-26 22:09           ` François Dumont
2016-09-27 10:32             ` Jonathan Wakely
2016-09-28 19:35               ` François Dumont
2016-09-28 19:47                 ` Jonathan Wakely
2017-12-29 16:10         ` Andreas Schwab

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=46b4f297-c0da-b0b0-03ef-bba019b97ec7@gmail.com \
    --to=frs.dumont@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=libstdc++@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).