Home | History | Annotate | Download | only in stl
      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 
    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    */
    166 protected:
    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
    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