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