pthread_alloc
上传用户:kellyonhid
上传日期:2013-10-12
资源大小:932k
文件大小:15k
源码类别:

3D图形编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 1996
  3.  * Silicon Graphics Computer Systems, Inc.
  4.  *
  5.  * Permission to use, copy, modify, distribute and sell this software
  6.  * and its documentation for any purpose is hereby granted without fee,
  7.  * provided that the above copyright notice appear in all copies and
  8.  * that both that copyright notice and this permission notice appear
  9.  * in supporting documentation.  Silicon Graphics makes no
  10.  * representations about the suitability of this software for any
  11.  * purpose.  It is provided "as is" without express or implied warranty.
  12.  */
  13. #ifndef __SGI_STL_PTHREAD_ALLOC
  14. #define __SGI_STL_PTHREAD_ALLOC
  15. // Pthread-specific node allocator.
  16. // This is similar to the default allocator, except that free-list
  17. // information is kept separately for each thread, avoiding locking.
  18. // This should be reasonably fast even in the presence of threads.
  19. // The down side is that storage may not be well-utilized.
  20. // It is not an error to allocate memory in thread A and deallocate
  21. // it in thread B.  But this effectively transfers ownership of the memory,
  22. // so that it can only be reallocated by thread B.  Thus this can effectively
  23. // result in a storage leak if it's done on a regular basis.
  24. // It can also result in frequent sharing of
  25. // cache lines among processors, with potentially serious performance
  26. // consequences.
  27. #include <stl_config.h>
  28. #include <stl_alloc.h>
  29. #ifndef __RESTRICT
  30. #  define __RESTRICT
  31. #endif
  32. __STL_BEGIN_NAMESPACE
  33. #define __STL_DATA_ALIGNMENT 8
  34. union _Pthread_alloc_obj {
  35.     union _Pthread_alloc_obj * __free_list_link;
  36.     char __client_data[__STL_DATA_ALIGNMENT];    /* The client sees this.    */
  37. };
  38. // Pthread allocators don't appear to the client to have meaningful
  39. // instances.  We do in fact need to associate some state with each
  40. // thread.  That state is represented by
  41. // _Pthread_alloc_per_thread_state<_Max_size>.
  42. template<size_t _Max_size>
  43. struct _Pthread_alloc_per_thread_state {
  44.   typedef _Pthread_alloc_obj __obj;
  45.   enum { _S_NFREELISTS = _Max_size/__STL_DATA_ALIGNMENT };
  46.   _Pthread_alloc_obj* volatile __free_list[_S_NFREELISTS]; 
  47.   _Pthread_alloc_per_thread_state<_Max_size> * __next; 
  48. // Free list link for list of available per thread structures.
  49.    // When one of these becomes available for reuse due to thread
  50. // termination, any objects in its free list remain associated
  51. // with it.  The whole structure may then be used by a newly
  52. // created thread.
  53.   _Pthread_alloc_per_thread_state() : __next(0)
  54.   {
  55.     memset((void *)__free_list, 0, _S_NFREELISTS * sizeof(__obj *));
  56.   }
  57.   // Returns an object of size __n, and possibly adds to size n free list.
  58.   void *_M_refill(size_t __n);
  59. };
  60. // Pthread-specific allocator.
  61. // The argument specifies the largest object size allocated from per-thread
  62. // free lists.  Larger objects are allocated using malloc_alloc.
  63. // Max_size must be a power of 2.
  64. template <size_t _Max_size = 128>
  65. class _Pthread_alloc_template {
  66. public: // but only for internal use:
  67.   typedef _Pthread_alloc_obj __obj;
  68.   // Allocates a chunk for nobjs of size size.  nobjs may be reduced
  69.   // if it is inconvenient to allocate the requested number.
  70.   static char *_S_chunk_alloc(size_t __size, int &__nobjs);
  71.   enum {_S_ALIGN = __STL_DATA_ALIGNMENT};
  72.   static size_t _S_round_up(size_t __bytes) {
  73.         return (((__bytes) + _S_ALIGN-1) & ~(_S_ALIGN - 1));
  74.   }
  75.   static size_t _S_freelist_index(size_t __bytes) {
  76.         return (((__bytes) + _S_ALIGN-1)/_S_ALIGN - 1);
  77.   }
  78. private:
  79.   // Chunk allocation state. And other shared state.
  80.   // Protected by _S_chunk_allocator_lock.
  81.   static pthread_mutex_t _S_chunk_allocator_lock;
  82.   static char *_S_start_free;
  83.   static char *_S_end_free;
  84.   static size_t _S_heap_size;
  85.   static _Pthread_alloc_per_thread_state<_Max_size>* _S_free_per_thread_states;
  86.   static pthread_key_t _S_key;
  87.   static bool _S_key_initialized;
  88.         // Pthread key under which per thread state is stored. 
  89.         // Allocator instances that are currently unclaimed by any thread.
  90.   static void _S_destructor(void *instance);
  91.         // Function to be called on thread exit to reclaim per thread
  92.         // state.
  93.   static _Pthread_alloc_per_thread_state<_Max_size> *_S_new_per_thread_state();
  94.         // Return a recycled or new per thread state.
  95.   static _Pthread_alloc_per_thread_state<_Max_size> *_S_get_per_thread_state();
  96.         // ensure that the current thread has an associated
  97.         // per thread state.
  98.   friend class _M_lock;
  99.   class _M_lock {
  100.       public:
  101.         _M_lock () { pthread_mutex_lock(&_S_chunk_allocator_lock); }
  102.         ~_M_lock () { pthread_mutex_unlock(&_S_chunk_allocator_lock); }
  103.   };
  104. public:
  105.   /* n must be > 0      */
  106.   static void * allocate(size_t __n)
  107.   {
  108.     __obj * volatile * __my_free_list;
  109.     __obj * __RESTRICT __result;
  110.     _Pthread_alloc_per_thread_state<_Max_size>* __a;
  111.     if (__n > _Max_size) {
  112.         return(malloc_alloc::allocate(__n));
  113.     }
  114.     if (!_S_key_initialized ||
  115.         !(__a = (_Pthread_alloc_per_thread_state<_Max_size>*)
  116.                                  pthread_getspecific(_S_key))) {
  117.         __a = _S_get_per_thread_state();
  118.     }
  119.     __my_free_list = __a -> __free_list + _S_freelist_index(__n);
  120.     __result = *__my_free_list;
  121.     if (__result == 0) {
  122.         void *__r = __a -> _M_refill(_S_round_up(__n));
  123.         return __r;
  124.     }
  125.     *__my_free_list = __result -> __free_list_link;
  126.     return (__result);
  127.   };
  128.   /* p may not be 0 */
  129.   static void deallocate(void *__p, size_t __n)
  130.   {
  131.     __obj *__q = (__obj *)__p;
  132.     __obj * volatile * __my_free_list;
  133.     _Pthread_alloc_per_thread_state<_Max_size>* __a;
  134.     if (__n > _Max_size) {
  135.         malloc_alloc::deallocate(__p, __n);
  136.         return;
  137.     }
  138.     if (!_S_key_initialized ||
  139.         !(__a = (_Pthread_alloc_per_thread_state<_Max_size> *)
  140.                 pthread_getspecific(_S_key))) {
  141.         __a = _S_get_per_thread_state();
  142.     }
  143.     __my_free_list = __a->__free_list + _S_freelist_index(__n);
  144.     __q -> __free_list_link = *__my_free_list;
  145.     *__my_free_list = __q;
  146.   }
  147.   static void * reallocate(void *__p, size_t __old_sz, size_t __new_sz);
  148. } ;
  149. typedef _Pthread_alloc_template<> pthread_alloc;
  150. template <size_t _Max_size>
  151. void _Pthread_alloc_template<_Max_size>::_S_destructor(void * __instance)
  152. {
  153.     _M_lock __lock_instance; // Need to acquire lock here.
  154.     _Pthread_alloc_per_thread_state<_Max_size>* __s =
  155.         (_Pthread_alloc_per_thread_state<_Max_size> *)__instance;
  156.     __s -> __next = _S_free_per_thread_states;
  157.     _S_free_per_thread_states = __s;
  158. }
  159. template <size_t _Max_size>
  160. _Pthread_alloc_per_thread_state<_Max_size> *
  161. _Pthread_alloc_template<_Max_size>::_S_new_per_thread_state()
  162. {    
  163.     /* lock already held here. */
  164.     if (0 != _S_free_per_thread_states) {
  165.         _Pthread_alloc_per_thread_state<_Max_size> *__result =
  166. _S_free_per_thread_states;
  167.         _S_free_per_thread_states = _S_free_per_thread_states -> __next;
  168.         return __result;
  169.     } else {
  170.         return new _Pthread_alloc_per_thread_state<_Max_size>;
  171.     }
  172. }
  173. template <size_t _Max_size>
  174. _Pthread_alloc_per_thread_state<_Max_size> *
  175. _Pthread_alloc_template<_Max_size>::_S_get_per_thread_state()
  176. {
  177.     /*REFERENCED*/
  178.     _M_lock __lock_instance; // Need to acquire lock here.
  179.     _Pthread_alloc_per_thread_state<_Max_size> * __result;
  180.     if (!_S_key_initialized) {
  181.         if (pthread_key_create(&_S_key, _S_destructor)) {
  182.             abort();  // failed
  183.         }
  184.         _S_key_initialized = true;
  185.     }
  186.     __result = _S_new_per_thread_state();
  187.     if (pthread_setspecific(_S_key, __result)) abort();
  188.     return __result;
  189. }
  190. /* We allocate memory in large chunks in order to avoid fragmenting     */
  191. /* the malloc heap too much.                                            */
  192. /* We assume that size is properly aligned.                             */
  193. template <size_t _Max_size>
  194. char *_Pthread_alloc_template<_Max_size>
  195. ::_S_chunk_alloc(size_t __size, int &__nobjs)
  196. {
  197.   {
  198.     char * __result;
  199.     size_t __total_bytes;
  200.     size_t __bytes_left;
  201.     /*REFERENCED*/
  202.     _M_lock __lock_instance;         // Acquire lock for this routine
  203.     __total_bytes = __size * __nobjs;
  204.     __bytes_left = _S_end_free - _S_start_free;
  205.     if (__bytes_left >= __total_bytes) {
  206.         __result = _S_start_free;
  207.         _S_start_free += __total_bytes;
  208.         return(__result);
  209.     } else if (__bytes_left >= __size) {
  210.         __nobjs = __bytes_left/__size;
  211.         __total_bytes = __size * __nobjs;
  212.         __result = _S_start_free;
  213.         _S_start_free += __total_bytes;
  214.         return(__result);
  215.     } else {
  216.         size_t __bytes_to_get =
  217. 2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
  218.         // Try to make use of the left-over piece.
  219.         if (__bytes_left > 0) {
  220.             _Pthread_alloc_per_thread_state<_Max_size>* __a = 
  221.                 (_Pthread_alloc_per_thread_state<_Max_size>*)
  222. pthread_getspecific(_S_key);
  223.             __obj * volatile * __my_free_list =
  224.                         __a->__free_list + _S_freelist_index(__bytes_left);
  225.             ((__obj *)_S_start_free) -> __free_list_link = *__my_free_list;
  226.             *__my_free_list = (__obj *)_S_start_free;
  227.         }
  228. #       ifdef _SGI_SOURCE
  229.           // Try to get memory that's aligned on something like a
  230.           // cache line boundary, so as to avoid parceling out
  231.           // parts of the same line to different threads and thus
  232.           // possibly different processors.
  233.           {
  234.             const int __cache_line_size = 128;  // probable upper bound
  235.             __bytes_to_get &= ~(__cache_line_size-1);
  236.             _S_start_free = (char *)memalign(__cache_line_size, __bytes_to_get); 
  237.             if (0 == _S_start_free) {
  238.               _S_start_free = (char *)malloc_alloc::allocate(__bytes_to_get);
  239.             }
  240.           }
  241. #       else  /* !SGI_SOURCE */
  242.           _S_start_free = (char *)malloc_alloc::allocate(__bytes_to_get);
  243. #       endif
  244.         _S_heap_size += __bytes_to_get;
  245.         _S_end_free = _S_start_free + __bytes_to_get;
  246.     }
  247.   }
  248.   // lock is released here
  249.   return(_S_chunk_alloc(__size, __nobjs));
  250. }
  251. /* Returns an object of size n, and optionally adds to size n free list.*/
  252. /* We assume that n is properly aligned.                                */
  253. /* We hold the allocation lock.                                         */
  254. template <size_t _Max_size>
  255. void *_Pthread_alloc_per_thread_state<_Max_size>
  256. ::_M_refill(size_t __n)
  257. {
  258.     int __nobjs = 128;
  259.     char * __chunk =
  260. _Pthread_alloc_template<_Max_size>::_S_chunk_alloc(__n, __nobjs);
  261.     __obj * volatile * __my_free_list;
  262.     __obj * __result;
  263.     __obj * __current_obj, * __next_obj;
  264.     int __i;
  265.     if (1 == __nobjs)  {
  266.         return(__chunk);
  267.     }
  268.     __my_free_list = __free_list
  269.  + _Pthread_alloc_template<_Max_size>::_S_freelist_index(__n);
  270.     /* Build free list in chunk */
  271.       __result = (__obj *)__chunk;
  272.       *__my_free_list = __next_obj = (__obj *)(__chunk + __n);
  273.       for (__i = 1; ; __i++) {
  274.         __current_obj = __next_obj;
  275.         __next_obj = (__obj *)((char *)__next_obj + __n);
  276.         if (__nobjs - 1 == __i) {
  277.             __current_obj -> __free_list_link = 0;
  278.             break;
  279.         } else {
  280.             __current_obj -> __free_list_link = __next_obj;
  281.         }
  282.       }
  283.     return(__result);
  284. }
  285. template <size_t _Max_size>
  286. void *_Pthread_alloc_template<_Max_size>
  287. ::reallocate(void *__p, size_t __old_sz, size_t __new_sz)
  288. {
  289.     void * __result;
  290.     size_t __copy_sz;
  291.     if (__old_sz > _Max_size
  292. && __new_sz > _Max_size) {
  293.         return(realloc(__p, __new_sz));
  294.     }
  295.     if (_S_round_up(__old_sz) == _S_round_up(__new_sz)) return(__p);
  296.     __result = allocate(__new_sz);
  297.     __copy_sz = __new_sz > __old_sz? __old_sz : __new_sz;
  298.     memcpy(__result, __p, __copy_sz);
  299.     deallocate(__p, __old_sz);
  300.     return(__result);
  301. }
  302. template <size_t _Max_size>
  303. _Pthread_alloc_per_thread_state<_Max_size> *
  304. _Pthread_alloc_template<_Max_size>::_S_free_per_thread_states = 0;
  305. template <size_t _Max_size>
  306. pthread_key_t _Pthread_alloc_template<_Max_size>::_S_key;
  307. template <size_t _Max_size>
  308. bool _Pthread_alloc_template<_Max_size>::_S_key_initialized = false;
  309. template <size_t _Max_size>
  310. pthread_mutex_t _Pthread_alloc_template<_Max_size>::_S_chunk_allocator_lock
  311. = PTHREAD_MUTEX_INITIALIZER;
  312. template <size_t _Max_size>
  313. char *_Pthread_alloc_template<_Max_size>
  314. ::_S_start_free = 0;
  315. template <size_t _Max_size>
  316. char *_Pthread_alloc_template<_Max_size>
  317. ::_S_end_free = 0;
  318. template <size_t _Max_size>
  319. size_t _Pthread_alloc_template<_Max_size>
  320. ::_S_heap_size = 0;
  321. #ifdef __STL_USE_STD_ALLOCATORS
  322. template <class _T>
  323. class pthread_allocator {
  324.   typedef pthread_alloc _S_Alloc;          // The underlying allocator.
  325. public:
  326.   typedef size_t    size_type;
  327.   typedef ptrdiff_t difference_type;
  328.   typedef _T*       pointer;
  329.   typedef const _T* const_pointer;
  330.   typedef _T&       reference;
  331.   typedef const _T&  const_reference;
  332.   typedef _T        value_type;
  333.   template <class _U> struct rebind {
  334.     typedef pthread_allocator<_U> other;
  335.   };
  336.   pthread_allocator() __STL_NOTHROW {}
  337.   pthread_allocator(const pthread_allocator& a) __STL_NOTHROW {}
  338.   template <class _U> pthread_allocator(const pthread_allocator<_U>&)
  339. __STL_NOTHROW {}
  340.   ~pthread_allocator() __STL_NOTHROW {}
  341.   pointer address(reference __x) const { return &__x; }
  342.   const_pointer address(const_reference __x) const { return &__x; }
  343.   // __n is permitted to be 0.  The C++ standard says nothing about what
  344.   // the return value is when __n == 0.
  345.   _T* allocate(size_type __n, const void* = 0) {
  346.     return __n != 0 ? static_cast<_T*>(_S_Alloc::allocate(__n * sizeof(_T))) : 0;
  347.   }
  348.   // p is not permitted to be a null pointer.
  349.   void deallocate(pointer __p, size_type __n)
  350.     { _S_Alloc::deallocate(__p, __n * sizeof(_T)); }
  351.   size_type max_size() const __STL_NOTHROW 
  352.     { return size_t(-1) / sizeof(_T); }
  353.   void construct(pointer __p, const _T& __val) { new(__p) _T(__val); }
  354.   void destroy(pointer _p) { _p->~_T(); }
  355. };
  356. template<>
  357. class pthread_allocator<void> {
  358. public:
  359.   typedef size_t      size_type;
  360.   typedef ptrdiff_t   difference_type;
  361.   typedef void*       pointer;
  362.   typedef const void* const_pointer;
  363.   typedef void        value_type;
  364.   template <class _U> struct rebind {
  365.     typedef pthread_allocator<_U> other;
  366.   };
  367. };
  368. template <size_t _Max_size>
  369. inline bool operator==(const _Pthread_alloc_template<_Max_size>&,
  370.                        const _Pthread_alloc_template<_Max_size>&)
  371. {
  372.   return true;
  373. }
  374. template <class _T1, class _T2>
  375. inline bool operator==(const pthread_allocator<_T1>&,
  376.                        const pthread_allocator<_T2>& a2) 
  377. {
  378.   return true;
  379. }
  380. template <class _T1, class _T2>
  381. inline bool operator!=(const pthread_allocator<_T1>&,
  382.                        const pthread_allocator<_T2>&)
  383. {
  384.   return false;
  385. }
  386. template <class _T, size_t _Max_size>
  387. struct _Alloc_traits<_T, _Pthread_alloc_template<_Max_size> >
  388. {
  389.   static const bool _S_instanceless = true;
  390.   typedef simple_alloc<_T, _Pthread_alloc_template<_Max_size> > _Alloc_type;
  391.   typedef __allocator<_T, _Pthread_alloc_template<_Max_size> > allocator_type;
  392. };
  393. template <class _T, class _U, size_t _Max_size>
  394. struct _Alloc_traits<_T, __allocator<_U, _Pthread_alloc_template<_Max_size> > >
  395. {
  396.   static const bool _S_instanceless = true;
  397.   typedef simple_alloc<_T, _Pthread_alloc_template<_Max_size> > _Alloc_type;
  398.   typedef __allocator<_T, _Pthread_alloc_template<_Max_size> > allocator_type;
  399. };
  400. template <class _T, class _U>
  401. struct _Alloc_traits<_T, pthread_allocator<_U> >
  402. {
  403.   static const bool _S_instanceless = true;
  404.   typedef simple_alloc<_T, _Pthread_alloc_template<> > _Alloc_type;
  405.   typedef pthread_allocator<_T> allocator_type;
  406. };
  407. #endif /* __STL_USE_STD_ALLOCATORS */
  408. __STL_END_NAMESPACE
  409. #endif /* __SGI_STL_PTHREAD_ALLOC */
  410. // Local Variables:
  411. // mode:C++
  412. // End: