diff options
Diffstat (limited to 'libstdc++-v3/include/bits/stl_alloc.h')
-rw-r--r-- | libstdc++-v3/include/bits/stl_alloc.h | 200 |
1 files changed, 97 insertions, 103 deletions
diff --git a/libstdc++-v3/include/bits/stl_alloc.h b/libstdc++-v3/include/bits/stl_alloc.h index 1ae80f40512..fceed498df6 100644 --- a/libstdc++-v3/include/bits/stl_alloc.h +++ b/libstdc++-v3/include/bits/stl_alloc.h @@ -89,6 +89,8 @@ #include <bits/functexcept.h> // For __throw_bad_alloc #include <bits/stl_threads.h> +#include <bits/atomicity.h> + namespace std { /** @@ -111,6 +113,7 @@ namespace std { ::operator delete(__p); } }; + /** * @if maint * A malloc-based allocator. Typically slower than the @@ -159,7 +162,7 @@ namespace std { void (* __old)() = __malloc_alloc_oom_handler; __malloc_alloc_oom_handler = __f; - return(__old); + return __old; } }; @@ -179,11 +182,11 @@ namespace std { __my_malloc_handler = __malloc_alloc_oom_handler; if (0 == __my_malloc_handler) - std::__throw_bad_alloc(); + std::__throw_bad_alloc(); (*__my_malloc_handler)(); __result = malloc(__n); if (__result) - return(__result); + return __result; } } @@ -204,19 +207,13 @@ namespace std (*__my_malloc_handler)(); __result = realloc(__p, __n); if (__result) - return(__result); + return __result; } } #endif - - // Determines the underlying allocator choice for the node allocator. -#ifdef __USE_MALLOC - typedef __malloc_alloc_template<0> __mem_interface; -#else + // Should not be referenced within the library anymore. typedef __new_alloc __mem_interface; -#endif - /** * @if maint @@ -230,25 +227,25 @@ namespace std * (See @link Allocators allocators info @endlink for more.) */ template<typename _Tp, typename _Alloc> - class __simple_alloc - { - public: - static _Tp* - allocate(size_t __n) - { return 0 == __n ? 0 : (_Tp*) _Alloc::allocate(__n * sizeof (_Tp)); } - - static _Tp* - allocate() - { return (_Tp*) _Alloc::allocate(sizeof (_Tp)); } - - static void - deallocate(_Tp* __p, size_t __n) - { if (0 != __n) _Alloc::deallocate(__p, __n * sizeof (_Tp)); } - - static void - deallocate(_Tp* __p) - { _Alloc::deallocate(__p, sizeof (_Tp)); } - }; + class __simple_alloc + { + public: + static _Tp* + allocate(size_t __n) + { return 0 == __n ? 0 : (_Tp*) _Alloc::allocate(__n * sizeof (_Tp)); } + + static _Tp* + allocate() + { return (_Tp*) _Alloc::allocate(sizeof (_Tp)); } + + static void + deallocate(_Tp* __p, size_t __n) + { if (0 != __n) _Alloc::deallocate(__p, __n * sizeof (_Tp)); } + + static void + deallocate(_Tp* __p) + { _Alloc::deallocate(__p, sizeof (_Tp)); } + }; /** @@ -306,23 +303,16 @@ namespace std }; -#ifdef __USE_MALLOC - - typedef __mem_interface __alloc; - typedef __mem_interface __single_client_alloc; - -#else - - /** * @if maint - * Default node allocator. "SGI" style. Uses __mem_interface for its - * underlying requests (and makes as few requests as possible). - * **** Currently __mem_interface is always __new_alloc, never __malloc*. + * Default node allocator. "SGI" style. Uses various allocators to + * fulfill underlying requests (and makes as few requests as possible + * when in default high-speed pool mode). * * Important implementation properties: + * 0. If globally mandated, then allocate objects from __new_alloc * 1. If the clients request an object of size > _MAX_BYTES, the resulting - * object will be obtained directly from the underlying __mem_interface. + * object will be obtained directly from __new_alloc * 2. In all other cases, we allocate an object of size exactly * _S_round_up(requested_size). Thus the client has enough size * information that we can return the object to the proper free list @@ -393,54 +383,69 @@ namespace std } __attribute__ ((__unused__)); friend struct _Lock; + static _Atomic_word _S_force_new; + public: // __n must be > 0 static void* allocate(size_t __n) { - void* __ret = 0; - - if (__n > (size_t) _MAX_BYTES) - __ret = __mem_interface::allocate(__n); - else - { - _Obj* volatile* __my_free_list = _S_free_list - + _S_freelist_index(__n); - // Acquire the lock here with a constructor call. This - // ensures that it is released in exit or during stack - // unwinding. - _Lock __lock_instance; - _Obj* __restrict__ __result = *__my_free_list; - if (__result == 0) - __ret = _S_refill(_S_round_up(__n)); - else - { - *__my_free_list = __result -> _M_free_list_link; - __ret = __result; - } - } - return __ret; - }; + void* __ret = 0; + + // If there is a race through here, assume answer from getenv + // will resolve in same direction. Inspired by techniques + // to efficiently support threading found in basic_string.h. + if (_S_force_new == 0) + { + if (getenv("GLIBCPP_FORCE_NEW")) + __atomic_add(&_S_force_new, 1); + else + __atomic_add(&_S_force_new, -1); + // Trust but verify... + assert (_S_force_new != 0); + } + + if ((__n > (size_t) _MAX_BYTES) || (_S_force_new > 0)) + __ret = __new_alloc::allocate(__n); + else + { + _Obj* volatile* __my_free_list = _S_free_list + + _S_freelist_index(__n); + // Acquire the lock here with a constructor call. This + // ensures that it is released in exit or during stack + // unwinding. + _Lock __lock_instance; + _Obj* __restrict__ __result = *__my_free_list; + if (__result == 0) + __ret = _S_refill(_S_round_up(__n)); + else + { + *__my_free_list = __result -> _M_free_list_link; + __ret = __result; + } + } + return __ret; + } // __p may not be 0 static void deallocate(void* __p, size_t __n) { - if (__n > (size_t) _MAX_BYTES) - __mem_interface::deallocate(__p, __n); - else - { - _Obj* volatile* __my_free_list = _S_free_list - + _S_freelist_index(__n); - _Obj* __q = (_Obj*)__p; - - // Acquire the lock here with a constructor call. This - // ensures that it is released in exit or during stack - // unwinding. - _Lock __lock_instance; - __q -> _M_free_list_link = *__my_free_list; - *__my_free_list = __q; - } + if ((__n > (size_t) _MAX_BYTES) || (_S_force_new > 0)) + __new_alloc::deallocate(__p, __n); + else + { + _Obj* volatile* __my_free_list = _S_free_list + + _S_freelist_index(__n); + _Obj* __q = (_Obj*)__p; + + // Acquire the lock here with a constructor call. This + // ensures that it is released in exit or during stack + // unwinding. + _Lock __lock_instance; + __q -> _M_free_list_link = *__my_free_list; + *__my_free_list = __q; + } } #ifdef _GLIBCPP_DEPRECATED @@ -449,6 +454,8 @@ namespace std #endif }; + template<bool __threads, int __inst> _Atomic_word + __default_alloc_template<__threads, __inst>::_S_force_new = 0; template<bool __threads, int __inst> inline bool @@ -464,8 +471,8 @@ namespace std // We allocate memory in large chunks in order to avoid fragmenting the - // malloc heap (or whatever __mem_interface is using) too much. We assume - // that __size is properly aligned. We hold the allocation lock. + // heap too much. We assume that __size is properly aligned. We hold + // the allocation lock. template<bool __threads, int __inst> char* __default_alloc_template<__threads, __inst>:: @@ -479,7 +486,7 @@ namespace std { __result = _S_start_free; _S_start_free += __total_bytes; - return(__result); + return __result ; } else if (__bytes_left >= __size) { @@ -487,7 +494,7 @@ namespace std __total_bytes = __size * __nobjs; __result = _S_start_free; _S_start_free += __total_bytes; - return(__result); + return __result; } else { @@ -502,7 +509,7 @@ namespace std ((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list; *__my_free_list = (_Obj*)_S_start_free; } - _S_start_free = (char*) __mem_interface::allocate(__bytes_to_get); + _S_start_free = (char*) __new_alloc::allocate(__bytes_to_get); if (0 == _S_start_free) { size_t __i; @@ -521,19 +528,19 @@ namespace std *__my_free_list = __p -> _M_free_list_link; _S_start_free = (char*)__p; _S_end_free = _S_start_free + __i; - return(_S_chunk_alloc(__size, __nobjs)); + return _S_chunk_alloc(__size, __nobjs); // Any leftover piece will eventually make it to the // right free list. } } _S_end_free = 0; // In case of exception. - _S_start_free = (char*)__mem_interface::allocate(__bytes_to_get); + _S_start_free = (char*)__new_alloc::allocate(__bytes_to_get); // This should either throw an exception or remedy the situation. // Thus we assume it succeeded. } _S_heap_size += __bytes_to_get; _S_end_free = _S_start_free + __bytes_to_get; - return(_S_chunk_alloc(__size, __nobjs)); + return _S_chunk_alloc(__size, __nobjs); } } @@ -554,7 +561,7 @@ namespace std int __i; if (1 == __nobjs) - return(__chunk); + return __chunk; __my_free_list = _S_free_list + _S_freelist_index(__n); // Build free list in chunk. @@ -617,7 +624,6 @@ namespace std typedef __default_alloc_template<true,0> __alloc; typedef __default_alloc_template<false,0> __single_client_alloc; -#endif /* ! __USE_MALLOC */ /** @@ -627,10 +633,6 @@ namespace std * of stl_alloc.h.) * * The underlying allocator behaves as follows. - * - if __USE_MALLOC then - * - thread safety depends on malloc and is entirely out of our hands - * - __malloc_alloc_template is used for memory requests - * - else (the default) * - __default_alloc_template is used via two typedefs * - "__single_client_alloc" typedef does no locking for threads * - "__alloc" typedef is threadsafe via the locks @@ -784,7 +786,7 @@ namespace std }; template<typename _Alloc> - class __allocator<void, _Alloc> + struct __allocator<void, _Alloc> { typedef size_t size_type; typedef ptrdiff_t difference_type; @@ -907,7 +909,6 @@ namespace std typedef __allocator<_Tp, __malloc_alloc_template<__inst> > allocator_type; }; -#ifndef __USE_MALLOC template<typename _Tp, bool __threads, int __inst> struct _Alloc_traits<_Tp, __default_alloc_template<__threads, __inst> > { @@ -917,7 +918,6 @@ namespace std typedef __allocator<_Tp, __default_alloc_template<__threads, __inst> > allocator_type; }; -#endif template<typename _Tp, typename _Alloc> struct _Alloc_traits<_Tp, __debug_alloc<_Alloc> > @@ -940,7 +940,6 @@ namespace std typedef __allocator<_Tp, __malloc_alloc_template<__inst> > allocator_type; }; -#ifndef __USE_MALLOC template<typename _Tp, typename _Tp1, bool __thr, int __inst> struct _Alloc_traits<_Tp, __allocator<_Tp1, __default_alloc_template<__thr, __inst> > > { @@ -950,7 +949,6 @@ namespace std typedef __allocator<_Tp, __default_alloc_template<__thr,__inst> > allocator_type; }; -#endif template<typename _Tp, typename _Tp1, typename _Alloc> struct _Alloc_traits<_Tp, __allocator<_Tp1, __debug_alloc<_Alloc> > > @@ -966,11 +964,7 @@ namespace std // NB: This syntax is a GNU extension. extern template class allocator<char>; extern template class allocator<wchar_t>; -#ifdef __USE_MALLOC - extern template class __malloc_alloc_template<0>; -#else extern template class __default_alloc_template<true,0>; -#endif } // namespace std #endif |