1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2007-2012. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/interprocess for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10 #include <boost/interprocess/detail/config_begin.hpp>
11 #include <boost/interprocess/managed_shared_memory.hpp>
12 #include <boost/interprocess/smart_ptr/unique_ptr.hpp>
13 #include <boost/interprocess/smart_ptr/deleter.hpp>
14 #include <boost/interprocess/detail/type_traits.hpp>
15 #include <vector>
16 #include <cstddef>
17 #include <string>
18 #include "get_process_id_name.hpp"
19 
20 namespace boost {
21 namespace interprocess {
22 namespace test {
23 
24 template <class NodePool>
25 struct test_node_pool
26 {
27    static bool allocate_then_deallocate(NodePool &pool);
28    static bool deallocate_free_blocks(NodePool &pool);
29 };
30 
31 template <class NodePool>
allocate_then_deallocate(NodePool & pool)32 bool test_node_pool<NodePool>::allocate_then_deallocate(NodePool &pool)
33 {
34    const typename NodePool::size_type num_alloc = 1 + 3*pool.get_real_num_node();
35 
36    std::vector<void*> nodes;
37 
38    //Precondition, the pool must be empty
39    if(0 != pool.num_free_nodes()){
40       return false;
41    }
42 
43    //First allocate nodes
44    for(std::size_t i = 0; i < num_alloc; ++i){
45       nodes.push_back(pool.allocate_node());
46    }
47 
48    //Check that the free count is correct
49    if((pool.get_real_num_node() - 1) != pool.num_free_nodes()){
50       return false;
51    }
52 
53    //Now deallocate all and check again
54    for(std::size_t i = 0; i < num_alloc; ++i){
55        pool.deallocate_node(nodes[i]);
56    }
57 
58    //Check that the free count is correct
59    if(4*pool.get_real_num_node() != pool.num_free_nodes()){
60       return false;
61    }
62 
63    pool.deallocate_free_blocks();
64 
65    if(0 != pool.num_free_nodes()){
66       return false;
67    }
68 
69    return true;
70 }
71 
72 template <class NodePool>
deallocate_free_blocks(NodePool & pool)73 bool test_node_pool<NodePool>::deallocate_free_blocks(NodePool &pool)
74 {
75    const std::size_t max_blocks        = 10;
76    const std::size_t max_nodes         = max_blocks*pool.get_real_num_node();
77    const std::size_t nodes_per_block   = pool.get_real_num_node();
78 
79    std::vector<void*> nodes;
80 
81    //Precondition, the pool must be empty
82    if(0 != pool.num_free_nodes()){
83       return false;
84    }
85 
86    //First allocate nodes
87    for(std::size_t i = 0; i < max_nodes; ++i){
88       nodes.push_back(pool.allocate_node());
89    }
90 
91    //Check that the free count is correct
92    if(0 != pool.num_free_nodes()){
93       return false;
94    }
95 
96    //Now deallocate one of each block per iteration
97    for(std::size_t node_i = 0; node_i < nodes_per_block; ++node_i){
98       //Deallocate a node per block
99       for(std::size_t i = 0; i < max_blocks; ++i){
100          pool.deallocate_node(nodes[i*nodes_per_block + node_i]);
101       }
102 
103       //Check that the free count is correct
104       if(max_blocks*(node_i+1) != pool.num_free_nodes()){
105          return false;
106       }
107 
108       //Now try to deallocate free blocks
109       pool.deallocate_free_blocks();
110 
111       //Until we don't deallocate the last node of every block
112       //no node should be deallocated
113       if(node_i != (nodes_per_block - 1)){
114          if(max_blocks*(node_i+1) != pool.num_free_nodes()){
115             return false;
116          }
117       }
118       else{
119          //If this is the last iteration, all the memory should
120          //have been deallocated.
121          if(0 != pool.num_free_nodes()){
122             return false;
123          }
124       }
125    }
126 
127    return true;
128 }
129 
130 template<class node_pool_t>
test_all_node_pool()131 bool test_all_node_pool()
132 {
133    using namespace boost::interprocess;
134    typedef managed_shared_memory::segment_manager segment_manager;
135 
136    typedef boost::interprocess::test::test_node_pool<node_pool_t> test_node_pool_t;
137    shared_memory_object::remove(test::get_process_id_name());
138    {
139      managed_shared_memory shm(create_only, test::get_process_id_name(), 4*1024*sizeof(segment_manager::void_pointer));
140 
141       typedef deleter<node_pool_t, segment_manager> deleter_t;
142       typedef unique_ptr<node_pool_t, deleter_t> unique_ptr_t;
143 
144       //Delete the pool when the tests end
145       unique_ptr_t p
146          (shm.construct<node_pool_t>(anonymous_instance)(shm.get_segment_manager())
147          ,deleter_t(shm.get_segment_manager()));
148 
149       //Now call each test
150       if(!test_node_pool_t::allocate_then_deallocate(*p))
151          return false;
152       if(!test_node_pool_t::deallocate_free_blocks(*p))
153          return false;
154    }
155    shared_memory_object::remove(test::get_process_id_name());
156    return true;
157 }
158 
159 }  //namespace test {
160 }  //namespace interprocess {
161 }  //namespace boost {
162 
163 #include <boost/interprocess/detail/config_end.hpp>
164