00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifndef _CPP_BITS_PTHREAD_ALLOCIMPL_H
00015 #define _CPP_BITS_PTHREAD_ALLOCIMPL_H 1
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <bits/c++config.h>
00031 #include <bits/std_cerrno.h>
00032 #include <bits/stl_alloc.h>
00033 #ifndef __RESTRICT
00034 # define __RESTRICT
00035 #endif
00036
00037 #include <new>
00038
00039 namespace std
00040 {
00041
00042 #define __STL_DATA_ALIGNMENT 8
00043
00044 union _Pthread_alloc_obj {
00045 union _Pthread_alloc_obj * __free_list_link;
00046 char __client_data[__STL_DATA_ALIGNMENT];
00047 };
00048
00049
00050
00051
00052
00053
00054 template<size_t _Max_size>
00055 struct _Pthread_alloc_per_thread_state {
00056 typedef _Pthread_alloc_obj __obj;
00057 enum { _S_NFREELISTS = _Max_size/__STL_DATA_ALIGNMENT };
00058 _Pthread_alloc_obj* volatile __free_list[_S_NFREELISTS];
00059 _Pthread_alloc_per_thread_state<_Max_size> * __next;
00060
00061
00062
00063
00064
00065 _Pthread_alloc_per_thread_state() : __next(0)
00066 {
00067 memset((void *)__free_list, 0, (size_t) _S_NFREELISTS * sizeof(__obj *));
00068 }
00069
00070 void *_M_refill(size_t __n);
00071 };
00072
00073
00074
00075
00076
00077 template <size_t _Max_size = 128>
00078 class _Pthread_alloc_template {
00079
00080 public:
00081
00082 typedef _Pthread_alloc_obj __obj;
00083
00084
00085
00086 static char *_S_chunk_alloc(size_t __size, int &__nobjs);
00087
00088 enum {_S_ALIGN = __STL_DATA_ALIGNMENT};
00089
00090 static size_t _S_round_up(size_t __bytes) {
00091 return (((__bytes) + (int) _S_ALIGN-1) & ~((int) _S_ALIGN - 1));
00092 }
00093 static size_t _S_freelist_index(size_t __bytes) {
00094 return (((__bytes) + (int) _S_ALIGN-1)/(int)_S_ALIGN - 1);
00095 }
00096
00097 private:
00098
00099
00100 static pthread_mutex_t _S_chunk_allocator_lock;
00101 static char *_S_start_free;
00102 static char *_S_end_free;
00103 static size_t _S_heap_size;
00104 static _Pthread_alloc_per_thread_state<_Max_size>* _S_free_per_thread_states;
00105 static pthread_key_t _S_key;
00106 static bool _S_key_initialized;
00107
00108
00109 static void _S_destructor(void *instance);
00110
00111
00112 static _Pthread_alloc_per_thread_state<_Max_size> *_S_new_per_thread_state();
00113
00114 static _Pthread_alloc_per_thread_state<_Max_size> *_S_get_per_thread_state();
00115
00116
00117 class _M_lock;
00118 friend class _M_lock;
00119 class _M_lock {
00120 public:
00121 _M_lock () { pthread_mutex_lock(&_S_chunk_allocator_lock); }
00122 ~_M_lock () { pthread_mutex_unlock(&_S_chunk_allocator_lock); }
00123 };
00124
00125 public:
00126
00127
00128 static void * allocate(size_t __n)
00129 {
00130 __obj * volatile * __my_free_list;
00131 __obj * __RESTRICT __result;
00132 _Pthread_alloc_per_thread_state<_Max_size>* __a;
00133
00134 if (__n > _Max_size) {
00135 return(malloc_alloc::allocate(__n));
00136 }
00137 if (!_S_key_initialized ||
00138 !(__a = (_Pthread_alloc_per_thread_state<_Max_size>*)
00139 pthread_getspecific(_S_key))) {
00140 __a = _S_get_per_thread_state();
00141 }
00142 __my_free_list = __a -> __free_list + _S_freelist_index(__n);
00143 __result = *__my_free_list;
00144 if (__result == 0) {
00145 void *__r = __a -> _M_refill(_S_round_up(__n));
00146 return __r;
00147 }
00148 *__my_free_list = __result -> __free_list_link;
00149 return (__result);
00150 };
00151
00152
00153 static void deallocate(void *__p, size_t __n)
00154 {
00155 __obj *__q = (__obj *)__p;
00156 __obj * volatile * __my_free_list;
00157 _Pthread_alloc_per_thread_state<_Max_size>* __a;
00158
00159 if (__n > _Max_size) {
00160 malloc_alloc::deallocate(__p, __n);
00161 return;
00162 }
00163 if (!_S_key_initialized ||
00164 !(__a = (_Pthread_alloc_per_thread_state<_Max_size> *)
00165 pthread_getspecific(_S_key))) {
00166 __a = _S_get_per_thread_state();
00167 }
00168 __my_free_list = __a->__free_list + _S_freelist_index(__n);
00169 __q -> __free_list_link = *__my_free_list;
00170 *__my_free_list = __q;
00171 }
00172
00173 static void * reallocate(void *__p, size_t __old_sz, size_t __new_sz);
00174
00175 } ;
00176
00177 typedef _Pthread_alloc_template<> pthread_alloc;
00178
00179
00180 template <size_t _Max_size>
00181 void _Pthread_alloc_template<_Max_size>::_S_destructor(void * __instance)
00182 {
00183 _M_lock __lock_instance;
00184 _Pthread_alloc_per_thread_state<_Max_size>* __s =
00185 (_Pthread_alloc_per_thread_state<_Max_size> *)__instance;
00186 __s -> __next = _S_free_per_thread_states;
00187 _S_free_per_thread_states = __s;
00188 }
00189
00190 template <size_t _Max_size>
00191 _Pthread_alloc_per_thread_state<_Max_size> *
00192 _Pthread_alloc_template<_Max_size>::_S_new_per_thread_state()
00193 {
00194
00195 if (0 != _S_free_per_thread_states) {
00196 _Pthread_alloc_per_thread_state<_Max_size> *__result =
00197 _S_free_per_thread_states;
00198 _S_free_per_thread_states = _S_free_per_thread_states -> __next;
00199 return __result;
00200 } else {
00201 return new _Pthread_alloc_per_thread_state<_Max_size>;
00202 }
00203 }
00204
00205 template <size_t _Max_size>
00206 _Pthread_alloc_per_thread_state<_Max_size> *
00207 _Pthread_alloc_template<_Max_size>::_S_get_per_thread_state()
00208 {
00209
00210 _M_lock __lock_instance;
00211 int __ret_code;
00212 _Pthread_alloc_per_thread_state<_Max_size> * __result;
00213 if (!_S_key_initialized) {
00214 if (pthread_key_create(&_S_key, _S_destructor)) {
00215 std::__throw_bad_alloc();
00216 }
00217 _S_key_initialized = true;
00218 }
00219 __result = _S_new_per_thread_state();
00220 __ret_code = pthread_setspecific(_S_key, __result);
00221 if (__ret_code) {
00222 if (__ret_code == ENOMEM) {
00223 std::__throw_bad_alloc();
00224 } else {
00225
00226 abort();
00227 }
00228 }
00229 return __result;
00230 }
00231
00232
00233
00234
00235 template <size_t _Max_size>
00236 char *_Pthread_alloc_template<_Max_size>
00237 ::_S_chunk_alloc(size_t __size, int &__nobjs)
00238 {
00239 {
00240 char * __result;
00241 size_t __total_bytes;
00242 size_t __bytes_left;
00243
00244 _M_lock __lock_instance;
00245
00246 __total_bytes = __size * __nobjs;
00247 __bytes_left = _S_end_free - _S_start_free;
00248 if (__bytes_left >= __total_bytes) {
00249 __result = _S_start_free;
00250 _S_start_free += __total_bytes;
00251 return(__result);
00252 } else if (__bytes_left >= __size) {
00253 __nobjs = __bytes_left/__size;
00254 __total_bytes = __size * __nobjs;
00255 __result = _S_start_free;
00256 _S_start_free += __total_bytes;
00257 return(__result);
00258 } else {
00259 size_t __bytes_to_get =
00260 2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
00261
00262 if (__bytes_left > 0) {
00263 _Pthread_alloc_per_thread_state<_Max_size>* __a =
00264 (_Pthread_alloc_per_thread_state<_Max_size>*)
00265 pthread_getspecific(_S_key);
00266 __obj * volatile * __my_free_list =
00267 __a->__free_list + _S_freelist_index(__bytes_left);
00268
00269 ((__obj *)_S_start_free) -> __free_list_link = *__my_free_list;
00270 *__my_free_list = (__obj *)_S_start_free;
00271 }
00272 # ifdef _SGI_SOURCE
00273
00274
00275
00276
00277 {
00278 const int __cache_line_size = 128;
00279 __bytes_to_get &= ~(__cache_line_size-1);
00280 _S_start_free = (char *)memalign(__cache_line_size, __bytes_to_get);
00281 if (0 == _S_start_free) {
00282 _S_start_free = (char *)malloc_alloc::allocate(__bytes_to_get);
00283 }
00284 }
00285 # else
00286 _S_start_free = (char *)malloc_alloc::allocate(__bytes_to_get);
00287 # endif
00288 _S_heap_size += __bytes_to_get;
00289 _S_end_free = _S_start_free + __bytes_to_get;
00290 }
00291 }
00292
00293 return(_S_chunk_alloc(__size, __nobjs));
00294 }
00295
00296
00297
00298
00299
00300 template <size_t _Max_size>
00301 void *_Pthread_alloc_per_thread_state<_Max_size>
00302 ::_M_refill(size_t __n)
00303 {
00304 int __nobjs = 128;
00305 char * __chunk =
00306 _Pthread_alloc_template<_Max_size>::_S_chunk_alloc(__n, __nobjs);
00307 __obj * volatile * __my_free_list;
00308 __obj * __result;
00309 __obj * __current_obj, * __next_obj;
00310 int __i;
00311
00312 if (1 == __nobjs) {
00313 return(__chunk);
00314 }
00315 __my_free_list = __free_list
00316 + _Pthread_alloc_template<_Max_size>::_S_freelist_index(__n);
00317
00318
00319 __result = (__obj *)__chunk;
00320 *__my_free_list = __next_obj = (__obj *)(__chunk + __n);
00321 for (__i = 1; ; __i++) {
00322 __current_obj = __next_obj;
00323 __next_obj = (__obj *)((char *)__next_obj + __n);
00324 if (__nobjs - 1 == __i) {
00325 __current_obj -> __free_list_link = 0;
00326 break;
00327 } else {
00328 __current_obj -> __free_list_link = __next_obj;
00329 }
00330 }
00331 return(__result);
00332 }
00333
00334 template <size_t _Max_size>
00335 void *_Pthread_alloc_template<_Max_size>
00336 ::reallocate(void *__p, size_t __old_sz, size_t __new_sz)
00337 {
00338 void * __result;
00339 size_t __copy_sz;
00340
00341 if (__old_sz > _Max_size
00342 && __new_sz > _Max_size) {
00343 return(realloc(__p, __new_sz));
00344 }
00345 if (_S_round_up(__old_sz) == _S_round_up(__new_sz)) return(__p);
00346 __result = allocate(__new_sz);
00347 __copy_sz = __new_sz > __old_sz? __old_sz : __new_sz;
00348 memcpy(__result, __p, __copy_sz);
00349 deallocate(__p, __old_sz);
00350 return(__result);
00351 }
00352
00353 template <size_t _Max_size>
00354 _Pthread_alloc_per_thread_state<_Max_size> *
00355 _Pthread_alloc_template<_Max_size>::_S_free_per_thread_states = 0;
00356
00357 template <size_t _Max_size>
00358 pthread_key_t _Pthread_alloc_template<_Max_size>::_S_key;
00359
00360 template <size_t _Max_size>
00361 bool _Pthread_alloc_template<_Max_size>::_S_key_initialized = false;
00362
00363 template <size_t _Max_size>
00364 pthread_mutex_t _Pthread_alloc_template<_Max_size>::_S_chunk_allocator_lock
00365 = PTHREAD_MUTEX_INITIALIZER;
00366
00367 template <size_t _Max_size>
00368 char *_Pthread_alloc_template<_Max_size>
00369 ::_S_start_free = 0;
00370
00371 template <size_t _Max_size>
00372 char *_Pthread_alloc_template<_Max_size>
00373 ::_S_end_free = 0;
00374
00375 template <size_t _Max_size>
00376 size_t _Pthread_alloc_template<_Max_size>
00377 ::_S_heap_size = 0;
00378
00379
00380 template <class _Tp>
00381 class pthread_allocator {
00382 typedef pthread_alloc _S_Alloc;
00383 public:
00384 typedef size_t size_type;
00385 typedef ptrdiff_t difference_type;
00386 typedef _Tp* pointer;
00387 typedef const _Tp* const_pointer;
00388 typedef _Tp& reference;
00389 typedef const _Tp& const_reference;
00390 typedef _Tp value_type;
00391
00392 template <class _NewType> struct rebind {
00393 typedef pthread_allocator<_NewType> other;
00394 };
00395
00396 pthread_allocator() __STL_NOTHROW {}
00397 pthread_allocator(const pthread_allocator& a) __STL_NOTHROW {}
00398 template <class _OtherType>
00399 pthread_allocator(const pthread_allocator<_OtherType>&)
00400 __STL_NOTHROW {}
00401 ~pthread_allocator() __STL_NOTHROW {}
00402
00403 pointer address(reference __x) const { return &__x; }
00404 const_pointer address(const_reference __x) const { return &__x; }
00405
00406
00407
00408 _Tp* allocate(size_type __n, const void* = 0) {
00409 return __n != 0 ? static_cast<_Tp*>(_S_Alloc::allocate(__n * sizeof(_Tp)))
00410 : 0;
00411 }
00412
00413
00414 void deallocate(pointer __p, size_type __n)
00415 { _S_Alloc::deallocate(__p, __n * sizeof(_Tp)); }
00416
00417 size_type max_size() const __STL_NOTHROW
00418 { return size_t(-1) / sizeof(_Tp); }
00419
00420 void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }
00421 void destroy(pointer _p) { _p->~_Tp(); }
00422 };
00423
00424 template<>
00425 class pthread_allocator<void> {
00426 public:
00427 typedef size_t size_type;
00428 typedef ptrdiff_t difference_type;
00429 typedef void* pointer;
00430 typedef const void* const_pointer;
00431 typedef void value_type;
00432
00433 template <class _NewType> struct rebind {
00434 typedef pthread_allocator<_NewType> other;
00435 };
00436 };
00437
00438 template <size_t _Max_size>
00439 inline bool operator==(const _Pthread_alloc_template<_Max_size>&,
00440 const _Pthread_alloc_template<_Max_size>&)
00441 {
00442 return true;
00443 }
00444
00445 template <class _T1, class _T2>
00446 inline bool operator==(const pthread_allocator<_T1>&,
00447 const pthread_allocator<_T2>& a2)
00448 {
00449 return true;
00450 }
00451
00452 template <class _T1, class _T2>
00453 inline bool operator!=(const pthread_allocator<_T1>&,
00454 const pthread_allocator<_T2>&)
00455 {
00456 return false;
00457 }
00458
00459 template <class _Tp, size_t _Max_size>
00460 struct _Alloc_traits<_Tp, _Pthread_alloc_template<_Max_size> >
00461 {
00462 static const bool _S_instanceless = true;
00463 typedef simple_alloc<_Tp, _Pthread_alloc_template<_Max_size> > _Alloc_type;
00464 typedef __allocator<_Tp, _Pthread_alloc_template<_Max_size> >
00465 allocator_type;
00466 };
00467
00468 template <class _Tp, class _Atype, size_t _Max>
00469 struct _Alloc_traits<_Tp, __allocator<_Atype, _Pthread_alloc_template<_Max> > >
00470 {
00471 static const bool _S_instanceless = true;
00472 typedef simple_alloc<_Tp, _Pthread_alloc_template<_Max> > _Alloc_type;
00473 typedef __allocator<_Tp, _Pthread_alloc_template<_Max> > allocator_type;
00474 };
00475
00476 template <class _Tp, class _Atype>
00477 struct _Alloc_traits<_Tp, pthread_allocator<_Atype> >
00478 {
00479 static const bool _S_instanceless = true;
00480 typedef simple_alloc<_Tp, _Pthread_alloc_template<> > _Alloc_type;
00481 typedef pthread_allocator<_Tp> allocator_type;
00482 };
00483
00484
00485 }
00486
00487 #endif
00488
00489
00490
00491