00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #ifndef _MT_ALLOCATOR_H
00035 #define _MT_ALLOCATOR_H 1
00036
00037 #include <new>
00038 #include <cstdlib>
00039 #include <bits/functexcept.h>
00040 #include <ext/atomicity.h>
00041 #include <bits/stl_move.h>
00042
00043 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
00044
00045 using std::size_t;
00046 using std::ptrdiff_t;
00047
00048 typedef void (*__destroy_handler)(void*);
00049
00050
00051 struct __pool_base
00052 {
00053
00054
00055 typedef unsigned short int _Binmap_type;
00056
00057
00058
00059 struct _Tune
00060 {
00061
00062 enum { _S_align = 8 };
00063 enum { _S_max_bytes = 128 };
00064 enum { _S_min_bin = 8 };
00065 enum { _S_chunk_size = 4096 - 4 * sizeof(void*) };
00066 enum { _S_max_threads = 4096 };
00067 enum { _S_freelist_headroom = 10 };
00068
00069
00070
00071
00072 size_t _M_align;
00073
00074
00075
00076
00077
00078
00079 size_t _M_max_bytes;
00080
00081
00082
00083
00084 size_t _M_min_bin;
00085
00086
00087
00088
00089
00090
00091
00092 size_t _M_chunk_size;
00093
00094
00095
00096
00097
00098
00099
00100 size_t _M_max_threads;
00101
00102
00103
00104
00105
00106
00107
00108 size_t _M_freelist_headroom;
00109
00110
00111 bool _M_force_new;
00112
00113 explicit
00114 _Tune()
00115 : _M_align(_S_align), _M_max_bytes(_S_max_bytes), _M_min_bin(_S_min_bin),
00116 _M_chunk_size(_S_chunk_size), _M_max_threads(_S_max_threads),
00117 _M_freelist_headroom(_S_freelist_headroom),
00118 _M_force_new(std::getenv("GLIBCXX_FORCE_NEW") ? true : false)
00119 { }
00120
00121 explicit
00122 _Tune(size_t __align, size_t __maxb, size_t __minbin, size_t __chunk,
00123 size_t __maxthreads, size_t __headroom, bool __force)
00124 : _M_align(__align), _M_max_bytes(__maxb), _M_min_bin(__minbin),
00125 _M_chunk_size(__chunk), _M_max_threads(__maxthreads),
00126 _M_freelist_headroom(__headroom), _M_force_new(__force)
00127 { }
00128 };
00129
00130 struct _Block_address
00131 {
00132 void* _M_initial;
00133 _Block_address* _M_next;
00134 };
00135
00136 const _Tune&
00137 _M_get_options() const
00138 { return _M_options; }
00139
00140 void
00141 _M_set_options(_Tune __t)
00142 {
00143 if (!_M_init)
00144 _M_options = __t;
00145 }
00146
00147 bool
00148 _M_check_threshold(size_t __bytes)
00149 { return __bytes > _M_options._M_max_bytes || _M_options._M_force_new; }
00150
00151 size_t
00152 _M_get_binmap(size_t __bytes)
00153 { return _M_binmap[__bytes]; }
00154
00155 size_t
00156 _M_get_align()
00157 { return _M_options._M_align; }
00158
00159 explicit
00160 __pool_base()
00161 : _M_options(_Tune()), _M_binmap(NULL), _M_init(false) { }
00162
00163 explicit
00164 __pool_base(const _Tune& __options)
00165 : _M_options(__options), _M_binmap(NULL), _M_init(false) { }
00166
00167 private:
00168 explicit
00169 __pool_base(const __pool_base&);
00170
00171 __pool_base&
00172 operator=(const __pool_base&);
00173
00174 protected:
00175
00176 _Tune _M_options;
00177
00178 _Binmap_type* _M_binmap;
00179
00180
00181
00182
00183 bool _M_init;
00184 };
00185
00186
00187
00188
00189
00190
00191 template<bool _Thread>
00192 class __pool;
00193
00194
00195 template<>
00196 class __pool<false> : public __pool_base
00197 {
00198 public:
00199 union _Block_record
00200 {
00201
00202 _Block_record* _M_next;
00203 };
00204
00205 struct _Bin_record
00206 {
00207
00208 _Block_record** _M_first;
00209
00210
00211 _Block_address* _M_address;
00212 };
00213
00214 void
00215 _M_initialize_once()
00216 {
00217 if (__builtin_expect(_M_init == false, false))
00218 _M_initialize();
00219 }
00220
00221 void
00222 _M_destroy() throw();
00223
00224 char*
00225 _M_reserve_block(size_t __bytes, const size_t __thread_id);
00226
00227 void
00228 _M_reclaim_block(char* __p, size_t __bytes);
00229
00230 size_t
00231 _M_get_thread_id() { return 0; }
00232
00233 const _Bin_record&
00234 _M_get_bin(size_t __which)
00235 { return _M_bin[__which]; }
00236
00237 void
00238 _M_adjust_freelist(const _Bin_record&, _Block_record*, size_t)
00239 { }
00240
00241 explicit __pool()
00242 : _M_bin(NULL), _M_bin_size(1) { }
00243
00244 explicit __pool(const __pool_base::_Tune& __tune)
00245 : __pool_base(__tune), _M_bin(NULL), _M_bin_size(1) { }
00246
00247 private:
00248
00249
00250
00251 _Bin_record* _M_bin;
00252
00253
00254 size_t _M_bin_size;
00255
00256 void
00257 _M_initialize();
00258 };
00259
00260 #ifdef __GTHREADS
00261
00262 template<>
00263 class __pool<true> : public __pool_base
00264 {
00265 public:
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275 struct _Thread_record
00276 {
00277
00278 _Thread_record* _M_next;
00279
00280
00281 size_t _M_id;
00282 };
00283
00284 union _Block_record
00285 {
00286
00287 _Block_record* _M_next;
00288
00289
00290 size_t _M_thread_id;
00291 };
00292
00293 struct _Bin_record
00294 {
00295
00296
00297
00298 _Block_record** _M_first;
00299
00300
00301 _Block_address* _M_address;
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312 size_t* _M_free;
00313 size_t* _M_used;
00314
00315
00316
00317
00318 __gthread_mutex_t* _M_mutex;
00319 };
00320
00321
00322 void
00323 _M_initialize(__destroy_handler);
00324
00325 void
00326 _M_initialize_once()
00327 {
00328 if (__builtin_expect(_M_init == false, false))
00329 _M_initialize();
00330 }
00331
00332 void
00333 _M_destroy() throw();
00334
00335 char*
00336 _M_reserve_block(size_t __bytes, const size_t __thread_id);
00337
00338 void
00339 _M_reclaim_block(char* __p, size_t __bytes);
00340
00341 const _Bin_record&
00342 _M_get_bin(size_t __which)
00343 { return _M_bin[__which]; }
00344
00345 void
00346 _M_adjust_freelist(const _Bin_record& __bin, _Block_record* __block,
00347 size_t __thread_id)
00348 {
00349 if (__gthread_active_p())
00350 {
00351 __block->_M_thread_id = __thread_id;
00352 --__bin._M_free[__thread_id];
00353 ++__bin._M_used[__thread_id];
00354 }
00355 }
00356
00357
00358 void
00359 _M_destroy_thread_key(void*);
00360
00361 size_t
00362 _M_get_thread_id();
00363
00364 explicit __pool()
00365 : _M_bin(NULL), _M_bin_size(1), _M_thread_freelist(NULL)
00366 { }
00367
00368 explicit __pool(const __pool_base::_Tune& __tune)
00369 : __pool_base(__tune), _M_bin(NULL), _M_bin_size(1),
00370 _M_thread_freelist(NULL)
00371 { }
00372
00373 private:
00374
00375
00376
00377 _Bin_record* _M_bin;
00378
00379
00380 size_t _M_bin_size;
00381
00382 _Thread_record* _M_thread_freelist;
00383 void* _M_thread_freelist_initial;
00384
00385 void
00386 _M_initialize();
00387 };
00388 #endif
00389
00390 template<template <bool> class _PoolTp, bool _Thread>
00391 struct __common_pool
00392 {
00393 typedef _PoolTp<_Thread> pool_type;
00394
00395 static pool_type&
00396 _S_get_pool()
00397 {
00398 static pool_type _S_pool;
00399 return _S_pool;
00400 }
00401 };
00402
00403 template<template <bool> class _PoolTp, bool _Thread>
00404 struct __common_pool_base;
00405
00406 template<template <bool> class _PoolTp>
00407 struct __common_pool_base<_PoolTp, false>
00408 : public __common_pool<_PoolTp, false>
00409 {
00410 using __common_pool<_PoolTp, false>::_S_get_pool;
00411
00412 static void
00413 _S_initialize_once()
00414 {
00415 static bool __init;
00416 if (__builtin_expect(__init == false, false))
00417 {
00418 _S_get_pool()._M_initialize_once();
00419 __init = true;
00420 }
00421 }
00422 };
00423
00424 #ifdef __GTHREADS
00425 template<template <bool> class _PoolTp>
00426 struct __common_pool_base<_PoolTp, true>
00427 : public __common_pool<_PoolTp, true>
00428 {
00429 using __common_pool<_PoolTp, true>::_S_get_pool;
00430
00431 static void
00432 _S_initialize()
00433 { _S_get_pool()._M_initialize_once(); }
00434
00435 static void
00436 _S_initialize_once()
00437 {
00438 static bool __init;
00439 if (__builtin_expect(__init == false, false))
00440 {
00441 if (__gthread_active_p())
00442 {
00443
00444 static __gthread_once_t __once = __GTHREAD_ONCE_INIT;
00445 __gthread_once(&__once, _S_initialize);
00446 }
00447
00448
00449
00450
00451 _S_get_pool()._M_initialize_once();
00452 __init = true;
00453 }
00454 }
00455 };
00456 #endif
00457
00458
00459 template<template <bool> class _PoolTp, bool _Thread>
00460 struct __common_pool_policy : public __common_pool_base<_PoolTp, _Thread>
00461 {
00462 template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp,
00463 bool _Thread1 = _Thread>
00464 struct _M_rebind
00465 { typedef __common_pool_policy<_PoolTp1, _Thread1> other; };
00466
00467 using __common_pool_base<_PoolTp, _Thread>::_S_get_pool;
00468 using __common_pool_base<_PoolTp, _Thread>::_S_initialize_once;
00469 };
00470
00471
00472 template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
00473 struct __per_type_pool
00474 {
00475 typedef _Tp value_type;
00476 typedef _PoolTp<_Thread> pool_type;
00477
00478 static pool_type&
00479 _S_get_pool()
00480 {
00481
00482 typedef typename pool_type::_Block_record _Block_record;
00483 const static size_t __a = (__alignof__(_Tp) >= sizeof(_Block_record)
00484 ? __alignof__(_Tp) : sizeof(_Block_record));
00485
00486 typedef typename __pool_base::_Tune _Tune;
00487 static _Tune _S_tune(__a, sizeof(_Tp) * 64,
00488 sizeof(_Tp) * 2 >= __a ? sizeof(_Tp) * 2 : __a,
00489 sizeof(_Tp) * size_t(_Tune::_S_chunk_size),
00490 _Tune::_S_max_threads,
00491 _Tune::_S_freelist_headroom,
00492 std::getenv("GLIBCXX_FORCE_NEW") ? true : false);
00493 static pool_type _S_pool(_S_tune);
00494 return _S_pool;
00495 }
00496 };
00497
00498 template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
00499 struct __per_type_pool_base;
00500
00501 template<typename _Tp, template <bool> class _PoolTp>
00502 struct __per_type_pool_base<_Tp, _PoolTp, false>
00503 : public __per_type_pool<_Tp, _PoolTp, false>
00504 {
00505 using __per_type_pool<_Tp, _PoolTp, false>::_S_get_pool;
00506
00507 static void
00508 _S_initialize_once()
00509 {
00510 static bool __init;
00511 if (__builtin_expect(__init == false, false))
00512 {
00513 _S_get_pool()._M_initialize_once();
00514 __init = true;
00515 }
00516 }
00517 };
00518
00519 #ifdef __GTHREADS
00520 template<typename _Tp, template <bool> class _PoolTp>
00521 struct __per_type_pool_base<_Tp, _PoolTp, true>
00522 : public __per_type_pool<_Tp, _PoolTp, true>
00523 {
00524 using __per_type_pool<_Tp, _PoolTp, true>::_S_get_pool;
00525
00526 static void
00527 _S_initialize()
00528 { _S_get_pool()._M_initialize_once(); }
00529
00530 static void
00531 _S_initialize_once()
00532 {
00533 static bool __init;
00534 if (__builtin_expect(__init == false, false))
00535 {
00536 if (__gthread_active_p())
00537 {
00538
00539 static __gthread_once_t __once = __GTHREAD_ONCE_INIT;
00540 __gthread_once(&__once, _S_initialize);
00541 }
00542
00543
00544
00545
00546 _S_get_pool()._M_initialize_once();
00547 __init = true;
00548 }
00549 }
00550 };
00551 #endif
00552
00553
00554 template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
00555 struct __per_type_pool_policy
00556 : public __per_type_pool_base<_Tp, _PoolTp, _Thread>
00557 {
00558 template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp,
00559 bool _Thread1 = _Thread>
00560 struct _M_rebind
00561 { typedef __per_type_pool_policy<_Tp1, _PoolTp1, _Thread1> other; };
00562
00563 using __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_get_pool;
00564 using __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_initialize_once;
00565 };
00566
00567
00568
00569 template<typename _Tp>
00570 class __mt_alloc_base
00571 {
00572 public:
00573 typedef size_t size_type;
00574 typedef ptrdiff_t difference_type;
00575 typedef _Tp* pointer;
00576 typedef const _Tp* const_pointer;
00577 typedef _Tp& reference;
00578 typedef const _Tp& const_reference;
00579 typedef _Tp value_type;
00580
00581 pointer
00582 address(reference __x) const
00583 { return &__x; }
00584
00585 const_pointer
00586 address(const_reference __x) const
00587 { return &__x; }
00588
00589 size_type
00590 max_size() const throw()
00591 { return size_t(-1) / sizeof(_Tp); }
00592
00593
00594
00595 void
00596 construct(pointer __p, const _Tp& __val)
00597 { ::new((void *)__p) _Tp(__val); }
00598
00599 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00600 template<typename... _Args>
00601 void
00602 construct(pointer __p, _Args&&... __args)
00603 { ::new((void *)__p) _Tp(std::forward<_Args>(__args)...); }
00604 #endif
00605
00606 void
00607 destroy(pointer __p) { __p->~_Tp(); }
00608 };
00609
00610 #ifdef __GTHREADS
00611 #define __thread_default true
00612 #else
00613 #define __thread_default false
00614 #endif
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626 template<typename _Tp,
00627 typename _Poolp = __common_pool_policy<__pool, __thread_default> >
00628 class __mt_alloc : public __mt_alloc_base<_Tp>
00629 {
00630 public:
00631 typedef size_t size_type;
00632 typedef ptrdiff_t difference_type;
00633 typedef _Tp* pointer;
00634 typedef const _Tp* const_pointer;
00635 typedef _Tp& reference;
00636 typedef const _Tp& const_reference;
00637 typedef _Tp value_type;
00638 typedef _Poolp __policy_type;
00639 typedef typename _Poolp::pool_type __pool_type;
00640
00641 template<typename _Tp1, typename _Poolp1 = _Poolp>
00642 struct rebind
00643 {
00644 typedef typename _Poolp1::template _M_rebind<_Tp1>::other pol_type;
00645 typedef __mt_alloc<_Tp1, pol_type> other;
00646 };
00647
00648 __mt_alloc() throw() { }
00649
00650 __mt_alloc(const __mt_alloc&) throw() { }
00651
00652 template<typename _Tp1, typename _Poolp1>
00653 __mt_alloc(const __mt_alloc<_Tp1, _Poolp1>&) throw() { }
00654
00655 ~__mt_alloc() throw() { }
00656
00657 pointer
00658 allocate(size_type __n, const void* = 0);
00659
00660 void
00661 deallocate(pointer __p, size_type __n);
00662
00663 const __pool_base::_Tune
00664 _M_get_options()
00665 {
00666
00667 return __policy_type::_S_get_pool()._M_get_options();
00668 }
00669
00670 void
00671 _M_set_options(__pool_base::_Tune __t)
00672 { __policy_type::_S_get_pool()._M_set_options(__t); }
00673 };
00674
00675 template<typename _Tp, typename _Poolp>
00676 typename __mt_alloc<_Tp, _Poolp>::pointer
00677 __mt_alloc<_Tp, _Poolp>::
00678 allocate(size_type __n, const void*)
00679 {
00680 if (__builtin_expect(__n > this->max_size(), false))
00681 std::__throw_bad_alloc();
00682
00683 __policy_type::_S_initialize_once();
00684
00685
00686
00687 __pool_type& __pool = __policy_type::_S_get_pool();
00688 const size_t __bytes = __n * sizeof(_Tp);
00689 if (__pool._M_check_threshold(__bytes))
00690 {
00691 void* __ret = ::operator new(__bytes);
00692 return static_cast<_Tp*>(__ret);
00693 }
00694
00695
00696 const size_t __which = __pool._M_get_binmap(__bytes);
00697 const size_t __thread_id = __pool._M_get_thread_id();
00698
00699
00700
00701 char* __c;
00702 typedef typename __pool_type::_Bin_record _Bin_record;
00703 const _Bin_record& __bin = __pool._M_get_bin(__which);
00704 if (__bin._M_first[__thread_id])
00705 {
00706
00707 typedef typename __pool_type::_Block_record _Block_record;
00708 _Block_record* __block = __bin._M_first[__thread_id];
00709 __bin._M_first[__thread_id] = __block->_M_next;
00710
00711 __pool._M_adjust_freelist(__bin, __block, __thread_id);
00712 __c = reinterpret_cast<char*>(__block) + __pool._M_get_align();
00713 }
00714 else
00715 {
00716
00717 __c = __pool._M_reserve_block(__bytes, __thread_id);
00718 }
00719 return static_cast<_Tp*>(static_cast<void*>(__c));
00720 }
00721
00722 template<typename _Tp, typename _Poolp>
00723 void
00724 __mt_alloc<_Tp, _Poolp>::
00725 deallocate(pointer __p, size_type __n)
00726 {
00727 if (__builtin_expect(__p != 0, true))
00728 {
00729
00730
00731 __pool_type& __pool = __policy_type::_S_get_pool();
00732 const size_t __bytes = __n * sizeof(_Tp);
00733 if (__pool._M_check_threshold(__bytes))
00734 ::operator delete(__p);
00735 else
00736 __pool._M_reclaim_block(reinterpret_cast<char*>(__p), __bytes);
00737 }
00738 }
00739
00740 template<typename _Tp, typename _Poolp>
00741 inline bool
00742 operator==(const __mt_alloc<_Tp, _Poolp>&, const __mt_alloc<_Tp, _Poolp>&)
00743 { return true; }
00744
00745 template<typename _Tp, typename _Poolp>
00746 inline bool
00747 operator!=(const __mt_alloc<_Tp, _Poolp>&, const __mt_alloc<_Tp, _Poolp>&)
00748 { return false; }
00749
00750 #undef __thread_default
00751
00752 _GLIBCXX_END_NAMESPACE
00753
00754 #endif