Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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