Update of /cvsroot/boost/boost/boost/interprocess/allocators/detail
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv17930/allocators/detail
Modified Files:
node_pool.hpp
Log Message:
Changes for official inclusion in the regression tests
Index: node_pool.hpp
===================================================================
RCS file:
/cvsroot/boost/boost/boost/interprocess/allocators/detail/node_pool.hpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- node_pool.hpp 7 Aug 2006 13:58:38 -0000 1.2
+++ node_pool.hpp 4 May 2007 20:53:10 -0000 1.3
@@ -1,6 +1,6 @@
//////////////////////////////////////////////////////////////////////////////
//
-// (C) Copyright Ion Gaztañaga 2005-2006. Distributed under the Boost
+// (C) Copyright Ion Gaztañaga 2005-2007. 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)
//
@@ -8,11 +8,12 @@
//
//////////////////////////////////////////////////////////////////////////////
-#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_ALGO_HPP
-#define BOOST_INTERPROCESS_NODE_ALLOCATOR_ALGO_HPP
+#ifndef BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP
+#define BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
+# pragma warning (disable : 4503)
#endif
#include <boost/interprocess/detail/config_begin.hpp>
@@ -21,25 +22,26 @@
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/exceptions.hpp>
+#include <boost/intrusive/slist.hpp>
#include <boost/math/common_factor_ct.hpp>
+#include <boost/interprocess/allocators/detail/node_tools.hpp>
#include <cstddef>
+#include <functional>
#include <assert.h>
/*!\file
- Describes the real pool allocator shared by many Interprocess pool
allocators
+ Describes the real adaptive pool shared by many Interprocess adaptive pool
allocators
*/
namespace boost {
-
namespace interprocess {
-
namespace detail {
-/*!Pooled shared memory allocator using single segregated storage. Includes
- a reference count but the class does not delete itself, this is
- responsibility of user classes. Node size (NodeSize) and the number of
- nodes allocated per chunk (NumAlloc) are known at compile time*/
-template<class SegmentManager, std::size_t NodeSize, std::size_t NumAlloc >
+//!Pooled shared memory allocator using single segregated storage. Includes
+//!a reference count but the class does not delete itself, this is
+//!responsibility of user classes. Node size (NodeSize) and the number of
+//!nodes allocated per chunk (NumAlloc) are known at compile time
+template< class SegmentManager, std::size_t NodeSize, std::size_t NumAlloc >
class private_node_pool
{
//Non-copyable
@@ -50,37 +52,48 @@
typedef typename SegmentManager::void_pointer void_pointer;
typedef typename pointer_to_other<void_pointer, char>::type char_ptr_t;
+ //A node object will hold node_t when it's not allocated
+ public:
+ typedef typename node_slist<void_pointer>::slist_hook_t slist_hook_t;
+ typedef typename node_slist<void_pointer>::node_t node_t;
+ typedef typename node_slist<void_pointer>::node_slist_t free_nodes_t;
+
+ private:
+ typedef boost::intrusive::slist
+ <typename slist_hook_t::template value_traits<node_t>, false >
chunkslist_t;
+
enum { RealNodeSize =
- boost::math::static_lcm<NodeSize, sizeof(char_ptr_t)>::value };
+ boost::math::static_lcm<NodeSize, sizeof(node_t)>::value };
enum { BlockSize =
- detail::ct_rounded_size<RealNodeSize*NumAlloc,
sizeof(char_ptr_t)>::value };
- enum { ChunkSize = BlockSize + sizeof(char_ptr_t) };
+ detail::ct_rounded_size<RealNodeSize*NumAlloc,
sizeof(node_t)>::value };
+ enum { ChunkSize = BlockSize + sizeof(node_t) };
+ enum { NumNode = NumAlloc };
- public:
- /*!Segment manager typedef*/
+ public:
+
+ enum { nodes_per_chunk = NumNode };
+ enum { node_size = NodeSize };
+
+ //!Segment manager typedef
typedef SegmentManager segment_manager;
- /*!Constructor from a segment manager. Never throws*/
+ //!Constructor from a segment manager. Never throws
private_node_pool(segment_manager *segment_mngr)
- : //To indicate null, we set pointers to themselves
- //General purpose allocator
+ : //General purpose allocator
mp_segment_mngr(segment_mngr),
- mp_firstBlock(0),
- mp_free(0),
//Debug node count
- m_allocated(0),
- m_free_nodes(0)
+ m_allocated(0)
{}
- /*!Destructor. Deallocates all allocated chunks. Never throws*/
+ //!Destructor. Deallocates all allocated chunks. Never throws
~private_node_pool()
- { priv_clear(); }
+ { priv_clear(); }
- /*!Returns the segment manager. Never throws*/
+ //!Returns the segment manager. Never throws
segment_manager* get_segment_manager()const
- { return mp_segment_mngr.get(); }
+ { return detail::get_pointer(mp_segment_mngr); }
- /*!Allocates array of count elements. Can throw
boost::interprocess::bad_alloc*/
+ //!Allocates array of count elements. Can throw
boost::interprocess::bad_alloc
void *allocate(std::size_t count)
{
std::size_t bytes = count*NodeSize;
@@ -90,7 +103,7 @@
return priv_alloc_node();
}
- /*!Deallocates an array pointed by ptr. Never throws*/
+ //!Deallocates an array pointed by ptr. Never throws
void deallocate(void *ptr, std::size_t count)
{
std::size_t bytes = count*NodeSize;
@@ -100,147 +113,232 @@
priv_dealloc_node(ptr);
}
- /*!Allocates a singly linked list of n nodes ending in null pointer.
- can throw boost::interprocess::bad_alloc*/
- void *allocate_nodes(std::size_t n)
+ //!Allocates a singly linked list of n nodes ending in null pointer.
+ //!can throw boost::interprocess::bad_alloc
+ void allocate_nodes(const std::size_t n, free_nodes_t &nodes)
{
- while(m_free_nodes < n){
- priv_alloc_chunk();
+ std::size_t i = 0;
+ try{
+ for(; i < n; ++i){
+ nodes.push_front(*priv_alloc_node());
+ }
}
+ catch(...){
+ priv_deallocate_nodes(nodes, i);
+ throw;
+ }
+ }
- m_allocated += n;
- m_free_nodes -= n;
- void *ret = mp_free.get();
+ //!Deallocates a linked list of nodes. Never throws
+ void deallocate_nodes(free_nodes_t &nodes)
+ { priv_deallocate_nodes(nodes, nodes.size()); }
- while(n--){
- //We take the first free node
- if(n == 0){
- //Last node we must mark next node as null
- char *end = mp_free.get();
- mp_free = next_node(end);
- //Mark next node of last node as null
- next_node(end) = 0;
- }
- else{
- mp_free = next_node(mp_free.get());
- }
+ //!Deallocates the first n nodes of a linked list of nodes. Never throws
+ void deallocate_nodes(free_nodes_t &nodes, std::size_t n)
+ { priv_deallocate_nodes(nodes, n); }
+
+ void deallocate_free_chunks()
+ { priv_deallocate_free_chunks(); }
+
+ std::size_t num_free_nodes()
+ { return m_freelist.size(); }
+
+ private:
+
+ void priv_deallocate_nodes(free_nodes_t &nodes, const std::size_t num)
+ {
+ assert(nodes.size() >= num);
+ for(std::size_t i = 0; i < num; ++i){
+ node_t *to_deallocate = &nodes.front();
+ nodes.pop_front();
+ deallocate(to_deallocate, 1);
}
- return ret;
}
- /*!Deallocates a linked list of nodes ending in null pointer. Never throws*/
- void deallocate_nodes(void *nodes)
+ struct push_in_list
{
- char *node = char_ptr_cast(nodes);
- char_ptr_t tmp;
- while(node){
- tmp = next_node(node);
- priv_dealloc_node(node);
- node = tmp.get();
+ push_in_list(free_nodes_t &l, typename free_nodes_t::iterator &it)
+ : slist_(l), last_it_(it)
+ {}
+
+ void operator()(typename free_nodes_t::pointer p) const
+ {
+ slist_.push_front(*p);
+ if(slist_.size() == 1){ //Cache last element
+ ++last_it_ = slist_.begin();
+ }
}
- }
- private:
+ private:
+ free_nodes_t &slist_;
+ typename free_nodes_t::iterator &last_it_;
+ };
- /*!Deallocates all used memory. Never throws*/
+ struct is_between
+ : std::unary_function<typename free_nodes_t::value_type, bool>
+ {
+ is_between(const void *addr, std::size_t size)
+ : beg_((const char *)addr), end_(beg_+size)
+ {}
+
+ bool operator()(typename free_nodes_t::const_reference v) const
+ {
+ return (beg_ <= (const char *)&v &&
+ end_ > (const char *)&v);
+ }
+ private:
+ const char * beg_;
+ const char * end_;
+ };
+
+ void priv_deallocate_free_chunks()
+ {
+ typedef typename free_nodes_t::iterator nodelist_iterator;
+ typename chunkslist_t::iterator bit(m_chunklist.before_begin()),
+ it(m_chunklist.begin()),
+ itend(m_chunklist.end());
+ free_nodes_t backup_list;
+ nodelist_iterator backup_list_last = backup_list.before_begin();
+
+ while(it != itend){
+ //Collect all the nodes from the chunk pointed by it
+ //and push them in the list
+ free_nodes_t free_nodes;
+ nodelist_iterator last_it = free_nodes.before_begin();
+ const void *addr = get_chunk_from_hook(&*it);
+
+ //Execute the algorithm and get an iterator to the last value
+ m_freelist.remove_and_destroy_if
+ (is_between(addr, BlockSize), push_in_list(free_nodes, last_it));
+
+ //If the number of nodes is equal to nodes_per_chunk
+ //this means that the block can be deallocated
+ if(free_nodes.size() == nodes_per_chunk){
+ //Unlink the nodes
+ free_nodes.clear();
+ it = m_chunklist.erase_after(bit);
+ mp_segment_mngr->deallocate((void*)addr);
+ }
+ //Otherwise, insert them in the backup list, since the
+ //next "remove_if" does not need to check them again.
+ else{
+ //Assign the iterator to the last value if necessary
+ if(backup_list.empty() && !m_freelist.empty()){
+ backup_list_last = last_it;
+ }
+ //Transfer nodes. This is constant time.
+ backup_list.splice_after
+ ( backup_list.before_begin()
+ , free_nodes
+ , free_nodes.before_begin()
+ , last_it
+ , free_nodes.size());
+ bit = it;
+ ++it;
+ }
+ }
+ //We should have removed all the nodes from the free list
+ assert(m_freelist.empty());
+
+ //Now pass all the node to the free list again
+ m_freelist.splice_after
+ ( m_freelist.before_begin()
+ , backup_list
+ , backup_list.before_begin()
+ , backup_list_last
+ , backup_list.size());
+ }
+
+ //!Deallocates all used memory. Never throws
void priv_clear()
{
//check for memory leaks
assert(m_allocated==0);
+ typename chunkslist_t::iterator
+ it(m_chunklist.begin()), itend(m_chunklist.end()), aux;
+
//We iterate though the NodeBlock list to free the memory
- char_ptr_t pNextBlock;
- while(mp_firstBlock){
- pNextBlock = priv_next_chunk(mp_firstBlock.get());
- mp_segment_mngr->deallocate(mp_firstBlock.get());
- mp_firstBlock = pNextBlock;
+ while(!m_chunklist.empty()){
+ void *addr = get_chunk_from_hook(&m_chunklist.front());
+ m_chunklist.pop_front();
+ mp_segment_mngr->deallocate(addr);
}
-
- mp_firstBlock = 0;
- mp_free = 0;
}
- /*!Allocates one node, using single segregated storage algorithm.
- Never throws*/
- void *priv_alloc_node()
+ //!Allocates one node, using single segregated storage algorithm.
+ //!Never throws
+ node_t *priv_alloc_node()
{
//If there are no free nodes we allocate a new block
- if (!mp_free)
+ if (m_freelist.empty())
priv_alloc_chunk();
//We take the first free node
- char_ptr_t pTmp = mp_free;
- mp_free = next_node(mp_free.get());
+ node_t *n = (node_t*)&m_freelist.front();
+ m_freelist.pop_front();
++m_allocated;
- --m_free_nodes;
- return pTmp.get();
+ return n;
}
- /*!Deallocates one node, using single segregated storage algorithm.
- Never throws*/
+ //!Deallocates one node, using single segregated storage algorithm.
+ //!Never throws
void priv_dealloc_node(void *pElem)
{
//We put the node at the beginning of the free node list
- char *pTmp = detail::char_ptr_cast(pElem);
- //We must build the offset pointer in memory
- next_node(pTmp) = mp_free;
- mp_free = pTmp;
+ node_t * to_deallocate = static_cast<node_t*>(pElem);
+ m_freelist.push_front(*to_deallocate);
assert(m_allocated>0);
--m_allocated;
- ++m_free_nodes;
}
- /*!Allocates a chunk of nodes. Can throw boost::interprocess::bad_alloc*/
+ //!Allocates a chunk of nodes. Can throw boost::interprocess::bad_alloc
void priv_alloc_chunk()
{
//We allocate a new NodeBlock and put it as first
//element in the free Node list
char *pNode =
detail::char_ptr_cast(mp_segment_mngr->allocate(ChunkSize));
char *pBlock = pNode;
- priv_next_chunk(pBlock) = mp_firstBlock;
- mp_firstBlock = pBlock;
+ m_chunklist.push_front(get_chunk_hook(pBlock));
//We initialize all Nodes in Node Block to insert
//them in the free Node list
- for(std::size_t i = 0; i < NumAlloc; ++i){
- next_node(pNode) = mp_free;
- mp_free = pNode;
+ for(std::size_t i = 0; i < NumAlloc; ++i){
+ m_freelist.push_front(*(node_t*)pNode );
pNode += RealNodeSize;
}
- m_free_nodes += NumAlloc;
}
- public:
- /*!Returns a reference to the next node from a raw pointer pointing
- to a free node. Never throws*/
- static inline char_ptr_t &next_node (void *node)
- { return *static_cast<char_ptr_t*>(node); }
-
private:
- /*!Returns a reference to the next chunk from a raw pointer pointing
- to a chunk. Never throws*/
- static inline char_ptr_t & priv_next_chunk (void *chunk)
+ //!Returns a reference to the chunk hook placed in the end of the chunk
+ static inline node_t & get_chunk_hook (void *chunk)
{
- return *static_cast<char_ptr_t*>(
+ return *static_cast<node_t*>(
static_cast<void*>((detail::char_ptr_cast(chunk)+BlockSize)));
}
+ //!Returns the starting address of the chunk reference to the chunk hook
placed in the end of the chunk
+ static inline void *get_chunk_from_hook (node_t *hook)
+ {
+ return static_cast<void*>((detail::char_ptr_cast(hook) - BlockSize));
+ }
+
private:
typedef typename pointer_to_other
<void_pointer, segment_manager>::type segment_mngr_ptr_t;
segment_mngr_ptr_t mp_segment_mngr; //Segment manager
- char_ptr_t mp_firstBlock; //Ptr to the first block
- char_ptr_t mp_free; //Ptr to the first free node
- std::size_t m_allocated; //Used nodes for debugging
- std::size_t m_free_nodes; //Free nodes
+
+ chunkslist_t m_chunklist; //Intrusive container of chunks
+ free_nodes_t m_freelist; //Intrusive container of free nods
+ std::size_t m_allocated; //Used nodes for debugging
};
-/*!Pooled shared memory allocator using single segregated storage. Includes
- a reference count but the class does not delete itself, this is
- responsibility of user classes. Node size (NodeSize) and the number of
- nodes allocated per chunk (NumAlloc) are known at compile time*/
+//!Pooled shared memory allocator using single segregated storage. Includes
+//!a reference count but the class does not delete itself, this is
+//!responsibility of user classes. Node size (NodeSize) and the number of
+//!nodes allocated per chunk (NumAlloc) are known at compile time
template<class SegmentManager, class Mutex,
std::size_t NodeSize, std::size_t NumAlloc>
class shared_node_pool
@@ -254,18 +352,20 @@
<SegmentManager,
NodeSize, NumAlloc> private_node_allocator_t;
public:
- /*!Segment manager typedef*/
+ //!Segment manager typedef
typedef SegmentManager segment_manager;
- /*!Constructor from a segment manager. Never throws*/
+ typedef typename private_node_allocator_t::free_nodes_t free_nodes_t;
+
+ //!Constructor from a segment manager. Never throws
shared_node_pool(segment_manager *segment_mngr)
: private_node_allocator_t(segment_mngr){}
- /*!Destructor. Deallocates all allocated chunks. Never throws*/
+ //!Destructor. Deallocates all allocated chunks. Never throws
~shared_node_pool()
- {}
+ {}
- /*!Allocates array of count elements. Can throw
boost::interprocess::bad_alloc*/
+ //!Allocates array of count elements. Can throw
boost::interprocess::bad_alloc
void *allocate(std::size_t count)
{
//-----------------------
@@ -274,7 +374,7 @@
return private_node_allocator_t::allocate(count);
}
- /*!Deallocates an array pointed by ptr. Never throws*/
+ //!Deallocates an array pointed by ptr. Never throws
void deallocate(void *ptr, std::size_t count)
{
//-----------------------
@@ -283,18 +383,26 @@
private_node_allocator_t::deallocate(ptr, count);
}
- /*!Allocates a singly linked list of n nodes ending in null pointer.
- can throw boost::interprocess::bad_alloc*/
- void *allocate_nodes(std::size_t n)
+ //!Allocates a singly linked list of n nodes ending in null pointer.
+ //!can throw boost::interprocess::bad_alloc
+ void allocate_nodes(const std::size_t n, free_nodes_t &nodes)
{
//-----------------------
boost::interprocess::scoped_lock<Mutex> guard(m_header);
//-----------------------
- return private_node_allocator_t::allocate_nodes(n);
+ private_node_allocator_t::allocate_nodes(n, nodes);
}
- /*!Deallocates a linked list of nodes ending in null pointer. Never throws*/
- void deallocate_nodes(void * nodes)
+ //!Deallocates a linked list of nodes ending in null pointer. Never throws
+ void deallocate_nodes(free_nodes_t &nodes, std::size_t n)
+ {
+ //-----------------------
+ boost::interprocess::scoped_lock<Mutex> guard(m_header);
+ //-----------------------
+ private_node_allocator_t::deallocate_nodes(nodes, n);
+ }
+
+ void deallocate_nodes(free_nodes_t &nodes)
{
//-----------------------
boost::interprocess::scoped_lock<Mutex> guard(m_header);
@@ -302,7 +410,7 @@
private_node_allocator_t::deallocate_nodes(nodes);
}
- /*!Increments internal reference count and returns new count. Never throws*/
+ //!Increments internal reference count and returns new count. Never throws
std::size_t inc_ref_count()
{
//-----------------------
@@ -311,7 +419,7 @@
return ++m_header.m_usecount;
}
- /*!Decrements internal reference count and returns new count. Never throws*/
+ //!Decrements internal reference count and returns new count. Never throws
std::size_t dec_ref_count()
{
//-----------------------
@@ -322,11 +430,11 @@
}
private:
- /*!This struct includes needed data and derives from
- interprocess_mutex to allow EBO when using null interprocess_mutex*/
+ //!This struct includes needed data and derives from
+ //!interprocess_mutex to allow EBO when using null_mutex
struct header_t : Mutex
{
- std::size_t m_usecount; //Number of attached
allocators
+ std::size_t m_usecount; //Number of attached allocators
header_t()
: m_usecount(0) {}
@@ -334,12 +442,9 @@
};
} //namespace detail {
-
} //namespace interprocess {
-
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
-#endif //#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_ALGO_HPP
-
+#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Boost-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/boost-cvs