stl_threads.h (_Atomic_swap): Kill it...
authorLoren J. Rittle <ljrittle@acm.org>
Mon, 5 May 2003 22:28:16 +0000 (22:28 +0000)
committerLoren J. Rittle <ljrittle@gcc.gnu.org>
Mon, 5 May 2003 22:28:16 +0000 (22:28 +0000)
* include/bits/stl_threads.h (_Atomic_swap): Kill it...
(_Swap_lock_struct<>): ...and the horse it rode in on.
* src/globals.cc (_Swap_lock_struct<>): Likewise.
* include/ext/stl_rope.h (_Rope_RopeRep<>::_M_c_string_lock): New
member to support...
* include/ext/ropeimpl.h (rope<>::c_str): Follow *all* memory
visibility rules related to POSIX threads.
* testsuite/thread/pthread7-rope.cc: New test.

From-SVN: r66507

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/stl_threads.h
libstdc++-v3/include/ext/ropeimpl.h
libstdc++-v3/include/ext/stl_rope.h
libstdc++-v3/src/globals.cc
libstdc++-v3/testsuite/thread/pthread7-rope.cc [new file with mode: 0644]

index b9269e7..c218015 100644 (file)
@@ -1,3 +1,15 @@
+2003-05-05  Loren J. Rittle  <ljrittle@acm.org>
+           (Inspired by an alternate patch from Danny Smith.)
+
+       * include/bits/stl_threads.h (_Atomic_swap): Kill it...
+       (_Swap_lock_struct<>): ...and the horse it rode in on.
+       * src/globals.cc (_Swap_lock_struct<>): Likewise.
+       * include/ext/stl_rope.h (_Rope_RopeRep<>::_M_c_string_lock): New
+       member to support...
+       * include/ext/ropeimpl.h (rope<>::c_str): Follow *all* memory
+       visibility rules related to POSIX threads.
+       * testsuite/thread/pthread7-rope.cc: New test.
+
 2003-05-04  Paolo Carlini  <pcarlini@unitus.it>
 
        * testsuite/21_strings/basic_string/find/char/3.cc: New
index b21ebdd..53baf25 100644 (file)
@@ -97,35 +97,6 @@ namespace std
       return __tmp;
     }
   };
-
-  // Atomic swap on unsigned long
-  // This is guaranteed to behave as though it were atomic only if all
-  // possibly concurrent updates use _Atomic_swap.
-  // In some cases the operation is emulated with a lock.
-#if defined (__GTHREAD_MUTEX_INIT)
-  // This could be optimized to use the atomicity.h abstraction layer.
-  // vyzo: simple _Atomic_swap implementation following the guidelines above
-  // We use a template here only to get a unique initialized instance.
-  template<int __dummy>
-    struct _Swap_lock_struct 
-    { static __gthread_mutex_t _S_swap_lock; };
-
-  template<int __dummy>
-    __gthread_mutex_t
-    _Swap_lock_struct<__dummy>::_S_swap_lock = __GTHREAD_MUTEX_INIT;
-
-  // This should be portable, but performance is expected to be quite
-  // awful.  This really needs platform specific code.
-  inline unsigned long 
-  _Atomic_swap(unsigned long * __p, unsigned long __q) 
-  {
-    __gthread_mutex_lock(&_Swap_lock_struct<0>::_S_swap_lock);
-    unsigned long __result = *__p;
-    *__p = __q;
-    __gthread_mutex_unlock(&_Swap_lock_struct<0>::_S_swap_lock);
-    return __result;
-  }
-#endif
 } //namespace std
 
   // Locking class.  Note that this class *does not have a
index a1fba60..8be840e 100644 (file)
@@ -1450,26 +1450,17 @@ const _CharT* rope<_CharT,_Alloc>::c_str() const {
                                             // but probably fast.
         return _S_empty_c_str;
     }
-    __GC_CONST _CharT* __old_c_string = this->_M_tree_ptr->_M_c_string;
-    if (0 != __old_c_string) return(__old_c_string);
-    size_t __s = size();
-    _CharT* __result = _Data_allocate(__s + 1);
-    _S_flatten(this->_M_tree_ptr, __result);
-    __result[__s] = _S_eos((_CharT*)0);
-#   ifdef __GC
-       _M_tree_ptr->_M_c_string = __result;
-#   else
-      if ((__old_c_string = (__GC_CONST _CharT*)
-             std::_Atomic_swap((unsigned long *)
-                              (&(this->_M_tree_ptr->_M_c_string)),
-                         (unsigned long)__result)) != 0) {
-       // It must have been added in the interim.  Hence it had to have been
-       // separately allocated.  Deallocate the old copy, since we just
-       // replaced it.
-       _Destroy(__old_c_string, __old_c_string + __s + 1);
-       _Data_deallocate(__old_c_string, __s + 1);
+    __gthread_mutex_lock (&this->_M_tree_ptr->_M_c_string_lock);
+    __GC_CONST _CharT* __result = this->_M_tree_ptr->_M_c_string;
+    if (0 == __result)
+      {
+       size_t __s = size();
+       __result = _Data_allocate(__s + 1);
+       _S_flatten(this->_M_tree_ptr, __result);
+       __result[__s] = _S_eos((_CharT*)0);
+       this->_M_tree_ptr->_M_c_string = __result;
       }
-#   endif
+    __gthread_mutex_unlock (&this->_M_tree_ptr->_M_c_string_lock);
     return(__result);
 }
 
