[multiple changes]
2005-09-11 Benjamin Kosnik <bkoz@redhat.com> PR libstdc++/19265 PR libstdc++/22309 * include/ext/mt_allocator.h (__gnu_cxx::__create_handler): Remove. (__pool<true>::_M_destroy_thread_key): Compatibility only. (__pool<true>::_M_initialize(__destroy): Same. (__pool<true>::_M_initialize): New. (__pool<true>::_M_initialize_once): Nothing fancy. (__pool<true>::_M_once): Remove. (__common_pool): New. (__common_pool_base): New. (__per_type_pool): New. (__per_type_pool_base): New. * src/mt_allocator.cc: Same. * config/linker-map.gnu (__pool<true>::_M_initialize()): Add. 2005-09-11 Jakub Jelinek <jakub@redhat.com> PR libstdc++/19265 PR libstdc++/22309 * src/mt_allocator.cc (__gnu_internal::freelist_mutex): Make static. (__gnu_internal::__freelist): New type. (__gnu_internal::freelist): New variable. (__gnu_internal::_M_destroy_thread_key): New function. (__gnu_cxx::__pool<true>::_M_destroy): Don't delete _M_thread_freelist_initial. (__gnu_cxx::__pool<true>::_M_initialize): Make argument nameless. Don't use _M_thread_freelist and _M_thread_freelist_initial __pool<true> fields, instead use __gnu_internal::freelist fields, call gthread_key_create just once. Use __gnu_internal::_M_destroy_thread_key as key destructor. (__gnu_cxx::__pool<true>::_M_get_thread_id): Store size_t id rather than _Thread_record* in the thread specific value. Don't use _M_thread_freelist __pool<true> field, instead use __gnu_internal::freelist fields. (__gnu_cxx::__pool<true>::_M_destroy_thread_key): Do nothing. 2005-09-11 Benjamin Kosnik <bkoz@redhat.com> Jakub Jelinek <jakub@redhat.com> PR libstdc++/19265 PR libstdc++/22309 * testsuite/testsuite_shared.cc: New. * testsuite/lib/dg-options.exp (dg-require-sharedlib): New. * testsuite/lib/libstdc++.exp (libstdc++_init): Look for shared library, and set v3-sharedlib based on this. (check_v3_target_sharedlib): New. (proc v3-build_support): Build shared objects. * testsuite/ext/mt_allocator/22309_thread.cc: New, use above. From-SVN: r104161
This commit is contained in:
parent
56b4ea3de8
commit
2f9f6cef1c
@ -1,3 +1,55 @@
|
||||
2005-09-11 Benjamin Kosnik <bkoz@redhat.com>
|
||||
|
||||
PR libstdc++/19265
|
||||
PR libstdc++/22309
|
||||
* include/ext/mt_allocator.h
|
||||
(__gnu_cxx::__create_handler): Remove.
|
||||
(__pool<true>::_M_destroy_thread_key): Compatibility only.
|
||||
(__pool<true>::_M_initialize(__destroy): Same.
|
||||
(__pool<true>::_M_initialize): New.
|
||||
(__pool<true>::_M_initialize_once): Nothing fancy.
|
||||
(__pool<true>::_M_once): Remove.
|
||||
(__common_pool): New.
|
||||
(__common_pool_base): New.
|
||||
(__per_type_pool): New.
|
||||
(__per_type_pool_base): New.
|
||||
* src/mt_allocator.cc: Same.
|
||||
* config/linker-map.gnu (__pool<true>::_M_initialize()): Add.
|
||||
|
||||
2005-09-11 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR libstdc++/19265
|
||||
PR libstdc++/22309
|
||||
* src/mt_allocator.cc (__gnu_internal::freelist_mutex): Make static.
|
||||
(__gnu_internal::__freelist): New type.
|
||||
(__gnu_internal::freelist): New variable.
|
||||
(__gnu_internal::_M_destroy_thread_key): New function.
|
||||
(__gnu_cxx::__pool<true>::_M_destroy): Don't delete
|
||||
_M_thread_freelist_initial.
|
||||
(__gnu_cxx::__pool<true>::_M_initialize): Make argument nameless.
|
||||
Don't use _M_thread_freelist and _M_thread_freelist_initial
|
||||
__pool<true> fields, instead use __gnu_internal::freelist fields, call
|
||||
gthread_key_create just once. Use
|
||||
__gnu_internal::_M_destroy_thread_key as key destructor.
|
||||
(__gnu_cxx::__pool<true>::_M_get_thread_id): Store size_t id
|
||||
rather than _Thread_record* in the thread specific value. Don't
|
||||
use _M_thread_freelist __pool<true> field, instead use
|
||||
__gnu_internal::freelist fields.
|
||||
(__gnu_cxx::__pool<true>::_M_destroy_thread_key): Do nothing.
|
||||
|
||||
2005-09-11 Benjamin Kosnik <bkoz@redhat.com>
|
||||
Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR libstdc++/19265
|
||||
PR libstdc++/22309
|
||||
* testsuite/testsuite_shared.cc: New.
|
||||
* testsuite/lib/dg-options.exp (dg-require-sharedlib): New.
|
||||
* testsuite/lib/libstdc++.exp (libstdc++_init): Look for shared
|
||||
library, and set v3-sharedlib based on this.
|
||||
(check_v3_target_sharedlib): New.
|
||||
(proc v3-build_support): Build shared objects.
|
||||
* testsuite/ext/mt_allocator/22309_thread.cc: New, use above.
|
||||
|
||||
2005-09-11 Paolo Carlini <pcarlini@suse.de>
|
||||
|
||||
PR libstdc++/23781
|
||||
|
@ -515,8 +515,8 @@ GLIBCXX_3.4.3 {
|
||||
} GLIBCXX_3.4.2;
|
||||
|
||||
GLIBCXX_3.4.4 {
|
||||
|
||||
_ZN9__gnu_cxx6__poolILb0EE13_M_initializeEv;
|
||||
|
||||
_ZN9__gnu_cxx6__poolILb0EE13_M_initializeEv;
|
||||
_ZN9__gnu_cxx6__poolILb1EE13_M_initializeEPFvPvE;
|
||||
_ZN9__gnu_cxx6__poolILb1EE21_M_destroy_thread_keyEPv;
|
||||
_ZN9__gnu_cxx6__poolILb1EE16_M_get_thread_idEv;
|
||||
@ -571,6 +571,8 @@ GLIBCXX_3.4.6 {
|
||||
|
||||
_ZNKSt15basic_stringbufIwSt11char_traitsIwESaIwEE3strEv;
|
||||
|
||||
_ZN9__gnu_cxx6__poolILb1EE13_M_initializeEv;
|
||||
|
||||
} GLIBCXX_3.4.5;
|
||||
|
||||
# Symbols in the support library (libsupc++) have their own tag.
|
||||
|
@ -43,7 +43,6 @@
|
||||
namespace __gnu_cxx
|
||||
{
|
||||
typedef void (*__destroy_handler)(void*);
|
||||
typedef void (*__create_handler)(void);
|
||||
|
||||
/// @brief Base class for pool object.
|
||||
struct __pool_base
|
||||
@ -185,12 +184,6 @@ namespace __gnu_cxx
|
||||
template<bool _Thread>
|
||||
class __pool;
|
||||
|
||||
template<>
|
||||
class __pool<true>;
|
||||
|
||||
template<>
|
||||
class __pool<false>;
|
||||
|
||||
/// Specialization for single thread.
|
||||
template<>
|
||||
class __pool<false> : public __pool_base
|
||||
@ -313,24 +306,15 @@ namespace __gnu_cxx
|
||||
__gthread_mutex_t* _M_mutex;
|
||||
};
|
||||
|
||||
// XXX GLIBCXX_ABI Deprecated
|
||||
void
|
||||
_M_initialize(__destroy_handler __d);
|
||||
_M_initialize(__destroy_handler);
|
||||
|
||||
void
|
||||
_M_initialize_once(__create_handler __c)
|
||||
_M_initialize_once()
|
||||
{
|
||||
// Although the test in __gthread_once() would suffice, we
|
||||
// wrap test of the once condition in our own unlocked
|
||||
// check. This saves one function call to pthread_once()
|
||||
// (which itself only tests for the once value unlocked anyway
|
||||
// and immediately returns if set)
|
||||
if (__builtin_expect(_M_init == false, false))
|
||||
{
|
||||
if (__gthread_active_p())
|
||||
__gthread_once(&_M_once, __c);
|
||||
if (!_M_init)
|
||||
__c();
|
||||
}
|
||||
_M_initialize();
|
||||
}
|
||||
|
||||
void
|
||||
@ -358,28 +342,21 @@ namespace __gnu_cxx
|
||||
}
|
||||
}
|
||||
|
||||
// XXX GLIBCXX_ABI Deprecated
|
||||
void
|
||||
_M_destroy_thread_key(void* __freelist_pos);
|
||||
_M_destroy_thread_key(void*);
|
||||
|
||||
size_t
|
||||
_M_get_thread_id();
|
||||
|
||||
explicit __pool()
|
||||
: _M_bin(NULL), _M_bin_size(1), _M_thread_freelist(NULL)
|
||||
{
|
||||
// On some platforms, __gthread_once_t is an aggregate.
|
||||
__gthread_once_t __tmp = __GTHREAD_ONCE_INIT;
|
||||
_M_once = __tmp;
|
||||
}
|
||||
{ }
|
||||
|
||||
explicit __pool(const __pool_base::_Tune& __tune)
|
||||
: __pool_base(__tune), _M_bin(NULL), _M_bin_size(1),
|
||||
_M_thread_freelist(NULL)
|
||||
{
|
||||
// On some platforms, __gthread_once_t is an aggregate.
|
||||
__gthread_once_t __tmp = __GTHREAD_ONCE_INIT;
|
||||
_M_once = __tmp;
|
||||
}
|
||||
{ }
|
||||
|
||||
private:
|
||||
// An "array" of bin_records each of which represents a specific
|
||||
@ -390,39 +367,131 @@ namespace __gnu_cxx
|
||||
// Actual value calculated in _M_initialize().
|
||||
size_t _M_bin_size;
|
||||
|
||||
__gthread_once_t _M_once;
|
||||
|
||||
_Thread_record* _M_thread_freelist;
|
||||
void* _M_thread_freelist_initial;
|
||||
|
||||
void
|
||||
_M_initialize();
|
||||
};
|
||||
#endif
|
||||
|
||||
template<template <bool> class _PoolTp, bool _Thread>
|
||||
struct __common_pool
|
||||
{
|
||||
typedef _PoolTp<_Thread> pool_type;
|
||||
|
||||
static pool_type&
|
||||
_S_get_pool()
|
||||
{
|
||||
static pool_type _S_pool;
|
||||
return _S_pool;
|
||||
}
|
||||
};
|
||||
|
||||
template<template <bool> class _PoolTp, bool _Thread>
|
||||
struct __common_pool_base;
|
||||
|
||||
template<template <bool> class _PoolTp>
|
||||
struct __common_pool_base<_PoolTp, false>
|
||||
: public __common_pool<_PoolTp, false>
|
||||
{
|
||||
using __common_pool<_PoolTp, false>::_S_get_pool;
|
||||
|
||||
static void
|
||||
_S_initialize_once()
|
||||
{
|
||||
static bool __init;
|
||||
if (__builtin_expect(__init == false, false))
|
||||
{
|
||||
_S_get_pool()._M_initialize_once();
|
||||
__init = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __GTHREADS
|
||||
template<template <bool> class _PoolTp>
|
||||
struct __common_pool_base<_PoolTp, true>
|
||||
: public __common_pool<_PoolTp, true>
|
||||
{
|
||||
using __common_pool<_PoolTp, true>::_S_get_pool;
|
||||
|
||||
static void
|
||||
_S_initialize()
|
||||
{ _S_get_pool()._M_initialize_once(); }
|
||||
|
||||
static void
|
||||
_S_initialize_once()
|
||||
{
|
||||
static bool __init;
|
||||
if (__builtin_expect(__init == false, false))
|
||||
{
|
||||
if (__gthread_active_p())
|
||||
{
|
||||
// On some platforms, __gthread_once_t is an aggregate.
|
||||
static __gthread_once_t __once = __GTHREAD_ONCE_INIT;
|
||||
__gthread_once(&__once, _S_initialize);
|
||||
}
|
||||
else
|
||||
_S_get_pool()._M_initialize_once();
|
||||
__init = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
/// @brief Policy for shared __pool objects.
|
||||
template<template <bool> class _PoolTp, bool _Thread>
|
||||
struct __common_pool_policy;
|
||||
|
||||
/// Partial specialization for single thread.
|
||||
template<template <bool> class _PoolTp>
|
||||
struct __common_pool_policy<_PoolTp, false>
|
||||
struct __common_pool_policy : public __common_pool_base<_PoolTp, _Thread>
|
||||
{
|
||||
typedef _PoolTp<false> pool_type;
|
||||
|
||||
template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp,
|
||||
bool _Thread1 = false>
|
||||
bool _Thread1 = _Thread>
|
||||
struct _M_rebind
|
||||
{ typedef __common_pool_policy<_PoolTp1, _Thread1> other; };
|
||||
|
||||
using __common_pool_base<_PoolTp, _Thread>::_S_get_pool;
|
||||
using __common_pool_base<_PoolTp, _Thread>::_S_initialize_once;
|
||||
};
|
||||
|
||||
|
||||
template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
|
||||
struct __per_type_pool
|
||||
{
|
||||
typedef _Tp value_type;
|
||||
typedef _PoolTp<_Thread> pool_type;
|
||||
|
||||
static pool_type&
|
||||
_S_get_pool()
|
||||
{
|
||||
static pool_type _S_pool;
|
||||
// Sane defaults for the _PoolTp.
|
||||
typedef typename pool_type::_Block_record _Block_record;
|
||||
const static size_t __a = (__alignof__(_Tp) >= sizeof(_Block_record)
|
||||
? __alignof__(_Tp) : sizeof(_Block_record));
|
||||
|
||||
typedef typename __pool_base::_Tune _Tune;
|
||||
static _Tune _S_tune(__a, sizeof(_Tp) * 64,
|
||||
sizeof(_Tp) * 2 >= __a ? sizeof(_Tp) * 2 : __a,
|
||||
sizeof(_Tp) * size_t(_Tune::_S_chunk_size),
|
||||
_Tune::_S_max_threads,
|
||||
_Tune::_S_freelist_headroom,
|
||||
getenv("GLIBCXX_FORCE_NEW") ? true : false);
|
||||
static pool_type _S_pool(_S_tune);
|
||||
return _S_pool;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
|
||||
struct __per_type_pool_base;
|
||||
|
||||
template<typename _Tp, template <bool> class _PoolTp>
|
||||
struct __per_type_pool_base<_Tp, _PoolTp, false>
|
||||
: public __per_type_pool<_Tp, _PoolTp, false>
|
||||
{
|
||||
using __per_type_pool<_Tp, _PoolTp, false>::_S_get_pool;
|
||||
|
||||
static void
|
||||
_S_initialize_once()
|
||||
{
|
||||
_S_initialize_once()
|
||||
{
|
||||
static bool __init;
|
||||
if (__builtin_expect(__init == false, false))
|
||||
{
|
||||
@ -432,152 +501,51 @@ namespace __gnu_cxx
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __GTHREADS
|
||||
/// Partial specialization for thread enabled, via gthreads.h.
|
||||
template<template <bool> class _PoolTp>
|
||||
struct __common_pool_policy<_PoolTp, true>
|
||||
#ifdef __GTHREADS
|
||||
template<typename _Tp, template <bool> class _PoolTp>
|
||||
struct __per_type_pool_base<_Tp, _PoolTp, true>
|
||||
: public __per_type_pool<_Tp, _PoolTp, true>
|
||||
{
|
||||
typedef _PoolTp<true> pool_type;
|
||||
|
||||
template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp,
|
||||
bool _Thread1 = true>
|
||||
struct _M_rebind
|
||||
{ typedef __common_pool_policy<_PoolTp1, _Thread1> other; };
|
||||
|
||||
static pool_type&
|
||||
_S_get_pool()
|
||||
{
|
||||
static pool_type _S_pool;
|
||||
return _S_pool;
|
||||
}
|
||||
using __per_type_pool<_Tp, _PoolTp, true>::_S_get_pool;
|
||||
|
||||
static void
|
||||
_S_initialize_once()
|
||||
_S_initialize()
|
||||
{ _S_get_pool()._M_initialize_once(); }
|
||||
|
||||
static void
|
||||
_S_initialize_once()
|
||||
{
|
||||
static bool __init;
|
||||
if (__builtin_expect(__init == false, false))
|
||||
{
|
||||
_S_get_pool()._M_initialize_once(_S_initialize);
|
||||
if (__gthread_active_p())
|
||||
{
|
||||
// On some platforms, __gthread_once_t is an aggregate.
|
||||
static __gthread_once_t __once = __GTHREAD_ONCE_INIT;
|
||||
__gthread_once(&__once, _S_initialize);
|
||||
}
|
||||
else
|
||||
_S_get_pool()._M_initialize_once();
|
||||
__init = true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static void
|
||||
_S_destroy_thread_key(void* __freelist_pos)
|
||||
{ _S_get_pool()._M_destroy_thread_key(__freelist_pos); }
|
||||
|
||||
static void
|
||||
_S_initialize()
|
||||
{ _S_get_pool()._M_initialize(_S_destroy_thread_key); }
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/// @brief Policy for individual __pool objects.
|
||||
template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
|
||||
struct __per_type_pool_policy;
|
||||
|
||||
/// Partial specialization for single thread.
|
||||
template<typename _Tp, template <bool> class _PoolTp>
|
||||
struct __per_type_pool_policy<_Tp, _PoolTp, false>
|
||||
struct __per_type_pool_policy
|
||||
: public __per_type_pool_base<_Tp, _PoolTp, _Thread>
|
||||
{
|
||||
typedef _Tp value_type;
|
||||
typedef _PoolTp<false> pool_type;
|
||||
|
||||
template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp,
|
||||
bool _Thread1 = false>
|
||||
bool _Thread1 = _Thread>
|
||||
struct _M_rebind
|
||||
{ typedef __per_type_pool_policy<_Tp1, _PoolTp1, _Thread1> other; };
|
||||
|
||||
static pool_type&
|
||||
_S_get_pool()
|
||||
{
|
||||
// Sane defaults for the _PoolTp.
|
||||
typedef typename pool_type::_Block_record _Block_record;
|
||||
const static size_t __align = (__alignof__(_Tp) >= sizeof(_Block_record)
|
||||
? __alignof__(_Tp)
|
||||
: sizeof(_Block_record));
|
||||
using __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_get_pool;
|
||||
using __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_initialize_once;
|
||||
};
|
||||
|
||||
typedef typename __pool_base::_Tune _Tune;
|
||||
static _Tune _S_tune(__align, sizeof(_Tp) * 64,
|
||||
sizeof(_Tp) * 2 >= __align ? sizeof(_Tp) * 2
|
||||
: __align,
|
||||
sizeof(_Tp) * size_t(_Tune::_S_chunk_size),
|
||||
_Tune::_S_max_threads,
|
||||
_Tune::_S_freelist_headroom,
|
||||
getenv("GLIBCXX_FORCE_NEW") ? true : false);
|
||||
static pool_type _S_pool(_S_tune);
|
||||
return _S_pool;
|
||||
}
|
||||
|
||||
static void
|
||||
_S_initialize_once()
|
||||
{
|
||||
static bool __init;
|
||||
if (__builtin_expect(__init == false, false))
|
||||
{
|
||||
_S_get_pool()._M_initialize_once();
|
||||
__init = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __GTHREADS
|
||||
/// Partial specialization for thread enabled, via gthreads.h.
|
||||
template<typename _Tp, template <bool> class _PoolTp>
|
||||
struct __per_type_pool_policy<_Tp, _PoolTp, true>
|
||||
{
|
||||
typedef _Tp value_type;
|
||||
typedef _PoolTp<true> pool_type;
|
||||
|
||||
template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp,
|
||||
bool _Thread1 = true>
|
||||
struct _M_rebind
|
||||
{ typedef __per_type_pool_policy<_Tp1, _PoolTp1, _Thread1> other; };
|
||||
|
||||
static pool_type&
|
||||
_S_get_pool()
|
||||
{
|
||||
// Sane defaults for the _PoolTp.
|
||||
typedef typename pool_type::_Block_record _Block_record;
|
||||
const static size_t __align = (__alignof__(_Tp) >= sizeof(_Block_record)
|
||||
? __alignof__(_Tp)
|
||||
: sizeof(_Block_record));
|
||||
|
||||
typedef typename __pool_base::_Tune _Tune;
|
||||
static _Tune _S_tune(__align, sizeof(_Tp) * 64,
|
||||
sizeof(_Tp) * 2 >= __align ? sizeof(_Tp) * 2
|
||||
: __align,
|
||||
sizeof(_Tp) * size_t(_Tune::_S_chunk_size),
|
||||
_Tune::_S_max_threads,
|
||||
_Tune::_S_freelist_headroom,
|
||||
getenv("GLIBCXX_FORCE_NEW") ? true : false);
|
||||
static pool_type _S_pool(_S_tune);
|
||||
return _S_pool;
|
||||
}
|
||||
|
||||
static void
|
||||
_S_initialize_once()
|
||||
{
|
||||
static bool __init;
|
||||
if (__builtin_expect(__init == false, false))
|
||||
{
|
||||
_S_get_pool()._M_initialize_once(_S_initialize);
|
||||
__init = true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static void
|
||||
_S_destroy_thread_key(void* __freelist_pos)
|
||||
{ _S_get_pool()._M_destroy_thread_key(__freelist_pos); }
|
||||
|
||||
static void
|
||||
_S_initialize()
|
||||
{ _S_get_pool()._M_initialize(_S_destroy_thread_key); }
|
||||
};
|
||||
#endif
|
||||
|
||||
/// @brief Base class for _Tp dependent member functions.
|
||||
template<typename _Tp>
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Allocator details.
|
||||
|
||||
// Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Librarbooly. This library is free
|
||||
// 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)
|
||||
@ -37,10 +37,42 @@
|
||||
|
||||
namespace __gnu_internal
|
||||
{
|
||||
#ifdef __GTHREADS
|
||||
struct __freelist
|
||||
{
|
||||
typedef __gnu_cxx::__pool<true>::_Thread_record _Thread_record;
|
||||
_Thread_record* _M_thread_freelist;
|
||||
_Thread_record* _M_thread_freelist_array;
|
||||
size_t _M_max_threads;
|
||||
__gthread_key_t _M_key;
|
||||
|
||||
~__freelist()
|
||||
{
|
||||
if (_M_thread_freelist_array)
|
||||
{
|
||||
__gthread_key_delete(_M_key);
|
||||
::operator delete(static_cast<void*>(_M_thread_freelist_array));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Ensure freelist is constructed first.
|
||||
static __freelist freelist;
|
||||
static __glibcxx_mutex_define_initialized(freelist_mutex);
|
||||
|
||||
#ifdef __GTHREADS
|
||||
__gthread_key_t freelist_key;
|
||||
static void
|
||||
_M_destroy_thread_key(void* __id)
|
||||
{
|
||||
// Return this thread id record to front of thread_freelist.
|
||||
__gnu_cxx::lock sentry(__gnu_internal::freelist_mutex);
|
||||
size_t _M_id = reinterpret_cast<size_t>(__id);
|
||||
|
||||
using namespace __gnu_internal;
|
||||
typedef __gnu_cxx::__pool<true>::_Thread_record _Thread_record;
|
||||
_Thread_record* __tr = &freelist._M_thread_freelist_array[_M_id - 1];
|
||||
__tr->_M_next = freelist._M_thread_freelist;
|
||||
freelist._M_thread_freelist = __tr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -171,6 +203,7 @@ namespace __gnu_cxx
|
||||
}
|
||||
_M_init = true;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __GTHREADS
|
||||
void
|
||||
@ -194,7 +227,6 @@ namespace __gnu_cxx
|
||||
::operator delete(__bin._M_used);
|
||||
::operator delete(__bin._M_mutex);
|
||||
}
|
||||
::operator delete(_M_thread_freelist_initial);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -386,8 +418,8 @@ namespace __gnu_cxx
|
||||
return reinterpret_cast<char*>(__block) + __options._M_align;
|
||||
}
|
||||
|
||||
void
|
||||
__pool<true>::_M_initialize(__destroy_handler __d)
|
||||
void
|
||||
__pool<true>::_M_initialize()
|
||||
{
|
||||
// _M_force_new must not change after the first allocate(),
|
||||
// which in turn calls this method, so if it's false, it's false
|
||||
@ -397,7 +429,7 @@ namespace __gnu_cxx
|
||||
_M_init = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create the bins.
|
||||
// Calculate the number of bins required based on _M_max_bytes.
|
||||
// _M_bin_size is statically-initialized to one.
|
||||
@ -433,29 +465,70 @@ namespace __gnu_cxx
|
||||
// directly and have no need for this.
|
||||
if (__gthread_active_p())
|
||||
{
|
||||
const size_t __k = sizeof(_Thread_record) * _M_options._M_max_threads;
|
||||
__v = ::operator new(__k);
|
||||
_M_thread_freelist = static_cast<_Thread_record*>(__v);
|
||||
_M_thread_freelist_initial = __v;
|
||||
|
||||
// NOTE! The first assignable thread id is 1 since the
|
||||
// global pool uses id 0
|
||||
size_t __i;
|
||||
for (__i = 1; __i < _M_options._M_max_threads; ++__i)
|
||||
{
|
||||
_Thread_record& __tr = _M_thread_freelist[__i - 1];
|
||||
__tr._M_next = &_M_thread_freelist[__i];
|
||||
__tr._M_id = __i;
|
||||
}
|
||||
|
||||
// Set last record.
|
||||
_M_thread_freelist[__i - 1]._M_next = NULL;
|
||||
_M_thread_freelist[__i - 1]._M_id = __i;
|
||||
|
||||
// Initialize per thread key to hold pointer to
|
||||
// _M_thread_freelist.
|
||||
__gthread_key_create(&__gnu_internal::freelist_key, __d);
|
||||
|
||||
{
|
||||
__gnu_cxx::lock sentry(__gnu_internal::freelist_mutex);
|
||||
|
||||
if (!__gnu_internal::freelist._M_thread_freelist_array
|
||||
|| __gnu_internal::freelist._M_max_threads
|
||||
< _M_options._M_max_threads)
|
||||
{
|
||||
const size_t __k = sizeof(_Thread_record)
|
||||
* _M_options._M_max_threads;
|
||||
__v = ::operator new(__k);
|
||||
_Thread_record* _M_thread_freelist
|
||||
= static_cast<_Thread_record*>(__v);
|
||||
|
||||
// NOTE! The first assignable thread id is 1 since the
|
||||
// global pool uses id 0
|
||||
size_t __i;
|
||||
for (__i = 1; __i < _M_options._M_max_threads; ++__i)
|
||||
{
|
||||
_Thread_record& __tr = _M_thread_freelist[__i - 1];
|
||||
__tr._M_next = &_M_thread_freelist[__i];
|
||||
__tr._M_id = __i;
|
||||
}
|
||||
|
||||
// Set last record.
|
||||
_M_thread_freelist[__i - 1]._M_next = NULL;
|
||||
_M_thread_freelist[__i - 1]._M_id = __i;
|
||||
|
||||
if (!__gnu_internal::freelist._M_thread_freelist_array)
|
||||
{
|
||||
// Initialize per thread key to hold pointer to
|
||||
// _M_thread_freelist.
|
||||
__gthread_key_create(&__gnu_internal::freelist._M_key,
|
||||
__gnu_internal::_M_destroy_thread_key);
|
||||
__gnu_internal::freelist._M_thread_freelist
|
||||
= _M_thread_freelist;
|
||||
}
|
||||
else
|
||||
{
|
||||
_Thread_record* _M_old_freelist
|
||||
= __gnu_internal::freelist._M_thread_freelist;
|
||||
_Thread_record* _M_old_array
|
||||
= __gnu_internal::freelist._M_thread_freelist_array;
|
||||
__gnu_internal::freelist._M_thread_freelist
|
||||
= &_M_thread_freelist[_M_old_freelist - _M_old_array];
|
||||
while (_M_old_freelist)
|
||||
{
|
||||
size_t next_id;
|
||||
if (_M_old_freelist->_M_next)
|
||||
next_id = _M_old_freelist->_M_next - _M_old_array;
|
||||
else
|
||||
next_id = __gnu_internal::freelist._M_max_threads;
|
||||
_M_thread_freelist[_M_old_freelist->_M_id - 1]._M_next
|
||||
= &_M_thread_freelist[next_id];
|
||||
_M_old_freelist = _M_old_freelist->_M_next;
|
||||
}
|
||||
::operator delete(static_cast<void*>(_M_old_array));
|
||||
}
|
||||
__gnu_internal::freelist._M_thread_freelist_array
|
||||
= _M_thread_freelist;
|
||||
__gnu_internal::freelist._M_max_threads
|
||||
= _M_options._M_max_threads;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t __max_threads = _M_options._M_max_threads + 1;
|
||||
for (size_t __n = 0; __n < _M_bin_size; ++__n)
|
||||
{
|
||||
@ -514,23 +587,24 @@ namespace __gnu_cxx
|
||||
// returns it's id.
|
||||
if (__gthread_active_p())
|
||||
{
|
||||
void* v = __gthread_getspecific(__gnu_internal::freelist_key);
|
||||
_Thread_record* __freelist_pos = static_cast<_Thread_record*>(v);
|
||||
if (__freelist_pos == NULL)
|
||||
void* v = __gthread_getspecific(__gnu_internal::freelist._M_key);
|
||||
size_t _M_id = (size_t)v;
|
||||
if (_M_id == 0)
|
||||
{
|
||||
// Since _M_options._M_max_threads must be larger than
|
||||
// the theoretical max number of threads of the OS the
|
||||
// list can never be empty.
|
||||
{
|
||||
__gnu_cxx::lock sentry(__gnu_internal::freelist_mutex);
|
||||
__freelist_pos = _M_thread_freelist;
|
||||
_M_thread_freelist = _M_thread_freelist->_M_next;
|
||||
if (__gnu_internal::freelist._M_thread_freelist)
|
||||
{
|
||||
_M_id = __gnu_internal::freelist._M_thread_freelist->_M_id;
|
||||
__gnu_internal::freelist._M_thread_freelist
|
||||
= __gnu_internal::freelist._M_thread_freelist->_M_next;
|
||||
}
|
||||
}
|
||||
|
||||
__gthread_setspecific(__gnu_internal::freelist_key,
|
||||
static_cast<void*>(__freelist_pos));
|
||||
|
||||
__gthread_setspecific(__gnu_internal::freelist._M_key,
|
||||
(void*)_M_id);
|
||||
}
|
||||
return __freelist_pos->_M_id;
|
||||
return _M_id >= _M_options._M_max_threads ? 0 : _M_id;
|
||||
}
|
||||
|
||||
// Otherwise (no thread support or inactive) all requests are
|
||||
@ -538,14 +612,169 @@ namespace __gnu_cxx
|
||||
return 0;
|
||||
}
|
||||
|
||||
// XXX GLIBCXX_ABI Deprecated
|
||||
void
|
||||
__pool<true>::_M_destroy_thread_key(void*) { }
|
||||
|
||||
// XXX GLIBCXX_ABI Deprecated
|
||||
void
|
||||
__pool<true>::_M_destroy_thread_key(void* __freelist_pos)
|
||||
__pool<true>::_M_initialize(__destroy_handler)
|
||||
{
|
||||
// Return this thread id record to front of thread_freelist.
|
||||
__gnu_cxx::lock sentry(__gnu_internal::freelist_mutex);
|
||||
_Thread_record* __tr = static_cast<_Thread_record*>(__freelist_pos);
|
||||
__tr->_M_next = _M_thread_freelist;
|
||||
_M_thread_freelist = __tr;
|
||||
// _M_force_new must not change after the first allocate(),
|
||||
// which in turn calls this method, so if it's false, it's false
|
||||
// forever and we don't need to return here ever again.
|
||||
if (_M_options._M_force_new)
|
||||
{
|
||||
_M_init = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the bins.
|
||||
// Calculate the number of bins required based on _M_max_bytes.
|
||||
// _M_bin_size is statically-initialized to one.
|
||||
size_t __bin_size = _M_options._M_min_bin;
|
||||
while (_M_options._M_max_bytes > __bin_size)
|
||||
{
|
||||
__bin_size <<= 1;
|
||||
++_M_bin_size;
|
||||
}
|
||||
|
||||
// Setup the bin map for quick lookup of the relevant bin.
|
||||
const size_t __j = (_M_options._M_max_bytes + 1) * sizeof(_Binmap_type);
|
||||
_M_binmap = static_cast<_Binmap_type*>(::operator new(__j));
|
||||
_Binmap_type* __bp = _M_binmap;
|
||||
_Binmap_type __bin_max = _M_options._M_min_bin;
|
||||
_Binmap_type __bint = 0;
|
||||
for (_Binmap_type __ct = 0; __ct <= _M_options._M_max_bytes; ++__ct)
|
||||
{
|
||||
if (__ct > __bin_max)
|
||||
{
|
||||
__bin_max <<= 1;
|
||||
++__bint;
|
||||
}
|
||||
*__bp++ = __bint;
|
||||
}
|
||||
|
||||
// Initialize _M_bin and its members.
|
||||
void* __v = ::operator new(sizeof(_Bin_record) * _M_bin_size);
|
||||
_M_bin = static_cast<_Bin_record*>(__v);
|
||||
|
||||
// If __gthread_active_p() create and initialize the list of
|
||||
// free thread ids. Single threaded applications use thread id 0
|
||||
// directly and have no need for this.
|
||||
if (__gthread_active_p())
|
||||
{
|
||||
{
|
||||
__gnu_cxx::lock sentry(__gnu_internal::freelist_mutex);
|
||||
|
||||
if (!__gnu_internal::freelist._M_thread_freelist_array
|
||||
|| __gnu_internal::freelist._M_max_threads
|
||||
< _M_options._M_max_threads)
|
||||
{
|
||||
const size_t __k = sizeof(_Thread_record)
|
||||
* _M_options._M_max_threads;
|
||||
__v = ::operator new(__k);
|
||||
_Thread_record* _M_thread_freelist
|
||||
= static_cast<_Thread_record*>(__v);
|
||||
|
||||
// NOTE! The first assignable thread id is 1 since the
|
||||
// global pool uses id 0
|
||||
size_t __i;
|
||||
for (__i = 1; __i < _M_options._M_max_threads; ++__i)
|
||||
{
|
||||
_Thread_record& __tr = _M_thread_freelist[__i - 1];
|
||||
__tr._M_next = &_M_thread_freelist[__i];
|
||||
__tr._M_id = __i;
|
||||
}
|
||||
|
||||
// Set last record.
|
||||
_M_thread_freelist[__i - 1]._M_next = NULL;
|
||||
_M_thread_freelist[__i - 1]._M_id = __i;
|
||||
|
||||
if (!__gnu_internal::freelist._M_thread_freelist_array)
|
||||
{
|
||||
// Initialize per thread key to hold pointer to
|
||||
// _M_thread_freelist.
|
||||
__gthread_key_create(&__gnu_internal::freelist._M_key,
|
||||
__gnu_internal::_M_destroy_thread_key);
|
||||
__gnu_internal::freelist._M_thread_freelist
|
||||
= _M_thread_freelist;
|
||||
}
|
||||
else
|
||||
{
|
||||
_Thread_record* _M_old_freelist
|
||||
= __gnu_internal::freelist._M_thread_freelist;
|
||||
_Thread_record* _M_old_array
|
||||
= __gnu_internal::freelist._M_thread_freelist_array;
|
||||
__gnu_internal::freelist._M_thread_freelist
|
||||
= &_M_thread_freelist[_M_old_freelist - _M_old_array];
|
||||
while (_M_old_freelist)
|
||||
{
|
||||
size_t next_id;
|
||||
if (_M_old_freelist->_M_next)
|
||||
next_id = _M_old_freelist->_M_next - _M_old_array;
|
||||
else
|
||||
next_id = __gnu_internal::freelist._M_max_threads;
|
||||
_M_thread_freelist[_M_old_freelist->_M_id - 1]._M_next
|
||||
= &_M_thread_freelist[next_id];
|
||||
_M_old_freelist = _M_old_freelist->_M_next;
|
||||
}
|
||||
::operator delete(static_cast<void*>(_M_old_array));
|
||||
}
|
||||
__gnu_internal::freelist._M_thread_freelist_array
|
||||
= _M_thread_freelist;
|
||||
__gnu_internal::freelist._M_max_threads
|
||||
= _M_options._M_max_threads;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t __max_threads = _M_options._M_max_threads + 1;
|
||||
for (size_t __n = 0; __n < _M_bin_size; ++__n)
|
||||
{
|
||||
_Bin_record& __bin = _M_bin[__n];
|
||||
__v = ::operator new(sizeof(_Block_record*) * __max_threads);
|
||||
__bin._M_first = static_cast<_Block_record**>(__v);
|
||||
|
||||
__bin._M_address = NULL;
|
||||
|
||||
__v = ::operator new(sizeof(size_t) * __max_threads);
|
||||
__bin._M_free = static_cast<size_t*>(__v);
|
||||
|
||||
__v = ::operator new(sizeof(size_t) * __max_threads);
|
||||
__bin._M_used = static_cast<size_t*>(__v);
|
||||
|
||||
__v = ::operator new(sizeof(__gthread_mutex_t));
|
||||
__bin._M_mutex = static_cast<__gthread_mutex_t*>(__v);
|
||||
|
||||
#ifdef __GTHREAD_MUTEX_INIT
|
||||
{
|
||||
// Do not copy a POSIX/gthr mutex once in use.
|
||||
__gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
|
||||
*__bin._M_mutex = __tmp;
|
||||
}
|
||||
#else
|
||||
{ __GTHREAD_MUTEX_INIT_FUNCTION(__bin._M_mutex); }
|
||||
#endif
|
||||
for (size_t __threadn = 0; __threadn < __max_threads; ++__threadn)
|
||||
{
|
||||
__bin._M_first[__threadn] = NULL;
|
||||
__bin._M_free[__threadn] = 0;
|
||||
__bin._M_used[__threadn] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t __n = 0; __n < _M_bin_size; ++__n)
|
||||
{
|
||||
_Bin_record& __bin = _M_bin[__n];
|
||||
__v = ::operator new(sizeof(_Block_record*));
|
||||
__bin._M_first = static_cast<_Block_record**>(__v);
|
||||
__bin._M_first[0] = NULL;
|
||||
__bin._M_address = NULL;
|
||||
}
|
||||
}
|
||||
_M_init = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
101
libstdc++-v3/testsuite/ext/mt_allocator/22309_thread.cc
Normal file
101
libstdc++-v3/testsuite/ext/mt_allocator/22309_thread.cc
Normal file
@ -0,0 +1,101 @@
|
||||
// { dg-require-sharedlib "" }
|
||||
// { dg-do run { target *-*-linux* } }
|
||||
// { dg-options "-g -O2 -pthread -ldl" { target *-*-linux* } }
|
||||
|
||||
// Copyright (C) 2004, 2005 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
// USA.
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
|
||||
void
|
||||
check_dlopen(void*& h)
|
||||
{
|
||||
dlerror();
|
||||
void* tmp = dlopen("./testsuite_shared.so", RTLD_LAZY);
|
||||
if (!tmp)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Throws std::logic_error on NULL string.
|
||||
std::string error(dlerror());
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
catch (const std::logic_error&)
|
||||
{ }
|
||||
}
|
||||
h = tmp;
|
||||
}
|
||||
|
||||
void
|
||||
check_dlsym(void*& h)
|
||||
{
|
||||
dlerror();
|
||||
|
||||
typedef void (*function_type) (void);
|
||||
function_type fn;
|
||||
fn = reinterpret_cast<function_type>(dlsym(h, "foo"));
|
||||
|
||||
try
|
||||
{
|
||||
std::string error(dlerror());
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
catch (const std::logic_error&)
|
||||
{ }
|
||||
|
||||
fn();
|
||||
}
|
||||
|
||||
void
|
||||
check_dlclose(void*& h)
|
||||
{
|
||||
dlerror();
|
||||
if (dlclose(h) != 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string error(dlerror());
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
catch (const std::logic_error&)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
tf(void* arg)
|
||||
{
|
||||
void* h;
|
||||
check_dlopen(h);
|
||||
check_dlsym(h);
|
||||
check_dlclose(h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// libstdc++/22309
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
pthread_t th;
|
||||
pthread_create(&th, NULL, tf, NULL);
|
||||
pthread_join(th, NULL);
|
||||
return 0;
|
||||
}
|
@ -44,3 +44,12 @@ proc dg-require-cxa-atexit { args } {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
proc dg-require-sharedlib { args } {
|
||||
if { ![ check_v3_target_sharedlib ] } {
|
||||
upvar dg-do-what dg-do-what
|
||||
set dg-do-what [list [lindex ${dg-do-what} 0] "N" "P"]
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -14,7 +14,8 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
|
||||
# Define callbacks and load other libraries. This file is loaded relatively
|
||||
@ -79,6 +80,7 @@ proc v3-copy-files {srcfiles} {
|
||||
# Called once, during runtest.exp setup.
|
||||
proc libstdc++_init { testfile } {
|
||||
global env
|
||||
global v3-sharedlib
|
||||
global srcdir blddir objdir tool_root_dir
|
||||
global cxx cxxflags
|
||||
global includes
|
||||
@ -127,6 +129,15 @@ proc libstdc++_init { testfile } {
|
||||
}
|
||||
v3track gccdir 3
|
||||
|
||||
# Look for shared library. (ie libstdc++.so.)
|
||||
set v3-sharedlib 0
|
||||
set sharedlibdir [lookfor_file $blddir src/.libs/libstdc++.so]
|
||||
if {$sharedlibdir != ""} {
|
||||
set v3-sharedlib 1
|
||||
verbose -log "shared library support detected"
|
||||
}
|
||||
v3track v3-sharedlib 3
|
||||
|
||||
# Compute what needs to be added to the existing LD_LIBRARY_PATH.
|
||||
if {$gccdir != ""} {
|
||||
set ld_library_path ""
|
||||
@ -324,6 +335,7 @@ proc v3-build_support {} {
|
||||
global v3-threads
|
||||
global v3-test_objs
|
||||
global v3-symver
|
||||
global v3-sharedlib
|
||||
|
||||
# Figure out whether or not the library supports certain features.
|
||||
set v3-wchar_t 0
|
||||
@ -353,7 +365,7 @@ proc v3-build_support {} {
|
||||
|
||||
# Build the support objects.
|
||||
set source_files \
|
||||
[list testsuite_abi.cc testsuite_allocator.cc testsuite_character.cc testsuite_hooks.cc]
|
||||
[list testsuite_abi.cc testsuite_allocator.cc testsuite_character.cc testsuite_hooks.cc ]
|
||||
foreach f $source_files {
|
||||
set object_file [file rootname $f].o
|
||||
# Compile with "-w" so that warnings issued by the compiler
|
||||
@ -365,6 +377,27 @@ proc v3-build_support {} {
|
||||
}
|
||||
append v3-test_objs "$object_file "
|
||||
}
|
||||
|
||||
# Build the shared support objects.
|
||||
if { ${v3-sharedlib} == 1 } {
|
||||
set source_files \
|
||||
[list testsuite_shared.cc]
|
||||
foreach f $source_files {
|
||||
set object_file [file rootname $f].so
|
||||
# Compile with "-w" so that warnings issued by the compiler
|
||||
# do not prevent compilation.
|
||||
if { [v3_target_compile $srcdir/$f $object_file "executable" \
|
||||
[list "incdir=$srcdir" "additional_flags=-w -shared -fPIC -DPIC"]]
|
||||
!= "" } {
|
||||
error "could not compile $f"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc check_v3_target_sharedlib { } {
|
||||
global v3-sharedlib
|
||||
return ${v3-sharedlib}
|
||||
}
|
||||
|
||||
proc check_v3_target_namedlocale { } {
|
||||
@ -491,27 +524,27 @@ proc check_v3_target_cxa_atexit { } {
|
||||
puts $f "static unsigned int count;"
|
||||
puts $f "struct X"
|
||||
puts $f "{"
|
||||
puts $f "X() { count = 1; }"
|
||||
puts $f "~X()"
|
||||
puts $f "{"
|
||||
puts $f " if (count != 3)"
|
||||
puts $f " exit(1);"
|
||||
puts $f " count = 4;"
|
||||
puts $f "}"
|
||||
puts $f " X() { count = 1; }"
|
||||
puts $f " ~X()"
|
||||
puts $f " {"
|
||||
puts $f " if (count != 3)"
|
||||
puts $f " exit(1);"
|
||||
puts $f " count = 4;"
|
||||
puts $f " }"
|
||||
puts $f "};"
|
||||
puts $f "void f()"
|
||||
puts $f "{"
|
||||
puts $f "static X x;"
|
||||
puts $f " static X x;"
|
||||
puts $f "}"
|
||||
puts $f "struct Y"
|
||||
puts $f "{"
|
||||
puts $f "Y() { f(); count = 2; }"
|
||||
puts $f "~Y()"
|
||||
puts $f "{"
|
||||
puts $f "if (count != 2)"
|
||||
puts $f " exit(1);"
|
||||
puts $f "count = 3;"
|
||||
puts $f "}"
|
||||
puts $f " Y() { f(); count = 2; }"
|
||||
puts $f " ~Y()"
|
||||
puts $f " {"
|
||||
puts $f " if (count != 2)"
|
||||
puts $f " exit(1);"
|
||||
puts $f " count = 3;"
|
||||
puts $f " }"
|
||||
puts $f "};"
|
||||
puts $f "Y y;"
|
||||
puts $f "int main()"
|
||||
|
36
libstdc++-v3/testsuite/testsuite_shared.cc
Normal file
36
libstdc++-v3/testsuite/testsuite_shared.cc
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2004, 2005 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
// USA.
|
||||
|
||||
#include <string>
|
||||
#include <ext/mt_allocator.h>
|
||||
|
||||
// libstdc++/22309
|
||||
extern "C" void
|
||||
foo()
|
||||
{
|
||||
typedef char value_t;
|
||||
|
||||
typedef __gnu_cxx::__common_pool_policy<__gnu_cxx::__pool, true> policy_t;
|
||||
typedef __gnu_cxx::__mt_alloc<value_t, policy_t> allocator_t;
|
||||
|
||||
typedef std::char_traits<value_t> traits_t;
|
||||
typedef std::basic_string<value_t, traits_t, allocator_t> string_t;
|
||||
|
||||
string_t s;
|
||||
s += "west beach, indiana dunes";
|
||||
}
|
Loading…
Reference in New Issue
Block a user