Chris@16
|
1 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
2 //
|
Chris@16
|
3 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
Chris@16
|
4 // Software License, Version 1.0. (See accompanying file
|
Chris@16
|
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6 //
|
Chris@16
|
7 // See http://www.boost.org/libs/interprocess for documentation.
|
Chris@16
|
8 //
|
Chris@16
|
9 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
10
|
Chris@16
|
11 #ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP
|
Chris@16
|
12 #define BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP
|
Chris@16
|
13
|
Chris@101
|
14 #ifndef BOOST_CONFIG_HPP
|
Chris@101
|
15 # include <boost/config.hpp>
|
Chris@101
|
16 #endif
|
Chris@101
|
17 #
|
Chris@101
|
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
|
Chris@16
|
19 # pragma once
|
Chris@16
|
20 #endif
|
Chris@16
|
21
|
Chris@16
|
22 #include <boost/interprocess/detail/config_begin.hpp>
|
Chris@16
|
23 #include <boost/interprocess/detail/workaround.hpp>
|
Chris@16
|
24
|
Chris@101
|
25 #include <boost/core/no_exceptions_support.hpp>
|
Chris@16
|
26 #include <boost/interprocess/detail/type_traits.hpp>
|
Chris@16
|
27
|
Chris@16
|
28 #include <boost/interprocess/detail/transform_iterator.hpp>
|
Chris@16
|
29
|
Chris@16
|
30 #include <boost/interprocess/detail/mpl.hpp>
|
Chris@101
|
31 #include <boost/interprocess/detail/nothrow.hpp>
|
Chris@16
|
32 #include <boost/interprocess/detail/segment_manager_helper.hpp>
|
Chris@16
|
33 #include <boost/interprocess/detail/named_proxy.hpp>
|
Chris@16
|
34 #include <boost/interprocess/detail/utilities.hpp>
|
Chris@16
|
35 #include <boost/interprocess/offset_ptr.hpp>
|
Chris@16
|
36 #include <boost/interprocess/indexes/iset_index.hpp>
|
Chris@16
|
37 #include <boost/interprocess/exceptions.hpp>
|
Chris@16
|
38 #include <boost/interprocess/allocators/allocator.hpp>
|
Chris@16
|
39 #include <boost/interprocess/smart_ptr/deleter.hpp>
|
Chris@101
|
40 #include <boost/move/utility_core.hpp>
|
Chris@16
|
41 #include <boost/interprocess/sync/scoped_lock.hpp>
|
Chris@101
|
42 // container/detail
|
Chris@101
|
43 #include <boost/container/detail/minimal_char_traits_header.hpp>
|
Chris@101
|
44 #include <boost/container/detail/placement_new.hpp>
|
Chris@101
|
45 // std
|
Chris@16
|
46 #include <cstddef> //std::size_t
|
Chris@101
|
47 #include <boost/intrusive/detail/minimal_pair_header.hpp>
|
Chris@16
|
48 #include <boost/assert.hpp>
|
Chris@16
|
49 #ifndef BOOST_NO_EXCEPTIONS
|
Chris@16
|
50 #include <exception>
|
Chris@16
|
51 #endif
|
Chris@16
|
52
|
Chris@16
|
53 //!\file
|
Chris@16
|
54 //!Describes the object placed in a memory segment that provides
|
Chris@16
|
55 //!named object allocation capabilities for single-segment and
|
Chris@16
|
56 //!multi-segment allocations.
|
Chris@16
|
57
|
Chris@16
|
58 namespace boost{
|
Chris@16
|
59 namespace interprocess{
|
Chris@16
|
60
|
Chris@16
|
61 //!This object is the public base class of segment manager.
|
Chris@16
|
62 //!This class only depends on the memory allocation algorithm
|
Chris@16
|
63 //!and implements all the allocation features not related
|
Chris@16
|
64 //!to named or unique objects.
|
Chris@16
|
65 //!
|
Chris@16
|
66 //!Storing a reference to segment_manager forces
|
Chris@16
|
67 //!the holder class to be dependent on index types and character types.
|
Chris@16
|
68 //!When such dependence is not desirable and only anonymous and raw
|
Chris@16
|
69 //!allocations are needed, segment_manager_base is the correct answer.
|
Chris@16
|
70 template<class MemoryAlgorithm>
|
Chris@16
|
71 class segment_manager_base
|
Chris@16
|
72 : private MemoryAlgorithm
|
Chris@16
|
73 {
|
Chris@16
|
74 public:
|
Chris@16
|
75 typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
|
Chris@16
|
76 typedef typename MemoryAlgorithm::void_pointer void_pointer;
|
Chris@16
|
77 typedef typename MemoryAlgorithm::mutex_family mutex_family;
|
Chris@16
|
78 typedef MemoryAlgorithm memory_algorithm;
|
Chris@16
|
79
|
Chris@101
|
80 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
Chris@16
|
81
|
Chris@16
|
82 //Experimental. Don't use
|
Chris@16
|
83 typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain;
|
Chris@16
|
84 typedef typename MemoryAlgorithm::difference_type difference_type;
|
Chris@16
|
85 typedef typename MemoryAlgorithm::size_type size_type;
|
Chris@16
|
86
|
Chris@101
|
87 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
Chris@16
|
88
|
Chris@16
|
89 //!This constant indicates the payload size
|
Chris@16
|
90 //!associated with each allocation of the memory algorithm
|
Chris@16
|
91 static const size_type PayloadPerAllocation = MemoryAlgorithm::PayloadPerAllocation;
|
Chris@16
|
92
|
Chris@16
|
93 //!Constructor of the segment_manager_base
|
Chris@16
|
94 //!
|
Chris@16
|
95 //!"size" is the size of the memory segment where
|
Chris@16
|
96 //!the basic segment manager is being constructed.
|
Chris@16
|
97 //!
|
Chris@16
|
98 //!"reserved_bytes" is the number of bytes
|
Chris@16
|
99 //!after the end of the memory algorithm object itself
|
Chris@16
|
100 //!that the memory algorithm will exclude from
|
Chris@16
|
101 //!dynamic allocation
|
Chris@16
|
102 //!
|
Chris@16
|
103 //!Can throw
|
Chris@16
|
104 segment_manager_base(size_type sz, size_type reserved_bytes)
|
Chris@16
|
105 : MemoryAlgorithm(sz, reserved_bytes)
|
Chris@16
|
106 {
|
Chris@16
|
107 BOOST_ASSERT((sizeof(segment_manager_base<MemoryAlgorithm>) == sizeof(MemoryAlgorithm)));
|
Chris@16
|
108 }
|
Chris@16
|
109
|
Chris@16
|
110 //!Returns the size of the memory
|
Chris@16
|
111 //!segment
|
Chris@16
|
112 size_type get_size() const
|
Chris@16
|
113 { return MemoryAlgorithm::get_size(); }
|
Chris@16
|
114
|
Chris@16
|
115 //!Returns the number of free bytes of the memory
|
Chris@16
|
116 //!segment
|
Chris@16
|
117 size_type get_free_memory() const
|
Chris@16
|
118 { return MemoryAlgorithm::get_free_memory(); }
|
Chris@16
|
119
|
Chris@16
|
120 //!Obtains the minimum size needed by
|
Chris@16
|
121 //!the segment manager
|
Chris@16
|
122 static size_type get_min_size (size_type size)
|
Chris@16
|
123 { return MemoryAlgorithm::get_min_size(size); }
|
Chris@16
|
124
|
Chris@16
|
125 //!Allocates nbytes bytes. This function is only used in
|
Chris@16
|
126 //!single-segment management. Never throws
|
Chris@101
|
127 void * allocate (size_type nbytes, const std::nothrow_t &)
|
Chris@16
|
128 { return MemoryAlgorithm::allocate(nbytes); }
|
Chris@16
|
129
|
Chris@101
|
130 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
Chris@16
|
131
|
Chris@16
|
132 //Experimental. Dont' use.
|
Chris@101
|
133 //!Allocates n_elements of elem_bytes bytes.
|
Chris@16
|
134 //!Throws bad_alloc on failure. chain.size() is not increased on failure.
|
Chris@16
|
135 void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
|
Chris@16
|
136 {
|
Chris@16
|
137 size_type prev_size = chain.size();
|
Chris@16
|
138 MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain);
|
Chris@16
|
139 if(!elem_bytes || chain.size() == prev_size){
|
Chris@16
|
140 throw bad_alloc();
|
Chris@16
|
141 }
|
Chris@16
|
142 }
|
Chris@16
|
143
|
Chris@16
|
144 //!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
|
Chris@16
|
145 //!Throws bad_alloc on failure. chain.size() is not increased on failure.
|
Chris@16
|
146 void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
|
Chris@16
|
147 {
|
Chris@16
|
148 size_type prev_size = chain.size();
|
Chris@16
|
149 MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain);
|
Chris@16
|
150 if(!sizeof_element || chain.size() == prev_size){
|
Chris@16
|
151 throw bad_alloc();
|
Chris@16
|
152 }
|
Chris@16
|
153 }
|
Chris@16
|
154
|
Chris@101
|
155 //!Allocates n_elements of elem_bytes bytes.
|
Chris@16
|
156 //!Non-throwing version. chain.size() is not increased on failure.
|
Chris@101
|
157 void allocate_many(const std::nothrow_t &, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
|
Chris@16
|
158 { MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); }
|
Chris@16
|
159
|
Chris@16
|
160 //!Allocates n_elements, each one of
|
Chris@16
|
161 //!element_lengths[i]*sizeof_element bytes.
|
Chris@16
|
162 //!Non-throwing version. chain.size() is not increased on failure.
|
Chris@101
|
163 void allocate_many(const std::nothrow_t &, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
|
Chris@16
|
164 { MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, chain); }
|
Chris@16
|
165
|
Chris@16
|
166 //!Deallocates all elements contained in chain.
|
Chris@16
|
167 //!Never throws.
|
Chris@16
|
168 void deallocate_many(multiallocation_chain &chain)
|
Chris@16
|
169 { MemoryAlgorithm::deallocate_many(chain); }
|
Chris@16
|
170
|
Chris@101
|
171 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
Chris@16
|
172
|
Chris@16
|
173 //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc
|
Chris@16
|
174 //!on failure
|
Chris@16
|
175 void * allocate(size_type nbytes)
|
Chris@16
|
176 {
|
Chris@16
|
177 void * ret = MemoryAlgorithm::allocate(nbytes);
|
Chris@16
|
178 if(!ret)
|
Chris@16
|
179 throw bad_alloc();
|
Chris@16
|
180 return ret;
|
Chris@16
|
181 }
|
Chris@16
|
182
|
Chris@16
|
183 //!Allocates nbytes bytes. This function is only used in
|
Chris@16
|
184 //!single-segment management. Never throws
|
Chris@101
|
185 void * allocate_aligned (size_type nbytes, size_type alignment, const std::nothrow_t &)
|
Chris@16
|
186 { return MemoryAlgorithm::allocate_aligned(nbytes, alignment); }
|
Chris@16
|
187
|
Chris@16
|
188 //!Allocates nbytes bytes. This function is only used in
|
Chris@16
|
189 //!single-segment management. Throws bad_alloc when fails
|
Chris@16
|
190 void * allocate_aligned(size_type nbytes, size_type alignment)
|
Chris@16
|
191 {
|
Chris@16
|
192 void * ret = MemoryAlgorithm::allocate_aligned(nbytes, alignment);
|
Chris@16
|
193 if(!ret)
|
Chris@16
|
194 throw bad_alloc();
|
Chris@16
|
195 return ret;
|
Chris@16
|
196 }
|
Chris@16
|
197
|
Chris@101
|
198 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
Chris@101
|
199
|
Chris@16
|
200 template<class T>
|
Chris@101
|
201 T *allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
|
Chris@101
|
202 size_type &prefer_in_recvd_out_size, T *&reuse)
|
Chris@16
|
203 {
|
Chris@101
|
204 T *ret = MemoryAlgorithm::allocation_command
|
Chris@101
|
205 (command | boost::interprocess::nothrow_allocation, limit_size, prefer_in_recvd_out_size, reuse);
|
Chris@101
|
206 if(!(command & boost::interprocess::nothrow_allocation) && !ret)
|
Chris@16
|
207 throw bad_alloc();
|
Chris@16
|
208 return ret;
|
Chris@16
|
209 }
|
Chris@16
|
210
|
Chris@101
|
211 void *raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects,
|
Chris@101
|
212 size_type &prefer_in_recvd_out_size, void *&reuse, size_type sizeof_object = 1)
|
Chris@16
|
213 {
|
Chris@101
|
214 void *ret = MemoryAlgorithm::raw_allocation_command
|
Chris@101
|
215 ( command | boost::interprocess::nothrow_allocation, limit_objects,
|
Chris@101
|
216 prefer_in_recvd_out_size, reuse, sizeof_object);
|
Chris@101
|
217 if(!(command & boost::interprocess::nothrow_allocation) && !ret)
|
Chris@16
|
218 throw bad_alloc();
|
Chris@16
|
219 return ret;
|
Chris@16
|
220 }
|
Chris@16
|
221
|
Chris@101
|
222 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
Chris@101
|
223
|
Chris@16
|
224 //!Deallocates the bytes allocated with allocate/allocate_many()
|
Chris@16
|
225 //!pointed by addr
|
Chris@16
|
226 void deallocate (void *addr)
|
Chris@16
|
227 { MemoryAlgorithm::deallocate(addr); }
|
Chris@16
|
228
|
Chris@16
|
229 //!Increases managed memory in extra_size bytes more. This only works
|
Chris@16
|
230 //!with single-segment management.
|
Chris@16
|
231 void grow(size_type extra_size)
|
Chris@16
|
232 { MemoryAlgorithm::grow(extra_size); }
|
Chris@16
|
233
|
Chris@16
|
234 //!Decreases managed memory to the minimum. This only works
|
Chris@16
|
235 //!with single-segment management.
|
Chris@16
|
236 void shrink_to_fit()
|
Chris@16
|
237 { MemoryAlgorithm::shrink_to_fit(); }
|
Chris@16
|
238
|
Chris@16
|
239 //!Returns the result of "all_memory_deallocated()" function
|
Chris@16
|
240 //!of the used memory algorithm
|
Chris@16
|
241 bool all_memory_deallocated()
|
Chris@16
|
242 { return MemoryAlgorithm::all_memory_deallocated(); }
|
Chris@16
|
243
|
Chris@16
|
244 //!Returns the result of "check_sanity()" function
|
Chris@16
|
245 //!of the used memory algorithm
|
Chris@16
|
246 bool check_sanity()
|
Chris@16
|
247 { return MemoryAlgorithm::check_sanity(); }
|
Chris@16
|
248
|
Chris@16
|
249 //!Writes to zero free memory (memory not yet allocated)
|
Chris@16
|
250 //!of the memory algorithm
|
Chris@16
|
251 void zero_free_memory()
|
Chris@16
|
252 { MemoryAlgorithm::zero_free_memory(); }
|
Chris@16
|
253
|
Chris@16
|
254 //!Returns the size of the buffer previously allocated pointed by ptr
|
Chris@16
|
255 size_type size(const void *ptr) const
|
Chris@16
|
256 { return MemoryAlgorithm::size(ptr); }
|
Chris@16
|
257
|
Chris@101
|
258 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
Chris@16
|
259 protected:
|
Chris@16
|
260 void * prot_anonymous_construct
|
Chris@16
|
261 (size_type num, bool dothrow, ipcdetail::in_place_interface &table)
|
Chris@16
|
262 {
|
Chris@16
|
263 typedef ipcdetail::block_header<size_type> block_header_t;
|
Chris@16
|
264 block_header_t block_info ( size_type(table.size*num)
|
Chris@16
|
265 , size_type(table.alignment)
|
Chris@16
|
266 , anonymous_type
|
Chris@16
|
267 , 1
|
Chris@16
|
268 , 0);
|
Chris@16
|
269
|
Chris@16
|
270 //Allocate memory
|
Chris@101
|
271 void *ptr_struct = this->allocate(block_info.total_size(), nothrow<>::get());
|
Chris@16
|
272
|
Chris@16
|
273 //Check if there is enough memory
|
Chris@16
|
274 if(!ptr_struct){
|
Chris@16
|
275 if(dothrow){
|
Chris@16
|
276 throw bad_alloc();
|
Chris@16
|
277 }
|
Chris@16
|
278 else{
|
Chris@16
|
279 return 0;
|
Chris@16
|
280 }
|
Chris@16
|
281 }
|
Chris@16
|
282
|
Chris@16
|
283 //Build scoped ptr to avoid leaks with constructor exception
|
Chris@16
|
284 ipcdetail::mem_algo_deallocator<MemoryAlgorithm> mem(ptr_struct, *this);
|
Chris@16
|
285
|
Chris@16
|
286 //Now construct the header
|
Chris@101
|
287 block_header_t * hdr = ::new(ptr_struct, boost_container_new_t()) block_header_t(block_info);
|
Chris@16
|
288 void *ptr = 0; //avoid gcc warning
|
Chris@16
|
289 ptr = hdr->value();
|
Chris@16
|
290
|
Chris@16
|
291 //Now call constructors
|
Chris@16
|
292 ipcdetail::array_construct(ptr, num, table);
|
Chris@16
|
293
|
Chris@16
|
294 //All constructors successful, we don't want erase memory
|
Chris@16
|
295 mem.release();
|
Chris@16
|
296 return ptr;
|
Chris@16
|
297 }
|
Chris@16
|
298
|
Chris@16
|
299 //!Calls the destructor and makes an anonymous deallocate
|
Chris@16
|
300 void prot_anonymous_destroy(const void *object, ipcdetail::in_place_interface &table)
|
Chris@16
|
301 {
|
Chris@16
|
302
|
Chris@16
|
303 //Get control data from associated with this object
|
Chris@16
|
304 typedef ipcdetail::block_header<size_type> block_header_t;
|
Chris@16
|
305 block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment);
|
Chris@16
|
306
|
Chris@16
|
307 //-------------------------------
|
Chris@16
|
308 //scoped_lock<rmutex> guard(m_header);
|
Chris@16
|
309 //-------------------------------
|
Chris@16
|
310
|
Chris@16
|
311 if(ctrl_data->alloc_type() != anonymous_type){
|
Chris@16
|
312 //This is not an anonymous object, the pointer is wrong!
|
Chris@16
|
313 BOOST_ASSERT(0);
|
Chris@16
|
314 }
|
Chris@16
|
315
|
Chris@16
|
316 //Call destructors and free memory
|
Chris@16
|
317 //Build scoped ptr to avoid leaks with destructor exception
|
Chris@16
|
318 std::size_t destroyed = 0;
|
Chris@16
|
319 table.destroy_n(const_cast<void*>(object), ctrl_data->m_value_bytes/table.size, destroyed);
|
Chris@16
|
320 this->deallocate(ctrl_data);
|
Chris@16
|
321 }
|
Chris@101
|
322 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
Chris@16
|
323 };
|
Chris@16
|
324
|
Chris@16
|
325 //!This object is placed in the beginning of memory segment and
|
Chris@16
|
326 //!implements the allocation (named or anonymous) of portions
|
Chris@16
|
327 //!of the segment. This object contains two indexes that
|
Chris@16
|
328 //!maintain an association between a name and a portion of the segment.
|
Chris@16
|
329 //!
|
Chris@16
|
330 //!The first index contains the mappings for normal named objects using the
|
Chris@16
|
331 //!char type specified in the template parameter.
|
Chris@16
|
332 //!
|
Chris@16
|
333 //!The second index contains the association for unique instances. The key will
|
Chris@16
|
334 //!be the const char * returned from type_info.name() function for the unique
|
Chris@16
|
335 //!type to be constructed.
|
Chris@16
|
336 //!
|
Chris@16
|
337 //!segment_manager<CharType, MemoryAlgorithm, IndexType> inherits publicly
|
Chris@16
|
338 //!from segment_manager_base<MemoryAlgorithm> and inherits from it
|
Chris@16
|
339 //!many public functions related to anonymous object and raw memory allocation.
|
Chris@16
|
340 //!See segment_manager_base reference to know about those functions.
|
Chris@16
|
341 template<class CharType
|
Chris@16
|
342 ,class MemoryAlgorithm
|
Chris@16
|
343 ,template<class IndexConfig> class IndexType>
|
Chris@16
|
344 class segment_manager
|
Chris@16
|
345 : public segment_manager_base<MemoryAlgorithm>
|
Chris@16
|
346 {
|
Chris@101
|
347 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
Chris@16
|
348 //Non-copyable
|
Chris@16
|
349 segment_manager();
|
Chris@16
|
350 segment_manager(const segment_manager &);
|
Chris@16
|
351 segment_manager &operator=(const segment_manager &);
|
Chris@101
|
352 typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_t;
|
Chris@101
|
353 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
Chris@16
|
354
|
Chris@16
|
355 public:
|
Chris@101
|
356 typedef MemoryAlgorithm memory_algorithm;
|
Chris@101
|
357 typedef typename segment_manager_base_t::void_pointer void_pointer;
|
Chris@101
|
358 typedef typename segment_manager_base_t::size_type size_type;
|
Chris@101
|
359 typedef typename segment_manager_base_t::difference_type difference_type;
|
Chris@101
|
360 typedef CharType char_type;
|
Chris@16
|
361
|
Chris@16
|
362 typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
|
Chris@16
|
363
|
Chris@101
|
364 static const size_type PayloadPerAllocation = segment_manager_base_t::PayloadPerAllocation;
|
Chris@16
|
365
|
Chris@101
|
366 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
Chris@16
|
367 private:
|
Chris@16
|
368 typedef ipcdetail::block_header<size_type> block_header_t;
|
Chris@16
|
369 typedef ipcdetail::index_config<CharType, MemoryAlgorithm> index_config_named;
|
Chris@16
|
370 typedef ipcdetail::index_config<char, MemoryAlgorithm> index_config_unique;
|
Chris@16
|
371 typedef IndexType<index_config_named> index_type;
|
Chris@16
|
372 typedef ipcdetail::bool_<is_intrusive_index<index_type>::value > is_intrusive_t;
|
Chris@16
|
373 typedef ipcdetail::bool_<is_node_index<index_type>::value> is_node_index_t;
|
Chris@16
|
374
|
Chris@16
|
375 public:
|
Chris@16
|
376 typedef IndexType<index_config_named> named_index_t;
|
Chris@16
|
377 typedef IndexType<index_config_unique> unique_index_t;
|
Chris@16
|
378 typedef ipcdetail::char_ptr_holder<CharType> char_ptr_holder_t;
|
Chris@16
|
379 typedef ipcdetail::segment_manager_iterator_transform
|
Chris@16
|
380 <typename named_index_t::const_iterator
|
Chris@16
|
381 ,is_intrusive_index<index_type>::value> named_transform;
|
Chris@16
|
382
|
Chris@16
|
383 typedef ipcdetail::segment_manager_iterator_transform
|
Chris@16
|
384 <typename unique_index_t::const_iterator
|
Chris@16
|
385 ,is_intrusive_index<index_type>::value> unique_transform;
|
Chris@101
|
386 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
Chris@16
|
387
|
Chris@101
|
388 typedef typename segment_manager_base_t::mutex_family mutex_family;
|
Chris@16
|
389
|
Chris@16
|
390 typedef transform_iterator
|
Chris@16
|
391 <typename named_index_t::const_iterator, named_transform> const_named_iterator;
|
Chris@16
|
392 typedef transform_iterator
|
Chris@16
|
393 <typename unique_index_t::const_iterator, unique_transform> const_unique_iterator;
|
Chris@16
|
394
|
Chris@101
|
395 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
Chris@16
|
396
|
Chris@16
|
397 //!Constructor proxy object definition helper class
|
Chris@16
|
398 template<class T>
|
Chris@16
|
399 struct construct_proxy
|
Chris@16
|
400 {
|
Chris@16
|
401 typedef ipcdetail::named_proxy<segment_manager, T, false> type;
|
Chris@16
|
402 };
|
Chris@16
|
403
|
Chris@16
|
404 //!Constructor proxy object definition helper class
|
Chris@16
|
405 template<class T>
|
Chris@16
|
406 struct construct_iter_proxy
|
Chris@16
|
407 {
|
Chris@16
|
408 typedef ipcdetail::named_proxy<segment_manager, T, true> type;
|
Chris@16
|
409 };
|
Chris@16
|
410
|
Chris@101
|
411 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
Chris@16
|
412
|
Chris@16
|
413 //!Constructor of the segment manager
|
Chris@16
|
414 //!"size" is the size of the memory segment where
|
Chris@16
|
415 //!the segment manager is being constructed.
|
Chris@16
|
416 //!Can throw
|
Chris@16
|
417 explicit segment_manager(size_type segment_size)
|
Chris@101
|
418 : segment_manager_base_t(segment_size, priv_get_reserved_bytes())
|
Chris@101
|
419 , m_header(static_cast<segment_manager_base_t*>(get_this_pointer()))
|
Chris@16
|
420 {
|
Chris@16
|
421 (void) anonymous_instance; (void) unique_instance;
|
Chris@101
|
422 //Check EBO is applied, it's required
|
Chris@101
|
423 const void * const this_addr = this;
|
Chris@101
|
424 const void *const segm_addr = static_cast<segment_manager_base_t*>(this);
|
Chris@101
|
425 (void)this_addr; (void)segm_addr;
|
Chris@101
|
426 BOOST_ASSERT( this_addr == segm_addr);
|
Chris@16
|
427 }
|
Chris@16
|
428
|
Chris@101
|
429 //!Tries to find a previous named/unique allocation. Returns the address
|
Chris@16
|
430 //!and the object count. On failure the first member of the
|
Chris@16
|
431 //!returned pair is 0.
|
Chris@16
|
432 template <class T>
|
Chris@101
|
433 std::pair<T*, size_type> find (char_ptr_holder_t name)
|
Chris@16
|
434 { return this->priv_find_impl<T>(name, true); }
|
Chris@16
|
435
|
Chris@101
|
436 //!Tries to find a previous named/unique allocation. Returns the address
|
Chris@16
|
437 //!and the object count. On failure the first member of the
|
Chris@16
|
438 //!returned pair is 0. This search is not mutex-protected!
|
Chris@101
|
439 //!Use it only inside atomic_func() calls, where the internal mutex
|
Chris@101
|
440 //!is guaranteed to be locked.
|
Chris@16
|
441 template <class T>
|
Chris@101
|
442 std::pair<T*, size_type> find_no_lock (char_ptr_holder_t name)
|
Chris@16
|
443 { return this->priv_find_impl<T>(name, false); }
|
Chris@16
|
444
|
Chris@16
|
445 //!Returns throwing "construct" proxy
|
Chris@16
|
446 //!object
|
Chris@16
|
447 template <class T>
|
Chris@16
|
448 typename construct_proxy<T>::type
|
Chris@16
|
449 construct(char_ptr_holder_t name)
|
Chris@16
|
450 { return typename construct_proxy<T>::type (this, name, false, true); }
|
Chris@16
|
451
|
Chris@16
|
452 //!Returns throwing "search or construct" proxy
|
Chris@16
|
453 //!object
|
Chris@16
|
454 template <class T>
|
Chris@16
|
455 typename construct_proxy<T>::type find_or_construct(char_ptr_holder_t name)
|
Chris@16
|
456 { return typename construct_proxy<T>::type (this, name, true, true); }
|
Chris@16
|
457
|
Chris@16
|
458 //!Returns no throwing "construct" proxy
|
Chris@16
|
459 //!object
|
Chris@16
|
460 template <class T>
|
Chris@16
|
461 typename construct_proxy<T>::type
|
Chris@101
|
462 construct(char_ptr_holder_t name, const std::nothrow_t &)
|
Chris@16
|
463 { return typename construct_proxy<T>::type (this, name, false, false); }
|
Chris@16
|
464
|
Chris@16
|
465 //!Returns no throwing "search or construct"
|
Chris@16
|
466 //!proxy object
|
Chris@16
|
467 template <class T>
|
Chris@16
|
468 typename construct_proxy<T>::type
|
Chris@101
|
469 find_or_construct(char_ptr_holder_t name, const std::nothrow_t &)
|
Chris@16
|
470 { return typename construct_proxy<T>::type (this, name, true, false); }
|
Chris@16
|
471
|
Chris@16
|
472 //!Returns throwing "construct from iterators" proxy object
|
Chris@16
|
473 template <class T>
|
Chris@16
|
474 typename construct_iter_proxy<T>::type
|
Chris@16
|
475 construct_it(char_ptr_holder_t name)
|
Chris@16
|
476 { return typename construct_iter_proxy<T>::type (this, name, false, true); }
|
Chris@16
|
477
|
Chris@16
|
478 //!Returns throwing "search or construct from iterators"
|
Chris@16
|
479 //!proxy object
|
Chris@16
|
480 template <class T>
|
Chris@16
|
481 typename construct_iter_proxy<T>::type
|
Chris@16
|
482 find_or_construct_it(char_ptr_holder_t name)
|
Chris@16
|
483 { return typename construct_iter_proxy<T>::type (this, name, true, true); }
|
Chris@16
|
484
|
Chris@16
|
485 //!Returns no throwing "construct from iterators"
|
Chris@16
|
486 //!proxy object
|
Chris@16
|
487 template <class T>
|
Chris@16
|
488 typename construct_iter_proxy<T>::type
|
Chris@101
|
489 construct_it(char_ptr_holder_t name, const std::nothrow_t &)
|
Chris@16
|
490 { return typename construct_iter_proxy<T>::type (this, name, false, false); }
|
Chris@16
|
491
|
Chris@16
|
492 //!Returns no throwing "search or construct from iterators"
|
Chris@16
|
493 //!proxy object
|
Chris@16
|
494 template <class T>
|
Chris@16
|
495 typename construct_iter_proxy<T>::type
|
Chris@101
|
496 find_or_construct_it(char_ptr_holder_t name, const std::nothrow_t &)
|
Chris@16
|
497 { return typename construct_iter_proxy<T>::type (this, name, true, false); }
|
Chris@16
|
498
|
Chris@16
|
499 //!Calls object function blocking recursive interprocess_mutex and guarantees that
|
Chris@16
|
500 //!no new named_alloc or destroy will be executed by any process while
|
Chris@101
|
501 //!executing the object function call
|
Chris@16
|
502 template <class Func>
|
Chris@16
|
503 void atomic_func(Func &f)
|
Chris@16
|
504 { scoped_lock<rmutex> guard(m_header); f(); }
|
Chris@16
|
505
|
Chris@16
|
506 //!Tries to calls a functor guaranteeing that no new construction, search or
|
Chris@16
|
507 //!destruction will be executed by any process while executing the object
|
Chris@16
|
508 //!function call. If the atomic function can't be immediatelly executed
|
Chris@16
|
509 //!because the internal mutex is already locked, returns false.
|
Chris@16
|
510 //!If the functor throws, this function throws.
|
Chris@16
|
511 template <class Func>
|
Chris@16
|
512 bool try_atomic_func(Func &f)
|
Chris@16
|
513 {
|
Chris@16
|
514 scoped_lock<rmutex> guard(m_header, try_to_lock);
|
Chris@16
|
515 if(guard){
|
Chris@16
|
516 f();
|
Chris@16
|
517 return true;
|
Chris@16
|
518 }
|
Chris@16
|
519 else{
|
Chris@16
|
520 return false;
|
Chris@16
|
521 }
|
Chris@16
|
522 }
|
Chris@16
|
523
|
Chris@101
|
524 //!Destroys a previously created named/unique instance.
|
Chris@16
|
525 //!Returns false if the object was not present.
|
Chris@16
|
526 template <class T>
|
Chris@101
|
527 bool destroy(char_ptr_holder_t name)
|
Chris@16
|
528 {
|
Chris@101
|
529 BOOST_ASSERT(!name.is_anonymous());
|
Chris@16
|
530 ipcdetail::placement_destroy<T> dtor;
|
Chris@16
|
531
|
Chris@101
|
532 if(name.is_unique()){
|
Chris@101
|
533 return this->priv_generic_named_destroy<char>
|
Chris@101
|
534 ( typeid(T).name(), m_header.m_unique_index , dtor, is_intrusive_t());
|
Chris@101
|
535 }
|
Chris@101
|
536 else{
|
Chris@101
|
537 return this->priv_generic_named_destroy<CharType>
|
Chris@101
|
538 ( name.get(), m_header.m_named_index, dtor, is_intrusive_t());
|
Chris@101
|
539 }
|
Chris@16
|
540 }
|
Chris@16
|
541
|
Chris@16
|
542 //!Destroys an anonymous, unique or named object
|
Chris@101
|
543 //!using its address
|
Chris@16
|
544 template <class T>
|
Chris@16
|
545 void destroy_ptr(const T *p)
|
Chris@16
|
546 {
|
Chris@16
|
547 //If T is void transform it to char
|
Chris@16
|
548 typedef typename ipcdetail::char_if_void<T>::type data_t;
|
Chris@16
|
549 ipcdetail::placement_destroy<data_t> dtor;
|
Chris@16
|
550 priv_destroy_ptr(p, dtor);
|
Chris@16
|
551 }
|
Chris@16
|
552
|
Chris@16
|
553 //!Returns the name of an object created with construct/find_or_construct
|
Chris@16
|
554 //!functions. Does not throw
|
Chris@16
|
555 template<class T>
|
Chris@16
|
556 static const CharType *get_instance_name(const T *ptr)
|
Chris@16
|
557 { return priv_get_instance_name(block_header_t::block_header_from_value(ptr)); }
|
Chris@16
|
558
|
Chris@16
|
559 //!Returns the length of an object created with construct/find_or_construct
|
Chris@16
|
560 //!functions. Does not throw.
|
Chris@16
|
561 template<class T>
|
Chris@16
|
562 static size_type get_instance_length(const T *ptr)
|
Chris@16
|
563 { return priv_get_instance_length(block_header_t::block_header_from_value(ptr), sizeof(T)); }
|
Chris@16
|
564
|
Chris@16
|
565 //!Returns is the the name of an object created with construct/find_or_construct
|
Chris@16
|
566 //!functions. Does not throw
|
Chris@16
|
567 template<class T>
|
Chris@16
|
568 static instance_type get_instance_type(const T *ptr)
|
Chris@16
|
569 { return priv_get_instance_type(block_header_t::block_header_from_value(ptr)); }
|
Chris@16
|
570
|
Chris@16
|
571 //!Preallocates needed index resources to optimize the
|
Chris@16
|
572 //!creation of "num" named objects in the managed memory segment.
|
Chris@16
|
573 //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
|
Chris@16
|
574 void reserve_named_objects(size_type num)
|
Chris@16
|
575 {
|
Chris@16
|
576 //-------------------------------
|
Chris@16
|
577 scoped_lock<rmutex> guard(m_header);
|
Chris@16
|
578 //-------------------------------
|
Chris@16
|
579 m_header.m_named_index.reserve(num);
|
Chris@16
|
580 }
|
Chris@16
|
581
|
Chris@16
|
582 //!Preallocates needed index resources to optimize the
|
Chris@16
|
583 //!creation of "num" unique objects in the managed memory segment.
|
Chris@16
|
584 //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
|
Chris@16
|
585 void reserve_unique_objects(size_type num)
|
Chris@16
|
586 {
|
Chris@16
|
587 //-------------------------------
|
Chris@16
|
588 scoped_lock<rmutex> guard(m_header);
|
Chris@16
|
589 //-------------------------------
|
Chris@16
|
590 m_header.m_unique_index.reserve(num);
|
Chris@16
|
591 }
|
Chris@16
|
592
|
Chris@16
|
593 //!Calls shrink_to_fit in both named and unique object indexes
|
Chris@16
|
594 //!to try to free unused memory from those indexes.
|
Chris@16
|
595 void shrink_to_fit_indexes()
|
Chris@16
|
596 {
|
Chris@16
|
597 //-------------------------------
|
Chris@16
|
598 scoped_lock<rmutex> guard(m_header);
|
Chris@16
|
599 //-------------------------------
|
Chris@16
|
600 m_header.m_named_index.shrink_to_fit();
|
Chris@16
|
601 m_header.m_unique_index.shrink_to_fit();
|
Chris@16
|
602 }
|
Chris@16
|
603
|
Chris@16
|
604 //!Returns the number of named objects stored in
|
Chris@16
|
605 //!the segment.
|
Chris@16
|
606 size_type get_num_named_objects()
|
Chris@16
|
607 {
|
Chris@16
|
608 //-------------------------------
|
Chris@16
|
609 scoped_lock<rmutex> guard(m_header);
|
Chris@16
|
610 //-------------------------------
|
Chris@16
|
611 return m_header.m_named_index.size();
|
Chris@16
|
612 }
|
Chris@16
|
613
|
Chris@16
|
614 //!Returns the number of unique objects stored in
|
Chris@16
|
615 //!the segment.
|
Chris@16
|
616 size_type get_num_unique_objects()
|
Chris@16
|
617 {
|
Chris@16
|
618 //-------------------------------
|
Chris@16
|
619 scoped_lock<rmutex> guard(m_header);
|
Chris@16
|
620 //-------------------------------
|
Chris@16
|
621 return m_header.m_unique_index.size();
|
Chris@16
|
622 }
|
Chris@16
|
623
|
Chris@16
|
624 //!Obtains the minimum size needed by the
|
Chris@16
|
625 //!segment manager
|
Chris@16
|
626 static size_type get_min_size()
|
Chris@101
|
627 { return segment_manager_base_t::get_min_size(priv_get_reserved_bytes()); }
|
Chris@16
|
628
|
Chris@16
|
629 //!Returns a constant iterator to the beginning of the information about
|
Chris@16
|
630 //!the named allocations performed in this segment manager
|
Chris@16
|
631 const_named_iterator named_begin() const
|
Chris@16
|
632 {
|
Chris@16
|
633 return make_transform_iterator
|
Chris@16
|
634 (m_header.m_named_index.begin(), named_transform());
|
Chris@16
|
635 }
|
Chris@16
|
636
|
Chris@16
|
637 //!Returns a constant iterator to the end of the information about
|
Chris@16
|
638 //!the named allocations performed in this segment manager
|
Chris@16
|
639 const_named_iterator named_end() const
|
Chris@16
|
640 {
|
Chris@16
|
641 return make_transform_iterator
|
Chris@16
|
642 (m_header.m_named_index.end(), named_transform());
|
Chris@16
|
643 }
|
Chris@16
|
644
|
Chris@16
|
645 //!Returns a constant iterator to the beginning of the information about
|
Chris@16
|
646 //!the unique allocations performed in this segment manager
|
Chris@16
|
647 const_unique_iterator unique_begin() const
|
Chris@16
|
648 {
|
Chris@16
|
649 return make_transform_iterator
|
Chris@16
|
650 (m_header.m_unique_index.begin(), unique_transform());
|
Chris@16
|
651 }
|
Chris@16
|
652
|
Chris@16
|
653 //!Returns a constant iterator to the end of the information about
|
Chris@16
|
654 //!the unique allocations performed in this segment manager
|
Chris@16
|
655 const_unique_iterator unique_end() const
|
Chris@16
|
656 {
|
Chris@16
|
657 return make_transform_iterator
|
Chris@16
|
658 (m_header.m_unique_index.end(), unique_transform());
|
Chris@16
|
659 }
|
Chris@16
|
660
|
Chris@16
|
661 //!This is the default allocator to allocate types T
|
Chris@16
|
662 //!from this managed segment
|
Chris@16
|
663 template<class T>
|
Chris@16
|
664 struct allocator
|
Chris@16
|
665 {
|
Chris@16
|
666 typedef boost::interprocess::allocator<T, segment_manager> type;
|
Chris@16
|
667 };
|
Chris@16
|
668
|
Chris@16
|
669 //!Returns an instance of the default allocator for type T
|
Chris@16
|
670 //!initialized that allocates memory from this segment manager.
|
Chris@16
|
671 template<class T>
|
Chris@16
|
672 typename allocator<T>::type
|
Chris@16
|
673 get_allocator()
|
Chris@16
|
674 { return typename allocator<T>::type(this); }
|
Chris@16
|
675
|
Chris@16
|
676 //!This is the default deleter to delete types T
|
Chris@16
|
677 //!from this managed segment.
|
Chris@16
|
678 template<class T>
|
Chris@16
|
679 struct deleter
|
Chris@16
|
680 {
|
Chris@16
|
681 typedef boost::interprocess::deleter<T, segment_manager> type;
|
Chris@16
|
682 };
|
Chris@16
|
683
|
Chris@101
|
684 //!Returns an instance of the default deleter for type T
|
Chris@101
|
685 //!that will delete an object constructed in this segment manager.
|
Chris@16
|
686 template<class T>
|
Chris@16
|
687 typename deleter<T>::type
|
Chris@16
|
688 get_deleter()
|
Chris@16
|
689 { return typename deleter<T>::type(this); }
|
Chris@16
|
690
|
Chris@101
|
691 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
Chris@16
|
692
|
Chris@16
|
693 //!Generic named/anonymous new function. Offers all the possibilities,
|
Chris@16
|
694 //!such as throwing, search before creating, and the constructor is
|
Chris@16
|
695 //!encapsulated in an object function.
|
Chris@16
|
696 template<class T>
|
Chris@16
|
697 T *generic_construct(const CharType *name,
|
Chris@16
|
698 size_type num,
|
Chris@16
|
699 bool try2find,
|
Chris@16
|
700 bool dothrow,
|
Chris@16
|
701 ipcdetail::in_place_interface &table)
|
Chris@16
|
702 {
|
Chris@16
|
703 return static_cast<T*>
|
Chris@16
|
704 (priv_generic_construct(name, num, try2find, dothrow, table));
|
Chris@16
|
705 }
|
Chris@16
|
706
|
Chris@16
|
707 private:
|
Chris@16
|
708 //!Tries to find a previous named allocation. Returns the address
|
Chris@16
|
709 //!and the object count. On failure the first member of the
|
Chris@16
|
710 //!returned pair is 0.
|
Chris@16
|
711 template <class T>
|
Chris@16
|
712 std::pair<T*, size_type> priv_find_impl (const CharType* name, bool lock)
|
Chris@16
|
713 {
|
Chris@16
|
714 //The name can't be null, no anonymous object can be found by name
|
Chris@16
|
715 BOOST_ASSERT(name != 0);
|
Chris@16
|
716 ipcdetail::placement_destroy<T> table;
|
Chris@16
|
717 size_type sz;
|
Chris@16
|
718 void *ret;
|
Chris@16
|
719
|
Chris@16
|
720 if(name == reinterpret_cast<const CharType*>(-1)){
|
Chris@16
|
721 ret = priv_generic_find<char> (typeid(T).name(), m_header.m_unique_index, table, sz, is_intrusive_t(), lock);
|
Chris@16
|
722 }
|
Chris@16
|
723 else{
|
Chris@16
|
724 ret = priv_generic_find<CharType> (name, m_header.m_named_index, table, sz, is_intrusive_t(), lock);
|
Chris@16
|
725 }
|
Chris@16
|
726 return std::pair<T*, size_type>(static_cast<T*>(ret), sz);
|
Chris@16
|
727 }
|
Chris@16
|
728
|
Chris@16
|
729 //!Tries to find a previous unique allocation. Returns the address
|
Chris@16
|
730 //!and the object count. On failure the first member of the
|
Chris@16
|
731 //!returned pair is 0.
|
Chris@16
|
732 template <class T>
|
Chris@101
|
733 std::pair<T*, size_type> priv_find_impl (const ipcdetail::unique_instance_t* name, bool lock)
|
Chris@16
|
734 {
|
Chris@16
|
735 ipcdetail::placement_destroy<T> table;
|
Chris@16
|
736 size_type size;
|
Chris@16
|
737 void *ret = priv_generic_find<char>(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock);
|
Chris@16
|
738 return std::pair<T*, size_type>(static_cast<T*>(ret), size);
|
Chris@16
|
739 }
|
Chris@16
|
740
|
Chris@101
|
741 void *priv_generic_construct
|
Chris@101
|
742 (const CharType *name, size_type num, bool try2find, bool dothrow, ipcdetail::in_place_interface &table)
|
Chris@16
|
743 {
|
Chris@16
|
744 void *ret;
|
Chris@16
|
745 //Security overflow check
|
Chris@101
|
746 if(num > ((std::size_t)-1)/table.size){
|
Chris@16
|
747 if(dothrow)
|
Chris@16
|
748 throw bad_alloc();
|
Chris@16
|
749 else
|
Chris@16
|
750 return 0;
|
Chris@16
|
751 }
|
Chris@16
|
752 if(name == 0){
|
Chris@16
|
753 ret = this->prot_anonymous_construct(num, dothrow, table);
|
Chris@16
|
754 }
|
Chris@16
|
755 else if(name == reinterpret_cast<const CharType*>(-1)){
|
Chris@16
|
756 ret = this->priv_generic_named_construct<char>
|
Chris@16
|
757 (unique_type, table.type_name, num, try2find, dothrow, table, m_header.m_unique_index, is_intrusive_t());
|
Chris@16
|
758 }
|
Chris@16
|
759 else{
|
Chris@16
|
760 ret = this->priv_generic_named_construct<CharType>
|
Chris@16
|
761 (named_type, name, num, try2find, dothrow, table, m_header.m_named_index, is_intrusive_t());
|
Chris@16
|
762 }
|
Chris@16
|
763 return ret;
|
Chris@16
|
764 }
|
Chris@16
|
765
|
Chris@16
|
766 void priv_destroy_ptr(const void *ptr, ipcdetail::in_place_interface &dtor)
|
Chris@16
|
767 {
|
Chris@16
|
768 block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr, dtor.size, dtor.alignment);
|
Chris@16
|
769 switch(ctrl_data->alloc_type()){
|
Chris@16
|
770 case anonymous_type:
|
Chris@16
|
771 this->prot_anonymous_destroy(ptr, dtor);
|
Chris@16
|
772 break;
|
Chris@16
|
773
|
Chris@16
|
774 case named_type:
|
Chris@16
|
775 this->priv_generic_named_destroy<CharType>
|
Chris@16
|
776 (ctrl_data, m_header.m_named_index, dtor, is_node_index_t());
|
Chris@16
|
777 break;
|
Chris@16
|
778
|
Chris@16
|
779 case unique_type:
|
Chris@16
|
780 this->priv_generic_named_destroy<char>
|
Chris@16
|
781 (ctrl_data, m_header.m_unique_index, dtor, is_node_index_t());
|
Chris@16
|
782 break;
|
Chris@16
|
783
|
Chris@16
|
784 default:
|
Chris@16
|
785 //This type is unknown, bad pointer passed to this function!
|
Chris@16
|
786 BOOST_ASSERT(0);
|
Chris@16
|
787 break;
|
Chris@16
|
788 }
|
Chris@16
|
789 }
|
Chris@16
|
790
|
Chris@16
|
791 //!Returns the name of an object created with construct/find_or_construct
|
Chris@16
|
792 //!functions. Does not throw
|
Chris@16
|
793 static const CharType *priv_get_instance_name(block_header_t *ctrl_data)
|
Chris@16
|
794 {
|
Chris@16
|
795 boost::interprocess::allocation_type type = ctrl_data->alloc_type();
|
Chris@101
|
796 if(type == anonymous_type){
|
Chris@16
|
797 BOOST_ASSERT((type == anonymous_type && ctrl_data->m_num_char == 0) ||
|
Chris@16
|
798 (type == unique_type && ctrl_data->m_num_char != 0) );
|
Chris@16
|
799 return 0;
|
Chris@16
|
800 }
|
Chris@16
|
801 CharType *name = static_cast<CharType*>(ctrl_data->template name<CharType>());
|
Chris@16
|
802
|
Chris@16
|
803 //Sanity checks
|
Chris@16
|
804 BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharType));
|
Chris@16
|
805 BOOST_ASSERT(ctrl_data->m_num_char == std::char_traits<CharType>::length(name));
|
Chris@16
|
806 return name;
|
Chris@16
|
807 }
|
Chris@16
|
808
|
Chris@16
|
809 static size_type priv_get_instance_length(block_header_t *ctrl_data, size_type sizeofvalue)
|
Chris@16
|
810 {
|
Chris@16
|
811 //Get header
|
Chris@16
|
812 BOOST_ASSERT((ctrl_data->value_bytes() %sizeofvalue) == 0);
|
Chris@16
|
813 return ctrl_data->value_bytes()/sizeofvalue;
|
Chris@16
|
814 }
|
Chris@16
|
815
|
Chris@16
|
816 //!Returns is the the name of an object created with construct/find_or_construct
|
Chris@16
|
817 //!functions. Does not throw
|
Chris@16
|
818 static instance_type priv_get_instance_type(block_header_t *ctrl_data)
|
Chris@16
|
819 {
|
Chris@16
|
820 //Get header
|
Chris@16
|
821 BOOST_ASSERT((instance_type)ctrl_data->alloc_type() < max_allocation_type);
|
Chris@16
|
822 return (instance_type)ctrl_data->alloc_type();
|
Chris@16
|
823 }
|
Chris@16
|
824
|
Chris@16
|
825 static size_type priv_get_reserved_bytes()
|
Chris@16
|
826 {
|
Chris@16
|
827 //Get the number of bytes until the end of (*this)
|
Chris@101
|
828 //beginning in the end of the segment_manager_base_t base.
|
Chris@101
|
829 return sizeof(segment_manager) - sizeof(segment_manager_base_t);
|
Chris@16
|
830 }
|
Chris@16
|
831
|
Chris@16
|
832 template <class CharT>
|
Chris@16
|
833 void *priv_generic_find
|
Chris@16
|
834 (const CharT* name,
|
Chris@16
|
835 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
Chris@16
|
836 ipcdetail::in_place_interface &table,
|
Chris@101
|
837 size_type &length, ipcdetail::true_ is_intrusive, bool use_lock)
|
Chris@16
|
838 {
|
Chris@16
|
839 (void)is_intrusive;
|
Chris@16
|
840 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
|
Chris@16
|
841 typedef typename index_type::iterator index_it;
|
Chris@16
|
842
|
Chris@16
|
843 //-------------------------------
|
Chris@16
|
844 scoped_lock<rmutex> guard(priv_get_lock(use_lock));
|
Chris@16
|
845 //-------------------------------
|
Chris@16
|
846 //Find name in index
|
Chris@16
|
847 ipcdetail::intrusive_compare_key<CharT> key
|
Chris@16
|
848 (name, std::char_traits<CharT>::length(name));
|
Chris@16
|
849 index_it it = index.find(key);
|
Chris@16
|
850
|
Chris@16
|
851 //Initialize return values
|
Chris@16
|
852 void *ret_ptr = 0;
|
Chris@16
|
853 length = 0;
|
Chris@16
|
854
|
Chris@16
|
855 //If found, assign values
|
Chris@16
|
856 if(it != index.end()){
|
Chris@16
|
857 //Get header
|
Chris@16
|
858 block_header_t *ctrl_data = it->get_block_header();
|
Chris@16
|
859
|
Chris@16
|
860 //Sanity check
|
Chris@16
|
861 BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
|
Chris@16
|
862 BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
|
Chris@16
|
863 ret_ptr = ctrl_data->value();
|
Chris@16
|
864 length = ctrl_data->m_value_bytes/table.size;
|
Chris@16
|
865 }
|
Chris@16
|
866 return ret_ptr;
|
Chris@16
|
867 }
|
Chris@16
|
868
|
Chris@16
|
869 template <class CharT>
|
Chris@16
|
870 void *priv_generic_find
|
Chris@16
|
871 (const CharT* name,
|
Chris@16
|
872 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
Chris@16
|
873 ipcdetail::in_place_interface &table,
|
Chris@101
|
874 size_type &length, ipcdetail::false_ is_intrusive, bool use_lock)
|
Chris@16
|
875 {
|
Chris@16
|
876 (void)is_intrusive;
|
Chris@16
|
877 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
|
Chris@16
|
878 typedef typename index_type::key_type key_type;
|
Chris@16
|
879 typedef typename index_type::iterator index_it;
|
Chris@16
|
880
|
Chris@16
|
881 //-------------------------------
|
Chris@16
|
882 scoped_lock<rmutex> guard(priv_get_lock(use_lock));
|
Chris@16
|
883 //-------------------------------
|
Chris@16
|
884 //Find name in index
|
Chris@16
|
885 index_it it = index.find(key_type(name, std::char_traits<CharT>::length(name)));
|
Chris@16
|
886
|
Chris@16
|
887 //Initialize return values
|
Chris@16
|
888 void *ret_ptr = 0;
|
Chris@16
|
889 length = 0;
|
Chris@16
|
890
|
Chris@16
|
891 //If found, assign values
|
Chris@16
|
892 if(it != index.end()){
|
Chris@16
|
893 //Get header
|
Chris@16
|
894 block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
|
Chris@16
|
895 (ipcdetail::to_raw_pointer(it->second.m_ptr));
|
Chris@16
|
896
|
Chris@16
|
897 //Sanity check
|
Chris@16
|
898 BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
|
Chris@16
|
899 BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
|
Chris@16
|
900 ret_ptr = ctrl_data->value();
|
Chris@16
|
901 length = ctrl_data->m_value_bytes/table.size;
|
Chris@16
|
902 }
|
Chris@16
|
903 return ret_ptr;
|
Chris@16
|
904 }
|
Chris@16
|
905
|
Chris@16
|
906 template <class CharT>
|
Chris@16
|
907 bool priv_generic_named_destroy
|
Chris@16
|
908 (block_header_t *block_header,
|
Chris@16
|
909 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
Chris@101
|
910 ipcdetail::in_place_interface &table, ipcdetail::true_ is_node_index)
|
Chris@16
|
911 {
|
Chris@16
|
912 (void)is_node_index;
|
Chris@16
|
913 typedef typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator index_it;
|
Chris@16
|
914
|
Chris@16
|
915 index_it *ihdr = block_header_t::template to_first_header<index_it>(block_header);
|
Chris@16
|
916 return this->priv_generic_named_destroy_impl<CharT>(*ihdr, index, table);
|
Chris@16
|
917 }
|
Chris@16
|
918
|
Chris@16
|
919 template <class CharT>
|
Chris@16
|
920 bool priv_generic_named_destroy
|
Chris@16
|
921 (block_header_t *block_header,
|
Chris@16
|
922 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
Chris@16
|
923 ipcdetail::in_place_interface &table,
|
Chris@16
|
924 ipcdetail::false_ is_node_index)
|
Chris@16
|
925 {
|
Chris@16
|
926 (void)is_node_index;
|
Chris@16
|
927 CharT *name = static_cast<CharT*>(block_header->template name<CharT>());
|
Chris@16
|
928 return this->priv_generic_named_destroy<CharT>(name, index, table, is_intrusive_t());
|
Chris@16
|
929 }
|
Chris@16
|
930
|
Chris@16
|
931 template <class CharT>
|
Chris@16
|
932 bool priv_generic_named_destroy(const CharT *name,
|
Chris@16
|
933 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
Chris@101
|
934 ipcdetail::in_place_interface &table, ipcdetail::true_ is_intrusive_index)
|
Chris@16
|
935 {
|
Chris@16
|
936 (void)is_intrusive_index;
|
Chris@16
|
937 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
|
Chris@16
|
938 typedef typename index_type::iterator index_it;
|
Chris@16
|
939 typedef typename index_type::value_type intrusive_value_type;
|
Chris@16
|
940
|
Chris@16
|
941 //-------------------------------
|
Chris@16
|
942 scoped_lock<rmutex> guard(m_header);
|
Chris@16
|
943 //-------------------------------
|
Chris@16
|
944 //Find name in index
|
Chris@16
|
945 ipcdetail::intrusive_compare_key<CharT> key
|
Chris@16
|
946 (name, std::char_traits<CharT>::length(name));
|
Chris@16
|
947 index_it it = index.find(key);
|
Chris@16
|
948
|
Chris@16
|
949 //If not found, return false
|
Chris@16
|
950 if(it == index.end()){
|
Chris@16
|
951 //This name is not present in the index, wrong pointer or name!
|
Chris@16
|
952 //BOOST_ASSERT(0);
|
Chris@16
|
953 return false;
|
Chris@16
|
954 }
|
Chris@16
|
955
|
Chris@16
|
956 block_header_t *ctrl_data = it->get_block_header();
|
Chris@16
|
957 intrusive_value_type *iv = intrusive_value_type::get_intrusive_value_type(ctrl_data);
|
Chris@16
|
958 void *memory = iv;
|
Chris@16
|
959 void *values = ctrl_data->value();
|
Chris@16
|
960 std::size_t num = ctrl_data->m_value_bytes/table.size;
|
Chris@16
|
961
|
Chris@16
|
962 //Sanity check
|
Chris@16
|
963 BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
|
Chris@16
|
964 BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
|
Chris@16
|
965
|
Chris@16
|
966 //Erase node from index
|
Chris@16
|
967 index.erase(it);
|
Chris@16
|
968
|
Chris@16
|
969 //Destroy the headers
|
Chris@16
|
970 ctrl_data->~block_header_t();
|
Chris@16
|
971 iv->~intrusive_value_type();
|
Chris@16
|
972
|
Chris@16
|
973 //Call destructors and free memory
|
Chris@16
|
974 std::size_t destroyed;
|
Chris@16
|
975 table.destroy_n(values, num, destroyed);
|
Chris@16
|
976 this->deallocate(memory);
|
Chris@16
|
977 return true;
|
Chris@16
|
978 }
|
Chris@16
|
979
|
Chris@16
|
980 template <class CharT>
|
Chris@16
|
981 bool priv_generic_named_destroy(const CharT *name,
|
Chris@16
|
982 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
Chris@16
|
983 ipcdetail::in_place_interface &table,
|
Chris@16
|
984 ipcdetail::false_ is_intrusive_index)
|
Chris@16
|
985 {
|
Chris@16
|
986 (void)is_intrusive_index;
|
Chris@16
|
987 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
|
Chris@16
|
988 typedef typename index_type::iterator index_it;
|
Chris@16
|
989 typedef typename index_type::key_type key_type;
|
Chris@16
|
990
|
Chris@16
|
991 //-------------------------------
|
Chris@16
|
992 scoped_lock<rmutex> guard(m_header);
|
Chris@16
|
993 //-------------------------------
|
Chris@16
|
994 //Try to find the name in the index
|
Chris@16
|
995 index_it it = index.find(key_type (name,
|
Chris@16
|
996 std::char_traits<CharT>::length(name)));
|
Chris@16
|
997
|
Chris@16
|
998 //If not found, return false
|
Chris@16
|
999 if(it == index.end()){
|
Chris@16
|
1000 //This name is not present in the index, wrong pointer or name!
|
Chris@16
|
1001 //BOOST_ASSERT(0);
|
Chris@16
|
1002 return false;
|
Chris@16
|
1003 }
|
Chris@16
|
1004 return this->priv_generic_named_destroy_impl<CharT>(it, index, table);
|
Chris@16
|
1005 }
|
Chris@16
|
1006
|
Chris@16
|
1007 template <class CharT>
|
Chris@16
|
1008 bool priv_generic_named_destroy_impl
|
Chris@16
|
1009 (const typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator &it,
|
Chris@16
|
1010 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
Chris@16
|
1011 ipcdetail::in_place_interface &table)
|
Chris@16
|
1012 {
|
Chris@16
|
1013 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
|
Chris@16
|
1014 typedef typename index_type::iterator index_it;
|
Chris@16
|
1015
|
Chris@16
|
1016 //Get allocation parameters
|
Chris@16
|
1017 block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
|
Chris@16
|
1018 (ipcdetail::to_raw_pointer(it->second.m_ptr));
|
Chris@16
|
1019 char *stored_name = static_cast<char*>(static_cast<void*>(const_cast<CharT*>(it->first.name())));
|
Chris@16
|
1020 (void)stored_name;
|
Chris@16
|
1021
|
Chris@16
|
1022 //Check if the distance between the name pointer and the memory pointer
|
Chris@16
|
1023 //is correct (this can detect incorrect type in destruction)
|
Chris@101
|
1024 std::size_t num = ctrl_data->m_value_bytes/table.size;
|
Chris@16
|
1025 void *values = ctrl_data->value();
|
Chris@16
|
1026
|
Chris@16
|
1027 //Sanity check
|
Chris@16
|
1028 BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
|
Chris@16
|
1029 BOOST_ASSERT(static_cast<void*>(stored_name) == static_cast<void*>(ctrl_data->template name<CharT>()));
|
Chris@16
|
1030 BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
|
Chris@16
|
1031
|
Chris@16
|
1032 //Erase node from index
|
Chris@16
|
1033 index.erase(it);
|
Chris@16
|
1034
|
Chris@16
|
1035 //Destroy the header
|
Chris@16
|
1036 ctrl_data->~block_header_t();
|
Chris@16
|
1037
|
Chris@16
|
1038 void *memory;
|
Chris@16
|
1039 if(is_node_index_t::value){
|
Chris@16
|
1040 index_it *ihdr = block_header_t::template
|
Chris@16
|
1041 to_first_header<index_it>(ctrl_data);
|
Chris@16
|
1042 ihdr->~index_it();
|
Chris@16
|
1043 memory = ihdr;
|
Chris@16
|
1044 }
|
Chris@16
|
1045 else{
|
Chris@16
|
1046 memory = ctrl_data;
|
Chris@16
|
1047 }
|
Chris@16
|
1048
|
Chris@16
|
1049 //Call destructors and free memory
|
Chris@101
|
1050 std::size_t destroyed;
|
Chris@16
|
1051 table.destroy_n(values, num, destroyed);
|
Chris@16
|
1052 this->deallocate(memory);
|
Chris@16
|
1053 return true;
|
Chris@16
|
1054 }
|
Chris@16
|
1055
|
Chris@16
|
1056 template<class CharT>
|
Chris@101
|
1057 void * priv_generic_named_construct
|
Chris@101
|
1058 (unsigned char type, const CharT *name, size_type num, bool try2find,
|
Chris@101
|
1059 bool dothrow, ipcdetail::in_place_interface &table,
|
Chris@101
|
1060 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index, ipcdetail::true_ is_intrusive)
|
Chris@16
|
1061 {
|
Chris@16
|
1062 (void)is_intrusive;
|
Chris@16
|
1063 std::size_t namelen = std::char_traits<CharT>::length(name);
|
Chris@16
|
1064
|
Chris@16
|
1065 block_header_t block_info ( size_type(table.size*num)
|
Chris@16
|
1066 , size_type(table.alignment)
|
Chris@16
|
1067 , type
|
Chris@16
|
1068 , sizeof(CharT)
|
Chris@16
|
1069 , namelen);
|
Chris@16
|
1070
|
Chris@16
|
1071 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
|
Chris@16
|
1072 typedef typename index_type::iterator index_it;
|
Chris@16
|
1073 typedef std::pair<index_it, bool> index_ib;
|
Chris@16
|
1074
|
Chris@16
|
1075 //-------------------------------
|
Chris@16
|
1076 scoped_lock<rmutex> guard(m_header);
|
Chris@16
|
1077 //-------------------------------
|
Chris@16
|
1078 //Insert the node. This can throw.
|
Chris@16
|
1079 //First, we want to know if the key is already present before
|
Chris@16
|
1080 //we allocate any memory, and if the key is not present, we
|
Chris@16
|
1081 //want to allocate all memory in a single buffer that will
|
Chris@16
|
1082 //contain the name and the user buffer.
|
Chris@16
|
1083 //
|
Chris@16
|
1084 //Since equal_range(key) + insert(hint, value) approach is
|
Chris@16
|
1085 //quite inefficient in container implementations
|
Chris@16
|
1086 //(they re-test if the position is correct), I've chosen
|
Chris@16
|
1087 //to insert the node, do an ugly un-const cast and modify
|
Chris@16
|
1088 //the key (which is a smart pointer) to an equivalent one
|
Chris@16
|
1089 index_ib insert_ret;
|
Chris@16
|
1090
|
Chris@16
|
1091 typename index_type::insert_commit_data commit_data;
|
Chris@16
|
1092 typedef typename index_type::value_type intrusive_value_type;
|
Chris@16
|
1093
|
Chris@16
|
1094 BOOST_TRY{
|
Chris@16
|
1095 ipcdetail::intrusive_compare_key<CharT> key(name, namelen);
|
Chris@16
|
1096 insert_ret = index.insert_check(key, commit_data);
|
Chris@16
|
1097 }
|
Chris@16
|
1098 //Ignore exceptions
|
Chris@16
|
1099 BOOST_CATCH(...){
|
Chris@16
|
1100 if(dothrow)
|
Chris@16
|
1101 BOOST_RETHROW
|
Chris@16
|
1102 return 0;
|
Chris@16
|
1103 }
|
Chris@16
|
1104 BOOST_CATCH_END
|
Chris@16
|
1105
|
Chris@16
|
1106 index_it it = insert_ret.first;
|
Chris@16
|
1107
|
Chris@16
|
1108 //If found and this is find or construct, return data
|
Chris@16
|
1109 //else return null
|
Chris@16
|
1110 if(!insert_ret.second){
|
Chris@16
|
1111 if(try2find){
|
Chris@16
|
1112 return it->get_block_header()->value();
|
Chris@16
|
1113 }
|
Chris@16
|
1114 if(dothrow){
|
Chris@16
|
1115 throw interprocess_exception(already_exists_error);
|
Chris@16
|
1116 }
|
Chris@16
|
1117 else{
|
Chris@16
|
1118 return 0;
|
Chris@16
|
1119 }
|
Chris@16
|
1120 }
|
Chris@16
|
1121
|
Chris@16
|
1122 //Allocates buffer for name + data, this can throw (it hurts)
|
Chris@16
|
1123 void *buffer_ptr;
|
Chris@16
|
1124
|
Chris@16
|
1125 //Check if there is enough memory
|
Chris@16
|
1126 if(dothrow){
|
Chris@16
|
1127 buffer_ptr = this->allocate
|
Chris@16
|
1128 (block_info.template total_size_with_header<intrusive_value_type>());
|
Chris@16
|
1129 }
|
Chris@16
|
1130 else{
|
Chris@16
|
1131 buffer_ptr = this->allocate
|
Chris@101
|
1132 (block_info.template total_size_with_header<intrusive_value_type>(), nothrow<>::get());
|
Chris@16
|
1133 if(!buffer_ptr)
|
Chris@16
|
1134 return 0;
|
Chris@16
|
1135 }
|
Chris@16
|
1136
|
Chris@16
|
1137 //Now construct the intrusive hook plus the header
|
Chris@101
|
1138 intrusive_value_type * intrusive_hdr = ::new(buffer_ptr, boost_container_new_t()) intrusive_value_type();
|
Chris@101
|
1139 block_header_t * hdr = ::new(intrusive_hdr->get_block_header(), boost_container_new_t())block_header_t(block_info);
|
Chris@16
|
1140 void *ptr = 0; //avoid gcc warning
|
Chris@16
|
1141 ptr = hdr->value();
|
Chris@16
|
1142
|
Chris@16
|
1143 //Copy name to memory segment and insert data
|
Chris@16
|
1144 CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
|
Chris@16
|
1145 std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
|
Chris@16
|
1146
|
Chris@16
|
1147 BOOST_TRY{
|
Chris@16
|
1148 //Now commit the insertion using previous context data
|
Chris@16
|
1149 it = index.insert_commit(*intrusive_hdr, commit_data);
|
Chris@16
|
1150 }
|
Chris@16
|
1151 //Ignore exceptions
|
Chris@16
|
1152 BOOST_CATCH(...){
|
Chris@16
|
1153 if(dothrow)
|
Chris@16
|
1154 BOOST_RETHROW
|
Chris@16
|
1155 return 0;
|
Chris@16
|
1156 }
|
Chris@16
|
1157 BOOST_CATCH_END
|
Chris@16
|
1158
|
Chris@16
|
1159 //Avoid constructions if constructor is trivial
|
Chris@16
|
1160 //Build scoped ptr to avoid leaks with constructor exception
|
Chris@16
|
1161 ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
|
Chris@16
|
1162 (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
|
Chris@16
|
1163
|
Chris@16
|
1164 //Initialize the node value_eraser to erase inserted node
|
Chris@16
|
1165 //if something goes wrong. This will be executed *before*
|
Chris@16
|
1166 //the memory allocation as the intrusive value is built in that
|
Chris@16
|
1167 //memory
|
Chris@16
|
1168 value_eraser<index_type> v_eraser(index, it);
|
Chris@16
|
1169
|
Chris@16
|
1170 //Construct array, this can throw
|
Chris@16
|
1171 ipcdetail::array_construct(ptr, num, table);
|
Chris@16
|
1172
|
Chris@16
|
1173 //Release rollbacks since construction was successful
|
Chris@16
|
1174 v_eraser.release();
|
Chris@16
|
1175 mem.release();
|
Chris@16
|
1176 return ptr;
|
Chris@16
|
1177 }
|
Chris@16
|
1178
|
Chris@16
|
1179 //!Generic named new function for
|
Chris@16
|
1180 //!named functions
|
Chris@16
|
1181 template<class CharT>
|
Chris@101
|
1182 void * priv_generic_named_construct
|
Chris@101
|
1183 (unsigned char type, const CharT *name, size_type num, bool try2find, bool dothrow,
|
Chris@101
|
1184 ipcdetail::in_place_interface &table,
|
Chris@101
|
1185 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index, ipcdetail::false_ is_intrusive)
|
Chris@16
|
1186 {
|
Chris@16
|
1187 (void)is_intrusive;
|
Chris@16
|
1188 std::size_t namelen = std::char_traits<CharT>::length(name);
|
Chris@16
|
1189
|
Chris@16
|
1190 block_header_t block_info ( size_type(table.size*num)
|
Chris@16
|
1191 , size_type(table.alignment)
|
Chris@16
|
1192 , type
|
Chris@16
|
1193 , sizeof(CharT)
|
Chris@16
|
1194 , namelen);
|
Chris@16
|
1195
|
Chris@16
|
1196 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
|
Chris@16
|
1197 typedef typename index_type::key_type key_type;
|
Chris@16
|
1198 typedef typename index_type::mapped_type mapped_type;
|
Chris@16
|
1199 typedef typename index_type::value_type value_type;
|
Chris@16
|
1200 typedef typename index_type::iterator index_it;
|
Chris@16
|
1201 typedef std::pair<index_it, bool> index_ib;
|
Chris@16
|
1202
|
Chris@16
|
1203 //-------------------------------
|
Chris@16
|
1204 scoped_lock<rmutex> guard(m_header);
|
Chris@16
|
1205 //-------------------------------
|
Chris@16
|
1206 //Insert the node. This can throw.
|
Chris@16
|
1207 //First, we want to know if the key is already present before
|
Chris@16
|
1208 //we allocate any memory, and if the key is not present, we
|
Chris@16
|
1209 //want to allocate all memory in a single buffer that will
|
Chris@16
|
1210 //contain the name and the user buffer.
|
Chris@16
|
1211 //
|
Chris@16
|
1212 //Since equal_range(key) + insert(hint, value) approach is
|
Chris@16
|
1213 //quite inefficient in container implementations
|
Chris@16
|
1214 //(they re-test if the position is correct), I've chosen
|
Chris@16
|
1215 //to insert the node, do an ugly un-const cast and modify
|
Chris@16
|
1216 //the key (which is a smart pointer) to an equivalent one
|
Chris@16
|
1217 index_ib insert_ret;
|
Chris@16
|
1218 BOOST_TRY{
|
Chris@16
|
1219 insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0)));
|
Chris@16
|
1220 }
|
Chris@16
|
1221 //Ignore exceptions
|
Chris@16
|
1222 BOOST_CATCH(...){
|
Chris@16
|
1223 if(dothrow)
|
Chris@16
|
1224 BOOST_RETHROW;
|
Chris@16
|
1225 return 0;
|
Chris@16
|
1226 }
|
Chris@16
|
1227 BOOST_CATCH_END
|
Chris@16
|
1228
|
Chris@16
|
1229 index_it it = insert_ret.first;
|
Chris@16
|
1230
|
Chris@16
|
1231 //If found and this is find or construct, return data
|
Chris@16
|
1232 //else return null
|
Chris@16
|
1233 if(!insert_ret.second){
|
Chris@16
|
1234 if(try2find){
|
Chris@16
|
1235 block_header_t *hdr = static_cast<block_header_t*>
|
Chris@16
|
1236 (ipcdetail::to_raw_pointer(it->second.m_ptr));
|
Chris@16
|
1237 return hdr->value();
|
Chris@16
|
1238 }
|
Chris@16
|
1239 return 0;
|
Chris@16
|
1240 }
|
Chris@16
|
1241 //Initialize the node value_eraser to erase inserted node
|
Chris@16
|
1242 //if something goes wrong
|
Chris@16
|
1243 value_eraser<index_type> v_eraser(index, it);
|
Chris@16
|
1244
|
Chris@16
|
1245 //Allocates buffer for name + data, this can throw (it hurts)
|
Chris@16
|
1246 void *buffer_ptr;
|
Chris@16
|
1247 block_header_t * hdr;
|
Chris@16
|
1248
|
Chris@16
|
1249 //Allocate and construct the headers
|
Chris@16
|
1250 if(is_node_index_t::value){
|
Chris@16
|
1251 size_type total_size = block_info.template total_size_with_header<index_it>();
|
Chris@16
|
1252 if(dothrow){
|
Chris@16
|
1253 buffer_ptr = this->allocate(total_size);
|
Chris@16
|
1254 }
|
Chris@16
|
1255 else{
|
Chris@101
|
1256 buffer_ptr = this->allocate(total_size, nothrow<>::get());
|
Chris@16
|
1257 if(!buffer_ptr)
|
Chris@16
|
1258 return 0;
|
Chris@16
|
1259 }
|
Chris@101
|
1260 index_it *idr = ::new(buffer_ptr, boost_container_new_t()) index_it(it);
|
Chris@16
|
1261 hdr = block_header_t::template from_first_header<index_it>(idr);
|
Chris@16
|
1262 }
|
Chris@16
|
1263 else{
|
Chris@16
|
1264 if(dothrow){
|
Chris@16
|
1265 buffer_ptr = this->allocate(block_info.total_size());
|
Chris@16
|
1266 }
|
Chris@16
|
1267 else{
|
Chris@101
|
1268 buffer_ptr = this->allocate(block_info.total_size(), nothrow<>::get());
|
Chris@16
|
1269 if(!buffer_ptr)
|
Chris@16
|
1270 return 0;
|
Chris@16
|
1271 }
|
Chris@16
|
1272 hdr = static_cast<block_header_t*>(buffer_ptr);
|
Chris@16
|
1273 }
|
Chris@16
|
1274
|
Chris@101
|
1275 hdr = ::new(hdr, boost_container_new_t())block_header_t(block_info);
|
Chris@16
|
1276 void *ptr = 0; //avoid gcc warning
|
Chris@16
|
1277 ptr = hdr->value();
|
Chris@16
|
1278
|
Chris@16
|
1279 //Copy name to memory segment and insert data
|
Chris@16
|
1280 CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
|
Chris@16
|
1281 std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
|
Chris@16
|
1282
|
Chris@16
|
1283 //Do the ugly cast, please mama, forgive me!
|
Chris@16
|
1284 //This new key points to an identical string, so it must have the
|
Chris@16
|
1285 //same position than the overwritten key according to the predicate
|
Chris@16
|
1286 const_cast<key_type &>(it->first).name(name_ptr);
|
Chris@16
|
1287 it->second.m_ptr = hdr;
|
Chris@16
|
1288
|
Chris@16
|
1289 //Build scoped ptr to avoid leaks with constructor exception
|
Chris@16
|
1290 ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
|
Chris@16
|
1291 (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
|
Chris@16
|
1292
|
Chris@16
|
1293 //Construct array, this can throw
|
Chris@16
|
1294 ipcdetail::array_construct(ptr, num, table);
|
Chris@16
|
1295
|
Chris@16
|
1296 //All constructors successful, we don't want to release memory
|
Chris@16
|
1297 mem.release();
|
Chris@16
|
1298
|
Chris@16
|
1299 //Release node v_eraser since construction was successful
|
Chris@16
|
1300 v_eraser.release();
|
Chris@16
|
1301 return ptr;
|
Chris@16
|
1302 }
|
Chris@16
|
1303
|
Chris@16
|
1304 private:
|
Chris@16
|
1305 //!Returns the this pointer
|
Chris@16
|
1306 segment_manager *get_this_pointer()
|
Chris@16
|
1307 { return this; }
|
Chris@16
|
1308
|
Chris@16
|
1309 typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex;
|
Chris@16
|
1310
|
Chris@16
|
1311 scoped_lock<rmutex> priv_get_lock(bool use_lock)
|
Chris@16
|
1312 {
|
Chris@16
|
1313 scoped_lock<rmutex> local(m_header, defer_lock);
|
Chris@16
|
1314 if(use_lock){
|
Chris@16
|
1315 local.lock();
|
Chris@16
|
1316 }
|
Chris@16
|
1317 return scoped_lock<rmutex>(boost::move(local));
|
Chris@16
|
1318 }
|
Chris@16
|
1319
|
Chris@16
|
1320 //!This struct includes needed data and derives from
|
Chris@16
|
1321 //!rmutex to allow EBO when using null interprocess_mutex
|
Chris@16
|
1322 struct header_t
|
Chris@16
|
1323 : public rmutex
|
Chris@16
|
1324 {
|
Chris@16
|
1325 named_index_t m_named_index;
|
Chris@16
|
1326 unique_index_t m_unique_index;
|
Chris@16
|
1327
|
Chris@101
|
1328 header_t(segment_manager_base_t *segment_mngr_base)
|
Chris@101
|
1329 : m_named_index (segment_mngr_base)
|
Chris@101
|
1330 , m_unique_index(segment_mngr_base)
|
Chris@16
|
1331 {}
|
Chris@16
|
1332 } m_header;
|
Chris@16
|
1333
|
Chris@101
|
1334 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
Chris@16
|
1335 };
|
Chris@16
|
1336
|
Chris@16
|
1337
|
Chris@16
|
1338 }} //namespace boost { namespace interprocess
|
Chris@16
|
1339
|
Chris@16
|
1340 #include <boost/interprocess/detail/config_end.hpp>
|
Chris@16
|
1341
|
Chris@16
|
1342 #endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP
|
Chris@16
|
1343
|