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_DETAIL_MANAGED_MEMORY_IMPL_HPP 12 #define BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_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/interprocess/interprocess_fwd.hpp> 26 #include <boost/interprocess/detail/utilities.hpp> 27 #include <boost/interprocess/detail/os_file_functions.hpp> 28 #include <boost/interprocess/creation_tags.hpp> 29 #include <boost/interprocess/exceptions.hpp> 30 #include <boost/interprocess/segment_manager.hpp> 31 #include <boost/interprocess/sync/scoped_lock.hpp> 32 #include <boost/interprocess/detail/nothrow.hpp> 33 #include <boost/interprocess/detail/simple_swap.hpp> 34 // 35 #include <boost/core/no_exceptions_support.hpp> 36 // 37 #include <boost/intrusive/detail/minimal_pair_header.hpp> 38 #include <boost/assert.hpp> 39 40 //!\file 41 //!Describes a named shared memory allocation user class. 42 //! 43 44 namespace boost { 45 namespace interprocess { 46 namespace ipcdetail { 47 48 template<class BasicManagedMemoryImpl> 49 class create_open_func; 50 51 template< 52 class CharType, 53 class MemoryAlgorithm, 54 template<class IndexConfig> class IndexType 55 > 56 struct segment_manager_type 57 { 58 typedef segment_manager<CharType, MemoryAlgorithm, IndexType> type; 59 }; 60 61 //!This class is designed to be a base class to classes that manage 62 //!creation of objects in a fixed size memory buffer. Apart 63 //!from allocating raw memory, the user can construct named objects. To 64 //!achieve this, this class uses the reserved space provided by the allocation 65 //!algorithm to place a named_allocator_algo, who takes care of name mappings. 66 //!The class can be customized with the char type used for object names 67 //!and the memory allocation algorithm to be used.*/ 68 template < class CharType 69 , class MemoryAlgorithm 70 , template<class IndexConfig> class IndexType 71 , std::size_t Offset = 0 72 > 73 class basic_managed_memory_impl 74 { 75 //Non-copyable 76 basic_managed_memory_impl(const basic_managed_memory_impl &); 77 basic_managed_memory_impl &operator=(const basic_managed_memory_impl &); 78 79 template<class BasicManagedMemoryImpl> 80 friend class create_open_func; 81 82 public: 83 typedef typename segment_manager_type 84 <CharType, MemoryAlgorithm, IndexType>::type segment_manager; 85 typedef CharType char_type; 86 typedef MemoryAlgorithm memory_algorithm; 87 typedef typename MemoryAlgorithm::mutex_family mutex_family; 88 typedef CharType char_t; 89 typedef typename MemoryAlgorithm::size_type size_type; 90 typedef typename MemoryAlgorithm::difference_type difference_type; 91 typedef difference_type handle_t; 92 typedef typename segment_manager:: 93 const_named_iterator const_named_iterator; 94 typedef typename segment_manager:: 95 const_unique_iterator const_unique_iterator; 96 97 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) 98 99 typedef typename 100 segment_manager::char_ptr_holder_t char_ptr_holder_t; 101 //Experimental. Don't use. 102 103 typedef typename segment_manager::multiallocation_chain multiallocation_chain; 104 105 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED 106 107 static const size_type PayloadPerAllocation = segment_manager::PayloadPerAllocation; 108 109 private: 110 typedef basic_managed_memory_impl 111 <CharType, MemoryAlgorithm, IndexType, Offset> self_t; 112 protected: 113 template<class ManagedMemory> grow(const char * filename,size_type extra_bytes)114 static bool grow(const char *filename, size_type extra_bytes) 115 { 116 typedef typename ManagedMemory::device_type device_type; 117 //Increase file size 118 try{ 119 offset_t old_size; 120 { 121 device_type f(open_or_create, filename, read_write); 122 if(!f.get_size(old_size)) 123 return false; 124 f.truncate(old_size + extra_bytes); 125 } 126 ManagedMemory managed_memory(open_only, filename); 127 //Grow always works 128 managed_memory.self_t::grow(extra_bytes); 129 } 130 catch(...){ 131 return false; 132 } 133 return true; 134 } 135 136 template<class ManagedMemory> shrink_to_fit(const char * filename)137 static bool shrink_to_fit(const char *filename) 138 { 139 typedef typename ManagedMemory::device_type device_type; 140 size_type new_size; 141 try{ 142 ManagedMemory managed_memory(open_only, filename); 143 managed_memory.get_size(); 144 managed_memory.self_t::shrink_to_fit(); 145 new_size = managed_memory.get_size(); 146 } 147 catch(...){ 148 return false; 149 } 150 151 //Decrease file size 152 { 153 device_type f(open_or_create, filename, read_write); 154 f.truncate(new_size); 155 } 156 return true; 157 } 158 159 //!Constructor. Allocates basic resources. Never throws. basic_managed_memory_impl()160 basic_managed_memory_impl() 161 : mp_header(0){} 162 163 //!Destructor. Calls close. Never throws. ~basic_managed_memory_impl()164 ~basic_managed_memory_impl() 165 { this->close_impl(); } 166 167 //!Places segment manager in the reserved space. This can throw. create_impl(void * addr,size_type size)168 bool create_impl (void *addr, size_type size) 169 { 170 if(mp_header) return false; 171 172 //Check if there is enough space 173 if(size < segment_manager::get_min_size()) 174 return false; 175 176 //This function should not throw. The index construction can 177 //throw if constructor allocates memory. So we must catch it. 178 BOOST_TRY{ 179 //Let's construct the allocator in memory 180 BOOST_ASSERT((0 == (std::size_t)addr % boost::move_detail::alignment_of<segment_manager>::value)); 181 mp_header = ::new(addr, boost_container_new_t()) segment_manager(size); 182 } 183 BOOST_CATCH(...){ 184 return false; 185 } 186 BOOST_CATCH_END 187 return true; 188 } 189 190 //!Connects to a segment manager in the reserved buffer. Never throws. open_impl(void * addr,size_type)191 bool open_impl (void *addr, size_type) 192 { 193 if(mp_header) return false; 194 mp_header = static_cast<segment_manager*>(addr); 195 return true; 196 } 197 198 //!Frees resources. Never throws. close_impl()199 bool close_impl() 200 { 201 bool ret = mp_header != 0; 202 mp_header = 0; 203 return ret; 204 } 205 206 //!Frees resources and destroys common resources. Never throws. destroy_impl()207 bool destroy_impl() 208 { 209 if(mp_header == 0) 210 return false; 211 mp_header->~segment_manager(); 212 this->close_impl(); 213 return true; 214 } 215 216 //! grow(size_type extra_bytes)217 void grow(size_type extra_bytes) 218 { mp_header->grow(extra_bytes); } 219 shrink_to_fit()220 void shrink_to_fit() 221 { mp_header->shrink_to_fit(); } 222 223 public: 224 225 //!Returns segment manager. Never throws. get_segment_manager() const226 segment_manager *get_segment_manager() const 227 { return mp_header; } 228 229 //!Returns the base address of the memory in this process. Never throws. get_address() const230 void * get_address () const 231 { return reinterpret_cast<char*>(mp_header) - Offset; } 232 233 //!Returns the size of memory segment. Never throws. get_size() const234 size_type get_size () const 235 { return mp_header->get_size() + Offset; } 236 237 //!Returns the number of free bytes of the memory 238 //!segment get_free_memory() const239 size_type get_free_memory() const 240 { return mp_header->get_free_memory(); } 241 242 //!Returns the result of "all_memory_deallocated()" function 243 //!of the used memory algorithm all_memory_deallocated()244 bool all_memory_deallocated() 245 { return mp_header->all_memory_deallocated(); } 246 247 //!Returns the result of "check_sanity()" function 248 //!of the used memory algorithm check_sanity()249 bool check_sanity() 250 { return mp_header->check_sanity(); } 251 252 //!Writes to zero free memory (memory not yet allocated) of 253 //!the memory algorithm zero_free_memory()254 void zero_free_memory() 255 { mp_header->zero_free_memory(); } 256 257 //!Transforms an absolute address into an offset from base address. 258 //!The address must belong to the memory segment. Never throws. get_handle_from_address(const void * ptr) const259 handle_t get_handle_from_address (const void *ptr) const 260 { 261 return (handle_t)(reinterpret_cast<const char*>(ptr) - 262 reinterpret_cast<const char*>(this->get_address())); 263 } 264 265 //!Returns true if the address belongs to the managed memory segment belongs_to_segment(const void * ptr) const266 bool belongs_to_segment (const void *ptr) const 267 { 268 return ptr >= this->get_address() && 269 ptr < (reinterpret_cast<const char*>(this->get_address()) + this->get_size()); 270 } 271 272 //!Transforms previously obtained offset into an absolute address in the 273 //!process space of the current process. Never throws.*/ get_address_from_handle(handle_t offset) const274 void * get_address_from_handle (handle_t offset) const 275 { return reinterpret_cast<char*>(this->get_address()) + offset; } 276 277 //!Searches for nbytes of free memory in the segment, marks the 278 //!memory as used and return the pointer to the memory. If no 279 //!memory is available throws a boost::interprocess::bad_alloc exception allocate(size_type nbytes)280 void* allocate (size_type nbytes) 281 { return mp_header->allocate(nbytes); } 282 283 //!Searches for nbytes of free memory in the segment, marks the 284 //!memory as used and return the pointer to the memory. If no memory 285 //!is available returns 0. Never throws. allocate(size_type nbytes,const std::nothrow_t & tag)286 void* allocate (size_type nbytes, const std::nothrow_t &tag) 287 { return mp_header->allocate(nbytes, tag); } 288 289 //!Allocates nbytes bytes aligned to "alignment" bytes. "alignment" 290 //!must be power of two. If no memory 291 //!is available returns 0. Never throws. allocate_aligned(size_type nbytes,size_type alignment,const std::nothrow_t & tag)292 void * allocate_aligned (size_type nbytes, size_type alignment, const std::nothrow_t &tag) 293 { return mp_header->allocate_aligned(nbytes, alignment, tag); } 294 295 template<class T> allocation_command(boost::interprocess::allocation_type command,size_type limit_size,size_type & prefer_in_recvd_out_size,T * & reuse)296 T * allocation_command (boost::interprocess::allocation_type command, size_type limit_size, 297 size_type &prefer_in_recvd_out_size, T *&reuse) 298 { return mp_header->allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); } 299 300 //!Allocates nbytes bytes aligned to "alignment" bytes. "alignment" 301 //!must be power of two. If no 302 //!memory is available throws a boost::interprocess::bad_alloc exception allocate_aligned(size_type nbytes,size_type alignment)303 void * allocate_aligned(size_type nbytes, size_type alignment) 304 { return mp_header->allocate_aligned(nbytes, alignment); } 305 306 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) 307 308 //Experimental. Don't use. 309 310 //!Allocates n_elements of elem_bytes bytes. 311 //!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)312 void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) 313 { mp_header->allocate_many(elem_bytes, n_elements, chain); } 314 315 //!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes. 316 //!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)317 void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) 318 { mp_header->allocate_many(element_lengths, n_elements, sizeof_element, chain); } 319 320 //!Allocates n_elements of elem_bytes bytes. 321 //!Non-throwing version. chain.size() is not increased on failure. allocate_many(const std::nothrow_t & tag,size_type elem_bytes,size_type n_elements,multiallocation_chain & chain)322 void allocate_many(const std::nothrow_t &tag, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) 323 { mp_header->allocate_many(tag, elem_bytes, n_elements, chain); } 324 325 //!Allocates n_elements, each one of 326 //!element_lengths[i]*sizeof_element bytes. 327 //!Non-throwing version. chain.size() is not increased on failure. allocate_many(const std::nothrow_t & tag,const size_type * elem_sizes,size_type n_elements,size_type sizeof_element,multiallocation_chain & chain)328 void allocate_many(const std::nothrow_t &tag, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) 329 { mp_header->allocate_many(tag, elem_sizes, n_elements, sizeof_element, chain); } 330 331 //!Deallocates all elements contained in chain. 332 //!Never throws. deallocate_many(multiallocation_chain & chain)333 void deallocate_many(multiallocation_chain &chain) 334 { mp_header->deallocate_many(chain); } 335 336 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED 337 338 //!Marks previously allocated memory as free. Never throws. deallocate(void * addr)339 void deallocate (void *addr) 340 { if (mp_header) mp_header->deallocate(addr); } 341 342 //!Tries to find a previous named allocation address. Returns a memory 343 //!buffer and the object count. If not found returned pointer is 0. 344 //!Never throws. 345 template <class T> find(char_ptr_holder_t name)346 std::pair<T*, size_type> find (char_ptr_holder_t name) 347 { return mp_header->template find<T>(name); } 348 349 //!Creates a named object or array in memory 350 //! 351 //!Allocates and constructs a T object or an array of T in memory, 352 //!associates this with the given name and returns a pointer to the 353 //!created object. If an array is being constructed all objects are 354 //!created using the same parameters given to this function. 355 //! 356 //!-> If the name was previously used, returns 0. 357 //! 358 //!-> Throws boost::interprocess::bad_alloc if there is no available memory 359 //! 360 //!-> If T's constructor throws, the function throws that exception. 361 //! 362 //!Memory is freed automatically if T's constructor throws and if an 363 //!array was being constructed, destructors of created objects are called 364 //!before freeing the memory. 365 template <class T> 366 typename segment_manager::template construct_proxy<T>::type construct(char_ptr_holder_t name)367 construct(char_ptr_holder_t name) 368 { return mp_header->template construct<T>(name); } 369 370 //!Finds or creates a named object or array in memory 371 //! 372 //!Tries to find an object with the given name in memory. If 373 //!found, returns the pointer to this pointer. If the object is not found, 374 //!allocates and constructs a T object or an array of T in memory, 375 //!associates this with the given name and returns a pointer to the 376 //!created object. If an array is being constructed all objects are 377 //!created using the same parameters given to this function. 378 //! 379 //!-> Throws boost::interprocess::bad_alloc if there is no available memory 380 //! 381 //!-> If T's constructor throws, the function throws that exception. 382 //! 383 //!Memory is freed automatically if T's constructor throws and if an 384 //!array was being constructed, destructors of created objects are called 385 //!before freeing the memory. 386 template <class T> 387 typename segment_manager::template construct_proxy<T>::type find_or_construct(char_ptr_holder_t name)388 find_or_construct(char_ptr_holder_t name) 389 { return mp_header->template find_or_construct<T>(name); } 390 391 //!Creates a named object or array in memory 392 //! 393 //!Allocates and constructs a T object or an array of T in memory, 394 //!associates this with the given name and returns a pointer to the 395 //!created object. If an array is being constructed all objects are 396 //!created using the same parameters given to this function. 397 //! 398 //!-> If the name was previously used, returns 0. 399 //! 400 //!-> Returns 0 if there is no available memory 401 //! 402 //!-> If T's constructor throws, the function throws that exception. 403 //! 404 //!Memory is freed automatically if T's constructor throws and if an 405 //!array was being constructed, destructors of created objects are called 406 //!before freeing the memory. 407 template <class T> 408 typename segment_manager::template construct_proxy<T>::type construct(char_ptr_holder_t name,const std::nothrow_t & tag)409 construct(char_ptr_holder_t name, const std::nothrow_t &tag) 410 { return mp_header->template construct<T>(name, tag); } 411 412 //!Finds or creates a named object or array in memory 413 //! 414 //!Tries to find an object with the given name in memory. If 415 //!found, returns the pointer to this pointer. If the object is not found, 416 //!allocates and constructs a T object or an array of T in memory, 417 //!associates this with the given name and returns a pointer to the 418 //!created object. If an array is being constructed all objects are 419 //!created using the same parameters given to this function. 420 //! 421 //!-> Returns 0 if there is no available memory 422 //! 423 //!-> If T's constructor throws, the function throws that exception. 424 //! 425 //!Memory is freed automatically if T's constructor throws and if an 426 //!array was being constructed, destructors of created objects are called 427 //!before freeing the memory. 428 template <class T> 429 typename segment_manager::template construct_proxy<T>::type find_or_construct(char_ptr_holder_t name,const std::nothrow_t & tag)430 find_or_construct(char_ptr_holder_t name, const std::nothrow_t &tag) 431 { return mp_header->template find_or_construct<T>(name, tag); } 432 433 //!Creates a named array from iterators in memory 434 //! 435 //!Allocates and constructs an array of T in memory, 436 //!associates this with the given name and returns a pointer to the 437 //!created object. Each element in the array is created using the 438 //!objects returned when dereferencing iterators as parameters 439 //!and incrementing all iterators for each element. 440 //! 441 //!-> If the name was previously used, returns 0. 442 //! 443 //!-> Throws boost::interprocess::bad_alloc if there is no available memory 444 //! 445 //!-> If T's constructor throws, the function throws that exception. 446 //! 447 //!Memory is freed automatically if T's constructor throws and 448 //!destructors of created objects are called before freeing the memory. 449 template <class T> 450 typename segment_manager::template construct_iter_proxy<T>::type construct_it(char_ptr_holder_t name)451 construct_it(char_ptr_holder_t name) 452 { return mp_header->template construct_it<T>(name); } 453 454 //!Finds or creates a named array from iterators in memory 455 //! 456 //!Tries to find an object with the given name in memory. If 457 //!found, returns the pointer to this pointer. If the object is not found, 458 //!allocates and constructs an array of T in memory, 459 //!associates this with the given name and returns a pointer to the 460 //!created object. Each element in the array is created using the 461 //!objects returned when dereferencing iterators as parameters 462 //!and incrementing all iterators for each element. 463 //! 464 //!-> If the name was previously used, returns 0. 465 //! 466 //!-> Throws boost::interprocess::bad_alloc if there is no available memory 467 //! 468 //!-> If T's constructor throws, the function throws that exception. 469 //! 470 //!Memory is freed automatically if T's constructor throws and 471 //!destructors of created objects are called before freeing the memory. 472 template <class T> 473 typename segment_manager::template construct_iter_proxy<T>::type find_or_construct_it(char_ptr_holder_t name)474 find_or_construct_it(char_ptr_holder_t name) 475 { return mp_header->template find_or_construct_it<T>(name); } 476 477 //!Creates a named array from iterators in memory 478 //! 479 //!Allocates and constructs an array of T in memory, 480 //!associates this with the given name and returns a pointer to the 481 //!created object. Each element in the array is created using the 482 //!objects returned when dereferencing iterators as parameters 483 //!and incrementing all iterators for each element. 484 //! 485 //!-> If the name was previously used, returns 0. 486 //! 487 //!-> If there is no available memory, returns 0. 488 //! 489 //!-> If T's constructor throws, the function throws that exception. 490 //! 491 //!Memory is freed automatically if T's constructor throws and 492 //!destructors of created objects are called before freeing the memory.*/ 493 template <class T> 494 typename segment_manager::template construct_iter_proxy<T>::type construct_it(char_ptr_holder_t name,const std::nothrow_t & tag)495 construct_it(char_ptr_holder_t name, const std::nothrow_t &tag) 496 { return mp_header->template construct_it<T>(name, tag); } 497 498 //!Finds or creates a named array from iterators in memory 499 //! 500 //!Tries to find an object with the given name in memory. If 501 //!found, returns the pointer to this pointer. If the object is not found, 502 //!allocates and constructs an array of T in memory, 503 //!associates this with the given name and returns a pointer to the 504 //!created object. Each element in the array is created using the 505 //!objects returned when dereferencing iterators as parameters 506 //!and incrementing all iterators for each element. 507 //! 508 //!-> If the name was previously used, returns 0. 509 //! 510 //!-> If there is no available memory, returns 0. 511 //! 512 //!-> If T's constructor throws, the function throws that exception. 513 //! 514 //!Memory is freed automatically if T's constructor throws and 515 //!destructors of created objects are called before freeing the memory.*/ 516 template <class T> 517 typename segment_manager::template construct_iter_proxy<T>::type find_or_construct_it(char_ptr_holder_t name,const std::nothrow_t & tag)518 find_or_construct_it(char_ptr_holder_t name, const std::nothrow_t &tag) 519 { return mp_header->template find_or_construct_it<T>(name, tag); } 520 521 //!Calls a functor and guarantees that no new construction, search or 522 //!destruction will be executed by any process while executing the object 523 //!function call. If the functor throws, this function throws. 524 template <class Func> atomic_func(Func & f)525 void atomic_func(Func &f) 526 { mp_header->atomic_func(f); } 527 528 //!Tries to call a functor guaranteeing that no new construction, search or 529 //!destruction will be executed by any process while executing the object 530 //!function call. If the atomic function can't be immediatelly executed 531 //!because the internal mutex is already locked, returns false. 532 //!If the functor throws, this function throws. 533 template <class Func> try_atomic_func(Func & f)534 bool try_atomic_func(Func &f) 535 { return mp_header->try_atomic_func(f); } 536 537 //!Destroys a named memory object or array. 538 //! 539 //!Finds the object with the given name, calls its destructors, 540 //!frees used memory and returns true. 541 //! 542 //!-> If the object is not found, it returns false. 543 //! 544 //!Exception Handling: 545 //! 546 //!When deleting a dynamically object or array, the Standard 547 //!does not guarantee that dynamically allocated memory, will be released. 548 //!Also, when deleting arrays, the Standard doesn't require calling 549 //!destructors for the rest of the objects if for one of them the destructor 550 //!terminated with an exception. 551 //! 552 //!Destroying an object: 553 //! 554 //!If the destructor throws, the memory will be freed and that exception 555 //!will be thrown. 556 //! 557 //!Destroying an array: 558 //! 559 //!When destroying an array, if a destructor throws, the rest of 560 //!destructors are called. If any of these throws, the exceptions are 561 //!ignored. The name association will be erased, memory will be freed and 562 //!the first exception will be thrown. This guarantees the unlocking of 563 //!mutexes and other resources. 564 //! 565 //!For all theses reasons, classes with throwing destructors are not 566 //!recommended. 567 template <class T> destroy(const CharType * name)568 bool destroy(const CharType *name) 569 { return mp_header->template destroy<T>(name); } 570 571 //!Destroys the unique instance of type T 572 //! 573 //!Calls the destructor, frees used memory and returns true. 574 //! 575 //!Exception Handling: 576 //! 577 //!When deleting a dynamically object, the Standard does not 578 //!guarantee that dynamically allocated memory will be released. 579 //! 580 //!Destroying an object: 581 //! 582 //!If the destructor throws, the memory will be freed and that exception 583 //!will be thrown. 584 //! 585 //!For all theses reasons, classes with throwing destructors are not 586 //!recommended for memory. 587 template <class T> destroy(const unique_instance_t * const)588 bool destroy(const unique_instance_t *const ) 589 { return mp_header->template destroy<T>(unique_instance); } 590 591 //!Destroys the object (named, unique, or anonymous) 592 //! 593 //!Calls the destructor, frees used memory and returns true. 594 //! 595 //!Exception Handling: 596 //! 597 //!When deleting a dynamically object, the Standard does not 598 //!guarantee that dynamically allocated memory will be released. 599 //! 600 //!Destroying an object: 601 //! 602 //!If the destructor throws, the memory will be freed and that exception 603 //!will be thrown. 604 //! 605 //!For all theses reasons, classes with throwing destructors are not 606 //!recommended for memory. 607 template <class T> destroy_ptr(const T * ptr)608 void destroy_ptr(const T *ptr) 609 { mp_header->template destroy_ptr<T>(ptr); } 610 611 //!Returns the name of an object created with construct/find_or_construct 612 //!functions. If ptr points to an unique instance typeid(T).name() is returned. 613 template<class T> get_instance_name(const T * ptr)614 static const char_type *get_instance_name(const T *ptr) 615 { return segment_manager::get_instance_name(ptr); } 616 617 //!Returns is the type an object created with construct/find_or_construct 618 //!functions. Does not throw. 619 template<class T> get_instance_type(const T * ptr)620 static instance_type get_instance_type(const T *ptr) 621 { return segment_manager::get_instance_type(ptr); } 622 623 //!Returns the length of an object created with construct/find_or_construct 624 //!functions (1 if is a single element, >=1 if it's an array). Does not throw. 625 template<class T> get_instance_length(const T * ptr)626 static size_type get_instance_length(const T *ptr) 627 { return segment_manager::get_instance_length(ptr); } 628 629 //!Preallocates needed index resources to optimize the 630 //!creation of "num" named objects in the memory segment. 631 //!Can throw boost::interprocess::bad_alloc if there is no enough memory. reserve_named_objects(size_type num)632 void reserve_named_objects(size_type num) 633 { mp_header->reserve_named_objects(num); } 634 635 //!Preallocates needed index resources to optimize the 636 //!creation of "num" unique objects in the memory segment. 637 //!Can throw boost::interprocess::bad_alloc if there is no enough memory. reserve_unique_objects(size_type num)638 void reserve_unique_objects(size_type num) 639 { mp_header->reserve_unique_objects(num); } 640 641 //!Calls shrink_to_fit in both named and unique object indexes 642 //to try to free unused memory from those indexes. shrink_to_fit_indexes()643 void shrink_to_fit_indexes() 644 { mp_header->shrink_to_fit_indexes(); } 645 646 //!Returns the number of named objects stored 647 //!in the managed segment. get_num_named_objects()648 size_type get_num_named_objects() 649 { return mp_header->get_num_named_objects(); } 650 651 //!Returns the number of unique objects stored 652 //!in the managed segment. get_num_unique_objects()653 size_type get_num_unique_objects() 654 { return mp_header->get_num_unique_objects(); } 655 656 //!Returns a constant iterator to the index storing the 657 //!named allocations. NOT thread-safe. Never throws. named_begin() const658 const_named_iterator named_begin() const 659 { return mp_header->named_begin(); } 660 661 //!Returns a constant iterator to the end of the index 662 //!storing the named allocations. NOT thread-safe. Never throws. named_end() const663 const_named_iterator named_end() const 664 { return mp_header->named_end(); } 665 666 //!Returns a constant iterator to the index storing the 667 //!unique allocations. NOT thread-safe. Never throws. unique_begin() const668 const_unique_iterator unique_begin() const 669 { return mp_header->unique_begin(); } 670 671 //!Returns a constant iterator to the end of the index 672 //!storing the unique allocations. NOT thread-safe. Never throws. unique_end() const673 const_unique_iterator unique_end() const 674 { return mp_header->unique_end(); } 675 676 //!This is the default allocator to allocate types T 677 //!from this managed segment 678 template<class T> 679 struct allocator 680 { 681 typedef typename segment_manager::template allocator<T>::type type; 682 }; 683 684 //!Returns an instance of the default allocator for type T 685 //!initialized that allocates memory from this segment manager. 686 template<class T> 687 typename allocator<T>::type get_allocator()688 get_allocator() 689 { return mp_header->template get_allocator<T>(); } 690 691 //!This is the default deleter to delete types T 692 //!from this managed segment. 693 template<class T> 694 struct deleter 695 { 696 typedef typename segment_manager::template deleter<T>::type type; 697 }; 698 699 //!Returns an instance of the default allocator for type T 700 //!initialized that allocates memory from this segment manager. 701 template<class T> 702 typename deleter<T>::type get_deleter()703 get_deleter() 704 { return mp_header->template get_deleter<T>(); } 705 706 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) 707 //!Tries to find a previous named allocation address. Returns a memory 708 //!buffer and the object count. If not found returned pointer is 0. 709 //!Never throws. 710 template <class T> find_no_lock(char_ptr_holder_t name)711 std::pair<T*, size_type> find_no_lock (char_ptr_holder_t name) 712 { return mp_header->template find_no_lock<T>(name); } 713 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED 714 715 protected: 716 //!Swaps the segment manager's managed by this managed memory segment. 717 //!NOT thread-safe. Never throws. swap(basic_managed_memory_impl & other)718 void swap(basic_managed_memory_impl &other) 719 { (simple_swap)(mp_header, other.mp_header); } 720 721 private: 722 segment_manager *mp_header; 723 }; 724 725 template<class BasicManagedMemoryImpl> 726 class create_open_func 727 { 728 typedef typename BasicManagedMemoryImpl::size_type size_type; 729 730 public: 731 create_open_func(BasicManagedMemoryImpl * const frontend,create_enum_t type)732 create_open_func(BasicManagedMemoryImpl * const frontend, create_enum_t type) 733 : m_frontend(frontend), m_type(type){} 734 operator ()(void * addr,std::size_t size,bool created) const735 bool operator()(void *addr, std::size_t size, bool created) const 736 { 737 if( ((m_type == DoOpen) && created) || 738 ((m_type == DoCreate) && !created) || 739 //Check for overflow 740 size_type(-1) < size ){ 741 return false; 742 } 743 else if(created){ 744 return m_frontend->create_impl(addr, static_cast<size_type>(size)); 745 } 746 else{ 747 return m_frontend->open_impl (addr, static_cast<size_type>(size)); 748 } 749 } 750 get_min_size()751 static std::size_t get_min_size() 752 { 753 const size_type sz = BasicManagedMemoryImpl::segment_manager::get_min_size(); 754 if(sz > std::size_t(-1)){ 755 //The minimum size is not representable by std::size_t 756 BOOST_ASSERT(false); 757 return std::size_t(-1); 758 } 759 else{ 760 return static_cast<std::size_t>(sz); 761 } 762 } 763 764 private: 765 BasicManagedMemoryImpl *m_frontend; 766 create_enum_t m_type; 767 }; 768 769 } //namespace ipcdetail { 770 } //namespace interprocess { 771 } //namespace boost { 772 773 #include <boost/interprocess/detail/config_end.hpp> 774 775 #endif //BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP 776 777