1ffeaf689SAlexander Kabaev // Allocators -*- C++ -*- 2ffeaf689SAlexander Kabaev 3*f8a1b7d9SAlexander Kabaev // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 4*f8a1b7d9SAlexander Kabaev // Free Software Foundation, Inc. 5ffeaf689SAlexander Kabaev // 6ffeaf689SAlexander Kabaev // This file is part of the GNU ISO C++ Library. This library is free 7ffeaf689SAlexander Kabaev // software; you can redistribute it and/or modify it under the 8ffeaf689SAlexander Kabaev // terms of the GNU General Public License as published by the 9ffeaf689SAlexander Kabaev // Free Software Foundation; either version 2, or (at your option) 10ffeaf689SAlexander Kabaev // any later version. 11ffeaf689SAlexander Kabaev 12ffeaf689SAlexander Kabaev // This library is distributed in the hope that it will be useful, 13ffeaf689SAlexander Kabaev // but WITHOUT ANY WARRANTY; without even the implied warranty of 14ffeaf689SAlexander Kabaev // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15ffeaf689SAlexander Kabaev // GNU General Public License for more details. 16ffeaf689SAlexander Kabaev 17ffeaf689SAlexander Kabaev // You should have received a copy of the GNU General Public License along 18ffeaf689SAlexander Kabaev // with this library; see the file COPYING. If not, write to the Free 19*f8a1b7d9SAlexander Kabaev // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 20ffeaf689SAlexander Kabaev // USA. 21ffeaf689SAlexander Kabaev 22ffeaf689SAlexander Kabaev // As a special exception, you may use this file as part of a free software 23ffeaf689SAlexander Kabaev // library without restriction. Specifically, if other files instantiate 24ffeaf689SAlexander Kabaev // templates or use macros or inline functions from this file, or you compile 25ffeaf689SAlexander Kabaev // this file and link it with other files to produce an executable, this 26ffeaf689SAlexander Kabaev // file does not by itself cause the resulting executable to be covered by 27ffeaf689SAlexander Kabaev // the GNU General Public License. This exception does not however 28ffeaf689SAlexander Kabaev // invalidate any other reasons why the executable file might be covered by 29ffeaf689SAlexander Kabaev // the GNU General Public License. 30ffeaf689SAlexander Kabaev 31ffeaf689SAlexander Kabaev /* 32ffeaf689SAlexander Kabaev * Copyright (c) 1996-1997 33ffeaf689SAlexander Kabaev * Silicon Graphics Computer Systems, Inc. 34ffeaf689SAlexander Kabaev * 35ffeaf689SAlexander Kabaev * Permission to use, copy, modify, distribute and sell this software 36ffeaf689SAlexander Kabaev * and its documentation for any purpose is hereby granted without fee, 37ffeaf689SAlexander Kabaev * provided that the above copyright notice appear in all copies and 38ffeaf689SAlexander Kabaev * that both that copyright notice and this permission notice appear 39ffeaf689SAlexander Kabaev * in supporting documentation. Silicon Graphics makes no 40ffeaf689SAlexander Kabaev * representations about the suitability of this software for any 41ffeaf689SAlexander Kabaev * purpose. It is provided "as is" without express or implied warranty. 42ffeaf689SAlexander Kabaev */ 43ffeaf689SAlexander Kabaev 44ffeaf689SAlexander Kabaev /** @file ext/pool_allocator.h 45ffeaf689SAlexander Kabaev * This file is a GNU extension to the Standard C++ Library. 46ffeaf689SAlexander Kabaev */ 47*f8a1b7d9SAlexander Kabaev 48ffeaf689SAlexander Kabaev #ifndef _POOL_ALLOCATOR_H 49ffeaf689SAlexander Kabaev #define _POOL_ALLOCATOR_H 1 50ffeaf689SAlexander Kabaev 51ffeaf689SAlexander Kabaev #include <bits/c++config.h> 52f260e61bSAlexander Kabaev #include <cstdlib> 53ffeaf689SAlexander Kabaev #include <new> 54ffeaf689SAlexander Kabaev #include <bits/functexcept.h> 55*f8a1b7d9SAlexander Kabaev #include <ext/atomicity.h> 56*f8a1b7d9SAlexander Kabaev #include <ext/concurrence.h> 57ffeaf689SAlexander Kabaev 58*f8a1b7d9SAlexander Kabaev _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) 59*f8a1b7d9SAlexander Kabaev 60*f8a1b7d9SAlexander Kabaev using std::size_t; 61*f8a1b7d9SAlexander Kabaev using std::ptrdiff_t; 62*f8a1b7d9SAlexander Kabaev 63ffeaf689SAlexander Kabaev /** 64*f8a1b7d9SAlexander Kabaev * @brief Base class for __pool_alloc. 65*f8a1b7d9SAlexander Kabaev * 66ffeaf689SAlexander Kabaev * @if maint 67ffeaf689SAlexander Kabaev * Uses various allocators to fulfill underlying requests (and makes as 68ffeaf689SAlexander Kabaev * few requests as possible when in default high-speed pool mode). 69ffeaf689SAlexander Kabaev * 70ffeaf689SAlexander Kabaev * Important implementation properties: 71ffeaf689SAlexander Kabaev * 0. If globally mandated, then allocate objects from new 72ffeaf689SAlexander Kabaev * 1. If the clients request an object of size > _S_max_bytes, the resulting 73ffeaf689SAlexander Kabaev * object will be obtained directly from new 74ffeaf689SAlexander Kabaev * 2. In all other cases, we allocate an object of size exactly 75ffeaf689SAlexander Kabaev * _S_round_up(requested_size). Thus the client has enough size 76ffeaf689SAlexander Kabaev * information that we can return the object to the proper free list 77ffeaf689SAlexander Kabaev * without permanently losing part of the object. 78ffeaf689SAlexander Kabaev * 79ffeaf689SAlexander Kabaev * @endif 80ffeaf689SAlexander Kabaev */ 81f260e61bSAlexander Kabaev class __pool_alloc_base 82ffeaf689SAlexander Kabaev { 83ffeaf689SAlexander Kabaev protected: 84ffeaf689SAlexander Kabaev 85ffeaf689SAlexander Kabaev enum { _S_align = 8 }; 86ffeaf689SAlexander Kabaev enum { _S_max_bytes = 128 }; 87*f8a1b7d9SAlexander Kabaev enum { _S_free_list_size = (size_t)_S_max_bytes / (size_t)_S_align }; 88ffeaf689SAlexander Kabaev 89ffeaf689SAlexander Kabaev union _Obj 90ffeaf689SAlexander Kabaev { 91ffeaf689SAlexander Kabaev union _Obj* _M_free_list_link; 92ffeaf689SAlexander Kabaev char _M_client_data[1]; // The client sees this. 93ffeaf689SAlexander Kabaev }; 94ffeaf689SAlexander Kabaev 95ffeaf689SAlexander Kabaev static _Obj* volatile _S_free_list[_S_free_list_size]; 96ffeaf689SAlexander Kabaev 97ffeaf689SAlexander Kabaev // Chunk allocation state. 98ffeaf689SAlexander Kabaev static char* _S_start_free; 99ffeaf689SAlexander Kabaev static char* _S_end_free; 100ffeaf689SAlexander Kabaev static size_t _S_heap_size; 101ffeaf689SAlexander Kabaev 102ffeaf689SAlexander Kabaev size_t _M_round_up(size_t __bytes)103ffeaf689SAlexander Kabaev _M_round_up(size_t __bytes) 104ffeaf689SAlexander Kabaev { return ((__bytes + (size_t)_S_align - 1) & ~((size_t)_S_align - 1)); } 105ffeaf689SAlexander Kabaev 106ffeaf689SAlexander Kabaev _Obj* volatile* 107ffeaf689SAlexander Kabaev _M_get_free_list(size_t __bytes); 108ffeaf689SAlexander Kabaev 109*f8a1b7d9SAlexander Kabaev __mutex& 110ffeaf689SAlexander Kabaev _M_get_mutex(); 111ffeaf689SAlexander Kabaev 112ffeaf689SAlexander Kabaev // Returns an object of size __n, and optionally adds to size __n 113ffeaf689SAlexander Kabaev // free list. 114ffeaf689SAlexander Kabaev void* 115ffeaf689SAlexander Kabaev _M_refill(size_t __n); 116ffeaf689SAlexander Kabaev 117ffeaf689SAlexander Kabaev // Allocates a chunk for nobjs of size size. nobjs may be reduced 118ffeaf689SAlexander Kabaev // if it is inconvenient to allocate the requested number. 119ffeaf689SAlexander Kabaev char* 120ffeaf689SAlexander Kabaev _M_allocate_chunk(size_t __n, int& __nobjs); 121ffeaf689SAlexander Kabaev }; 122ffeaf689SAlexander Kabaev 123ffeaf689SAlexander Kabaev 124*f8a1b7d9SAlexander Kabaev /// @brief class __pool_alloc. 125ffeaf689SAlexander Kabaev template<typename _Tp> 126f260e61bSAlexander Kabaev class __pool_alloc : private __pool_alloc_base 127ffeaf689SAlexander Kabaev { 128ffeaf689SAlexander Kabaev private: 129ffeaf689SAlexander Kabaev static _Atomic_word _S_force_new; 130ffeaf689SAlexander Kabaev 131ffeaf689SAlexander Kabaev public: 132ffeaf689SAlexander Kabaev typedef size_t size_type; 133ffeaf689SAlexander Kabaev typedef ptrdiff_t difference_type; 134ffeaf689SAlexander Kabaev typedef _Tp* pointer; 135ffeaf689SAlexander Kabaev typedef const _Tp* const_pointer; 136ffeaf689SAlexander Kabaev typedef _Tp& reference; 137ffeaf689SAlexander Kabaev typedef const _Tp& const_reference; 138ffeaf689SAlexander Kabaev typedef _Tp value_type; 139ffeaf689SAlexander Kabaev 140ffeaf689SAlexander Kabaev template<typename _Tp1> 141ffeaf689SAlexander Kabaev struct rebind 142ffeaf689SAlexander Kabaev { typedef __pool_alloc<_Tp1> other; }; 143ffeaf689SAlexander Kabaev throw()144ffeaf689SAlexander Kabaev __pool_alloc() throw() { } 145ffeaf689SAlexander Kabaev throw()146ffeaf689SAlexander Kabaev __pool_alloc(const __pool_alloc&) throw() { } 147ffeaf689SAlexander Kabaev 148ffeaf689SAlexander Kabaev template<typename _Tp1> __pool_alloc(const __pool_alloc<_Tp1> &)149ffeaf689SAlexander Kabaev __pool_alloc(const __pool_alloc<_Tp1>&) throw() { } 150ffeaf689SAlexander Kabaev throw()151ffeaf689SAlexander Kabaev ~__pool_alloc() throw() { } 152ffeaf689SAlexander Kabaev 153ffeaf689SAlexander Kabaev pointer address(reference __x)154ffeaf689SAlexander Kabaev address(reference __x) const { return &__x; } 155ffeaf689SAlexander Kabaev 156ffeaf689SAlexander Kabaev const_pointer address(const_reference __x)157ffeaf689SAlexander Kabaev address(const_reference __x) const { return &__x; } 158ffeaf689SAlexander Kabaev 159ffeaf689SAlexander Kabaev size_type max_size()160ffeaf689SAlexander Kabaev max_size() const throw() 161ffeaf689SAlexander Kabaev { return size_t(-1) / sizeof(_Tp); } 162ffeaf689SAlexander Kabaev 163ffeaf689SAlexander Kabaev // _GLIBCXX_RESOLVE_LIB_DEFECTS 164ffeaf689SAlexander Kabaev // 402. wrong new expression in [some_] allocator::construct 165ffeaf689SAlexander Kabaev void construct(pointer __p,const _Tp & __val)166ffeaf689SAlexander Kabaev construct(pointer __p, const _Tp& __val) 167ffeaf689SAlexander Kabaev { ::new(__p) _Tp(__val); } 168ffeaf689SAlexander Kabaev 169ffeaf689SAlexander Kabaev void destroy(pointer __p)170ffeaf689SAlexander Kabaev destroy(pointer __p) { __p->~_Tp(); } 171ffeaf689SAlexander Kabaev 172ffeaf689SAlexander Kabaev pointer 173ffeaf689SAlexander Kabaev allocate(size_type __n, const void* = 0); 174ffeaf689SAlexander Kabaev 175ffeaf689SAlexander Kabaev void 176ffeaf689SAlexander Kabaev deallocate(pointer __p, size_type __n); 177ffeaf689SAlexander Kabaev }; 178ffeaf689SAlexander Kabaev 179ffeaf689SAlexander Kabaev template<typename _Tp> 180ffeaf689SAlexander Kabaev inline bool 181ffeaf689SAlexander Kabaev operator==(const __pool_alloc<_Tp>&, const __pool_alloc<_Tp>&) 182ffeaf689SAlexander Kabaev { return true; } 183ffeaf689SAlexander Kabaev 184ffeaf689SAlexander Kabaev template<typename _Tp> 185ffeaf689SAlexander Kabaev inline bool 186ffeaf689SAlexander Kabaev operator!=(const __pool_alloc<_Tp>&, const __pool_alloc<_Tp>&) 187ffeaf689SAlexander Kabaev { return false; } 188ffeaf689SAlexander Kabaev 189ffeaf689SAlexander Kabaev template<typename _Tp> 190ffeaf689SAlexander Kabaev _Atomic_word 191ffeaf689SAlexander Kabaev __pool_alloc<_Tp>::_S_force_new; 192ffeaf689SAlexander Kabaev 193ffeaf689SAlexander Kabaev template<typename _Tp> 194ffeaf689SAlexander Kabaev _Tp* allocate(size_type __n,const void *)195ffeaf689SAlexander Kabaev __pool_alloc<_Tp>::allocate(size_type __n, const void*) 196ffeaf689SAlexander Kabaev { 197ffeaf689SAlexander Kabaev pointer __ret = 0; 198*f8a1b7d9SAlexander Kabaev if (__builtin_expect(__n != 0, true)) 199ffeaf689SAlexander Kabaev { 200*f8a1b7d9SAlexander Kabaev if (__builtin_expect(__n > this->max_size(), false)) 201*f8a1b7d9SAlexander Kabaev std::__throw_bad_alloc(); 202*f8a1b7d9SAlexander Kabaev 203ffeaf689SAlexander Kabaev // If there is a race through here, assume answer from getenv 204ffeaf689SAlexander Kabaev // will resolve in same direction. Inspired by techniques 205ffeaf689SAlexander Kabaev // to efficiently support threading found in basic_string.h. 206ffeaf689SAlexander Kabaev if (_S_force_new == 0) 207ffeaf689SAlexander Kabaev { 208*f8a1b7d9SAlexander Kabaev if (std::getenv("GLIBCXX_FORCE_NEW")) 209*f8a1b7d9SAlexander Kabaev __atomic_add_dispatch(&_S_force_new, 1); 210ffeaf689SAlexander Kabaev else 211*f8a1b7d9SAlexander Kabaev __atomic_add_dispatch(&_S_force_new, -1); 212ffeaf689SAlexander Kabaev } 213ffeaf689SAlexander Kabaev 214ffeaf689SAlexander Kabaev const size_t __bytes = __n * sizeof(_Tp); 215ffeaf689SAlexander Kabaev if (__bytes > size_t(_S_max_bytes) || _S_force_new == 1) 216ffeaf689SAlexander Kabaev __ret = static_cast<_Tp*>(::operator new(__bytes)); 217ffeaf689SAlexander Kabaev else 218ffeaf689SAlexander Kabaev { 219ffeaf689SAlexander Kabaev _Obj* volatile* __free_list = _M_get_free_list(__bytes); 220ffeaf689SAlexander Kabaev 221*f8a1b7d9SAlexander Kabaev __scoped_lock sentry(_M_get_mutex()); 222ffeaf689SAlexander Kabaev _Obj* __restrict__ __result = *__free_list; 223ffeaf689SAlexander Kabaev if (__builtin_expect(__result == 0, 0)) 224ffeaf689SAlexander Kabaev __ret = static_cast<_Tp*>(_M_refill(_M_round_up(__bytes))); 225ffeaf689SAlexander Kabaev else 226ffeaf689SAlexander Kabaev { 227ffeaf689SAlexander Kabaev *__free_list = __result->_M_free_list_link; 228ffeaf689SAlexander Kabaev __ret = reinterpret_cast<_Tp*>(__result); 229ffeaf689SAlexander Kabaev } 230ffeaf689SAlexander Kabaev if (__builtin_expect(__ret == 0, 0)) 231ffeaf689SAlexander Kabaev std::__throw_bad_alloc(); 232ffeaf689SAlexander Kabaev } 233ffeaf689SAlexander Kabaev } 234ffeaf689SAlexander Kabaev return __ret; 235ffeaf689SAlexander Kabaev } 236ffeaf689SAlexander Kabaev 237ffeaf689SAlexander Kabaev template<typename _Tp> 238ffeaf689SAlexander Kabaev void deallocate(pointer __p,size_type __n)239ffeaf689SAlexander Kabaev __pool_alloc<_Tp>::deallocate(pointer __p, size_type __n) 240ffeaf689SAlexander Kabaev { 241*f8a1b7d9SAlexander Kabaev if (__builtin_expect(__n != 0 && __p != 0, true)) 242ffeaf689SAlexander Kabaev { 243ffeaf689SAlexander Kabaev const size_t __bytes = __n * sizeof(_Tp); 244ffeaf689SAlexander Kabaev if (__bytes > static_cast<size_t>(_S_max_bytes) || _S_force_new == 1) 245ffeaf689SAlexander Kabaev ::operator delete(__p); 246ffeaf689SAlexander Kabaev else 247ffeaf689SAlexander Kabaev { 248ffeaf689SAlexander Kabaev _Obj* volatile* __free_list = _M_get_free_list(__bytes); 249ffeaf689SAlexander Kabaev _Obj* __q = reinterpret_cast<_Obj*>(__p); 250ffeaf689SAlexander Kabaev 251*f8a1b7d9SAlexander Kabaev __scoped_lock sentry(_M_get_mutex()); 252ffeaf689SAlexander Kabaev __q ->_M_free_list_link = *__free_list; 253ffeaf689SAlexander Kabaev *__free_list = __q; 254ffeaf689SAlexander Kabaev } 255ffeaf689SAlexander Kabaev } 256ffeaf689SAlexander Kabaev } 257*f8a1b7d9SAlexander Kabaev 258*f8a1b7d9SAlexander Kabaev _GLIBCXX_END_NAMESPACE 259ffeaf689SAlexander Kabaev 260ffeaf689SAlexander Kabaev #endif 261