_pthread_alloc.h

00001 /*
00002  *
00003  * Copyright (c) 1994
00004  * Hewlett-Packard Company
00005  *
00006  * Copyright (c) 1996,1997
00007  * Silicon Graphics Computer Systems, Inc.
00008  *
00009  * Copyright (c) 1997
00010  * Moscow Center for SPARC Technology
00011  *
00012  * Copyright (c) 1999 
00013  * Boris Fomitchev
00014  *
00015  * This material is provided "as is", with absolutely no warranty expressed
00016  * or implied. Any use is at your own risk.
00017  *
00018  * Permission to use or copy this software for any purpose is hereby granted 
00019  * without fee, provided the above notices are retained on all copies.
00020  * Permission to modify the code and to distribute modified code is granted,
00021  * provided the above notices are retained, and a notice that the code was
00022  * modified is included with the above copyright notice.
00023  *
00024  */
00025 
00026 #ifndef _STLP_PTHREAD_ALLOC_H
00027 #define _STLP_PTHREAD_ALLOC_H
00028 
00029 // Pthread-specific node allocator.
00030 // This is similar to the default allocator, except that free-list
00031 // information is kept separately for each thread, avoiding locking.
00032 // This should be reasonably fast even in the presence of threads.
00033 // The down side is that storage may not be well-utilized.
00034 // It is not an error to allocate memory in thread A and deallocate
00035 // it in thread B.  But this effectively transfers ownership of the memory,
00036 // so that it can only be reallocated by thread B.  Thus this can effectively
00037 // result in a storage leak if it's done on a regular basis.
00038 // It can also result in frequent sharing of
00039 // cache lines among processors, with potentially serious performance
00040 // consequences.
00041 
00042 #ifndef _STLP_INTERNAL_ALLOC_H
00043 #include <stl/_alloc.h>
00044 #endif
00045 
00046 #ifndef __RESTRICT
00047 #  define __RESTRICT
00048 #endif
00049 
00050 _STLP_BEGIN_NAMESPACE
00051 
00052 #define _STLP_DATA_ALIGNMENT 8
00053 
00054 union _Pthread_alloc_obj {
00055     union _Pthread_alloc_obj * __free_list_link;
00056     char __client_data[_STLP_DATA_ALIGNMENT];    /* The client sees this.    */
00057 };
00058 
00059 // Pthread allocators don't appear to the client to have meaningful
00060 // instances.  We do in fact need to associate some state with each
00061 // thread.  That state is represented by
00062 // _Pthread_alloc_per_thread_state<_Max_size>.
00063 
00064 template<size_t _Max_size>
00065 struct _Pthread_alloc_per_thread_state {
00066   typedef _Pthread_alloc_obj __obj;
00067   enum { _S_NFREELISTS = _Max_size/_STLP_DATA_ALIGNMENT };
00068   _Pthread_alloc_obj* volatile __free_list[_S_NFREELISTS]; 
00069   _Pthread_alloc_per_thread_state<_Max_size> * __next; 
00070         // Free list link for list of available per thread structures.
00071         // When one of these becomes available for reuse due to thread
00072         // termination, any objects in its free list remain associated
00073         // with it.  The whole structure may then be used by a newly
00074         // created thread.
00075   _Pthread_alloc_per_thread_state() : __next(0)
00076   {
00077     memset((void *)__free_list, 0, (size_t)_S_NFREELISTS * sizeof(__obj *));
00078   }
00079   // Returns an object of size __n, and possibly adds to size n free list.
00080   void *_M_refill(size_t __n);
00081 };
00082 
00083 // Pthread-specific allocator.
00084 // The argument specifies the largest object size allocated from per-thread
00085 // free lists.  Larger objects are allocated using malloc_alloc.
00086 // Max_size must be a power of 2.
00087 template < __DFL_NON_TYPE_PARAM(size_t, _Max_size, _MAX_BYTES) >
00088 class _Pthread_alloc {
00089 
00090 public: // but only for internal use:
00091 
00092   typedef _Pthread_alloc_obj __obj;
00093 
00094   // Allocates a chunk for nobjs of size size.  nobjs may be reduced
00095   // if it is inconvenient to allocate the requested number.
00096   static char *_S_chunk_alloc(size_t __size, int &__nobjs);
00097 
00098   enum {_S_ALIGN = _STLP_DATA_ALIGNMENT};
00099 
00100   static size_t _S_round_up(size_t __bytes) {
00101         return (((__bytes) + (int)_S_ALIGN-1) & ~((int)_S_ALIGN - 1));
00102   }
00103   static size_t _S_freelist_index(size_t __bytes) {
00104         return (((__bytes) + (int)_S_ALIGN-1)/(int)_S_ALIGN - 1);
00105   }
00106 
00107 private:
00108   // Chunk allocation state. And other shared state.
00109   // Protected by _S_chunk_allocator_lock.
00110   static _STLP_mutex_base _S_chunk_allocator_lock;
00111   static char *_S_start_free;
00112   static char *_S_end_free;
00113   static size_t _S_heap_size;
00114   static _Pthread_alloc_per_thread_state<_Max_size>* _S_free_per_thread_states;
00115   static pthread_key_t _S_key;
00116   static bool _S_key_initialized;
00117         // Pthread key under which per thread state is stored. 
00118         // Allocator instances that are currently unclaimed by any thread.
00119   static void _S_destructor(void *instance);
00120         // Function to be called on thread exit to reclaim per thread
00121         // state.
00122   static _Pthread_alloc_per_thread_state<_Max_size> *_S_new_per_thread_state();
00123         // Return a recycled or new per thread state.
00124   static _Pthread_alloc_per_thread_state<_Max_size> *_S_get_per_thread_state();
00125         // ensure that the current thread has an associated
00126         // per thread state.
00127   class _M_lock;
00128   friend class _M_lock;
00129   class _M_lock {
00130       public:
00131         _M_lock () { _S_chunk_allocator_lock._M_acquire_lock(); }
00132         ~_M_lock () { _S_chunk_allocator_lock._M_release_lock(); }
00133   };
00134 
00135 public:
00136 
00137   /* n must be > 0      */
00138   static void * allocate(size_t __n)
00139   {
00140     __obj * volatile * __my_free_list;
00141     __obj * __RESTRICT __result;
00142     _Pthread_alloc_per_thread_state<_Max_size>* __a;
00143 
00144     if (__n > _Max_size) {
00145         return(__malloc_alloc<0>::allocate(__n));
00146     }
00147     if (!_S_key_initialized ||
00148         !(__a = (_Pthread_alloc_per_thread_state<_Max_size>*)
00149                                  pthread_getspecific(_S_key))) {
00150         __a = _S_get_per_thread_state();
00151     }
00152     __my_free_list = __a -> __free_list + _S_freelist_index(__n);
00153     __result = *__my_free_list;
00154     if (__result == 0) {
00155         void *__r = __a -> _M_refill(_S_round_up(__n));
00156         return __r;
00157     }
00158     *__my_free_list = __result -> __free_list_link;
00159     return (__result);
00160   };
00161 
00162   /* p may not be 0 */
00163   static void deallocate(void *__p, size_t __n)
00164   {
00165     __obj *__q = (__obj *)__p;
00166     __obj * volatile * __my_free_list;
00167     _Pthread_alloc_per_thread_state<_Max_size>* __a;
00168 
00169     if (__n > _Max_size) {
00170         __malloc_alloc<0>::deallocate(__p, __n);
00171         return;
00172     }
00173     if (!_S_key_initialized ||
00174         !(__a = (_Pthread_alloc_per_thread_state<_Max_size> *)
00175                 pthread_getspecific(_S_key))) {
00176         __a = _S_get_per_thread_state();
00177     }
00178     __my_free_list = __a->__free_list + _S_freelist_index(__n);
00179     __q -> __free_list_link = *__my_free_list;
00180     *__my_free_list = __q;
00181   }
00182 
00183   static void * reallocate(void *__p, size_t __old_sz, size_t __new_sz);
00184 
00185 } ;
00186 
00187 # if defined (_STLP_USE_TEMPLATE_EXPORT)
00188 _STLP_EXPORT_TEMPLATE_CLASS _Pthread_alloc<_MAX_BYTES>;
00189 # endif
00190 
00191 typedef _Pthread_alloc<_MAX_BYTES> __pthread_alloc;
00192 typedef __pthread_alloc pthread_alloc;
00193 
00194 template <class _Tp>
00195 class pthread_allocator {
00196   typedef pthread_alloc _S_Alloc;          // The underlying allocator.
00197 public:
00198   typedef size_t     size_type;
00199   typedef ptrdiff_t  difference_type;
00200   typedef _Tp*       pointer;
00201   typedef const _Tp* const_pointer;
00202   typedef _Tp&       reference;
00203   typedef const _Tp& const_reference;
00204   typedef _Tp        value_type;
00205 
00206 #ifdef _STLP_MEMBER_TEMPLATE_CLASSES
00207   template <class _NewType> struct rebind {
00208     typedef pthread_allocator<_NewType> other;
00209   };
00210 #endif
00211 
00212   pthread_allocator() _STLP_NOTHROW {}
00213   pthread_allocator(const pthread_allocator<_Tp>& a) _STLP_NOTHROW {}
00214 
00215 #if defined (_STLP_MEMBER_TEMPLATES) && defined (_STLP_FUNCTION_PARTIAL_ORDER)
00216   template <class _OtherType> pthread_allocator(const pthread_allocator<_OtherType>&)
00217                 _STLP_NOTHROW {}
00218 #endif
00219 
00220   ~pthread_allocator() _STLP_NOTHROW {}
00221 
00222   pointer address(reference __x) const { return &__x; }
00223   const_pointer address(const_reference __x) const { return &__x; }
00224 
00225   // __n is permitted to be 0.  The C++ standard says nothing about what
00226   // the return value is when __n == 0.
00227   _Tp* allocate(size_type __n, const void* = 0) {
00228     return __n != 0 ? __STATIC_CAST(_Tp*,_S_Alloc::allocate(__n * sizeof(_Tp)))
00229                     : 0;
00230   }
00231 
00232   // p is not permitted to be a null pointer.
00233   void deallocate(pointer __p, size_type __n)
00234     { _S_Alloc::deallocate(__p, __n * sizeof(_Tp)); }
00235 
00236   size_type max_size() const _STLP_NOTHROW 
00237     { return size_t(-1) / sizeof(_Tp); }
00238 
00239   void construct(pointer __p, const _Tp& __val) { _STLP_PLACEMENT_NEW (__p) _Tp(__val); }
00240   void destroy(pointer _p) { _p->~_Tp(); }
00241 };
00242 
00243 _STLP_TEMPLATE_NULL
00244 class _STLP_CLASS_DECLSPEC pthread_allocator<void> {
00245 public:
00246   typedef size_t      size_type;
00247   typedef ptrdiff_t   difference_type;
00248   typedef void*       pointer;
00249   typedef const void* const_pointer;
00250   typedef void        value_type;
00251 #ifdef _STLP_MEMBER_TEMPLATE_CLASSES
00252   template <class _NewType> struct rebind {
00253     typedef pthread_allocator<_NewType> other;
00254   };
00255 #endif
00256 };
00257 
00258 /*
00259 template <size_t _Max_size>
00260 inline bool operator==(const _Pthread_alloc<_Max_size>&,
00261                        const _Pthread_alloc<_Max_size>&)
00262 {
00263   return true;
00264 }
00265 */
00266 
00267 template <class _T1, class _T2>
00268 inline bool operator==(const pthread_allocator<_T1>&,
00269                        const pthread_allocator<_T2>& a2) 
00270 {
00271   return true;
00272 }
00273 
00274 #ifdef _STLP_FUNCTION_TMPL_PARTIAL_ORDER
00275 template <class _T1, class _T2>
00276 inline bool operator!=(const pthread_allocator<_T1>&,
00277                        const pthread_allocator<_T2>&)
00278 {
00279   return false;
00280 }
00281 #endif
00282 
00283 #ifdef _STLP_CLASS_PARTIAL_SPECIALIZATION
00284 
00285 template <class _Tp, size_t _Max_size>
00286 struct _Alloc_traits<_Tp, _Pthread_alloc<_Max_size> >
00287 {
00288   typedef __allocator<_Tp, _Pthread_alloc<_Max_size> > 
00289           allocator_type;
00290 };
00291 
00292 template <class _Tp, class _Atype>
00293 struct _Alloc_traits<_Tp, pthread_allocator<_Atype> >
00294 {
00295   typedef pthread_allocator<_Tp> allocator_type;
00296 };
00297 
00298 #endif
00299 
00300 #if !defined (_STLP_MEMBER_TEMPLATE_CLASSES)
00301 
00302 template <class _Tp1, class _Tp2>
00303 inline pthread_allocator<_Tp2>&
00304 __stl_alloc_rebind(pthread_allocator<_Tp1>& __x, const _Tp2*) {
00305   return (pthread_allocator<_Tp2>&)__x;
00306 }
00307 
00308 template <class _Tp1, class _Tp2>
00309 inline pthread_allocator<_Tp2>
00310 __stl_alloc_create(pthread_allocator<_Tp1>&, const _Tp2*) {
00311   return pthread_allocator<_Tp2>();
00312 }
00313 
00314 #endif /* _STLP_MEMBER_TEMPLATE_CLASSES */
00315 
00316 _STLP_END_NAMESPACE
00317 
00318 # if defined (_STLP_EXPOSE_GLOBALS_IMPLEMENTATION) && !defined (_STLP_LINK_TIME_INSTANTIATION)
00319 #  include <stl/_pthread_alloc.c>
00320 # endif
00321 
00322 #endif /* _STLP_PTHREAD_ALLOC */
00323 
00324 // Local Variables:
00325 // mode:C++
00326 // End:

Generated on Mon Jun 5 10:20:46 2006 for Intelligence.kdevelop by  doxygen 1.4.6