OSDN Git Service

2010-12-06 Joern Rennecke <amylaar@spamcop.net>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / src / debug.cc
index 9316ed6..188495a 100644 (file)
 #include <cctype>
 #include <cstdio>
 #include <cstdlib>
+#include <functional>
 
 using namespace std;
 
 namespace
 {
+  /** Returns different instances of __mutex depending on the passed address
+   *  in order to limit contention without breaking current library binary
+   *  compatibility. */
   __gnu_cxx::__mutex&
-  get_safe_base_mutex()
+  get_safe_base_mutex(void* __address)
   {
-    static __gnu_cxx::__mutex safe_base_mutex;
-    return safe_base_mutex;
+    const size_t mask = 0xf;
+    static __gnu_cxx::__mutex safe_base_mutex[mask + 1];
+    const size_t index = _Hash_impl::hash(__address) & mask;
+    return safe_base_mutex[index];
+  }
+
+  void
+  swap_seq(__gnu_debug::_Safe_sequence_base& __lhs,
+          __gnu_debug::_Safe_sequence_base& __rhs)
+  {
+    swap(__lhs._M_iterators, __rhs._M_iterators);
+    swap(__lhs._M_const_iterators, __rhs._M_const_iterators);
+    swap(__lhs._M_version, __rhs._M_version);
+    __gnu_debug::_Safe_iterator_base* __iter;
+    for (__iter = __rhs._M_iterators; __iter; __iter = __iter->_M_next)
+      __iter->_M_sequence = &__rhs;
+    for (__iter = __lhs._M_iterators; __iter; __iter = __iter->_M_next)
+      __iter->_M_sequence = &__lhs;
+    for (__iter = __rhs._M_const_iterators; __iter; __iter = __iter->_M_next)
+      __iter->_M_sequence = &__rhs;
+    for (__iter = __lhs._M_const_iterators; __iter; __iter = __iter->_M_next)
+      __iter->_M_sequence = &__lhs;
   }
 } // anonymous namespace
 
@@ -122,15 +146,17 @@ namespace __gnu_debug
       {
        _Safe_iterator_base* __old = __iter;
        __iter = __iter->_M_next;
-       __old->_M_detach_single();
+       __old->_M_reset();
       }
+    _M_iterators = 0;
     
     for (_Safe_iterator_base* __iter2 = _M_const_iterators; __iter2;)
       {
        _Safe_iterator_base* __old = __iter2;
        __iter2 = __iter2->_M_next;
-       __old->_M_detach_single();
+       __old->_M_reset();
       }
+    _M_const_iterators = 0;
   }
 
   void
@@ -173,32 +199,88 @@ namespace __gnu_debug
   _Safe_sequence_base::
   _M_swap(_Safe_sequence_base& __x)
   {
-    __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
-    swap(_M_iterators, __x._M_iterators);
-    swap(_M_const_iterators, __x._M_const_iterators);
-    swap(_M_version, __x._M_version);
-    _Safe_iterator_base* __iter;
-    for (__iter = _M_iterators; __iter; __iter = __iter->_M_next)
-      __iter->_M_sequence = this;
-    for (__iter = __x._M_iterators; __iter; __iter = __iter->_M_next)
-      __iter->_M_sequence = &__x;
-    for (__iter = _M_const_iterators; __iter; __iter = __iter->_M_next)
-      __iter->_M_sequence = this;
-    for (__iter = __x._M_const_iterators; __iter; __iter = __iter->_M_next)
-      __iter->_M_sequence = &__x;
+    // We need to lock both sequences to swap
+    using namespace __gnu_cxx;
+    __mutex *__this_mutex = &_M_get_mutex();
+    __mutex *__x_mutex = &__x._M_get_mutex();
+    if (__this_mutex == __x_mutex)
+      {
+       __scoped_lock __lock(*__this_mutex);
+       swap_seq(*this, __x);
+      }
+    else
+      {
+       __scoped_lock __l1(__this_mutex < __x_mutex
+                            ? *__this_mutex : *__x_mutex);
+       __scoped_lock __l2(__this_mutex < __x_mutex
+                            ? *__x_mutex : *__this_mutex);
+       swap_seq(*this, __x);
+      }
   }
 
   __gnu_cxx::__mutex&
   _Safe_sequence_base::
   _M_get_mutex() throw ()
