123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- // Copyright (C) 2000, 2001 Stephen Cleary
- //
- // Distributed under the Boost Software License, Version 1.0. (See
- // accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //
- // See http://www.boost.org for updates, documentation, and revision history.
- #ifndef BOOST_SINGLETON_POOL_HPP
- #define BOOST_SINGLETON_POOL_HPP
- /*!
- \file
- \brief The <tt>singleton_pool</tt> class allows other pool interfaces
- for types of the same size to share the same underlying pool.
- \details Header singleton_pool.hpp provides a template class <tt>singleton_pool</tt>,
- which provides access to a pool as a singleton object.
-
- */
- #include <boost/pool/poolfwd.hpp>
- // boost::pool
- #include <boost/pool/pool.hpp>
- // boost::details::pool::guard
- #include <boost/pool/detail/guard.hpp>
- #include <boost/type_traits/aligned_storage.hpp>
- namespace boost {
- /*!
- The singleton_pool class allows other pool interfaces
- for types of the same size to share the same pool. Template
- parameters are as follows:
- <b>Tag</b> User-specified type to uniquely identify this pool: allows different unbounded sets of singleton pools to exist.
- <b>RequestedSize</b> The size of each chunk returned by member function <tt>malloc()</tt>.
- <B>UserAllocator</b> User allocator, default = default_user_allocator_new_delete.
- <b>Mutex</B> This class is the type of mutex to use to protect simultaneous access to the underlying Pool.
- Can be any Boost.Thread Mutex type or <tt>boost::details::pool::null_mutex</tt>.
- It is exposed so that users may declare some singleton pools normally (i.e., with synchronization), but
- some singleton pools without synchronization (by specifying <tt>boost::details::pool::null_mutex</tt>) for efficiency reasons.
- The member typedef <tt>mutex</tt> exposes the value of this template parameter. The default for this
- parameter is boost::details::pool::default_mutex which is a synonym for either <tt>boost::details::pool::null_mutex</tt>
- (when threading support is turned off in the compiler (so BOOST_HAS_THREADS is not set), or threading support
- has ben explicitly disabled with BOOST_DISABLE_THREADS (Boost-wide disabling of threads) or BOOST_POOL_NO_MT (this library only))
- or for <tt>boost::mutex</tt> (when threading support is enabled in the compiler).
- <B>NextSize</b> The value of this parameter is passed to the underlying Pool when it is created and
- specifies the number of chunks to allocate in the first allocation request (defaults to 32).
- The member typedef <tt>static const value next_size</tt> exposes the value of this template parameter.
- <b>MaxSize</B>The value of this parameter is passed to the underlying Pool when it is created and
- specifies the maximum number of chunks to allocate in any single allocation request (defaults to 0).
- <b>Notes:</b>
- The underlying pool <i>p</i> referenced by the static functions
- in singleton_pool is actually declared in a way that is:
- 1 Thread-safe if there is only one thread running before main() begins and after main() ends
- -- all of the static functions of singleton_pool synchronize their access to p.
- 2 Guaranteed to be constructed before it is used --
- thus, the simple static object in the synopsis above would actually be an incorrect implementation.
- The actual implementation to guarantee this is considerably more complicated.
- 3 Note too that a different underlying pool p exists
- for each different set of template parameters,
- including implementation-specific ones.
- 4 The underlying pool is constructed "as if" by:
- pool<UserAllocator> p(RequestedSize, NextSize, MaxSize);
- \attention
- The underlying pool constructed by the singleton
- <b>is never freed</b>. This means that memory allocated
- by a singleton_pool can be still used after main() has
- completed, but may mean that some memory checking programs
- will complain about leaks from singleton_pool.
-
- */
- template <typename Tag,
- unsigned RequestedSize,
- typename UserAllocator,
- typename Mutex,
- unsigned NextSize,
- unsigned MaxSize >
- class singleton_pool
- {
- public:
- typedef Tag tag; /*!< The Tag template parameter uniquely
- identifies this pool and allows
- different unbounded sets of singleton pools to exist.
- For example, the pool allocators use two tag classes to ensure that the
- two different allocator types never share the same underlying singleton pool.
- Tag is never actually used by singleton_pool.
- */
- typedef Mutex mutex; //!< The type of mutex used to synchonise access to this pool (default <tt>details::pool::default_mutex</tt>).
- typedef UserAllocator user_allocator; //!< The user-allocator used by this pool, default = <tt>default_user_allocator_new_delete</tt>.
- typedef typename pool<UserAllocator>::size_type size_type; //!< size_type of user allocator.
- typedef typename pool<UserAllocator>::difference_type difference_type; //!< difference_type of user allocator.
- BOOST_STATIC_CONSTANT(unsigned, requested_size = RequestedSize); //!< The size of each chunk allocated by this pool.
- BOOST_STATIC_CONSTANT(unsigned, next_size = NextSize); //!< The number of chunks to allocate on the first allocation.
- private:
- singleton_pool();
- #ifndef BOOST_DOXYGEN
- struct pool_type: public Mutex, public pool<UserAllocator>
- {
- pool_type() : pool<UserAllocator>(RequestedSize, NextSize, MaxSize) {}
- }; // struct pool_type: Mutex
- #else
- //
- // This is invoked when we build with Doxygen only:
- //
- public:
- static pool<UserAllocator> p; //!< For exposition only!
- #endif
- public:
- static void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
- { //! Equivalent to SingletonPool::p.malloc(); synchronized.
- pool_type & p = get_pool();
- details::pool::guard<Mutex> g(p);
- return (p.malloc)();
- }
- static void * ordered_malloc()
- { //! Equivalent to SingletonPool::p.ordered_malloc(); synchronized.
- pool_type & p = get_pool();
- details::pool::guard<Mutex> g(p);
- return p.ordered_malloc();
- }
- static void * ordered_malloc(const size_type n)
- { //! Equivalent to SingletonPool::p.ordered_malloc(n); synchronized.
- pool_type & p = get_pool();
- details::pool::guard<Mutex> g(p);
- return p.ordered_malloc(n);
- }
- static bool is_from(void * const ptr)
- { //! Equivalent to SingletonPool::p.is_from(chunk); synchronized.
- //! \returns true if chunk is from SingletonPool::is_from(chunk)
- pool_type & p = get_pool();
- details::pool::guard<Mutex> g(p);
- return p.is_from(ptr);
- }
- static void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const ptr)
- { //! Equivalent to SingletonPool::p.free(chunk); synchronized.
- pool_type & p = get_pool();
- details::pool::guard<Mutex> g(p);
- (p.free)(ptr);
- }
- static void ordered_free(void * const ptr)
- { //! Equivalent to SingletonPool::p.ordered_free(chunk); synchronized.
- pool_type & p = get_pool();
- details::pool::guard<Mutex> g(p);
- p.ordered_free(ptr);
- }
- static void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const ptr, const size_type n)
- { //! Equivalent to SingletonPool::p.free(chunk, n); synchronized.
- pool_type & p = get_pool();
- details::pool::guard<Mutex> g(p);
- (p.free)(ptr, n);
- }
- static void ordered_free(void * const ptr, const size_type n)
- { //! Equivalent to SingletonPool::p.ordered_free(chunk, n); synchronized.
- pool_type & p = get_pool();
- details::pool::guard<Mutex> g(p);
- p.ordered_free(ptr, n);
- }
- static bool release_memory()
- { //! Equivalent to SingletonPool::p.release_memory(); synchronized.
- pool_type & p = get_pool();
- details::pool::guard<Mutex> g(p);
- return p.release_memory();
- }
- static bool purge_memory()
- { //! Equivalent to SingletonPool::p.purge_memory(); synchronized.
- pool_type & p = get_pool();
- details::pool::guard<Mutex> g(p);
- return p.purge_memory();
- }
- private:
- typedef boost::aligned_storage<sizeof(pool_type), boost::alignment_of<pool_type>::value> storage_type;
- static storage_type storage;
- static pool_type& get_pool()
- {
- static bool f = false;
- if(!f)
- {
- // This code *must* be called before main() starts,
- // and when only one thread is executing.
- f = true;
- new (&storage) pool_type;
- }
- // The following line does nothing else than force the instantiation
- // of singleton<T>::create_object, whose constructor is
- // called before main() begins.
- create_object.do_nothing();
- return *static_cast<pool_type*>(static_cast<void*>(&storage));
- }
- struct object_creator
- {
- object_creator()
- { // This constructor does nothing more than ensure that instance()
- // is called before main() begins, thus creating the static
- // T object before multithreading race issues can come up.
- singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::get_pool();
- }
- inline void do_nothing() const
- {
- }
- };
- static object_creator create_object;
- }; // struct singleton_pool
- template <typename Tag,
- unsigned RequestedSize,
- typename UserAllocator,
- typename Mutex,
- unsigned NextSize,
- unsigned MaxSize >
- typename singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::storage_type singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::storage;
- template <typename Tag,
- unsigned RequestedSize,
- typename UserAllocator,
- typename Mutex,
- unsigned NextSize,
- unsigned MaxSize >
- typename singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::object_creator singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::create_object;
- } // namespace boost
- #endif
|