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 \ 46 have this interface so please comment the _STLP_USE_PERTHREAD_ALLOC macro \ 47 or 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 \ 52 STLport 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 63 struct _Pthread_alloc_per_thread_state; 64 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; 70 71 public: 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 93 typedef _STLP_PRIV _Pthread_alloc __pthread_alloc; 94 typedef __pthread_alloc pthread_alloc; 95 96 template <class _Tp> 97 class pthread_allocator : public __stlport_class<pthread_allocator<_Tp> > { 98 typedef pthread_alloc _S_Alloc; // The underlying allocator. 99 public: 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 pthread_allocator()114 pthread_allocator() _STLP_NOTHROW {} pthread_allocator(const pthread_allocator<_Tp> & a)115 pthread_allocator(const pthread_allocator<_Tp>& a) _STLP_NOTHROW {} 116 117 #if defined (_STLP_MEMBER_TEMPLATES) /* && defined (_STLP_FUNCTION_PARTIAL_ORDER) */ pthread_allocator(const pthread_allocator<_OtherType> &)118 template <class _OtherType> pthread_allocator(const pthread_allocator<_OtherType>&) 119 _STLP_NOTHROW {} 120 #endif 121 ~pthread_allocator()122 ~pthread_allocator() _STLP_NOTHROW {} 123 address(reference __x)124 pointer address(reference __x) const { return &__x; } address(const_reference __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 deallocate(pointer __p,size_type __n)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 max_size()155 size_type max_size() const _STLP_NOTHROW 156 { return size_t(-1) / sizeof(_Tp); } 157 construct(pointer __p,const _Tp & __val)158 void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); } destroy(pointer _p)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 */ 166 protected: 167 #endif allocate(size_type __n,size_type & __allocated_n)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) _M_swap_workaround(pthread_allocator<_Tp> & __x)185 void _M_swap_workaround(pthread_allocator<_Tp>& __x) {} 186 #endif 187 }; 188 189 _STLP_TEMPLATE_NULL 190 class _STLP_CLASS_DECLSPEC pthread_allocator<void> { 191 public: 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 204 template <class _T1, class _T2> 205 inline bool operator==(const pthread_allocator<_T1>&, 206 const pthread_allocator<_T2>& a2) 207 { return true; } 208 209 #ifdef _STLP_FUNCTION_TMPL_PARTIAL_ORDER 210 template <class _T1, class _T2> 211 inline 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 219 template <class _Tp, class _Atype> 220 struct _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 227 template <class _Tp1, class _Tp2> 228 inline pthread_allocator<_Tp2>& 229 __stl_alloc_rebind(pthread_allocator<_Tp1>& __x, const _Tp2*) 230 { return (pthread_allocator<_Tp2>&)__x; } 231 232 template <class _Tp1, class _Tp2> 233 inline 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 241 template <class _Tp> 242 struct __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) 256 template <class _Tp> 257 struct __type_traits<pthread_allocator<_Tp> > : _STLP_PRIV __pthread_alloc_type_traits<_Tp> {}; 258 #else 259 _STLP_TEMPLATE_NULL 260 struct __type_traits<pthread_allocator<char> > : _STLP_PRIV __pthread_alloc_type_traits<char> {}; 261 # if defined (_STLP_HAS_WCHAR_T) 262 _STLP_TEMPLATE_NULL 263 struct __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 267 struct __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 276 template <class _Tp> 277 class per_thread_allocator { 278 typedef pthread_alloc _S_Alloc; // The underlying allocator. 279 typedef pthread_alloc::__state_type __state_type; 280 public: 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 */ 352 protected: 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 373 class _STLP_CLASS_DECLSPEC per_thread_allocator<void> { 374 public: 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 387 template <class _T1, class _T2> 388 inline 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 393 template <class _T1, class _T2> 394 inline 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 402 template <class _Tp, class _Atype> 403 struct _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 410 template <class _Tp1, class _Tp2> 411 inline per_thread_allocator<_Tp2>& 412 __stl_alloc_rebind(per_thread_allocator<_Tp1>& __x, const _Tp2*) 413 { return (per_thread_allocator<_Tp2>&)__x; } 414 415 template <class _Tp1, class _Tp2> 416 inline 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 424 template <class _Tp> 425 struct __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) 439 template <class _Tp> 440 struct __type_traits<per_thread_allocator<_Tp> > : _STLP_PRIV __perthread_alloc_type_traits<_Tp> {}; 441 #else 442 _STLP_TEMPLATE_NULL 443 struct __type_traits<per_thread_allocator<char> > : _STLP_PRIV __perthread_alloc_type_traits<char> {}; 444 # if defined (_STLP_HAS_WCHAR_T) 445 _STLP_TEMPLATE_NULL 446 struct __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 450 struct __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