debug.cc: Include debug/vector.
authorFrançois Dumont <fdumont@gcc.gnu.org>
Sun, 25 Sep 2016 20:26:02 +0000 (20:26 +0000)
committerFrançois Dumont <fdumont@gcc.gnu.org>
Sun, 25 Sep 2016 20:26:02 +0000 (20:26 +0000)
2016-09-25  François Dumont  <fdumont@gcc.gnu.org>

* src/c++11/debug.cc: Include debug/vector. Include cctype. Remove
functional.
(get_safe_base_mutex): Get mutex based on address lowest non nil bits.
* testsuite/23_containers/vector/debug/mutex_association.cc: New.

From-SVN: r240479

libstdc++-v3/ChangeLog
libstdc++-v3/src/c++11/debug.cc
libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc [new file with mode: 0644]

index 47a52b52656892e19b7965352af4f71918abafa7..6f134cbe2e2b9fda667c00a29e19eca649fef1ef 100644 (file)
@@ -1,5 +1,10 @@
 2016-09-25  François Dumont  <fdumont@gcc.gnu.org>
 
+       * src/c++11/debug.cc: Include debug/vector. Include cctype. Remove
+       functional.
+       (get_safe_base_mutex): Get mutex based on address lowest non nil bits.
+       * testsuite/23_containers/vector/debug/mutex_association.cc: New.
+
        * include/debug/bitset (bitset::reference::reference(const _Base_ref&,
        bitset*)): Remove __unused__ attribute.
        * include/debug/safe_base.h (_Safe_iterator_base): Make
index f25304c5310a45c0fd8dc6f51c0fe832f9e6b5d2..f58e829c47a343cdb6eee25ffae812e5bf514a3f 100644 (file)
 #include <debug/safe_unordered_base.h>
 #include <debug/safe_iterator.h>
 #include <debug/safe_local_iterator.h>
+#include <debug/vector>
 
 #include <cassert>
 #include <cstdio>
+#include <cctype> // for std::isspace
 
 #include <algorithm> // for std::min
-#include <functional> // for _Hash_impl
 
 #include <cxxabi.h> // for __cxa_demangle
 
@@ -47,11 +48,16 @@ namespace
    *  in order to limit contention without breaking current library binary
    *  compatibility. */
   __gnu_cxx::__mutex&
-  get_safe_base_mutex(void* __address)
+  get_safe_base_mutex(void* address)
   {
     const size_t mask = 0xf;
     static __gnu_cxx::__mutex safe_base_mutex[mask + 1];
-    const size_t index = _Hash_impl::hash(__address) & mask;
+
+    // Use arbitrarily __gnu_debug::vector<int> as the container giving
+    // alignment of debug containers.
+    const auto alignbits = __builtin_ctz(alignof(__gnu_debug::vector<int>));
+    const size_t index
+      = (reinterpret_cast<std::size_t>(address) >> alignbits) & mask;
     return safe_base_mutex[index];
   }
 
@@ -70,8 +76,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,
@@ -80,17 +86,58 @@ namespace
             __rhs, __rhs._M_const_iterators);
   }
 
+  template<typename _Action>
+    void
+    lock_and_run(__gnu_cxx::__mutex& lhs_mutex, __gnu_cxx::__mutex& rhs_mutex,
+                _Action 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)
+  {
+    lock_and_run(lhs_mutex, rhs_mutex,
+                [&lhs, &rhs]() { swap_seq_single(lhs, rhs); });
+  }
+
   void
-  swap_ucont(__gnu_debug::_Safe_unordered_container_base& __lhs,
-           __gnu_debug::_Safe_unordered_container_base& __rhs)
+  swap_ucont_single(__gnu_debug::_Safe_unordered_container_base& __lhs,
+                   __gnu_debug::_Safe_unordered_container_base& __rhs)
   {
-    swap_seq(__lhs, __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,
             __rhs, __rhs._M_const_local_iterators);
   }
 
+  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)
   {
@@ -242,25 +289,7 @@ namespace __gnu_debug
   void
   _Safe_sequence_base::
   _M_swap(_Safe_sequence_base& __x) noexcept
-  {
-    // 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);
-      }
-  }
+  { swap_seq(_M_get_mutex(), *this, __x._M_get_mutex(), __x); }
 
   __gnu_cxx::__mutex&
   _Safe_sequence_base::
@@ -384,7 +413,7 @@ namespace __gnu_debug
   __gnu_cxx::__mutex&
   _Safe_iterator_base::
   _M_get_mutex() throw ()
-  { return get_safe_base_mutex(_M_sequence); }
+  { return _M_sequence->_M_get_mutex(); }
 
   _Safe_unordered_container_base*
   _Safe_local_iterator_base::
@@ -462,25 +491,7 @@ namespace __gnu_debug
   void
   _Safe_unordered_container_base::
   _M_swap(_Safe_unordered_container_base& __x) noexcept
-  {
-    // 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);
-      }
-  }
+  { swap_ucont(_M_get_mutex(), *this, __x._M_get_mutex(), __x); }
 
   void
   _Safe_unordered_container_base::
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 (file)
index 0000000..a3c56e2
--- /dev/null
@@ -0,0 +1,42 @@
+// 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 <set>
+#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()
+{
+  std::set<__gnu_cxx::__mutex*> mutexes;
+  container conts[17];
+
+  for (int i = 0; i != 16; ++i)
+    VERIFY( mutexes.insert(&conts[i].get_mutex()).second );
+
+  VERIFY( !mutexes.insert(&conts[16].get_mutex()).second );
+}