index 95c3c0c..8a7d0b7 100644 (file)
@@ -483,6 +483,7 @@ struct _Rope_RopeRep : public _Rope_rep_base<_CharT,_Alloc>
     bool _M_is_balanced:8;
     unsigned char _M_depth;
     __GC_CONST _CharT* _M_c_string;
+    __gthread_mutex_t _M_c_string_lock;
                         /* Flattened version of string, if needed.  */
                         /* typically 0.                             */
                         /* If it's not 0, then the memory is owned  */
@@ -498,7 +499,12 @@ struct _Rope_RopeRep : public _Rope_rep_base<_CharT,_Alloc>
           _Refcount_Base(1),
 #         endif
           _M_tag(__t), _M_is_balanced(__b), _M_depth(__d), _M_c_string(0)
+#ifdef __GTHREAD_MUTEX_INIT
+         , _M_c_string_lock (__GTHREAD_MUTEX_INIT)
     { }
+#else
+    { __GTHREAD_MUTEX_INIT_FUNCTION (&_M_c_string_lock); }
+#endif
 #   ifdef __GC
         void _M_incr () {}
 #   endif
index 7ce86f5..31c1371 100644 (file)
@@ -227,9 +227,6 @@ namespace __gnu_cxx
   // allows static initialization of these objects on systems that need a
   // function call to initialize a mutex.  For example, see stl_threads.h.
 #ifdef __GTHREAD_MUTEX_INIT
-  // Need to provide explicit instantiations of static data for
-  // systems with broken weak linkage support.
-  template __gthread_mutex_t _Swap_lock_struct<0>::_S_swap_lock;
 #elif defined(__GTHREAD_MUTEX_INIT_FUNCTION)
   __gthread_once_t _GLIBCPP_once = __GTHREAD_ONCE_INIT;
   __gthread_mutex_t _GLIBCPP_mutex;
diff --git a/libstdc++-v3/testsuite/thread/pthread7-rope.cc b/libstdc++-v3/testsuite/thread/pthread7-rope.cc
new file mode 100644 (file)
index 0000000..12e71ef
--- /dev/null
@@ -0,0 +1,106 @@
+// 2003-05-03  Loren J. Rittle <rittle@labs.mot.com> <ljrittle@acm.org>
+//
+// Copyright (C) 2003 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 2, 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 COPYING.  If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* } }
+// { dg-options "-DDEBUG_ASSERT -pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* } }
+// { dg-options "-DDEBUG_ASSERT -pthreads" { target *-*-solaris* } }
+
+#include <ext/rope>
+#include <cstring>
+#include <testsuite_hooks.h>
+
+// Do not include <pthread.h> explicitly; if threads are properly
+// configured for the port, then it is picked up free from STL headers.
+
+#if __GTHREADS
+
+const int max_thread_count = 4;
+const int max_loop_count = 10000;
+
+__gnu_cxx::crope foo4;
+
+void* thread_main (void *)
+{
+  // To see a problem with gcc 3.3 and before, set a break point here.
+  // Single step through c_str implementation, call sched_yield after
+  // capture of NULL __old_c_string in any thread.  Single step
+  // through another thread past that same point.  Now, one thread
+  // will receive a bad pointer return.  Adding dummy sched_yield
+  // should never change program semantics under POSIX threads.
+  const char* data4 = foo4.c_str();
+
+  // Please note that the memory leak in the rope implementation with
+  // this test case, existed before and after fixing this bug...
+
+  VERIFY( !std::strcmp (data4, "barbazbonglehellohellohello") );
+}
+
+int
+main()
+{
+  pthread_t tid[max_thread_count];
+
+#if defined(__sun) && defined(__svr4__)
+  pthread_setconcurrency (max_thread_count);
+#endif
+
+  __gnu_cxx::crope foo;
+  foo += "bar";
+  foo += "baz";
+  foo += "bongle";
+  const char* data = foo.c_str();
+  VERIFY( !std::strcmp (data, "barbazbongle") );
+
+  const char* data2;
+  {
+    __gnu_cxx::crope foo2;
+    foo2 += "bar2";
+    foo2 += "baz2";
+    foo2 += "bongle2";
+    data2 = foo2.c_str();
+    VERIFY( !std::strcmp (data2, "bar2baz2bongle2") );
+  }
+
+  __gnu_cxx::crope foo3 ("hello");
+  const char* data3 = foo3.c_str();
+  VERIFY( !std::strcmp (data3, "hello") );
+
+  for (int j = 0; j < max_loop_count; j++)
+    {
+      foo4 = foo;
+      foo4 += foo3;
+      foo4 += foo3;
+      foo4 += foo3;
+
+      for (int i = 0; i < max_thread_count; i++)
+       pthread_create (&tid[i], NULL, thread_main, 0);
+
+      for (int i = 0; i < max_thread_count; i++)
+       pthread_join (tid[i], NULL);
+    }
+
+  // Nothing says the data will be trashed at this point...
+  VERIFY( std::strcmp (data2, "bar2baz2bongle2") );
+
+  return 0;
+}
+#else
+int main (void) {}
+#endif