Commit d38d4e5d by Benjamin Kosnik Committed by Benjamin Kosnik

new_allocator.h (new_allocator): Proper allocator class.


2003-12-23  Benjamin Kosnik  <bkoz@redhat.com>

	* include/ext/new_allocator.h (new_allocator): Proper allocator class.
	(__new_alloc): Delete.
	* include/ext/malloc_allocator.h (malloc_allocator): Same.
	(__malloc_alloc): Delete.
 	* include/ext/mt_allocator.h: Same, but weakly.
 	* include/ext/debug_allocator.h: Convert to the new style.
	* include/ext/pool_allocator.h: Use global new and delete directly.
	* include/backward/alloc.h: Don't inject malloc_allocator, or
	debug_allocator.
	* testsuite/ext/allocators.cc: Minimal fixups for usage of new
	classes.  Comment out tests with __pool_alloc for now.
	* testsuite/performance/allocator.cc: Same.

From-SVN: r74965
parent cbf6e52a
2003-12-23 Benjamin Kosnik <bkoz@redhat.com>
* include/ext/new_allocator.h (new_allocator): Proper allocator class.
(__new_alloc): Delete.
* include/ext/malloc_allocator.h (malloc_allocator): Same.
(__malloc_alloc): Delete.
* include/ext/mt_allocator.h: Same, but weakly.
* include/ext/debug_allocator.h: Convert to the new style.
* include/ext/pool_allocator.h: Use global new and delete directly.
* include/backward/alloc.h: Don't inject malloc_allocator, or
debug_allocator.
* testsuite/ext/allocators.cc: Minimal fixups for usage of new
classes. Comment out tests with __pool_alloc for now.
* testsuite/performance/allocator.cc: Same.
2003-12-22 Matt Austern <austern@apple.com> 2003-12-22 Matt Austern <austern@apple.com>
* include/bits/stl_bvector.h (_Bvector_alloc_base): Eliminate. * include/bits/stl_bvector.h (_Bvector_alloc_base): Eliminate.
......
...@@ -46,11 +46,7 @@ ...@@ -46,11 +46,7 @@
#include "backward_warning.h" #include "backward_warning.h"
#include <bits/c++config.h> #include <bits/c++config.h>
#include <bits/allocator.h> #include <bits/allocator.h>
#include <ext/debug_allocator.h>
#include <ext/malloc_allocator.h>
using __gnu_cxx::__malloc_alloc;
using __gnu_cxx::__debug_alloc;
using __gnu_cxx::__pool_alloc; using __gnu_cxx::__pool_alloc;
using std::__alloc; using std::__alloc;
using std::__simple_alloc; using std::__simple_alloc;
......
...@@ -48,92 +48,58 @@ ...@@ -48,92 +48,58 @@
#ifndef _DEBUG_ALLOCATOR_H #ifndef _DEBUG_ALLOCATOR_H
#define _DEBUG_ALLOCATOR_H 1 #define _DEBUG_ALLOCATOR_H 1
#include <bits/allocator_traits.h> #include <memory>
namespace __gnu_cxx namespace __gnu_cxx
{ {
/** /**
* @if maint * @brief A meta-allocator with debugging bits, as per [20.4].
* An adaptor for an underlying allocator (_Alloc) to check the size
* arguments for debugging.
* *
* "There is some evidence that this can confuse Purify." - SGI comment * This is precisely the allocator defined in the C++ Standard.
* - all allocation calls operator new
* - all deallocation calls operator delete
* *
* This adaptor is "SGI" style. The _Alloc parameter must also be "SGI".
* @endif
* (See @link Allocators allocators info @endlink for more.) * (See @link Allocators allocators info @endlink for more.)
*/ */
template<typename _Alloc> template<typename _Alloc>
class __debug_alloc class debug_allocator
{ {
public:
typedef typename _Alloc::size_type size_type;
typedef typename _Alloc::difference_type difference_type;
typedef typename _Alloc::pointer pointer;
typedef typename _Alloc::const_pointer const_pointer;
typedef typename _Alloc::reference reference;
typedef typename _Alloc::const_reference const_reference;
typedef typename _Alloc::value_type value_type;
private: private:
// Size of space used to store size. Note that this must be // Size of space used to store size. Note that this must be
// large enough to preserve alignment. // large enough to preserve alignment.
enum {_S_extra = 8}; const size_t _M_extra;
_Alloc _M_allocator;
public: public:
static void* debug_allocator() : _M_extra(8) { }
allocate(size_t __n)
pointer
allocate(size_type __n, std::allocator<void>::const_pointer = 0)
{ {
char* __result = (char*)_Alloc::allocate(__n + (int) _S_extra); pointer __result = _M_allocator.allocate(__n + _M_extra);
*(size_t*)__result = __n; *__result = __n;
return __result + (int) _S_extra; return __result + _M_extra;
} }
static void void
deallocate(void* __p, size_t __n) deallocate(pointer __p, size_type __n)
{ {
char* __real_p = (char*)__p - (int) _S_extra; pointer __real_p = __p - _M_extra;
if (*(size_t*)__real_p != __n) if (*__real_p != __n)
abort(); abort();
_Alloc::deallocate(__real_p, __n + (int) _S_extra); _M_allocator.deallocate(__real_p, __n + _M_extra);
} }
}; };
//@{
/** Comparison operators for all of the predifined SGI-style allocators.
* This ensures that __allocator<malloc_alloc> (for example) will work
* correctly. As required, all allocators compare equal.
*/
template<typename _Alloc>
inline bool
operator==(const __debug_alloc<_Alloc>&, const __debug_alloc<_Alloc>&)
{ return true; }
template<typename _Alloc>
inline bool
operator!=(const __debug_alloc<_Alloc>&, const __debug_alloc<_Alloc>&)
{ return false; }
//@}
} // namespace __gnu_cxx } // namespace __gnu_cxx
namespace std
{
//@{
/// Versions for the predefined "SGI" style allocators.
template<typename _Tp, typename _Alloc>
struct _Alloc_traits<_Tp, __gnu_cxx::__debug_alloc<_Alloc> >
{
static const bool _S_instanceless = true;
typedef __gnu_cxx::__debug_alloc<_Alloc> base_alloc_type;
typedef __simple_alloc<_Tp, base_alloc_type> _Alloc_type;
typedef __allocator<_Tp, base_alloc_type> allocator_type;
};
//@}
//@{
/// Versions for the __allocator adaptor used with the predefined
/// "SGI" style allocators.
template<typename _Tp, typename _Tp1, typename _Alloc>
struct _Alloc_traits<_Tp, __allocator<_Tp1,
__gnu_cxx::__debug_alloc<_Alloc> > >
{
static const bool _S_instanceless = true;
typedef __gnu_cxx::__debug_alloc<_Alloc> base_alloc_type;
typedef __simple_alloc<_Tp, base_alloc_type> _Alloc_type;
typedef __allocator<_Tp, base_alloc_type> allocator_type;
};
//@}
} // namespace std
#endif #endif
// Allocators -*- C++ -*- // Allocator that wraps "C" malloc -*- C++ -*-
// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. // Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
// //
...@@ -27,137 +27,78 @@ ...@@ -27,137 +27,78 @@
// invalidate any other reasons why the executable file might be covered by // invalidate any other reasons why the executable file might be covered by
// the GNU General Public License. // the GNU General Public License.
/*
* Copyright (c) 1996-1997
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*/
/** @file ext/debug_allocator.h
* This file is a GNU extension to the Standard C++ Library.
* You should only include this header if you are using GCC 3 or later.
*/
#ifndef _MALLOC_ALLOCATOR_H #ifndef _MALLOC_ALLOCATOR_H
#define _MALLOC_ALLOCATOR_H 1 #define _MALLOC_ALLOCATOR_H 1
#include <bits/allocator_traits.h> #include <new>
#include <memory>
namespace __gnu_cxx namespace __gnu_cxx
{ {
/** /**
* @if maint * @brief An allocator that uses malloc
* A malloc-based allocator. Typically slower than the *
* __pool_alloc (below). Typically thread-safe and more * This is precisely the allocator defined in the C++ Standard.
* storage efficient. The template argument is unused and is only present * - all allocation calls malloc
* to permit multiple instantiations (but see __pool_alloc * - all deallocation calls free
* for caveats). "SGI" style, plus __set_malloc_handler for OOM conditions. *
* @endif
* (See @link Allocators allocators info @endlink for more.) * (See @link Allocators allocators info @endlink for more.)
*/ */
template<int __inst> template<typename _Tp>
class __malloc_alloc class malloc_allocator
{ {
private:
static void* _S_oom_malloc(size_t);
static void (* __malloc_alloc_oom_handler)();
public: public:
static void* typedef size_t size_type;
allocate(size_t __n) typedef ptrdiff_t difference_type;
{ typedef _Tp* pointer;
void* __result = malloc(__n); typedef const _Tp* const_pointer;
if (__builtin_expect(__result == 0, 0)) typedef _Tp& reference;
__result = _S_oom_malloc(__n); typedef const _Tp& const_reference;
return __result; typedef _Tp value_type;
}
static void template<typename _Tp1>
deallocate(void* __p, size_t /* __n */) struct rebind
{ free(__p); } { typedef malloc_allocator<_Tp1> other; };
static void (* __set_malloc_handler(void (*__f)()))() malloc_allocator() throw() { }
{
void (* __old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = __f;
return __old;
}
};
// malloc_alloc out-of-memory handling malloc_allocator(const malloc_allocator&) throw() { }
template<int __inst>
void (* __malloc_alloc<__inst>::__malloc_alloc_oom_handler)() = 0;
template<int __inst> template<typename _Tp1>
void* malloc_allocator(const malloc_allocator<_Tp1>&) throw() { }
__malloc_alloc<__inst>::
_S_oom_malloc(size_t __n)
{
void (* __my_malloc_handler)();
void* __result;
for (;;) ~malloc_allocator() throw() { }
{
__my_malloc_handler = __malloc_alloc_oom_handler;
if (__builtin_expect(__my_malloc_handler == 0, 0))
__throw_bad_alloc();
(*__my_malloc_handler)();
__result = malloc(__n);
if (__result)
return __result;
}
}
//@{
/** Comparison operators for all of the predifined SGI-style allocators.
* This ensures that __allocator<malloc_alloc> (for example) will work
* correctly. As required, all allocators compare equal.
*/
template<int inst>
inline bool
operator==(const __malloc_alloc<inst>&, const __malloc_alloc<inst>&)
{ return true; }
template<int __inst>
inline bool
operator!=(const __malloc_alloc<__inst>&, const __malloc_alloc<__inst>&)
{ return false; }
//@}
} // namespace __gnu_cxx
namespace std pointer
{ address(reference __x) const { return &__x; }
//@{
/// Versions for the predefined "SGI" style allocators. const_pointer
template<typename _Tp, int __inst> address(const_reference __x) const { return &__x; }
struct _Alloc_traits<_Tp, __gnu_cxx::__malloc_alloc<__inst> >
{ // NB: __n is permitted to be 0. The C++ standard says nothing
static const bool _S_instanceless = true; // about what the return value is when __n == 0.
typedef __gnu_cxx:: __malloc_alloc<__inst> base_alloc_type; pointer
typedef __simple_alloc<_Tp, base_alloc_type> _Alloc_type; allocate(size_type __n, std::allocator<void>::const_pointer __h = 0)
typedef __allocator<_Tp, base_alloc_type> allocator_type; { return static_cast<_Tp*>(malloc(__n * sizeof(_Tp))); }
};
//@} // __p is not permitted to be a null pointer.
void
//@{ deallocate(pointer __p, size_type __n)
/// Versions for the __allocator adaptor used with the predefined { free(static_cast<void*>(__p)); }
/// "SGI" style allocators.
template<typename _Tp, typename _Tp1, int __inst> size_type
struct _Alloc_traits<_Tp, __allocator<_Tp1, max_size() const throw()
__gnu_cxx::__malloc_alloc<__inst> > > { return size_t(-1) / sizeof(_Tp); }
{
static const bool _S_instanceless = true; // _GLIBCXX_RESOLVE_LIB_DEFECTS
typedef __gnu_cxx:: __malloc_alloc<__inst> base_alloc_type; // 402. wrong new expression in [some_] allocator::construct
typedef __simple_alloc<_Tp, base_alloc_type> _Alloc_type; void
typedef __allocator<_Tp, base_alloc_type> allocator_type; construct(pointer __p, const _Tp& __val)
{ *__p = __val; }
void
destroy(pointer __p) { __p->~_Tp(); }
}; };
//@} } // namespace __gnu_cxx
} // namespace std
#endif #endif
...@@ -35,32 +35,83 @@ ...@@ -35,32 +35,83 @@
#ifndef _MT_ALLOCATOR_H #ifndef _MT_ALLOCATOR_H
#define _MT_ALLOCATOR_H 1 #define _MT_ALLOCATOR_H 1
#include <new>
#include <memory>
#include <cstdlib> #include <cstdlib>
#include <bits/functexcept.h> #include <bits/functexcept.h>
#include <bits/gthr.h> #include <bits/gthr.h>
#include <bits/atomicity.h> #include <bits/atomicity.h>
#include <bits/allocator_traits.h>
namespace __gnu_cxx namespace __gnu_cxx
{ {
/**
/** * This is a fixed size (power of 2) allocator which - when
* This is a fixed size (power of 2) allocator which - when compiled * compiled with thread support - will maintain one freelist per
* with thread support - will maintain one freelist per size per thread * size per thread plus a "global" one. Steps are taken to limit
* plus a "global" one. Steps are taken to limit the per thread freelist * the per thread freelist sizes (by returning excess back to
* sizes (by returning excess back to "global"). * "global").
* *
* Usage examples: * Usage examples:
* @code * @code
* vector<int, __gnu_cxx::__mt_alloc<0> > v1; * vector<int, __gnu_cxx::__mt_alloc<int> > v1;
* *
* typedef std::__allocator<char, __gnu_cxx::__mt_alloc<0> > string_alloc; * typedef __gnu_cxx::__mt_alloc<char> > string_allocator;
* std::basic_string<char, std::char_traits<char>, string_alloc> s1; * std::basic_string<char, std::char_traits<char>, string_allocator> s1;
* @endcode * @endcode
*/ */
template<int __inst> template<typename _Tp>
class __mt_alloc class __mt_alloc
{ {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef _Tp* pointer;
typedef const _Tp* const_pointer;
typedef _Tp& reference;
typedef const _Tp& const_reference;
typedef _Tp value_type;
template<typename _Tp1>
struct rebind
{ typedef __mt_alloc<_Tp1> other; };
__mt_alloc() throw()
{
// XXX
}
__mt_alloc(const __mt_alloc&) throw()
{
// XXX
}
template<typename _Tp1>
__mt_alloc(const __mt_alloc<_Tp1>&) throw()
{
// XXX
}
~__mt_alloc() throw() { }
pointer
address(reference __x) const { return &__x; }
const_pointer
address(const_reference __x) const { return &__x; }
size_type
max_size() const throw()
{ return size_t(-1) / sizeof(_Tp); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 402. wrong new expression in [some_] allocator::construct
void
construct(pointer __p, const _Tp& __val)
{ ::new(__p) _Tp(__val); }
void
destroy(pointer __p) { __p->~_Tp(); }
private: private:
/* /*
* We need to create the initial lists and set up some variables * We need to create the initial lists and set up some variables
...@@ -174,21 +225,19 @@ namespace __gnu_cxx ...@@ -174,21 +225,19 @@ namespace __gnu_cxx
static bin_record* _S_bin; static bin_record* _S_bin;
public: public:
static void* pointer
allocate(size_t __n) allocate(size_t __n, std::allocator<void>::const_pointer __h = 0)
{ {
/* /*
* Requests larger than _S_max_bytes are handled by * Requests larger than _S_max_bytes are handled by
* malloc/free directly * new/delete directly
*/ */
if (__n > _S_max_bytes) if (__n > _S_max_bytes)
{ {
void* __ret = malloc(__n); void* __ret = malloc(__n * sizeof(_Tp));
if (!__ret) if (!__ret)
__throw_bad_alloc(); __throw_bad_alloc();
return static_cast<_Tp*>(__ret);
return __ret;
} }
/* /*
...@@ -349,11 +398,11 @@ namespace __gnu_cxx ...@@ -349,11 +398,11 @@ namespace __gnu_cxx
_S_bin[bin].used[thread_id]++; _S_bin[bin].used[thread_id]++;
} }
return (void*)((char*)block + sizeof(block_record)); return static_cast<_Tp*>(static_cast<void*>((char*)block + sizeof(block_record)));
} }
static void void
deallocate(void* __p, size_t __n) deallocate(pointer __p, size_type __n)
{ {
/* /*
* Requests larger than _S_max_bytes are handled by * Requests larger than _S_max_bytes are handled by
...@@ -482,9 +531,9 @@ namespace __gnu_cxx ...@@ -482,9 +531,9 @@ namespace __gnu_cxx
} }
}; };
template<int __inst> template<typename _Tp>
void void
__mt_alloc<__inst>:: __mt_alloc<_Tp>::
_S_init() _S_init()
{ {
/* /*
...@@ -580,40 +629,32 @@ namespace __gnu_cxx ...@@ -580,40 +629,32 @@ namespace __gnu_cxx
for (size_t bin = 0; bin < _S_no_of_bins; bin++) for (size_t bin = 0; bin < _S_no_of_bins; bin++)
{ {
std::size_t __n = _S_max_threads + 1;
_S_bin[bin].first = (block_record**) _S_bin[bin].first = (block_record**)
malloc(sizeof(block_record*) * (_S_max_threads + 1)); malloc(sizeof(block_record*) * __n);
if (!_S_bin[bin].first) if (!_S_bin[bin].first)
__throw_bad_alloc(); __throw_bad_alloc();
_S_bin[bin].last = (block_record**) _S_bin[bin].last = (block_record**)
malloc(sizeof(block_record*) * (_S_max_threads + 1)); malloc(sizeof(block_record*) * __n);
if (!_S_bin[bin].last) if (!_S_bin[bin].last)
__throw_bad_alloc(); __throw_bad_alloc();
_S_bin[bin].free = (size_t*) _S_bin[bin].free = (size_t*) malloc(sizeof(size_t) * __n);
malloc(sizeof(size_t) * (_S_max_threads + 1));
if (!_S_bin[bin].free) if (!_S_bin[bin].free)
__throw_bad_alloc(); __throw_bad_alloc();
_S_bin[bin].used = (size_t*) _S_bin[bin].used = (size_t*) malloc(sizeof(size_t) * __n);
malloc(sizeof(size_t) * (_S_max_threads + 1));
if (!_S_bin[bin].used) if (!_S_bin[bin].used)
__throw_bad_alloc(); __throw_bad_alloc();
/*
* Ugly workaround of what at the time of writing seems to be
* a parser problem - see PR c++/9779 for more info.
*/
#ifdef __GTHREADS #ifdef __GTHREADS
size_t s = sizeof(__gthread_mutex_t); _S_bin[bin].mutex =(__gthread_mutex_t*) malloc(sizeof(__gthread_mutex_t));
_S_bin[bin].mutex = (__gthread_mutex_t*)malloc(s);
if (!_S_bin[bin].mutex)
__throw_bad_alloc();
#ifdef __GTHREAD_MUTEX_INIT #ifdef __GTHREAD_MUTEX_INIT
{ {
...@@ -639,19 +680,13 @@ namespace __gnu_cxx ...@@ -639,19 +680,13 @@ namespace __gnu_cxx
} }
#ifdef __GTHREADS #ifdef __GTHREADS
template<int __inst> template<typename _Tp>
void void
__mt_alloc<__inst>:: __mt_alloc<_Tp>::
_S_thread_key_destr(void* freelist_pos) _S_thread_key_destr(void* freelist_pos)
{ {
/* /*
* This is due to the ugly workaround mentioned in _S_init() * If the thread - when it dies - still has records on its
*/
if (freelist_pos == NULL)
return;
/*
* If the thread - when it dies - still have records on its
* freelist we return them to the global pool here. * freelist we return them to the global pool here.
*/ */
for (size_t bin = 0; bin < _S_no_of_bins; bin++) for (size_t bin = 0; bin < _S_no_of_bins; bin++)
...@@ -662,7 +697,6 @@ namespace __gnu_cxx ...@@ -662,7 +697,6 @@ namespace __gnu_cxx
if (block != NULL) if (block != NULL)
{ {
__gthread_mutex_lock(_S_bin[bin].mutex); __gthread_mutex_lock(_S_bin[bin].mutex);
while (block != NULL) while (block != NULL)
{ {
if (_S_bin[bin].first[0] == NULL) if (_S_bin[bin].first[0] == NULL)
...@@ -671,14 +705,11 @@ namespace __gnu_cxx ...@@ -671,14 +705,11 @@ namespace __gnu_cxx
_S_bin[bin].last[0]->next = block; _S_bin[bin].last[0]->next = block;
_S_bin[bin].last[0] = block; _S_bin[bin].last[0] = block;
block = block->next; block = block->next;
_S_bin[bin].free[0]++; _S_bin[bin].free[0]++;
} }
_S_bin[bin].last[0]->next = NULL; _S_bin[bin].last[0]->next = NULL;
__gthread_mutex_unlock(_S_bin[bin].mutex); __gthread_mutex_unlock(_S_bin[bin].mutex);
} }
} }
...@@ -687,18 +718,15 @@ namespace __gnu_cxx ...@@ -687,18 +718,15 @@ namespace __gnu_cxx
* Return this thread id record to thread_freelist * Return this thread id record to thread_freelist
*/ */
__gthread_mutex_lock(&_S_thread_freelist_mutex); __gthread_mutex_lock(&_S_thread_freelist_mutex);
_S_thread_freelist_last->next = (thread_record*)freelist_pos; _S_thread_freelist_last->next = (thread_record*)freelist_pos;
_S_thread_freelist_last = (thread_record*)freelist_pos; _S_thread_freelist_last = (thread_record*)freelist_pos;
_S_thread_freelist_last->next = NULL; _S_thread_freelist_last->next = NULL;
__gthread_mutex_unlock(&_S_thread_freelist_mutex); __gthread_mutex_unlock(&_S_thread_freelist_mutex);
} }
template<int __inst> template<typename _Tp>
size_t size_t
__mt_alloc<__inst>:: __mt_alloc<_Tp>::
_S_get_thread_id() _S_get_thread_id()
{ {
/* /*
...@@ -714,16 +742,14 @@ namespace __gnu_cxx ...@@ -714,16 +742,14 @@ namespace __gnu_cxx
if ((freelist_pos = if ((freelist_pos =
(thread_record*)__gthread_getspecific(_S_thread_key)) == NULL) (thread_record*)__gthread_getspecific(_S_thread_key)) == NULL)
{ {
__gthread_mutex_lock(&_S_thread_freelist_mutex);
/* /*
* Since _S_max_threads must be larger than the * Since _S_max_threads must be larger than the
* theoretical max number of threads of the OS the list * theoretical max number of threads of the OS the list
* can never be empty. * can never be empty.
*/ */
__gthread_mutex_lock(&_S_thread_freelist_mutex);
freelist_pos = _S_thread_freelist_first; freelist_pos = _S_thread_freelist_first;
_S_thread_freelist_first = _S_thread_freelist_first->next; _S_thread_freelist_first = _S_thread_freelist_first->next;
__gthread_mutex_unlock(&_S_thread_freelist_mutex); __gthread_mutex_unlock(&_S_thread_freelist_mutex);
__gthread_setspecific(_S_thread_key, (void*)freelist_pos); __gthread_setspecific(_S_thread_key, (void*)freelist_pos);
...@@ -754,23 +780,23 @@ namespace __gnu_cxx ...@@ -754,23 +780,23 @@ namespace __gnu_cxx
return 0; return 0;
} }
template<int __inst> __gthread_once_t template<typename _Tp> __gthread_once_t
__mt_alloc<__inst>::_S_once_mt = __GTHREAD_ONCE_INIT; __mt_alloc<_Tp>::_S_once_mt = __GTHREAD_ONCE_INIT;
#endif #endif
template<int __inst> bool template<typename _Tp> bool
__mt_alloc<__inst>::_S_initialized = false; __mt_alloc<_Tp>::_S_initialized = false;
template<int __inst> typename __mt_alloc<__inst>::binmap_type* template<typename _Tp> typename __mt_alloc<_Tp>::binmap_type*
__mt_alloc<__inst>::_S_binmap = NULL; __mt_alloc<_Tp>::_S_binmap = NULL;
/* /*
* Allocation requests (after round-up to power of 2) below this * Allocation requests (after round-up to power of 2) below this
* value will be handled by the allocator. A raw malloc/free() call * value will be handled by the allocator. A raw malloc/free() call
* will be used for requests larger than this value. * will be used for requests larger than this value.
*/ */
template<int __inst> size_t template<typename _Tp> size_t
__mt_alloc<__inst>::_S_max_bytes = 128; __mt_alloc<_Tp>::_S_max_bytes = 128;
/* /*
* In order to avoid fragmenting and minimize the number of malloc() * In order to avoid fragmenting and minimize the number of malloc()
...@@ -779,21 +805,21 @@ namespace __gnu_cxx ...@@ -779,21 +805,21 @@ namespace __gnu_cxx
* choosen the value below. See * choosen the value below. See
* http://gcc.gnu.org/ml/libstdc++/2001-07/msg00077.html * http://gcc.gnu.org/ml/libstdc++/2001-07/msg00077.html
*/ */
template<int __inst> size_t template<typename _Tp> size_t
__mt_alloc<__inst>::_S_chunk_size = 4096 - 4 * sizeof(void*); __mt_alloc<_Tp>::_S_chunk_size = 4096 - 4 * sizeof(void*);
/* /*
* The maximum number of supported threads. Our Linux 2.4.18 reports * The maximum number of supported threads. Our Linux 2.4.18 reports
* 4070 in /proc/sys/kernel/threads-max * 4070 in /proc/sys/kernel/threads-max
*/ */
template<int __inst> size_t template<typename _Tp> size_t
__mt_alloc<__inst>::_S_max_threads = 4096; __mt_alloc<_Tp>::_S_max_threads = 4096;
/* /*
* Actual value calculated in _S_init() * Actual value calculated in _S_init()
*/ */
template<int __inst> size_t template<typename _Tp> size_t
__mt_alloc<__inst>::_S_no_of_bins = 1; __mt_alloc<_Tp>::_S_no_of_bins = 1;
/* /*
* Each time a deallocation occurs in a threaded application we make * Each time a deallocation occurs in a threaded application we make
...@@ -802,63 +828,31 @@ namespace __gnu_cxx ...@@ -802,63 +828,31 @@ namespace __gnu_cxx
* more than _S_freelist_headroom % of the freelist, we move these * more than _S_freelist_headroom % of the freelist, we move these
* records back to the global pool. * records back to the global pool.
*/ */
template<int __inst> size_t template<typename _Tp> size_t
__mt_alloc<__inst>::_S_freelist_headroom = 10; __mt_alloc<_Tp>::_S_freelist_headroom = 10;
/* /*
* Actual initialization in _S_init() * Actual initialization in _S_init()
*/ */
#ifdef __GTHREADS #ifdef __GTHREADS
template<int __inst> typename __mt_alloc<__inst>::thread_record* template<typename _Tp> typename __mt_alloc<_Tp>::thread_record*
__mt_alloc<__inst>::_S_thread_freelist_first = NULL; __mt_alloc<_Tp>::_S_thread_freelist_first = NULL;
template<int __inst> typename __mt_alloc<__inst>::thread_record* template<typename _Tp> typename __mt_alloc<_Tp>::thread_record*
__mt_alloc<__inst>::_S_thread_freelist_last = NULL; __mt_alloc<_Tp>::_S_thread_freelist_last = NULL;
template<int __inst> __gthread_mutex_t template<typename _Tp> __gthread_mutex_t
__mt_alloc<__inst>::_S_thread_freelist_mutex = __GTHREAD_MUTEX_INIT; __mt_alloc<_Tp>::_S_thread_freelist_mutex = __GTHREAD_MUTEX_INIT;
/* /*
* Actual initialization in _S_init() * Actual initialization in _S_init()
*/ */
template<int __inst> __gthread_key_t template<typename _Tp> __gthread_key_t
__mt_alloc<__inst>::_S_thread_key; __mt_alloc<_Tp>::_S_thread_key;
#endif #endif
template<int __inst> typename __mt_alloc<__inst>::bin_record* template<typename _Tp> typename __mt_alloc<_Tp>::bin_record*
__mt_alloc<__inst>::_S_bin = NULL; __mt_alloc<_Tp>::_S_bin = NULL;
template<int __inst>
inline bool
operator==(const __mt_alloc<__inst>&, const __mt_alloc<__inst>&)
{ return true; }
template<int __inst>
inline bool
operator!=(const __mt_alloc<__inst>&, const __mt_alloc<__inst>&)
{ return false; }
} // namespace __gnu_cxx } // namespace __gnu_cxx
namespace std
{
template<typename _Tp, int __inst>
struct _Alloc_traits<_Tp, __gnu_cxx::__mt_alloc<__inst> >
{
static const bool _S_instanceless = true;
typedef __gnu_cxx:: __mt_alloc<__inst> base_alloc_type;
typedef __simple_alloc<_Tp, base_alloc_type> _Alloc_type;
typedef __allocator<_Tp, base_alloc_type> allocator_type;
};
template<typename _Tp, typename _Tp1, int __inst>
struct _Alloc_traits<_Tp,
__allocator<_Tp1, __gnu_cxx::__mt_alloc<__inst> > >
{
static const bool _S_instanceless = true;
typedef __gnu_cxx:: __mt_alloc<__inst> base_alloc_type;
typedef __simple_alloc<_Tp, base_alloc_type> _Alloc_type;
typedef __allocator<_Tp, base_alloc_type> allocator_type;
};
} // namespace std
#endif #endif
// Allocators -*- C++ -*- // Allocator that wraps operator new -*- C++ -*-
// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. // Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
// //
...@@ -35,23 +35,68 @@ ...@@ -35,23 +35,68 @@
namespace __gnu_cxx namespace __gnu_cxx
{ {
/** /**
* @if maint * @brief An allocator that uses global new, as per [20.4].
* A new-based allocator, as required by the standard. Allocation and *
* deallocation forward to global new and delete. "SGI" style, minus * This is precisely the allocator defined in the C++ Standard.
* reallocate(). * - all allocation calls operator new
* @endif * - all deallocation calls operator delete
*
* (See @link Allocators allocators info @endlink for more.) * (See @link Allocators allocators info @endlink for more.)
*/ */
class __new_alloc template<typename _Tp>
class new_allocator
{ {
public: public:
static void* typedef size_t size_type;
allocate(size_t __n) typedef ptrdiff_t difference_type;
{ return ::operator new(__n); } typedef _Tp* pointer;
typedef const _Tp* const_pointer;
typedef _Tp& reference;
typedef const _Tp& const_reference;
typedef _Tp value_type;
static void template<typename _Tp1>
deallocate(void* __p, size_t) struct rebind
{ typedef new_allocator<_Tp1> other; };
new_allocator() throw() { }
new_allocator(const new_allocator&) throw() { }
template<typename _Tp1>
new_allocator(const new_allocator<_Tp1>&) throw() { }
~new_allocator() throw() { }
pointer
address(reference __x) const { return &__x; }
const_pointer
address(const_reference __x) const { return &__x; }
// NB: __n is permitted to be 0. The C++ standard says nothing
// about what the return value is when __n == 0.
pointer
allocate(size_type __n, allocator<void>::const_pointer __h = 0)
{ return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); }
// __p is not permitted to be a null pointer.
void
deallocate(pointer __p, size_type __n)
{ ::operator delete(__p); } { ::operator delete(__p); }
size_type
max_size() const throw()
{ return size_t(-1) / sizeof(_Tp); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 402. wrong new expression in [some_] allocator::construct
void
construct(pointer __p, const _Tp& __val)
{ ::new(__p) _Tp(__val); }
void
destroy(pointer __p) { __p->~_Tp(); }
}; };
} // namespace __gnu_cxx } // namespace __gnu_cxx
......
...@@ -44,15 +44,14 @@ ...@@ -44,15 +44,14 @@
* This file is a GNU extension to the Standard C++ Library. * This file is a GNU extension to the Standard C++ Library.
* You should only include this header if you are using GCC 3 or later. * You should only include this header if you are using GCC 3 or later.
*/ */
#ifndef _POOL_ALLOCATOR_H #ifndef _POOL_ALLOCATOR_H
#define _POOL_ALLOCATOR_H 1 #define _POOL_ALLOCATOR_H 1
#include <new>
#include <bits/functexcept.h> #include <bits/functexcept.h>
#include <bits/stl_threads.h> #include <bits/stl_threads.h>
#include <bits/atomicity.h> #include <bits/atomicity.h>
#include <bits/allocator_traits.h> #include <bits/allocator_traits.h>
#include <ext/new_allocator.h>
namespace __gnu_cxx namespace __gnu_cxx
{ {
...@@ -65,9 +64,9 @@ namespace __gnu_cxx ...@@ -65,9 +64,9 @@ namespace __gnu_cxx
* when in default high-speed pool mode). * when in default high-speed pool mode).
* *
* Important implementation properties: * Important implementation properties:
* 0. If globally mandated, then allocate objects from __new_alloc * 0. If globally mandated, then allocate objects from new
* 1. If the clients request an object of size > _S_max_bytes, the resulting * 1. If the clients request an object of size > _S_max_bytes, the resulting
* object will be obtained directly from __new_alloc * object will be obtained directly from new
* 2. In all other cases, we allocate an object of size exactly * 2. In all other cases, we allocate an object of size exactly
* _S_round_up(requested_size). Thus the client has enough size * _S_round_up(requested_size). Thus the client has enough size
* information that we can return the object to the proper free list * information that we can return the object to the proper free list
...@@ -201,7 +200,7 @@ namespace __gnu_cxx ...@@ -201,7 +200,7 @@ namespace __gnu_cxx
((_Obj*)(void*)_S_start_free)->_M_free_list_link = *__free_list; ((_Obj*)(void*)_S_start_free)->_M_free_list_link = *__free_list;
*__free_list = (_Obj*)(void*)_S_start_free; *__free_list = (_Obj*)(void*)_S_start_free;
} }
_S_start_free = (char*) __new_alloc::allocate(__bytes_to_get); _S_start_free = new char[__bytes_to_get];
if (_S_start_free == 0) if (_S_start_free == 0)
{ {
size_t __i; size_t __i;
...@@ -226,7 +225,7 @@ namespace __gnu_cxx ...@@ -226,7 +225,7 @@ namespace __gnu_cxx
} }
} }
_S_end_free = 0; // In case of exception. _S_end_free = 0; // In case of exception.
_S_start_free = (char*)__new_alloc::allocate(__bytes_to_get); _S_start_free = new char[__bytes_to_get];
// This should either throw an exception or remedy the situation. // This should either throw an exception or remedy the situation.
// Thus we assume it succeeded. // Thus we assume it succeeded.
} }
...@@ -291,7 +290,7 @@ namespace __gnu_cxx ...@@ -291,7 +290,7 @@ namespace __gnu_cxx
} }
if ((__n > (size_t) _S_max_bytes) || (_S_force_new > 0)) if ((__n > (size_t) _S_max_bytes) || (_S_force_new > 0))
__ret = __new_alloc::allocate(__n); __ret = new char[__n];
else else
{ {
_Obj* volatile* __free_list = _S_free_list + _S_freelist_index(__n); _Obj* volatile* __free_list = _S_free_list + _S_freelist_index(__n);
...@@ -318,7 +317,7 @@ namespace __gnu_cxx ...@@ -318,7 +317,7 @@ namespace __gnu_cxx
__pool_alloc<__threads, __inst>::deallocate(void* __p, size_t __n) __pool_alloc<__threads, __inst>::deallocate(void* __p, size_t __n)
{ {
if ((__n > (size_t) _S_max_bytes) || (_S_force_new > 0)) if ((__n > (size_t) _S_max_bytes) || (_S_force_new > 0))
__new_alloc::deallocate(__p, __n); delete [] __p;
else else
{ {
_Obj* volatile* __free_list = _S_free_list + _S_freelist_index(__n); _Obj* volatile* __free_list = _S_free_list + _S_freelist_index(__n);
......
...@@ -22,25 +22,23 @@ ...@@ -22,25 +22,23 @@
#include <cstdlib> #include <cstdlib>
#include <memory> #include <memory>
#include <ext/pool_allocator.h> //#include <ext/pool_allocator.h>
#include <ext/debug_allocator.h> #include <ext/debug_allocator.h>
#include <ext/malloc_allocator.h> #include <ext/malloc_allocator.h>
#include <testsuite_hooks.h> #include <testsuite_hooks.h>
using __gnu_cxx::__malloc_alloc; using __gnu_cxx::malloc_allocator;
using __gnu_cxx::__debug_alloc; using __gnu_cxx::debug_allocator;
using __gnu_cxx::__pool_alloc;
template class __malloc_alloc<3>;
template class __debug_alloc<__malloc_alloc<3> >;
template class __pool_alloc<true, 3>;
template class __pool_alloc<false, 3>;
struct big template class malloc_allocator<int>;
{ template class debug_allocator<malloc_allocator<int> >;
long f[15];
};
#if 0
using __gnu_cxx::__pool_alloc;
template class __pool_alloc<true, 3>;
template class __pool_alloc<false, 3>;
#endif
bool new_called; bool new_called;
bool delete_called; bool delete_called;
...@@ -69,31 +67,39 @@ void check_allocator() ...@@ -69,31 +67,39 @@ void check_allocator()
delete_called = false; delete_called = false;
requested = 0; requested = 0;
std::__allocator<big, Alloc> a; Alloc a;
big *p = a.allocate(10); typename Alloc::pointer p = a.allocate(10);
if (uses_global_new_and_delete) if (uses_global_new_and_delete)
VERIFY( requested >= (10 * 15 * sizeof(long)) ); VERIFY( requested >= (10 * 15 * sizeof(long)) );
// Touch the far end of supposedly-allocated memory to check that we got
// all of it. Why "3"? Because it's my favorite integer between e and pi.
p[9].f[14] = 3;
VERIFY( new_called == uses_global_new_and_delete ); VERIFY( new_called == uses_global_new_and_delete );
a.deallocate(p,10); a.deallocate(p, 10);
VERIFY( delete_called == uses_global_new_and_delete ); VERIFY( delete_called == uses_global_new_and_delete );
} }
// These just help tracking down error messages. // These just help tracking down error messages.
void test01() { check_allocator<__malloc_alloc<3>, false>(); } void test01()
void test02() { check_allocator<__debug_alloc<__malloc_alloc<3> >, false>(); } { check_allocator<malloc_allocator<int>, false>(); }
void test03() { check_allocator<__pool_alloc<true, 3>, true>(); }
void test04() { check_allocator<__pool_alloc<false, 3>, true>(); } void test02()
{ check_allocator<debug_allocator<malloc_allocator<int> >, false>(); }
#if 0
void test03()
{ check_allocator<__pool_alloc<true, 3>, true>(); }
void test04()
{ check_allocator<__pool_alloc<false, 3>, true>(); }
#endif
int main() int main()
{ {
test01(); test01();
test02(); test02();
#if 0
test03(); test03();
test04(); test04();
#endif
return 0; return 0;
} }
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
#include <testsuite_performance.h> #include <testsuite_performance.h>
using namespace std; using namespace std;
using __gnu_cxx::__malloc_alloc; using __gnu_cxx::malloc_allocator;
using __gnu_cxx::__mt_alloc; using __gnu_cxx::__mt_alloc;
/* /*
...@@ -155,7 +155,7 @@ test_ints_malloc_alloc(int iterations) ...@@ -155,7 +155,7 @@ test_ints_malloc_alloc(int iterations)
tstart(); tstart();
for(int i = 0; i < iterations; i++) for(int i = 0; i < iterations; i++)
{ {
vector<int, __malloc_alloc<0> > v1; vector<int, malloc_allocator<int> > v1;
for(int j = 0; j < insert_values; j++) for(int j = 0; j < insert_values; j++)
{ {
...@@ -173,7 +173,7 @@ test_ints_mt_alloc(int iterations) ...@@ -173,7 +173,7 @@ test_ints_mt_alloc(int iterations)
tstart(); tstart();
for(int i = 0; i < iterations; i++) for(int i = 0; i < iterations; i++)
{ {
vector<int, __mt_alloc<0> > v1; vector<int, __mt_alloc<int> > v1;
for(int j = 0; j < insert_values; j++) for(int j = 0; j < insert_values; j++)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment