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
This commit is contained in:
parent
6ccfe27ca7
commit
1976f0d995
6 changed files with 134 additions and 51 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
106
libstdc++-v3/testsuite/thread/pthread7-rope.cc
Normal file
106
libstdc++-v3/testsuite/thread/pthread7-rope.cc
Normal file
|
@ -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
|
Loading…
Add table
Reference in a new issue