1/* 2 * 3 * Copyright (c) 1994 4 * Hewlett-Packard Company 5 * 6 * Copyright (c) 1996,1997 7 * Silicon Graphics Computer Systems, Inc. 8 * 9 * Copyright (c) 1997 10 * Moscow Center for SPARC Technology 11 * 12 * Copyright (c) 1999 13 * Boris Fomitchev 14 * 15 * This material is provided "as is", with absolutely no warranty expressed 16 * or implied. Any use is at your own risk. 17 * 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. 23 * 24 */ 25 26#ifndef _STLP_PTHREAD_ALLOC_H 27#define _STLP_PTHREAD_ALLOC_H 28 29/* 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 41 * consequences. 42 */ 43 44#if !defined (_STLP_PTHREADS) 45# error POSIX specific allocator implementation. Your system do not seems to \ 46have this interface so please comment the _STLP_USE_PERTHREAD_ALLOC macro \ 47or report to the STLport forum. 48#endif 49 50#if defined (_STLP_USE_NO_IOSTREAMS) 51# error You cannot use per thread allocator implementation without building \ 52STLport libraries. 53#endif 54 55#ifndef _STLP_INTERNAL_ALLOC_H 56# include <stl/_alloc.h> 57#endif 58 59_STLP_BEGIN_NAMESPACE 60 61_STLP_MOVE_TO_PRIV_NAMESPACE 62 63struct _Pthread_alloc_per_thread_state; 64 65// Pthread-specific allocator. 66class _STLP_CLASS_DECLSPEC _Pthread_alloc { 67public: // but only for internal use: 68 typedef _Pthread_alloc_per_thread_state __state_type; 69 typedef char value_type; 70 71public: 72 // Return a recycled or new per thread state. 73 static __state_type * _STLP_CALL _S_get_per_thread_state(); 74 75 /* n must be > 0 */ 76 static void * _STLP_CALL allocate(size_t& __n); 77 78 /* p may not be 0 */ 79 static void _STLP_CALL deallocate(void *__p, size_t __n); 80 81 // boris : versions for per_thread_allocator 82 /* n must be > 0 */ 83 static void * _STLP_CALL allocate(size_t& __n, __state_type* __a); 84 85 /* p may not be 0 */ 86 static void _STLP_CALL deallocate(void *__p, size_t __n, __state_type* __a); 87 88 static void * _STLP_CALL reallocate(void *__p, size_t __old_sz, size_t& __new_sz); 89}; 90 91_STLP_MOVE_TO_STD_NAMESPACE 92 93typedef _STLP_PRIV _Pthread_alloc __pthread_alloc; 94typedef __pthread_alloc pthread_alloc; 95 96template <class _Tp> 97class pthread_allocator : public __stlport_class<pthread_allocator<_Tp> > { 98 typedef pthread_alloc _S_Alloc; // The underlying allocator. 99public: 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; 107 108#ifdef _STLP_MEMBER_TEMPLATE_CLASSES 109 template <class _NewType> struct rebind { 110 typedef pthread_allocator<_NewType> other; 111 }; 112#endif 113 114 pthread_allocator() _STLP_NOTHROW {} 115 pthread_allocator(const pthread_allocator<_Tp>& a) _STLP_NOTHROW {} 116 117#if defined (_STLP_MEMBER_TEMPLATES) /* && defined (_STLP_FUNCTION_PARTIAL_ORDER) */ 118 template <class _OtherType> pthread_allocator(const pthread_allocator<_OtherType>&) 119 _STLP_NOTHROW {} 120#endif 121 122 ~pthread_allocator() _STLP_NOTHROW {} 123 124 pointer address(reference __x) const { return &__x; } 125 const_pointer address(const_reference __x) const { return &__x; } 126 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()) { 131 _STLP_THROW_BAD_ALLOC; 132 } 133 if (__n != 0) { 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) 137 memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size); 138#endif 139 return __ret; 140 } 141 else 142 return 0; 143 } 144 145 void deallocate(pointer __p, size_type __n) { 146 _STLP_ASSERT( (__p == 0) == (__n == 0) ) 147 if (__p != 0) { 148#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC) 149 memset((char*)__p, _STLP_SHRED_BYTE, __n * sizeof(value_type)); 150#endif 151 _S_Alloc::deallocate(__p, __n * sizeof(value_type)); 152 } 153 } 154 155 size_type max_size() const _STLP_NOTHROW 156 { return size_t(-1) / sizeof(_Tp); } 157 158 void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); } 159 void destroy(pointer _p) { _p->~_Tp(); } 160 161#if defined (_STLP_NO_EXTENSIONS) 162 /* STLport extension giving rounded size of an allocated memory buffer 163 * This method do not have to be part of a user defined allocator implementation 164 * and won't even be called if such a function was granted. 165 */ 166protected: 167#endif 168 _Tp* allocate(size_type __n, size_type& __allocated_n) { 169 if (__n > max_size()) { 170 _STLP_THROW_BAD_ALLOC; 171 } 172 if (__n != 0) { 173 size_type __buf_size = __n * sizeof(value_type); 174 _Tp* __ret = __REINTERPRET_CAST(value_type*, _S_Alloc::allocate(__buf_size)); 175#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC) 176 memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size); 177#endif 178 __allocated_n = __buf_size / sizeof(value_type); 179 return __ret; 180 } 181 else 182 return 0; 183 } 184#if defined (_STLP_USE_PARTIAL_SPEC_WORKAROUND) && !defined (_STLP_FUNCTION_TMPL_PARTIAL_ORDER) 185 void _M_swap_workaround(pthread_allocator<_Tp>& __x) {} 186#endif 187}; 188 189_STLP_TEMPLATE_NULL 190class _STLP_CLASS_DECLSPEC pthread_allocator<void> { 191public: 192 typedef size_t size_type; 193 typedef ptrdiff_t difference_type; 194 typedef void* pointer; 195 typedef const void* const_pointer; 196 typedef void value_type; 197#ifdef _STLP_MEMBER_TEMPLATE_CLASSES 198 template <class _NewType> struct rebind { 199 typedef pthread_allocator<_NewType> other; 200 }; 201#endif 202}; 203 204template <class _T1, class _T2> 205inline bool operator==(const pthread_allocator<_T1>&, 206 const pthread_allocator<_T2>& a2) 207{ return true; } 208 209#ifdef _STLP_FUNCTION_TMPL_PARTIAL_ORDER 210template <class _T1, class _T2> 211inline bool operator!=(const pthread_allocator<_T1>&, 212 const pthread_allocator<_T2>&) 213{ return false; } 214#endif 215 216 217#if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION) 218 219template <class _Tp, class _Atype> 220struct _Alloc_traits<_Tp, pthread_allocator<_Atype> > 221{ typedef pthread_allocator<_Tp> allocator_type; }; 222 223#endif 224 225#if defined (_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) 226 227template <class _Tp1, class _Tp2> 228inline pthread_allocator<_Tp2>& 229__stl_alloc_rebind(pthread_allocator<_Tp1>& __x, const _Tp2*) 230{ return (pthread_allocator<_Tp2>&)__x; } 231 232template <class _Tp1, class _Tp2> 233inline pthread_allocator<_Tp2> 234__stl_alloc_create(pthread_allocator<_Tp1>&, const _Tp2*) 235{ return pthread_allocator<_Tp2>(); } 236 237#endif 238 239_STLP_MOVE_TO_PRIV_NAMESPACE 240 241template <class _Tp> 242struct __pthread_alloc_type_traits { 243 typedef typename _IsSTLportClass<pthread_allocator<_Tp> >::_Ret _STLportAlloc; 244 //The default allocator implementation which is recognize thanks to the 245 //__stlport_class inheritance is a stateless object so: 246 typedef _STLportAlloc has_trivial_default_constructor; 247 typedef _STLportAlloc has_trivial_copy_constructor; 248 typedef _STLportAlloc has_trivial_assignment_operator; 249 typedef _STLportAlloc has_trivial_destructor; 250 typedef _STLportAlloc is_POD_type; 251}; 252 253_STLP_MOVE_TO_STD_NAMESPACE 254 255#if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION) 256template <class _Tp> 257struct __type_traits<pthread_allocator<_Tp> > : _STLP_PRIV __pthread_alloc_type_traits<_Tp> {}; 258#else 259_STLP_TEMPLATE_NULL 260struct __type_traits<pthread_allocator<char> > : _STLP_PRIV __pthread_alloc_type_traits<char> {}; 261# if defined (_STLP_HAS_WCHAR_T) 262_STLP_TEMPLATE_NULL 263struct __type_traits<pthread_allocator<wchar_t> > : _STLP_PRIV __pthread_alloc_type_traits<wchar_t> {}; 264# endif 265# if defined (_STLP_USE_PTR_SPECIALIZATIONS) 266_STLP_TEMPLATE_NULL 267struct __type_traits<pthread_allocator<void*> > : _STLP_PRIV __pthread_alloc_type_traits<void*> {}; 268# endif 269#endif 270 271// 272// per_thread_allocator<> : this allocator always return memory to the same thread 273// it was allocated from. 274// 275 276template <class _Tp> 277class per_thread_allocator { 278 typedef pthread_alloc _S_Alloc; // The underlying allocator. 279 typedef pthread_alloc::__state_type __state_type; 280public: 281 typedef size_t size_type; 282 typedef ptrdiff_t difference_type; 283 typedef _Tp* pointer; 284 typedef const _Tp* const_pointer; 285 typedef _Tp& reference; 286 typedef const _Tp& const_reference; 287 typedef _Tp value_type; 288 289#ifdef _STLP_MEMBER_TEMPLATE_CLASSES 290 template <class _NewType> struct rebind { 291 typedef per_thread_allocator<_NewType> other; 292 }; 293#endif 294 295 per_thread_allocator() _STLP_NOTHROW { 296 _M_state = _S_Alloc::_S_get_per_thread_state(); 297 } 298 per_thread_allocator(const per_thread_allocator<_Tp>& __a) _STLP_NOTHROW : _M_state(__a._M_state){} 299 300#if defined (_STLP_MEMBER_TEMPLATES) /* && defined (_STLP_FUNCTION_PARTIAL_ORDER) */ 301 template <class _OtherType> per_thread_allocator(const per_thread_allocator<_OtherType>& __a) 302 _STLP_NOTHROW : _M_state(__a._M_state) {} 303#endif 304 305 ~per_thread_allocator() _STLP_NOTHROW {} 306 307 pointer address(reference __x) const { return &__x; } 308 const_pointer address(const_reference __x) const { return &__x; } 309 310 // __n is permitted to be 0. The C++ standard says nothing about what 311 // the return value is when __n == 0. 312 _Tp* allocate(size_type __n, const void* = 0) { 313 if (__n > max_size()) { 314 _STLP_THROW_BAD_ALLOC; 315 } 316 if (__n != 0) { 317 size_type __buf_size = __n * sizeof(value_type); 318 _Tp* __ret = __REINTERPRET_CAST(_Tp*, _S_Alloc::allocate(__buf_size, _M_state)); 319#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC) 320 memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size); 321#endif 322 return __ret; 323 } 324 else 325 return 0; 326 } 327 328 void deallocate(pointer __p, size_type __n) { 329 _STLP_ASSERT( (__p == 0) == (__n == 0) ) 330 if (__p != 0) { 331#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC) 332 memset((char*)__p, _STLP_SHRED_BYTE, __n * sizeof(value_type)); 333#endif 334 _S_Alloc::deallocate(__p, __n * sizeof(value_type), _M_state); 335 } 336 } 337 338 size_type max_size() const _STLP_NOTHROW 339 { return size_t(-1) / sizeof(_Tp); } 340 341 void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); } 342 void destroy(pointer _p) { _p->~_Tp(); } 343 344 // state is being kept here 345 __state_type* _M_state; 346 347#if defined (_STLP_NO_EXTENSIONS) 348 /* STLport extension giving rounded size of an allocated memory buffer 349 * This method do not have to be part of a user defined allocator implementation 350 * and won't even be called if such a function was granted. 351 */ 352protected: 353#endif 354 _Tp* allocate(size_type __n, size_type& __allocated_n) { 355 if (__n > max_size()) { 356 _STLP_THROW_BAD_ALLOC; 357 } 358 if (__n != 0) { 359 size_type __buf_size = __n * sizeof(value_type); 360 _Tp* __ret = __REINTERPRET_CAST(value_type*, _S_Alloc::allocate(__buf_size, _M_state)); 361#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC) 362 memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size); 363#endif 364 __allocated_n = __buf_size / sizeof(value_type); 365 return __ret; 366 } 367 else 368 return 0; 369 } 370}; 371 372_STLP_TEMPLATE_NULL 373class _STLP_CLASS_DECLSPEC per_thread_allocator<void> { 374public: 375 typedef size_t size_type; 376 typedef ptrdiff_t difference_type; 377 typedef void* pointer; 378 typedef const void* const_pointer; 379 typedef void value_type; 380#ifdef _STLP_MEMBER_TEMPLATE_CLASSES 381 template <class _NewType> struct rebind { 382 typedef per_thread_allocator<_NewType> other; 383 }; 384#endif 385}; 386 387template <class _T1, class _T2> 388inline bool operator==(const per_thread_allocator<_T1>& __a1, 389 const per_thread_allocator<_T2>& __a2) 390{ return __a1._M_state == __a2._M_state; } 391 392#ifdef _STLP_FUNCTION_TMPL_PARTIAL_ORDER 393template <class _T1, class _T2> 394inline bool operator!=(const per_thread_allocator<_T1>& __a1, 395 const per_thread_allocator<_T2>& __a2) 396{ return __a1._M_state != __a2._M_state; } 397#endif 398 399 400#if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION) 401 402template <class _Tp, class _Atype> 403struct _Alloc_traits<_Tp, per_thread_allocator<_Atype> > 404{ typedef per_thread_allocator<_Tp> allocator_type; }; 405 406#endif 407 408#if defined (_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) 409 410template <class _Tp1, class _Tp2> 411inline per_thread_allocator<_Tp2>& 412__stl_alloc_rebind(per_thread_allocator<_Tp1>& __x, const _Tp2*) 413{ return (per_thread_allocator<_Tp2>&)__x; } 414 415template <class _Tp1, class _Tp2> 416inline per_thread_allocator<_Tp2> 417__stl_alloc_create(per_thread_allocator<_Tp1>&, const _Tp2*) 418{ return per_thread_allocator<_Tp2>(); } 419 420#endif /* _STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE */ 421 422_STLP_MOVE_TO_PRIV_NAMESPACE 423 424template <class _Tp> 425struct __perthread_alloc_type_traits { 426 typedef typename _IsSTLportClass<per_thread_allocator<_Tp> >::_Ret _STLportAlloc; 427 //The default allocator implementation which is recognize thanks to the 428 //__stlport_class inheritance is a stateless object so: 429 typedef __false_type has_trivial_default_constructor; 430 typedef _STLportAlloc has_trivial_copy_constructor; 431 typedef _STLportAlloc has_trivial_assignment_operator; 432 typedef _STLportAlloc has_trivial_destructor; 433 typedef __false_type is_POD_type; 434}; 435 436_STLP_MOVE_TO_STD_NAMESPACE 437 438#if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION) 439template <class _Tp> 440struct __type_traits<per_thread_allocator<_Tp> > : _STLP_PRIV __perthread_alloc_type_traits<_Tp> {}; 441#else 442_STLP_TEMPLATE_NULL 443struct __type_traits<per_thread_allocator<char> > : _STLP_PRIV __perthread_alloc_type_traits<char> {}; 444# if defined (_STLP_HAS_WCHAR_T) 445_STLP_TEMPLATE_NULL 446struct __type_traits<per_thread_allocator<wchar_t> > : _STLP_PRIV __perthread_alloc_type_traits<wchar_t> {}; 447# endif 448# if defined (_STLP_USE_PTR_SPECIALIZATIONS) 449_STLP_TEMPLATE_NULL 450struct __type_traits<per_thread_allocator<void*> > : _STLP_PRIV __perthread_alloc_type_traits<void*> {}; 451# endif 452#endif 453 454 455_STLP_END_NAMESPACE 456 457#endif /* _STLP_PTHREAD_ALLOC */ 458 459// Local Variables: 460// mode:C++ 461// End: 462