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