From: Loren J. Rittle Date: Mon, 5 May 2003 22:28:16 +0000 (+0000) Subject: stl_threads.h (_Atomic_swap): Kill it... X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1976f0d995f1849964ee76f2c6606117971cb7b5;p=platform%2Fupstream%2Fgcc.git stl_threads.h (_Atomic_swap): Kill it... * 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 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index b9269e7..c218015 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,15 @@ +2003-05-05 Loren J. Rittle + (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 * testsuite/21_strings/basic_string/find/char/3.cc: New diff --git a/libstdc++-v3/include/bits/stl_threads.h b/libstdc++-v3/include/bits/stl_threads.h index b21ebdd..53baf25 100644 --- a/libstdc++-v3/include/bits/stl_threads.h +++ b/libstdc++-v3/include/bits/stl_threads.h @@ -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 - struct _Swap_lock_struct - { static __gthread_mutex_t _S_swap_lock; }; - - template - __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 diff --git a/libstdc++-v3/include/ext/ropeimpl.h b/libstdc++-v3/include/ext/ropeimpl.h index a1fba60..8be840e 100644 --- a/libstdc++-v3/include/ext/ropeimpl.h +++ b/libstdc++-v3/include/ext/ropeimpl.h @@ -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); } diff --git a/libstdc++-v3/include/ext/stl_rope.h b/libstdc++-v3/include/ext/stl_rope.h index 95c3c0c..8a7d0b7 100644 --- a/libstdc++-v3/include/ext/stl_rope.h +++ b/libstdc++-v3/include/ext/stl_rope.h @@ -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 diff --git a/libstdc++-v3/src/globals.cc b/libstdc++-v3/src/globals.cc index 7ce86f5..31c1371 100644 --- a/libstdc++-v3/src/globals.cc +++ b/libstdc++-v3/src/globals.cc @@ -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 index 0000000..12e71ef --- /dev/null +++ b/libstdc++-v3/testsuite/thread/pthread7-rope.cc @@ -0,0 +1,106 @@ +// 2003-05-03 Loren J. Rittle +// +// 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 +#include +#include + +// Do not include 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