annotate DEPENDENCIES/generic/include/boost/interprocess/segment_manager.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
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