aboutsummaryrefslogtreecommitdiff
path: root/libstdc++/stl/pthread_alloc
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++/stl/pthread_alloc')
-rw-r--r--libstdc++/stl/pthread_alloc590
1 files changed, 361 insertions, 229 deletions
diff --git a/libstdc++/stl/pthread_alloc b/libstdc++/stl/pthread_alloc
index 4ca9d9e..887d8e8 100644
--- a/libstdc++/stl/pthread_alloc
+++ b/libstdc++/stl/pthread_alloc
@@ -20,7 +20,7 @@
// This should be reasonably fast even in the presence of threads.
// The down side is that storage may not be well-utilized.
// It is not an error to allocate memory in thread A and deallocate
-// it n thread B. But this effectively transfers ownership of the memory,
+// it in thread B. But this effectively transfers ownership of the memory,
// so that it can only be reallocated by thread B. Thus this can effectively
// result in a storage leak if it's done on a regular basis.
// It can also result in frequent sharing of
@@ -35,308 +35,440 @@
__STL_BEGIN_NAMESPACE
-// Note that this class has nonstatic members. We instantiate it once
-// per thread.
-template <bool dummy>
-class __pthread_alloc_template {
-
-private:
- enum {ALIGN = 8};
- enum {MAX_BYTES = 128}; // power of 2
- enum {NFREELISTS = MAX_BYTES/ALIGN};
+#define __STL_DATA_ALIGNMENT 8
+
+union _Pthread_alloc_obj {
+ union _Pthread_alloc_obj * __free_list_link;
+ char __client_data[__STL_DATA_ALIGNMENT]; /* The client sees this. */
+};
+
+// Pthread allocators don't appear to the client to have meaningful
+// instances. We do in fact need to associate some state with each
+// thread. That state is represented by
+// _Pthread_alloc_per_thread_state<_Max_size>.
+
+template<size_t _Max_size>
+struct _Pthread_alloc_per_thread_state {
+ typedef _Pthread_alloc_obj __obj;
+ enum { _S_NFREELISTS = _Max_size/__STL_DATA_ALIGNMENT };
+ _Pthread_alloc_obj* volatile __free_list[_S_NFREELISTS];
+ _Pthread_alloc_per_thread_state<_Max_size> * __next;
+ // Free list link for list of available per thread structures.
+ // When one of these becomes available for reuse due to thread
+ // termination, any objects in its free list remain associated
+ // with it. The whole structure may then be used by a newly
+ // created thread.
+ _Pthread_alloc_per_thread_state() : __next(0)
+ {
+ memset((void *)__free_list, 0, _S_NFREELISTS * sizeof(__obj *));
+ }
+ // Returns an object of size __n, and possibly adds to size n free list.
+ void *_M_refill(size_t __n);
+};
- union obj {
- union obj * free_list_link;
- char client_data[ALIGN]; /* The client sees this. */
- };
+// Pthread-specific allocator.
+// The argument specifies the largest object size allocated from per-thread
+// free lists. Larger objects are allocated using malloc_alloc.
+// Max_size must be a power of 2.
+template <size_t _Max_size = 128>
+class _Pthread_alloc_template {
- // Per instance state
- obj* volatile free_list[NFREELISTS];
- __pthread_alloc_template<dummy>* next; // Free list link
+public: // but only for internal use:
- static size_t ROUND_UP(size_t bytes) {
- return (((bytes) + ALIGN-1) & ~(ALIGN - 1));
- }
- static size_t FREELIST_INDEX(size_t bytes) {
- return (((bytes) + ALIGN-1)/ALIGN - 1);
- }
+ typedef _Pthread_alloc_obj __obj;
- // Returns an object of size n, and optionally adds to size n free list.
- void *refill(size_t n);
// Allocates a chunk for nobjs of size "size". nobjs may be reduced
// if it is inconvenient to allocate the requested number.
- static char *chunk_alloc(size_t size, int &nobjs);
+ static char *_S_chunk_alloc(size_t __size, int &__nobjs);
+
+ enum {_S_ALIGN = __STL_DATA_ALIGNMENT};
+
+ static size_t _S_round_up(size_t __bytes) {
+ return (((__bytes) + _S_ALIGN-1) & ~(_S_ALIGN - 1));
+ }
+ static size_t _S_freelist_index(size_t __bytes) {
+ return (((__bytes) + _S_ALIGN-1)/_S_ALIGN - 1);
+ }
+private:
// Chunk allocation state. And other shared state.
- // Protected by chunk_allocator_lock.
- static pthread_mutex_t chunk_allocator_lock;
- static char *start_free;
- static char *end_free;
- static size_t heap_size;
- static __pthread_alloc_template<dummy>* free_allocators;
- static pthread_key_t key;
- static bool key_initialized;
- // Pthread key under which allocator is stored.
- // Allocator instances that are currently unclaimed by any thread.
- static void destructor(void *instance);
- // Function to be called on thread exit to reclaim allocator
- // instance.
- static __pthread_alloc_template<dummy> *new_allocator();
- // Return a recycled or new allocator instance.
- static __pthread_alloc_template<dummy> *get_allocator_instance();
- // ensure that the current thread has an associated
- // allocator instance.
- class lock {
+ // Protected by _S_chunk_allocator_lock.
+ static pthread_mutex_t _S_chunk_allocator_lock;
+ static char *_S_start_free;
+ static char *_S_end_free;
+ static size_t _S_heap_size;
+ static _Pthread_alloc_per_thread_state<_Max_size>* _S_free_per_thread_states;
+ static pthread_key_t _S_key;
+ static bool _S_key_initialized;
+ // Pthread key under which per thread state is stored.
+ // Allocator instances that are currently unclaimed by any thread.
+ static void _S_destructor(void *instance);
+ // Function to be called on thread exit to reclaim per thread
+ // state.
+ static _Pthread_alloc_per_thread_state<_Max_size> *_S_new_per_thread_state();
+ // Return a recycled or new per thread state.
+ static _Pthread_alloc_per_thread_state<_Max_size> *_S_get_per_thread_state();
+ // ensure that the current thread has an associated
+ // per thread state.
+ friend class _M_lock;
+ class _M_lock {
public:
- lock () { pthread_mutex_lock(&chunk_allocator_lock); }
- ~lock () { pthread_mutex_unlock(&chunk_allocator_lock); }
+ _M_lock () { pthread_mutex_lock(&_S_chunk_allocator_lock); }
+ ~_M_lock () { pthread_mutex_unlock(&_S_chunk_allocator_lock); }
};
- friend class lock;
-
public:
- __pthread_alloc_template() : next(0)
- {
- memset((void *)free_list, 0, NFREELISTS * sizeof(obj *));
- }
-
- /* n must be > 0 */
- static void * allocate(size_t n)
+ /* n must be > 0 */
+ static void * allocate(size_t __n)
{
- obj * volatile * my_free_list;
- obj * __RESTRICT result;
- __pthread_alloc_template<dummy>* a;
+ __obj * volatile * __my_free_list;
+ __obj * __RESTRICT __result;
+ _Pthread_alloc_per_thread_state<_Max_size>* __a;
- if (n > MAX_BYTES) {
- return(malloc(n));
+ if (__n > _Max_size) {
+ return(malloc_alloc::allocate(__n));
}
- if (!key_initialized ||
- !(a = (__pthread_alloc_template<dummy>*)
- pthread_getspecific(key))) {
- a = get_allocator_instance();
+ if (!_S_key_initialized ||
+ !(__a = (_Pthread_alloc_per_thread_state<_Max_size>*)
+ pthread_getspecific(_S_key))) {
+ __a = _S_get_per_thread_state();
}
- my_free_list = a -> free_list + FREELIST_INDEX(n);
- result = *my_free_list;
- if (result == 0) {
- void *r = a -> refill(ROUND_UP(n));
- return r;
+ __my_free_list = __a -> __free_list + _S_freelist_index(__n);
+ __result = *__my_free_list;
+ if (__result == 0) {
+ void *__r = __a -> _M_refill(_S_round_up(__n));
+ return __r;
}
- *my_free_list = result -> free_list_link;
- return (result);
+ *__my_free_list = __result -> __free_list_link;
+ return (__result);
};
/* p may not be 0 */
- static void deallocate(void *p, size_t n)
+ static void deallocate(void *__p, size_t __n)
{
- obj *q = (obj *)p;
- obj * volatile * my_free_list;
- __pthread_alloc_template<dummy>* a;
+ __obj *__q = (__obj *)__p;
+ __obj * volatile * __my_free_list;
+ _Pthread_alloc_per_thread_state<_Max_size>* __a;
- if (n > MAX_BYTES) {
- free(p);
- return;
+ if (__n > _Max_size) {
+ malloc_alloc::deallocate(__p, __n);
+ return;
}
- if (!key_initialized ||
- !(a = (__pthread_alloc_template<dummy>*)
- pthread_getspecific(key))) {
- a = get_allocator_instance();
+ if (!_S_key_initialized ||
+ !(__a = (_Pthread_alloc_per_thread_state<_Max_size> *)
+ pthread_getspecific(_S_key))) {
+ __a = _S_get_per_thread_state();
}
- my_free_list = a->free_list + FREELIST_INDEX(n);
- q -> free_list_link = *my_free_list;
- *my_free_list = q;
+ __my_free_list = __a->__free_list + _S_freelist_index(__n);
+ __q -> __free_list_link = *__my_free_list;
+ *__my_free_list = __q;
}
- static void * reallocate(void *p, size_t old_sz, size_t new_sz);
+ static void * reallocate(void *__p, size_t __old_sz, size_t __new_sz);
} ;
-typedef __pthread_alloc_template<false> pthread_alloc;
+typedef _Pthread_alloc_template<> pthread_alloc;
-template <bool dummy>
-void __pthread_alloc_template<dummy>::destructor(void * instance)
+template <size_t _Max_size>
+void _Pthread_alloc_template<_Max_size>::_S_destructor(void * __instance)
{
- __pthread_alloc_template<dummy>* a =
- (__pthread_alloc_template<dummy>*)instance;
- a -> next = free_allocators;
- free_allocators = a;
+ _M_lock __lock_instance; // Need to acquire lock here.
+ _Pthread_alloc_per_thread_state<_Max_size>* __s =
+ (_Pthread_alloc_per_thread_state<_Max_size> *)__instance;
+ __s -> __next = _S_free_per_thread_states;
+ _S_free_per_thread_states = __s;
}
-template <bool dummy>
-__pthread_alloc_template<dummy>*
-__pthread_alloc_template<dummy>::new_allocator()
-{
- if (0 != free_allocators) {
- __pthread_alloc_template<dummy>* result = free_allocators;
- free_allocators = free_allocators -> next;
- return result;
+template <size_t _Max_size>
+_Pthread_alloc_per_thread_state<_Max_size> *
+_Pthread_alloc_template<_Max_size>::_S_new_per_thread_state()
+{
+ /* lock already held here. */
+ if (0 != _S_free_per_thread_states) {
+ _Pthread_alloc_per_thread_state<_Max_size> *__result =
+ _S_free_per_thread_states;
+ _S_free_per_thread_states = _S_free_per_thread_states -> __next;
+ return __result;
} else {
- return new __pthread_alloc_template<dummy>;
+ return new _Pthread_alloc_per_thread_state<_Max_size>;
}
}
-template <bool dummy>
-__pthread_alloc_template<dummy>*
-__pthread_alloc_template<dummy>::get_allocator_instance()
+template <size_t _Max_size>
+_Pthread_alloc_per_thread_state<_Max_size> *
+_Pthread_alloc_template<_Max_size>::_S_get_per_thread_state()
{
- __pthread_alloc_template<dummy>* result;
- if (!key_initialized) {
- /*REFERENCED*/
- lock lock_instance;
- if (!key_initialized) {
- if (pthread_key_create(&key, destructor)) {
- abort(); // failed
- }
- key_initialized = true;
- }
+ /*REFERENCED*/
+ _M_lock __lock_instance; // Need to acquire lock here.
+ _Pthread_alloc_per_thread_state<_Max_size> * __result;
+ if (!_S_key_initialized) {
+ if (pthread_key_create(&_S_key, _S_destructor)) {
+ abort(); // failed
+ }
+ _S_key_initialized = true;
}
- result = new_allocator();
- if (pthread_setspecific(key, result)) abort();
- return result;
+ __result = _S_new_per_thread_state();
+ if (pthread_setspecific(_S_key, __result)) abort();
+ return __result;
}
-/* We allocate memory in large chunks in order to avoid fragmenting */
-/* the malloc heap too much. */
-/* We assume that size is properly aligned. */
-template <bool dummy>
-char *__pthread_alloc_template<dummy>
-::chunk_alloc(size_t size, int &nobjs)
+/* We allocate memory in large chunks in order to avoid fragmenting */
+/* the malloc heap too much. */
+/* We assume that size is properly aligned. */
+template <size_t _Max_size>
+char *_Pthread_alloc_template<_Max_size>
+::_S_chunk_alloc(size_t __size, int &__nobjs)
{
{
- char * result;
- size_t total_bytes;
- size_t bytes_left;
+ char * __result;
+ size_t __total_bytes;
+ size_t __bytes_left;
/*REFERENCED*/
- lock lock_instance; // Acquire lock for this routine
-
- total_bytes = size * nobjs;
- bytes_left = end_free - start_free;
- if (bytes_left >= total_bytes) {
- result = start_free;
- start_free += total_bytes;
- return(result);
- } else if (bytes_left >= size) {
- nobjs = bytes_left/size;
- total_bytes = size * nobjs;
- result = start_free;
- start_free += total_bytes;
- return(result);
+ _M_lock __lock_instance; // Acquire lock for this routine
+
+ __total_bytes = __size * __nobjs;
+ __bytes_left = _S_end_free - _S_start_free;
+ if (__bytes_left >= __total_bytes) {
+ __result = _S_start_free;
+ _S_start_free += __total_bytes;
+ return(__result);
+ } else if (__bytes_left >= __size) {
+ __nobjs = __bytes_left/__size;
+ __total_bytes = __size * __nobjs;
+ __result = _S_start_free;
+ _S_start_free += __total_bytes;
+ return(__result);
} else {
- size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
- // Try to make use of the left-over piece.
- if (bytes_left > 0) {
- __pthread_alloc_template<dummy>* a =
- (__pthread_alloc_template<dummy>*)pthread_getspecific(key);
- obj * volatile * my_free_list =
- a->free_list + FREELIST_INDEX(bytes_left);
-
- ((obj *)start_free) -> free_list_link = *my_free_list;
- *my_free_list = (obj *)start_free;
- }
-# ifdef _SGI_SOURCE
- // Try to get memory that's aligned on something like a
- // cache line boundary, so as to avoid parceling out
- // parts of the same line to different threads and thus
- // possibly different processors.
- {
- const int cache_line_size = 128; // probable upper bound
- bytes_to_get &= ~(cache_line_size-1);
- start_free = (char *)memalign(cache_line_size, bytes_to_get);
- if (0 == start_free) {
- start_free = (char *)malloc_alloc::allocate(bytes_to_get);
- }
- }
-# else /* !SGI_SOURCE */
- start_free = (char *)malloc_alloc::allocate(bytes_to_get);
+ size_t __bytes_to_get =
+ 2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
+ // Try to make use of the left-over piece.
+ if (__bytes_left > 0) {
+ _Pthread_alloc_per_thread_state<_Max_size>* __a =
+ (_Pthread_alloc_per_thread_state<_Max_size>*)
+ pthread_getspecific(_S_key);
+ __obj * volatile * __my_free_list =
+ __a->__free_list + _S_freelist_index(__bytes_left);
+
+ ((__obj *)_S_start_free) -> __free_list_link = *__my_free_list;
+ *__my_free_list = (__obj *)_S_start_free;
+ }
+# ifdef _SGI_SOURCE
+ // Try to get memory that's aligned on something like a
+ // cache line boundary, so as to avoid parceling out
+ // parts of the same line to different threads and thus
+ // possibly different processors.
+ {
+ const int __cache_line_size = 128; // probable upper bound
+ __bytes_to_get &= ~(__cache_line_size-1);
+ _S_start_free = (char *)memalign(__cache_line_size, __bytes_to_get);
+ if (0 == _S_start_free) {
+ _S_start_free = (char *)malloc_alloc::allocate(__bytes_to_get);
+ }
+ }
+# else /* !SGI_SOURCE */
+ _S_start_free = (char *)malloc_alloc::allocate(__bytes_to_get);
# endif
- heap_size += bytes_to_get;
- end_free = start_free + bytes_to_get;
+ _S_heap_size += __bytes_to_get;
+ _S_end_free = _S_start_free + __bytes_to_get;
}
}
// lock is released here
- return(chunk_alloc(size, nobjs));
+ return(_S_chunk_alloc(__size, __nobjs));
}
/* Returns an object of size n, and optionally adds to size n free list.*/
-/* We assume that n is properly aligned. */
-/* We hold the allocation lock. */
-template <bool dummy>
-void *__pthread_alloc_template<dummy>
-::refill(size_t n)
+/* We assume that n is properly aligned. */
+/* We hold the allocation lock. */
+template <size_t _Max_size>
+void *_Pthread_alloc_per_thread_state<_Max_size>
+::_M_refill(size_t __n)
{
- int nobjs = 128;
- char * chunk = chunk_alloc(n, nobjs);
- obj * volatile * my_free_list;
- obj * result;
- obj * current_obj, * next_obj;
- int i;
-
- if (1 == nobjs) {
- return(chunk);
+ int __nobjs = 128;
+ char * __chunk =
+ _Pthread_alloc_template<_Max_size>::_S_chunk_alloc(__n, __nobjs);
+ __obj * volatile * __my_free_list;
+ __obj * __result;
+ __obj * __current_obj, * __next_obj;
+ int __i;
+
+ if (1 == __nobjs) {
+ return(__chunk);
}
- my_free_list = free_list + FREELIST_INDEX(n);
+ __my_free_list = __free_list
+ + _Pthread_alloc_template<_Max_size>::_S_freelist_index(__n);
/* Build free list in chunk */
- result = (obj *)chunk;
- *my_free_list = next_obj = (obj *)(chunk + n);
- for (i = 1; ; i++) {
- current_obj = next_obj;
- next_obj = (obj *)((char *)next_obj + n);
- if (nobjs - 1 == i) {
- current_obj -> free_list_link = 0;
- break;
- } else {
- current_obj -> free_list_link = next_obj;
- }
+ __result = (__obj *)__chunk;
+ *__my_free_list = __next_obj = (__obj *)(__chunk + __n);
+ for (__i = 1; ; __i++) {
+ __current_obj = __next_obj;
+ __next_obj = (__obj *)((char *)__next_obj + __n);
+ if (__nobjs - 1 == __i) {
+ __current_obj -> __free_list_link = 0;
+ break;
+ } else {
+ __current_obj -> __free_list_link = __next_obj;
+ }
}
- return(result);
+ return(__result);
}
-template <bool dummy>
-void *__pthread_alloc_template<dummy>
-::reallocate(void *p, size_t old_sz, size_t new_sz)
+template <size_t _Max_size>
+void *_Pthread_alloc_template<_Max_size>
+::reallocate(void *__p, size_t __old_sz, size_t __new_sz)
{
- void * result;
- size_t copy_sz;
+ void * __result;
+ size_t __copy_sz;
- if (old_sz > MAX_BYTES && new_sz > MAX_BYTES) {
- return(realloc(p, new_sz));
+ if (__old_sz > _Max_size
+ && __new_sz > _Max_size) {
+ return(realloc(__p, __new_sz));
}
- if (ROUND_UP(old_sz) == ROUND_UP(new_sz)) return(p);
- result = allocate(new_sz);
- copy_sz = new_sz > old_sz? old_sz : new_sz;
- memcpy(result, p, copy_sz);
- deallocate(p, old_sz);
- return(result);
+ if (_S_round_up(__old_sz) == _S_round_up(__new_sz)) return(__p);
+ __result = allocate(__new_sz);
+ __copy_sz = __new_sz > __old_sz? __old_sz : __new_sz;
+ memcpy(__result, __p, __copy_sz);
+ deallocate(__p, __old_sz);
+ return(__result);
}
-template <bool dummy>
-__pthread_alloc_template<dummy> *
-__pthread_alloc_template<dummy>::free_allocators = 0;
+template <size_t _Max_size>
+_Pthread_alloc_per_thread_state<_Max_size> *
+_Pthread_alloc_template<_Max_size>::_S_free_per_thread_states = 0;
-template <bool dummy>
-pthread_key_t __pthread_alloc_template<dummy>::key;
+template <size_t _Max_size>
+pthread_key_t _Pthread_alloc_template<_Max_size>::_S_key;
-template <bool dummy>
-bool __pthread_alloc_template<dummy>::key_initialized = false;
+template <size_t _Max_size>
+bool _Pthread_alloc_template<_Max_size>::_S_key_initialized = false;
-template <bool dummy>
-pthread_mutex_t __pthread_alloc_template<dummy>::chunk_allocator_lock
+template <size_t _Max_size>
+pthread_mutex_t _Pthread_alloc_template<_Max_size>::_S_chunk_allocator_lock
= PTHREAD_MUTEX_INITIALIZER;
-template <bool dummy>
-char *__pthread_alloc_template<dummy>
-::start_free = 0;
+template <size_t _Max_size>
+char *_Pthread_alloc_template<_Max_size>
+::_S_start_free = 0;
+
+template <size_t _Max_size>
+char *_Pthread_alloc_template<_Max_size>
+::_S_end_free = 0;
+
+template <size_t _Max_size>
+size_t _Pthread_alloc_template<_Max_size>
+::_S_heap_size = 0;
+
+#ifdef __STL_USE_STD_ALLOCATORS
+
+template <class _Tp>
+class pthread_allocator {
+ typedef pthread_alloc _S_Alloc; // The underlying allocator.
+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 <class _U> struct rebind {
+ typedef pthread_allocator<_U> other;
+ };
+
+ pthread_allocator() __STL_NOTHROW {}
+ pthread_allocator(const pthread_allocator& a) __STL_NOTHROW {}
+ template <class _U> pthread_allocator(const pthread_allocator<_U>&)
+ __STL_NOTHROW {}
+ ~pthread_allocator() __STL_NOTHROW {}
+
+ pointer address(reference __x) const { return &__x; }
+ const_pointer address(const_reference __x) const { return &__x; }
+
+ // __n is permitted to be 0. The C++ standard says nothing about what
+ // the return value is when __n == 0.
+ _Tp* allocate(size_type __n, const void* = 0) {
+ return __n != 0 ? static_cast<_Tp*>(_S_Alloc::allocate(__n * sizeof(_Tp)))
+ : 0;
+ }
+
+ // p is not permitted to be a null pointer.
+ void deallocate(pointer __p, size_type __n)
+ { _S_Alloc::deallocate(__p, __n * sizeof(_Tp)); }
+
+ size_type max_size() const __STL_NOTHROW
+ { return size_t(-1) / sizeof(_Tp); }
+
+ void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }
+ void destroy(pointer _p) { _p->~_Tp(); }
+};
+
+template<>
+class pthread_allocator<void> {
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef void* pointer;
+ typedef const void* const_pointer;
+ typedef void value_type;
+
+ template <class _U> struct rebind {
+ typedef pthread_allocator<_U> other;
+ };
+};
+
+template <size_t _Max_size>
+inline bool operator==(const _Pthread_alloc_template<_Max_size>&,
+ const _Pthread_alloc_template<_Max_size>&)
+{
+ return true;
+}
+
+template <class _T1, class _T2>
+inline bool operator==(const pthread_allocator<_T1>&,
+ const pthread_allocator<_T2>& a2)
+{
+ return true;
+}
+
+template <class _T1, class _T2>
+inline bool operator!=(const pthread_allocator<_T1>&,
+ const pthread_allocator<_T2>&)
+{
+ return false;
+}
+
+template <class _Tp, size_t _Max_size>
+struct _Alloc_traits<_Tp, _Pthread_alloc_template<_Max_size> >
+{
+ static const bool _S_instanceless = true;
+ typedef simple_alloc<_Tp, _Pthread_alloc_template<_Max_size> > _Alloc_type;
+ typedef __allocator<_Tp, _Pthread_alloc_template<_Max_size> >
+ allocator_type;
+};
+
+template <class _Tp, class _U, size_t _Max>
+struct _Alloc_traits<_Tp, __allocator<_U, _Pthread_alloc_template<_Max> > >
+{
+ static const bool _S_instanceless = true;
+ typedef simple_alloc<_Tp, _Pthread_alloc_template<_Max> > _Alloc_type;
+ typedef __allocator<_Tp, _Pthread_alloc_template<_Max> > allocator_type;
+};
+
+template <class _Tp, class _U>
+struct _Alloc_traits<_Tp, pthread_allocator<_U> >
+{
+ static const bool _S_instanceless = true;
+ typedef simple_alloc<_Tp, _Pthread_alloc_template<> > _Alloc_type;
+ typedef pthread_allocator<_Tp> allocator_type;
+};
-template <bool dummy>
-char *__pthread_alloc_template<dummy>
-::end_free = 0;
-template <bool dummy>
-size_t __pthread_alloc_template<dummy>
-::heap_size = 0;
+#endif /* __STL_USE_STD_ALLOCATORS */
__STL_END_NAMESPACE