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