pthread_
上传用户:nizebo
上传日期:2022-05-14
资源大小:882k
文件大小:16k
源码类别:

STL

开发平台:

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