-  { return get_safe_base_mutex(); }
+  { return get_safe_base_mutex(this); }
+
+  void
+  _Safe_sequence_base::
+  _M_attach(_Safe_iterator_base* __it, bool __constant)
+  {
+    __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
+    _M_attach_single(__it, __constant);
+  }
+
+  void
+  _Safe_sequence_base::
+  _M_attach_single(_Safe_iterator_base* __it, bool __constant) throw ()
+  {
+    _Safe_iterator_base*& __its =
+      __constant ? _M_const_iterators : _M_iterators;
+    __it->_M_next = __its;
+    if (__it->_M_next)
+      __it->_M_next->_M_prior = __it;
+    __its = __it;
+  }
+
+  void
+  _Safe_sequence_base::
+  _M_detach(_Safe_iterator_base* __it)
+  {
+    // Remove __it from this sequence's list
+    __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
+    _M_detach_single(__it);
+  }
+
+  void
+  _Safe_sequence_base::
+  _M_detach_single(_Safe_iterator_base* __it) throw ()
+  {
+    // Remove __it from this sequence's list
+    if (__it->_M_prior)
+      __it->_M_prior->_M_next = __it->_M_next;
+    if (__it->_M_next)
+      __it->_M_next->_M_prior = __it->_M_prior;
+       
+    if (_M_const_iterators == __it)
+      _M_const_iterators = __it->_M_next;
+    if (_M_iterators == __it)
+      _M_iterators = __it->_M_next;
+  }
 
   void
   _Safe_iterator_base::
   _M_attach(_Safe_sequence_base* __seq, bool __constant)
   {
-    __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
-    _M_attach_single(__seq, __constant);
+    _M_detach();
+    
+    // Attach to the new sequence (if there is one)
+    if (__seq)
+      {
+       _M_sequence = __seq;
+       _M_version = _M_sequence->_M_version;
+       _M_sequence->_M_attach(this, __constant);
+      }
   }
   
   void
@@ -212,21 +294,7 @@ namespace __gnu_debug
       {
        _M_sequence = __seq;
        _M_version = _M_sequence->_M_version;
-       _M_prior = 0;
-       if (__constant)
-         {
-           _M_next = _M_sequence->_M_const_iterators;
-           if (_M_next)
-             _M_next->_M_prior = this;
-           _M_sequence->_M_const_iterators = this;
-         }
-       else
-         {
-           _M_next = _M_sequence->_M_iterators;
-           if (_M_next)
-             _M_next->_M_prior = this;
-           _M_sequence->_M_iterators = this;
-         }
+       _M_sequence->_M_attach_single(this, __constant);
       }
   }
 
@@ -234,8 +302,12 @@ namespace __gnu_debug
   _Safe_iterator_base::
   _M_detach()
   {
-    __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
-    _M_detach_single();
+    if (_M_sequence)
+      {
+       _M_sequence->_M_detach(this);
+      }
+
+    _M_reset();
   }
 
   void
@@ -244,18 +316,16 @@ namespace __gnu_debug
   {
     if (_M_sequence)
       {
-       // Remove us from this sequence's list
-       if (_M_prior) 
-         _M_prior->_M_next = _M_next;
-       if (_M_next)  
-         _M_next->_M_prior = _M_prior;
-       
-       if (_M_sequence->_M_const_iterators == this)
-         _M_sequence->_M_const_iterators = _M_next;
-       if (_M_sequence->_M_iterators == this)
-         _M_sequence->_M_iterators = _M_next;
+       _M_sequence->_M_detach_single(this);
       }
 
+    _M_reset();
+  }
+
+  void
+  _Safe_iterator_base::
+  _M_reset() throw ()
+  {
     _M_sequence = 0;
     _M_version = 0;
     _M_prior = 0;
@@ -278,7 +348,7 @@ namespace __gnu_debug
   __gnu_cxx::__mutex&
   _Safe_iterator_base::
   _M_get_mutex() throw ()
-  { return get_safe_base_mutex(); }
+  { return get_safe_base_mutex(_M_sequence); }
 
   void
   _Error_formatter::_Parameter::