4 * Hewlett-Packard Company
6 * Copyright (c) 1996,1997
7 * Silicon Graphics Computer Systems, Inc.
10 * Moscow Center for SPARC Technology
15 * This material is provided "as is", with absolutely no warranty expressed
16 * or implied. Any use is at your own risk.
18 * Permission to use or copy this software for any purpose is hereby granted
19 * without fee, provided the above notices are retained on all copies.
20 * Permission to modify the code and to distribute modified code is granted,
21 * provided the above notices are retained, and a notice that the code was
22 * modified is included with the above copyright notice.
26 #ifndef _STLP_PTHREAD_ALLOC_H
27 #define _STLP_PTHREAD_ALLOC_H
30 * Pthread-specific node allocator.
31 * This is similar to the default allocator, except that free-list
32 * information is kept separately for each thread, avoiding locking.
33 * This should be reasonably fast even in the presence of threads.
34 * The down side is that storage may not be well-utilized.
35 * It is not an error to allocate memory in thread A and deallocate
36 * it in thread B. But this effectively transfers ownership of the memory,
37 * so that it can only be reallocated by thread B. Thus this can effectively
38 * result in a storage leak if it's done on a regular basis.
39 * It can also result in frequent sharing of
40 * cache lines among processors, with potentially serious performance
44 #if !defined (_STLP_PTHREADS)
45 # error POSIX specific allocator implementation. Your system do not seems to \
46 have this interface so please comment the _STLP_USE_PERTHREAD_ALLOC macro \
47 or report to the STLport forum.
50 #if defined (_STLP_USE_NO_IOSTREAMS)
51 # error You cannot use per thread allocator implementation without building \
55 #ifndef _STLP_INTERNAL_ALLOC_H
56 # include <stl/_alloc.h>
61 _STLP_MOVE_TO_PRIV_NAMESPACE
63 struct _Pthread_alloc_per_thread_state;
65 // Pthread-specific allocator.
66 class _STLP_CLASS_DECLSPEC _Pthread_alloc {
67 public: // but only for internal use:
68 typedef _Pthread_alloc_per_thread_state __state_type;
69 typedef char value_type;
72 // Return a recycled or new per thread state.
73 static __state_type * _STLP_CALL _S_get_per_thread_state();
76 static void * _STLP_CALL allocate(size_t& __n);
79 static void _STLP_CALL deallocate(void *__p, size_t __n);
81 // boris : versions for per_thread_allocator
83 static void * _STLP_CALL allocate(size_t& __n, __state_type* __a);
86 static void _STLP_CALL deallocate(void *__p, size_t __n, __state_type* __a);
88 static void * _STLP_CALL reallocate(void *__p, size_t __old_sz, size_t& __new_sz);
91 _STLP_MOVE_TO_STD_NAMESPACE
93 typedef _STLP_PRIV _Pthread_alloc __pthread_alloc;
94 typedef __pthread_alloc pthread_alloc;
97 class pthread_allocator : public __stlport_class<pthread_allocator<_Tp> > {
98 typedef pthread_alloc _S_Alloc; // The underlying allocator.
100 typedef size_t size_type;
101 typedef ptrdiff_t difference_type;
102 typedef _Tp* pointer;
103 typedef const _Tp* const_pointer;
104 typedef _Tp& reference;
105 typedef const _Tp& const_reference;
106 typedef _Tp value_type;
108 #ifdef _STLP_MEMBER_TEMPLATE_CLASSES
109 template <class _NewType> struct rebind {
110 typedef pthread_allocator<_NewType> other;
114 pthread_allocator() _STLP_NOTHROW {}
115 pthread_allocator(const pthread_allocator<_Tp>& a) _STLP_NOTHROW {}
117 #if defined (_STLP_MEMBER_TEMPLATES) /* && defined (_STLP_FUNCTION_PARTIAL_ORDER) */
118 template <class _OtherType> pthread_allocator(const pthread_allocator<_OtherType>&)
122 ~pthread_allocator() _STLP_NOTHROW {}
124 pointer address(reference __x) const { return &__x; }
125 const_pointer address(const_reference __x) const { return &__x; }
127 // __n is permitted to be 0. The C++ standard says nothing about what
128 // the return value is when __n == 0.
129 _Tp* allocate(size_type __n, const void* = 0) {
130 if (__n > max_size()) {
134 size_type __buf_size = __n * sizeof(value_type);
135 _Tp* __ret = __REINTERPRET_CAST(value_type*, _S_Alloc::allocate(__buf_size));
136 #if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
138 memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size);
147 void deallocate(pointer __p, size_type __n) {
148 _STLP_ASSERT( (__p == 0) == (__n == 0) )
150 #if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
151 memset((char*)__p, _STLP_SHRED_BYTE, __n * sizeof(value_type));
153 _S_Alloc::deallocate(__p, __n * sizeof(value_type));
157 size_type max_size() const _STLP_NOTHROW
158 { return size_t(-1) / sizeof(_Tp); }
160 void construct(pointer __p, const _Tp& __val) { _STLP_PLACEMENT_NEW (__p) _Tp(__val); }
161 void destroy(pointer _p) { _p->~_Tp(); }
163 #if defined (_STLP_NO_EXTENSIONS)
164 /* STLport extension giving rounded size of an allocated memory buffer
165 * This method do not have to be part of a user defined allocator implementation
166 * and won't even be called if such a function was granted.
170 _Tp* allocate(size_type __n, size_type& __allocated_n) {
171 if (__n > max_size()) {
175 size_type __buf_size = __n * sizeof(value_type);
176 _Tp* __ret = __REINTERPRET_CAST(value_type*, _S_Alloc::allocate(__buf_size));
177 #if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
179 memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size);
182 __allocated_n = __buf_size / sizeof(value_type);
191 class _STLP_CLASS_DECLSPEC pthread_allocator<void> {
193 typedef size_t size_type;
194 typedef ptrdiff_t difference_type;
195 typedef void* pointer;
196 typedef const void* const_pointer;
197 typedef void value_type;
198 #ifdef _STLP_MEMBER_TEMPLATE_CLASSES
199 template <class _NewType> struct rebind {
200 typedef pthread_allocator<_NewType> other;
205 template <class _T1, class _T2>
206 inline bool operator==(const pthread_allocator<_T1>&,
207 const pthread_allocator<_T2>& a2)
210 #ifdef _STLP_FUNCTION_TMPL_PARTIAL_ORDER
211 template <class _T1, class _T2>
212 inline bool operator!=(const pthread_allocator<_T1>&,
213 const pthread_allocator<_T2>&)
218 #if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION)
220 # if defined (_STLP_USE_RAW_SGI_ALLOCATORS)
222 struct _Alloc_traits<_Tp, _Pthread_alloc>
223 { typedef __allocator<_Tp, _Pthread_alloc> allocator_type; };
226 template <class _Tp, class _Atype>
227 struct _Alloc_traits<_Tp, pthread_allocator<_Atype> >
228 { typedef pthread_allocator<_Tp> allocator_type; };
232 #if defined (_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE)
234 template <class _Tp1, class _Tp2>
235 inline pthread_allocator<_Tp2>&
236 __stl_alloc_rebind(pthread_allocator<_Tp1>& __x, const _Tp2*)
237 { return (pthread_allocator<_Tp2>&)__x; }
239 template <class _Tp1, class _Tp2>
240 inline pthread_allocator<_Tp2>
241 __stl_alloc_create(pthread_allocator<_Tp1>&, const _Tp2*)
242 { return pthread_allocator<_Tp2>(); }
246 _STLP_MOVE_TO_PRIV_NAMESPACE
249 struct __pthread_alloc_type_traits {
250 typedef typename _IsSTLportClass<pthread_allocator<_Tp> >::_Ret _STLportAlloc;
251 //The default allocator implementation which is recognize thanks to the
252 //__stlport_class inheritance is a stateless object so:
253 typedef _STLportAlloc has_trivial_default_constructor;
254 typedef _STLportAlloc has_trivial_copy_constructor;
255 typedef _STLportAlloc has_trivial_assignment_operator;
256 typedef _STLportAlloc has_trivial_destructor;
257 typedef _STLportAlloc is_POD_type;
260 _STLP_MOVE_TO_STD_NAMESPACE
262 #if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION)
264 struct __type_traits<pthread_allocator<_Tp> > : _STLP_PRIV __pthread_alloc_type_traits<_Tp> {};
267 struct __type_traits<pthread_allocator<char> > : _STLP_PRIV __pthread_alloc_type_traits<char> {};
268 # if defined (_STLP_HAS_WCHAR_T)
270 struct __type_traits<pthread_allocator<wchar_t> > : _STLP_PRIV __pthread_alloc_type_traits<wchar_t> {};
272 # if defined (_STLP_USE_PTR_SPECIALIZATIONS)
274 struct __type_traits<pthread_allocator<void*> > : _STLP_PRIV __pthread_alloc_type_traits<void*> {};
279 // per_thread_allocator<> : this allocator always return memory to the same thread
280 // it was allocated from.
284 class per_thread_allocator {
285 typedef pthread_alloc _S_Alloc; // The underlying allocator.
286 typedef pthread_alloc::__state_type __state_type;
288 typedef size_t size_type;
289 typedef ptrdiff_t difference_type;
290 typedef _Tp* pointer;
291 typedef const _Tp* const_pointer;
292 typedef _Tp& reference;
293 typedef const _Tp& const_reference;
294 typedef _Tp value_type;
296 #ifdef _STLP_MEMBER_TEMPLATE_CLASSES
297 template <class _NewType> struct rebind {
298 typedef per_thread_allocator<_NewType> other;
302 per_thread_allocator() _STLP_NOTHROW {
303 _M_state = _S_Alloc::_S_get_per_thread_state();
305 per_thread_allocator(const per_thread_allocator<_Tp>& __a) _STLP_NOTHROW : _M_state(__a._M_state){}
307 #if defined (_STLP_MEMBER_TEMPLATES) /* && defined (_STLP_FUNCTION_PARTIAL_ORDER) */
308 template <class _OtherType> per_thread_allocator(const per_thread_allocator<_OtherType>& __a)
309 _STLP_NOTHROW : _M_state(__a._M_state) {}
312 ~per_thread_allocator() _STLP_NOTHROW {}
314 pointer address(reference __x) const { return &__x; }
315 const_pointer address(const_reference __x) const { return &__x; }
317 // __n is permitted to be 0. The C++ standard says nothing about what
318 // the return value is when __n == 0.
319 _Tp* allocate(size_type __n, const void* = 0) {
320 if (__n > max_size()) {
324 size_type __buf_size = __n * sizeof(value_type);
325 _Tp* __ret = __REINTERPRET_CAST(_Tp*, _S_Alloc::allocate(__buf_size, _M_state));
326 #if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
328 memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size);
337 void deallocate(pointer __p, size_type __n) {
338 _STLP_ASSERT( (__p == 0) == (__n == 0) )
340 #if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
341 memset((char*)__p, _STLP_SHRED_BYTE, __n * sizeof(value_type));
343 _S_Alloc::deallocate(__p, __n * sizeof(value_type), _M_state);
347 size_type max_size() const _STLP_NOTHROW
348 { return size_t(-1) / sizeof(_Tp); }
350 void construct(pointer __p, const _Tp& __val) { _STLP_PLACEMENT_NEW (__p) _Tp(__val); }
351 void destroy(pointer _p) { _p->~_Tp(); }
353 // state is being kept here
354 __state_type* _M_state;
356 #if defined (_STLP_NO_EXTENSIONS)
357 /* STLport extension giving rounded size of an allocated memory buffer
358 * This method do not have to be part of a user defined allocator implementation
359 * and won't even be called if such a function was granted.
363 _Tp* allocate(size_type __n, size_type& __allocated_n) {
364 if (__n > max_size()) {
368 size_type __buf_size = __n * sizeof(value_type);
369 _Tp* __ret = __REINTERPRET_CAST(value_type*, _S_Alloc::allocate(__buf_size, _M_state));
370 #if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
372 memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size);
375 __allocated_n = __buf_size / sizeof(value_type);
384 class _STLP_CLASS_DECLSPEC per_thread_allocator<void> {
386 typedef size_t size_type;
387 typedef ptrdiff_t difference_type;
388 typedef void* pointer;
389 typedef const void* const_pointer;
390 typedef void value_type;
391 #ifdef _STLP_MEMBER_TEMPLATE_CLASSES
392 template <class _NewType> struct rebind {
393 typedef per_thread_allocator<_NewType> other;
398 template <class _T1, class _T2>
399 inline bool operator==(const per_thread_allocator<_T1>& __a1,
400 const per_thread_allocator<_T2>& __a2)
401 { return __a1._M_state == __a2._M_state; }
403 #ifdef _STLP_FUNCTION_TMPL_PARTIAL_ORDER
404 template <class _T1, class _T2>
405 inline bool operator!=(const per_thread_allocator<_T1>& __a1,
406 const per_thread_allocator<_T2>& __a2)
407 { return __a1._M_state != __a2._M_state; }
411 #if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION)
413 template <class _Tp, class _Atype>
414 struct _Alloc_traits<_Tp, per_thread_allocator<_Atype> >
415 { typedef per_thread_allocator<_Tp> allocator_type; };
419 #if defined (_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE)
421 template <class _Tp1, class _Tp2>
422 inline per_thread_allocator<_Tp2>&
423 __stl_alloc_rebind(per_thread_allocator<_Tp1>& __x, const _Tp2*)
424 { return (per_thread_allocator<_Tp2>&)__x; }
426 template <class _Tp1, class _Tp2>
427 inline per_thread_allocator<_Tp2>
428 __stl_alloc_create(per_thread_allocator<_Tp1>&, const _Tp2*)
429 { return per_thread_allocator<_Tp2>(); }
431 #endif /* _STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE */
433 _STLP_MOVE_TO_PRIV_NAMESPACE
436 struct __perthread_alloc_type_traits {
437 typedef typename _IsSTLportClass<per_thread_allocator<_Tp> >::_Ret _STLportAlloc;
438 //The default allocator implementation which is recognize thanks to the
439 //__stlport_class inheritance is a stateless object so:
440 typedef __false_type has_trivial_default_constructor;
441 typedef _STLportAlloc has_trivial_copy_constructor;
442 typedef _STLportAlloc has_trivial_assignment_operator;
443 typedef _STLportAlloc has_trivial_destructor;
444 typedef __false_type is_POD_type;
447 _STLP_MOVE_TO_STD_NAMESPACE
449 #if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION)
451 struct __type_traits<per_thread_allocator<_Tp> > : _STLP_PRIV __perthread_alloc_type_traits<_Tp> {};
454 struct __type_traits<per_thread_allocator<char> > : _STLP_PRIV __perthread_alloc_type_traits<char> {};
455 # if defined (_STLP_HAS_WCHAR_T)
457 struct __type_traits<per_thread_allocator<wchar_t> > : _STLP_PRIV __perthread_alloc_type_traits<wchar_t> {};
459 # if defined (_STLP_USE_PTR_SPECIALIZATIONS)
461 struct __type_traits<per_thread_allocator<void*> > : _STLP_PRIV __perthread_alloc_type_traits<void*> {};
468 #endif /* _STLP_PTHREAD_ALLOC */