Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // See http://www.boost.org/libs/interprocess for documentation. Chris@16: // Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: #ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP Chris@16: #define BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP Chris@16: Chris@101: #ifndef BOOST_CONFIG_HPP Chris@101: # include Chris@101: #endif Chris@101: # Chris@101: #if defined(BOOST_HAS_PRAGMA_ONCE) Chris@16: # pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@101: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@101: // container/detail Chris@101: #include Chris@101: #include Chris@101: // std Chris@16: #include //std::size_t Chris@101: #include Chris@16: #include Chris@16: #ifndef BOOST_NO_EXCEPTIONS Chris@16: #include Chris@16: #endif Chris@16: Chris@16: //!\file Chris@16: //!Describes the object placed in a memory segment that provides Chris@16: //!named object allocation capabilities for single-segment and Chris@16: //!multi-segment allocations. Chris@16: Chris@16: namespace boost{ Chris@16: namespace interprocess{ Chris@16: Chris@16: //!This object is the public base class of segment manager. Chris@16: //!This class only depends on the memory allocation algorithm Chris@16: //!and implements all the allocation features not related Chris@16: //!to named or unique objects. Chris@16: //! Chris@16: //!Storing a reference to segment_manager forces Chris@16: //!the holder class to be dependent on index types and character types. Chris@16: //!When such dependence is not desirable and only anonymous and raw Chris@16: //!allocations are needed, segment_manager_base is the correct answer. Chris@16: template Chris@16: class segment_manager_base Chris@16: : private MemoryAlgorithm Chris@16: { Chris@16: public: Chris@16: typedef segment_manager_base segment_manager_base_type; Chris@16: typedef typename MemoryAlgorithm::void_pointer void_pointer; Chris@16: typedef typename MemoryAlgorithm::mutex_family mutex_family; Chris@16: typedef MemoryAlgorithm memory_algorithm; Chris@16: Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@16: Chris@16: //Experimental. Don't use Chris@16: typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; Chris@16: typedef typename MemoryAlgorithm::difference_type difference_type; Chris@16: typedef typename MemoryAlgorithm::size_type size_type; Chris@16: Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@16: Chris@16: //!This constant indicates the payload size Chris@16: //!associated with each allocation of the memory algorithm Chris@16: static const size_type PayloadPerAllocation = MemoryAlgorithm::PayloadPerAllocation; Chris@16: Chris@16: //!Constructor of the segment_manager_base Chris@16: //! Chris@16: //!"size" is the size of the memory segment where Chris@16: //!the basic segment manager is being constructed. Chris@16: //! Chris@16: //!"reserved_bytes" is the number of bytes Chris@16: //!after the end of the memory algorithm object itself Chris@16: //!that the memory algorithm will exclude from Chris@16: //!dynamic allocation Chris@16: //! Chris@16: //!Can throw Chris@16: segment_manager_base(size_type sz, size_type reserved_bytes) Chris@16: : MemoryAlgorithm(sz, reserved_bytes) Chris@16: { Chris@16: BOOST_ASSERT((sizeof(segment_manager_base) == sizeof(MemoryAlgorithm))); Chris@16: } Chris@16: Chris@16: //!Returns the size of the memory Chris@16: //!segment Chris@16: size_type get_size() const Chris@16: { return MemoryAlgorithm::get_size(); } Chris@16: Chris@16: //!Returns the number of free bytes of the memory Chris@16: //!segment Chris@16: size_type get_free_memory() const Chris@16: { return MemoryAlgorithm::get_free_memory(); } Chris@16: Chris@16: //!Obtains the minimum size needed by Chris@16: //!the segment manager Chris@16: static size_type get_min_size (size_type size) Chris@16: { return MemoryAlgorithm::get_min_size(size); } Chris@16: Chris@16: //!Allocates nbytes bytes. This function is only used in Chris@16: //!single-segment management. Never throws Chris@101: void * allocate (size_type nbytes, const std::nothrow_t &) Chris@16: { return MemoryAlgorithm::allocate(nbytes); } Chris@16: Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@16: Chris@16: //Experimental. Dont' use. Chris@101: //!Allocates n_elements of elem_bytes bytes. Chris@16: //!Throws bad_alloc on failure. chain.size() is not increased on failure. Chris@16: void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) Chris@16: { Chris@16: size_type prev_size = chain.size(); Chris@16: MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); Chris@16: if(!elem_bytes || chain.size() == prev_size){ Chris@16: throw bad_alloc(); Chris@16: } Chris@16: } Chris@16: Chris@16: //!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes. Chris@16: //!Throws bad_alloc on failure. chain.size() is not increased on failure. Chris@16: void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) Chris@16: { Chris@16: size_type prev_size = chain.size(); Chris@16: MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain); Chris@16: if(!sizeof_element || chain.size() == prev_size){ Chris@16: throw bad_alloc(); Chris@16: } Chris@16: } Chris@16: Chris@101: //!Allocates n_elements of elem_bytes bytes. Chris@16: //!Non-throwing version. chain.size() is not increased on failure. Chris@101: void allocate_many(const std::nothrow_t &, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) Chris@16: { MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); } Chris@16: Chris@16: //!Allocates n_elements, each one of Chris@16: //!element_lengths[i]*sizeof_element bytes. Chris@16: //!Non-throwing version. chain.size() is not increased on failure. Chris@101: void allocate_many(const std::nothrow_t &, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) Chris@16: { MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, chain); } Chris@16: Chris@16: //!Deallocates all elements contained in chain. Chris@16: //!Never throws. Chris@16: void deallocate_many(multiallocation_chain &chain) Chris@16: { MemoryAlgorithm::deallocate_many(chain); } Chris@16: Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@16: Chris@16: //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc Chris@16: //!on failure Chris@16: void * allocate(size_type nbytes) Chris@16: { Chris@16: void * ret = MemoryAlgorithm::allocate(nbytes); Chris@16: if(!ret) Chris@16: throw bad_alloc(); Chris@16: return ret; Chris@16: } Chris@16: Chris@16: //!Allocates nbytes bytes. This function is only used in Chris@16: //!single-segment management. Never throws Chris@101: void * allocate_aligned (size_type nbytes, size_type alignment, const std::nothrow_t &) Chris@16: { return MemoryAlgorithm::allocate_aligned(nbytes, alignment); } Chris@16: Chris@16: //!Allocates nbytes bytes. This function is only used in Chris@16: //!single-segment management. Throws bad_alloc when fails Chris@16: void * allocate_aligned(size_type nbytes, size_type alignment) Chris@16: { Chris@16: void * ret = MemoryAlgorithm::allocate_aligned(nbytes, alignment); Chris@16: if(!ret) Chris@16: throw bad_alloc(); Chris@16: return ret; Chris@16: } Chris@16: Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@101: Chris@16: template Chris@101: T *allocation_command (boost::interprocess::allocation_type command, size_type limit_size, Chris@101: size_type &prefer_in_recvd_out_size, T *&reuse) Chris@16: { Chris@101: T *ret = MemoryAlgorithm::allocation_command Chris@101: (command | boost::interprocess::nothrow_allocation, limit_size, prefer_in_recvd_out_size, reuse); Chris@101: if(!(command & boost::interprocess::nothrow_allocation) && !ret) Chris@16: throw bad_alloc(); Chris@16: return ret; Chris@16: } Chris@16: Chris@101: void *raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects, Chris@101: size_type &prefer_in_recvd_out_size, void *&reuse, size_type sizeof_object = 1) Chris@16: { Chris@101: void *ret = MemoryAlgorithm::raw_allocation_command Chris@101: ( command | boost::interprocess::nothrow_allocation, limit_objects, Chris@101: prefer_in_recvd_out_size, reuse, sizeof_object); Chris@101: if(!(command & boost::interprocess::nothrow_allocation) && !ret) Chris@16: throw bad_alloc(); Chris@16: return ret; Chris@16: } Chris@16: Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@101: Chris@16: //!Deallocates the bytes allocated with allocate/allocate_many() Chris@16: //!pointed by addr Chris@16: void deallocate (void *addr) Chris@16: { MemoryAlgorithm::deallocate(addr); } Chris@16: Chris@16: //!Increases managed memory in extra_size bytes more. This only works Chris@16: //!with single-segment management. Chris@16: void grow(size_type extra_size) Chris@16: { MemoryAlgorithm::grow(extra_size); } Chris@16: Chris@16: //!Decreases managed memory to the minimum. This only works Chris@16: //!with single-segment management. Chris@16: void shrink_to_fit() Chris@16: { MemoryAlgorithm::shrink_to_fit(); } Chris@16: Chris@16: //!Returns the result of "all_memory_deallocated()" function Chris@16: //!of the used memory algorithm Chris@16: bool all_memory_deallocated() Chris@16: { return MemoryAlgorithm::all_memory_deallocated(); } Chris@16: Chris@16: //!Returns the result of "check_sanity()" function Chris@16: //!of the used memory algorithm Chris@16: bool check_sanity() Chris@16: { return MemoryAlgorithm::check_sanity(); } Chris@16: Chris@16: //!Writes to zero free memory (memory not yet allocated) Chris@16: //!of the memory algorithm Chris@16: void zero_free_memory() Chris@16: { MemoryAlgorithm::zero_free_memory(); } Chris@16: Chris@16: //!Returns the size of the buffer previously allocated pointed by ptr Chris@16: size_type size(const void *ptr) const Chris@16: { return MemoryAlgorithm::size(ptr); } Chris@16: Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@16: protected: Chris@16: void * prot_anonymous_construct Chris@16: (size_type num, bool dothrow, ipcdetail::in_place_interface &table) Chris@16: { Chris@16: typedef ipcdetail::block_header block_header_t; Chris@16: block_header_t block_info ( size_type(table.size*num) Chris@16: , size_type(table.alignment) Chris@16: , anonymous_type Chris@16: , 1 Chris@16: , 0); Chris@16: Chris@16: //Allocate memory Chris@101: void *ptr_struct = this->allocate(block_info.total_size(), nothrow<>::get()); Chris@16: Chris@16: //Check if there is enough memory Chris@16: if(!ptr_struct){ Chris@16: if(dothrow){ Chris@16: throw bad_alloc(); Chris@16: } Chris@16: else{ Chris@16: return 0; Chris@16: } Chris@16: } Chris@16: Chris@16: //Build scoped ptr to avoid leaks with constructor exception Chris@16: ipcdetail::mem_algo_deallocator mem(ptr_struct, *this); Chris@16: Chris@16: //Now construct the header Chris@101: block_header_t * hdr = ::new(ptr_struct, boost_container_new_t()) block_header_t(block_info); Chris@16: void *ptr = 0; //avoid gcc warning Chris@16: ptr = hdr->value(); Chris@16: Chris@16: //Now call constructors Chris@16: ipcdetail::array_construct(ptr, num, table); Chris@16: Chris@16: //All constructors successful, we don't want erase memory Chris@16: mem.release(); Chris@16: return ptr; Chris@16: } Chris@16: Chris@16: //!Calls the destructor and makes an anonymous deallocate Chris@16: void prot_anonymous_destroy(const void *object, ipcdetail::in_place_interface &table) Chris@16: { Chris@16: Chris@16: //Get control data from associated with this object Chris@16: typedef ipcdetail::block_header block_header_t; Chris@16: block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment); Chris@16: Chris@16: //------------------------------- Chris@16: //scoped_lock guard(m_header); Chris@16: //------------------------------- Chris@16: Chris@16: if(ctrl_data->alloc_type() != anonymous_type){ Chris@16: //This is not an anonymous object, the pointer is wrong! Chris@16: BOOST_ASSERT(0); Chris@16: } Chris@16: Chris@16: //Call destructors and free memory Chris@16: //Build scoped ptr to avoid leaks with destructor exception Chris@16: std::size_t destroyed = 0; Chris@16: table.destroy_n(const_cast(object), ctrl_data->m_value_bytes/table.size, destroyed); Chris@16: this->deallocate(ctrl_data); Chris@16: } Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@16: }; Chris@16: Chris@16: //!This object is placed in the beginning of memory segment and Chris@16: //!implements the allocation (named or anonymous) of portions Chris@16: //!of the segment. This object contains two indexes that Chris@16: //!maintain an association between a name and a portion of the segment. Chris@16: //! Chris@16: //!The first index contains the mappings for normal named objects using the Chris@16: //!char type specified in the template parameter. Chris@16: //! Chris@16: //!The second index contains the association for unique instances. The key will Chris@16: //!be the const char * returned from type_info.name() function for the unique Chris@16: //!type to be constructed. Chris@16: //! Chris@16: //!segment_manager inherits publicly Chris@16: //!from segment_manager_base and inherits from it Chris@16: //!many public functions related to anonymous object and raw memory allocation. Chris@16: //!See segment_manager_base reference to know about those functions. Chris@16: template class IndexType> Chris@16: class segment_manager Chris@16: : public segment_manager_base Chris@16: { Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@16: //Non-copyable Chris@16: segment_manager(); Chris@16: segment_manager(const segment_manager &); Chris@16: segment_manager &operator=(const segment_manager &); Chris@101: typedef segment_manager_base segment_manager_base_t; Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@16: Chris@16: public: Chris@101: typedef MemoryAlgorithm memory_algorithm; Chris@101: typedef typename segment_manager_base_t::void_pointer void_pointer; Chris@101: typedef typename segment_manager_base_t::size_type size_type; Chris@101: typedef typename segment_manager_base_t::difference_type difference_type; Chris@101: typedef CharType char_type; Chris@16: Chris@16: typedef segment_manager_base segment_manager_base_type; Chris@16: Chris@101: static const size_type PayloadPerAllocation = segment_manager_base_t::PayloadPerAllocation; Chris@16: Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@16: private: Chris@16: typedef ipcdetail::block_header block_header_t; Chris@16: typedef ipcdetail::index_config index_config_named; Chris@16: typedef ipcdetail::index_config index_config_unique; Chris@16: typedef IndexType index_type; Chris@16: typedef ipcdetail::bool_::value > is_intrusive_t; Chris@16: typedef ipcdetail::bool_::value> is_node_index_t; Chris@16: Chris@16: public: Chris@16: typedef IndexType named_index_t; Chris@16: typedef IndexType unique_index_t; Chris@16: typedef ipcdetail::char_ptr_holder char_ptr_holder_t; Chris@16: typedef ipcdetail::segment_manager_iterator_transform Chris@16: ::value> named_transform; Chris@16: Chris@16: typedef ipcdetail::segment_manager_iterator_transform Chris@16: ::value> unique_transform; Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@16: Chris@101: typedef typename segment_manager_base_t::mutex_family mutex_family; Chris@16: Chris@16: typedef transform_iterator Chris@16: const_named_iterator; Chris@16: typedef transform_iterator Chris@16: const_unique_iterator; Chris@16: Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@16: Chris@16: //!Constructor proxy object definition helper class Chris@16: template Chris@16: struct construct_proxy Chris@16: { Chris@16: typedef ipcdetail::named_proxy type; Chris@16: }; Chris@16: Chris@16: //!Constructor proxy object definition helper class Chris@16: template Chris@16: struct construct_iter_proxy Chris@16: { Chris@16: typedef ipcdetail::named_proxy type; Chris@16: }; Chris@16: Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@16: Chris@16: //!Constructor of the segment manager Chris@16: //!"size" is the size of the memory segment where Chris@16: //!the segment manager is being constructed. Chris@16: //!Can throw Chris@16: explicit segment_manager(size_type segment_size) Chris@101: : segment_manager_base_t(segment_size, priv_get_reserved_bytes()) Chris@101: , m_header(static_cast(get_this_pointer())) Chris@16: { Chris@16: (void) anonymous_instance; (void) unique_instance; Chris@101: //Check EBO is applied, it's required Chris@101: const void * const this_addr = this; Chris@101: const void *const segm_addr = static_cast(this); Chris@101: (void)this_addr; (void)segm_addr; Chris@101: BOOST_ASSERT( this_addr == segm_addr); Chris@16: } Chris@16: Chris@101: //!Tries to find a previous named/unique allocation. Returns the address Chris@16: //!and the object count. On failure the first member of the Chris@16: //!returned pair is 0. Chris@16: template Chris@101: std::pair find (char_ptr_holder_t name) Chris@16: { return this->priv_find_impl(name, true); } Chris@16: Chris@101: //!Tries to find a previous named/unique allocation. Returns the address Chris@16: //!and the object count. On failure the first member of the Chris@16: //!returned pair is 0. This search is not mutex-protected! Chris@101: //!Use it only inside atomic_func() calls, where the internal mutex Chris@101: //!is guaranteed to be locked. Chris@16: template Chris@101: std::pair find_no_lock (char_ptr_holder_t name) Chris@16: { return this->priv_find_impl(name, false); } Chris@16: Chris@16: //!Returns throwing "construct" proxy Chris@16: //!object Chris@16: template Chris@16: typename construct_proxy::type Chris@16: construct(char_ptr_holder_t name) Chris@16: { return typename construct_proxy::type (this, name, false, true); } Chris@16: Chris@16: //!Returns throwing "search or construct" proxy Chris@16: //!object Chris@16: template Chris@16: typename construct_proxy::type find_or_construct(char_ptr_holder_t name) Chris@16: { return typename construct_proxy::type (this, name, true, true); } Chris@16: Chris@16: //!Returns no throwing "construct" proxy Chris@16: //!object Chris@16: template Chris@16: typename construct_proxy::type Chris@101: construct(char_ptr_holder_t name, const std::nothrow_t &) Chris@16: { return typename construct_proxy::type (this, name, false, false); } Chris@16: Chris@16: //!Returns no throwing "search or construct" Chris@16: //!proxy object Chris@16: template Chris@16: typename construct_proxy::type Chris@101: find_or_construct(char_ptr_holder_t name, const std::nothrow_t &) Chris@16: { return typename construct_proxy::type (this, name, true, false); } Chris@16: Chris@16: //!Returns throwing "construct from iterators" proxy object Chris@16: template Chris@16: typename construct_iter_proxy::type Chris@16: construct_it(char_ptr_holder_t name) Chris@16: { return typename construct_iter_proxy::type (this, name, false, true); } Chris@16: Chris@16: //!Returns throwing "search or construct from iterators" Chris@16: //!proxy object Chris@16: template Chris@16: typename construct_iter_proxy::type Chris@16: find_or_construct_it(char_ptr_holder_t name) Chris@16: { return typename construct_iter_proxy::type (this, name, true, true); } Chris@16: Chris@16: //!Returns no throwing "construct from iterators" Chris@16: //!proxy object Chris@16: template Chris@16: typename construct_iter_proxy::type Chris@101: construct_it(char_ptr_holder_t name, const std::nothrow_t &) Chris@16: { return typename construct_iter_proxy::type (this, name, false, false); } Chris@16: Chris@16: //!Returns no throwing "search or construct from iterators" Chris@16: //!proxy object Chris@16: template Chris@16: typename construct_iter_proxy::type Chris@101: find_or_construct_it(char_ptr_holder_t name, const std::nothrow_t &) Chris@16: { return typename construct_iter_proxy::type (this, name, true, false); } Chris@16: Chris@16: //!Calls object function blocking recursive interprocess_mutex and guarantees that Chris@16: //!no new named_alloc or destroy will be executed by any process while Chris@101: //!executing the object function call Chris@16: template Chris@16: void atomic_func(Func &f) Chris@16: { scoped_lock guard(m_header); f(); } Chris@16: Chris@16: //!Tries to calls a functor guaranteeing that no new construction, search or Chris@16: //!destruction will be executed by any process while executing the object Chris@16: //!function call. If the atomic function can't be immediatelly executed Chris@16: //!because the internal mutex is already locked, returns false. Chris@16: //!If the functor throws, this function throws. Chris@16: template Chris@16: bool try_atomic_func(Func &f) Chris@16: { Chris@16: scoped_lock guard(m_header, try_to_lock); Chris@16: if(guard){ Chris@16: f(); Chris@16: return true; Chris@16: } Chris@16: else{ Chris@16: return false; Chris@16: } Chris@16: } Chris@16: Chris@101: //!Destroys a previously created named/unique instance. Chris@16: //!Returns false if the object was not present. Chris@16: template Chris@101: bool destroy(char_ptr_holder_t name) Chris@16: { Chris@101: BOOST_ASSERT(!name.is_anonymous()); Chris@16: ipcdetail::placement_destroy dtor; Chris@16: Chris@101: if(name.is_unique()){ Chris@101: return this->priv_generic_named_destroy Chris@101: ( typeid(T).name(), m_header.m_unique_index , dtor, is_intrusive_t()); Chris@101: } Chris@101: else{ Chris@101: return this->priv_generic_named_destroy Chris@101: ( name.get(), m_header.m_named_index, dtor, is_intrusive_t()); Chris@101: } Chris@16: } Chris@16: Chris@16: //!Destroys an anonymous, unique or named object Chris@101: //!using its address Chris@16: template Chris@16: void destroy_ptr(const T *p) Chris@16: { Chris@16: //If T is void transform it to char Chris@16: typedef typename ipcdetail::char_if_void::type data_t; Chris@16: ipcdetail::placement_destroy dtor; Chris@16: priv_destroy_ptr(p, dtor); Chris@16: } Chris@16: Chris@16: //!Returns the name of an object created with construct/find_or_construct Chris@16: //!functions. Does not throw Chris@16: template Chris@16: static const CharType *get_instance_name(const T *ptr) Chris@16: { return priv_get_instance_name(block_header_t::block_header_from_value(ptr)); } Chris@16: Chris@16: //!Returns the length of an object created with construct/find_or_construct Chris@16: //!functions. Does not throw. Chris@16: template Chris@16: static size_type get_instance_length(const T *ptr) Chris@16: { return priv_get_instance_length(block_header_t::block_header_from_value(ptr), sizeof(T)); } Chris@16: Chris@16: //!Returns is the the name of an object created with construct/find_or_construct Chris@16: //!functions. Does not throw Chris@16: template Chris@16: static instance_type get_instance_type(const T *ptr) Chris@16: { return priv_get_instance_type(block_header_t::block_header_from_value(ptr)); } Chris@16: Chris@16: //!Preallocates needed index resources to optimize the Chris@16: //!creation of "num" named objects in the managed memory segment. Chris@16: //!Can throw boost::interprocess::bad_alloc if there is no enough memory. Chris@16: void reserve_named_objects(size_type num) Chris@16: { Chris@16: //------------------------------- Chris@16: scoped_lock guard(m_header); Chris@16: //------------------------------- Chris@16: m_header.m_named_index.reserve(num); Chris@16: } Chris@16: Chris@16: //!Preallocates needed index resources to optimize the Chris@16: //!creation of "num" unique objects in the managed memory segment. Chris@16: //!Can throw boost::interprocess::bad_alloc if there is no enough memory. Chris@16: void reserve_unique_objects(size_type num) Chris@16: { Chris@16: //------------------------------- Chris@16: scoped_lock guard(m_header); Chris@16: //------------------------------- Chris@16: m_header.m_unique_index.reserve(num); Chris@16: } Chris@16: Chris@16: //!Calls shrink_to_fit in both named and unique object indexes Chris@16: //!to try to free unused memory from those indexes. Chris@16: void shrink_to_fit_indexes() Chris@16: { Chris@16: //------------------------------- Chris@16: scoped_lock guard(m_header); Chris@16: //------------------------------- Chris@16: m_header.m_named_index.shrink_to_fit(); Chris@16: m_header.m_unique_index.shrink_to_fit(); Chris@16: } Chris@16: Chris@16: //!Returns the number of named objects stored in Chris@16: //!the segment. Chris@16: size_type get_num_named_objects() Chris@16: { Chris@16: //------------------------------- Chris@16: scoped_lock guard(m_header); Chris@16: //------------------------------- Chris@16: return m_header.m_named_index.size(); Chris@16: } Chris@16: Chris@16: //!Returns the number of unique objects stored in Chris@16: //!the segment. Chris@16: size_type get_num_unique_objects() Chris@16: { Chris@16: //------------------------------- Chris@16: scoped_lock guard(m_header); Chris@16: //------------------------------- Chris@16: return m_header.m_unique_index.size(); Chris@16: } Chris@16: Chris@16: //!Obtains the minimum size needed by the Chris@16: //!segment manager Chris@16: static size_type get_min_size() Chris@101: { return segment_manager_base_t::get_min_size(priv_get_reserved_bytes()); } Chris@16: Chris@16: //!Returns a constant iterator to the beginning of the information about Chris@16: //!the named allocations performed in this segment manager Chris@16: const_named_iterator named_begin() const Chris@16: { Chris@16: return make_transform_iterator Chris@16: (m_header.m_named_index.begin(), named_transform()); Chris@16: } Chris@16: Chris@16: //!Returns a constant iterator to the end of the information about Chris@16: //!the named allocations performed in this segment manager Chris@16: const_named_iterator named_end() const Chris@16: { Chris@16: return make_transform_iterator Chris@16: (m_header.m_named_index.end(), named_transform()); Chris@16: } Chris@16: Chris@16: //!Returns a constant iterator to the beginning of the information about Chris@16: //!the unique allocations performed in this segment manager Chris@16: const_unique_iterator unique_begin() const Chris@16: { Chris@16: return make_transform_iterator Chris@16: (m_header.m_unique_index.begin(), unique_transform()); Chris@16: } Chris@16: Chris@16: //!Returns a constant iterator to the end of the information about Chris@16: //!the unique allocations performed in this segment manager Chris@16: const_unique_iterator unique_end() const Chris@16: { Chris@16: return make_transform_iterator Chris@16: (m_header.m_unique_index.end(), unique_transform()); Chris@16: } Chris@16: Chris@16: //!This is the default allocator to allocate types T Chris@16: //!from this managed segment Chris@16: template Chris@16: struct allocator Chris@16: { Chris@16: typedef boost::interprocess::allocator type; Chris@16: }; Chris@16: Chris@16: //!Returns an instance of the default allocator for type T Chris@16: //!initialized that allocates memory from this segment manager. Chris@16: template Chris@16: typename allocator::type Chris@16: get_allocator() Chris@16: { return typename allocator::type(this); } Chris@16: Chris@16: //!This is the default deleter to delete types T Chris@16: //!from this managed segment. Chris@16: template Chris@16: struct deleter Chris@16: { Chris@16: typedef boost::interprocess::deleter type; Chris@16: }; Chris@16: Chris@101: //!Returns an instance of the default deleter for type T Chris@101: //!that will delete an object constructed in this segment manager. Chris@16: template Chris@16: typename deleter::type Chris@16: get_deleter() Chris@16: { return typename deleter::type(this); } Chris@16: Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@16: Chris@16: //!Generic named/anonymous new function. Offers all the possibilities, Chris@16: //!such as throwing, search before creating, and the constructor is Chris@16: //!encapsulated in an object function. Chris@16: template Chris@16: T *generic_construct(const CharType *name, Chris@16: size_type num, Chris@16: bool try2find, Chris@16: bool dothrow, Chris@16: ipcdetail::in_place_interface &table) Chris@16: { Chris@16: return static_cast Chris@16: (priv_generic_construct(name, num, try2find, dothrow, table)); Chris@16: } Chris@16: Chris@16: private: Chris@16: //!Tries to find a previous named allocation. Returns the address Chris@16: //!and the object count. On failure the first member of the Chris@16: //!returned pair is 0. Chris@16: template Chris@16: std::pair priv_find_impl (const CharType* name, bool lock) Chris@16: { Chris@16: //The name can't be null, no anonymous object can be found by name Chris@16: BOOST_ASSERT(name != 0); Chris@16: ipcdetail::placement_destroy table; Chris@16: size_type sz; Chris@16: void *ret; Chris@16: Chris@16: if(name == reinterpret_cast(-1)){ Chris@16: ret = priv_generic_find (typeid(T).name(), m_header.m_unique_index, table, sz, is_intrusive_t(), lock); Chris@16: } Chris@16: else{ Chris@16: ret = priv_generic_find (name, m_header.m_named_index, table, sz, is_intrusive_t(), lock); Chris@16: } Chris@16: return std::pair(static_cast(ret), sz); Chris@16: } Chris@16: Chris@16: //!Tries to find a previous unique allocation. Returns the address Chris@16: //!and the object count. On failure the first member of the Chris@16: //!returned pair is 0. Chris@16: template Chris@101: std::pair priv_find_impl (const ipcdetail::unique_instance_t* name, bool lock) Chris@16: { Chris@16: ipcdetail::placement_destroy table; Chris@16: size_type size; Chris@16: void *ret = priv_generic_find(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock); Chris@16: return std::pair(static_cast(ret), size); Chris@16: } Chris@16: Chris@101: void *priv_generic_construct Chris@101: (const CharType *name, size_type num, bool try2find, bool dothrow, ipcdetail::in_place_interface &table) Chris@16: { Chris@16: void *ret; Chris@16: //Security overflow check Chris@101: if(num > ((std::size_t)-1)/table.size){ Chris@16: if(dothrow) Chris@16: throw bad_alloc(); Chris@16: else Chris@16: return 0; Chris@16: } Chris@16: if(name == 0){ Chris@16: ret = this->prot_anonymous_construct(num, dothrow, table); Chris@16: } Chris@16: else if(name == reinterpret_cast(-1)){ Chris@16: ret = this->priv_generic_named_construct Chris@16: (unique_type, table.type_name, num, try2find, dothrow, table, m_header.m_unique_index, is_intrusive_t()); Chris@16: } Chris@16: else{ Chris@16: ret = this->priv_generic_named_construct Chris@16: (named_type, name, num, try2find, dothrow, table, m_header.m_named_index, is_intrusive_t()); Chris@16: } Chris@16: return ret; Chris@16: } Chris@16: Chris@16: void priv_destroy_ptr(const void *ptr, ipcdetail::in_place_interface &dtor) Chris@16: { Chris@16: block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr, dtor.size, dtor.alignment); Chris@16: switch(ctrl_data->alloc_type()){ Chris@16: case anonymous_type: Chris@16: this->prot_anonymous_destroy(ptr, dtor); Chris@16: break; Chris@16: Chris@16: case named_type: Chris@16: this->priv_generic_named_destroy Chris@16: (ctrl_data, m_header.m_named_index, dtor, is_node_index_t()); Chris@16: break; Chris@16: Chris@16: case unique_type: Chris@16: this->priv_generic_named_destroy Chris@16: (ctrl_data, m_header.m_unique_index, dtor, is_node_index_t()); Chris@16: break; Chris@16: Chris@16: default: Chris@16: //This type is unknown, bad pointer passed to this function! Chris@16: BOOST_ASSERT(0); Chris@16: break; Chris@16: } Chris@16: } Chris@16: Chris@16: //!Returns the name of an object created with construct/find_or_construct Chris@16: //!functions. Does not throw Chris@16: static const CharType *priv_get_instance_name(block_header_t *ctrl_data) Chris@16: { Chris@16: boost::interprocess::allocation_type type = ctrl_data->alloc_type(); Chris@101: if(type == anonymous_type){ Chris@16: BOOST_ASSERT((type == anonymous_type && ctrl_data->m_num_char == 0) || Chris@16: (type == unique_type && ctrl_data->m_num_char != 0) ); Chris@16: return 0; Chris@16: } Chris@16: CharType *name = static_cast(ctrl_data->template name()); Chris@16: Chris@16: //Sanity checks Chris@16: BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharType)); Chris@16: BOOST_ASSERT(ctrl_data->m_num_char == std::char_traits::length(name)); Chris@16: return name; Chris@16: } Chris@16: Chris@16: static size_type priv_get_instance_length(block_header_t *ctrl_data, size_type sizeofvalue) Chris@16: { Chris@16: //Get header Chris@16: BOOST_ASSERT((ctrl_data->value_bytes() %sizeofvalue) == 0); Chris@16: return ctrl_data->value_bytes()/sizeofvalue; Chris@16: } Chris@16: Chris@16: //!Returns is the the name of an object created with construct/find_or_construct Chris@16: //!functions. Does not throw Chris@16: static instance_type priv_get_instance_type(block_header_t *ctrl_data) Chris@16: { Chris@16: //Get header Chris@16: BOOST_ASSERT((instance_type)ctrl_data->alloc_type() < max_allocation_type); Chris@16: return (instance_type)ctrl_data->alloc_type(); Chris@16: } Chris@16: Chris@16: static size_type priv_get_reserved_bytes() Chris@16: { Chris@16: //Get the number of bytes until the end of (*this) Chris@101: //beginning in the end of the segment_manager_base_t base. Chris@101: return sizeof(segment_manager) - sizeof(segment_manager_base_t); Chris@16: } Chris@16: Chris@16: template Chris@16: void *priv_generic_find Chris@16: (const CharT* name, Chris@16: IndexType > &index, Chris@16: ipcdetail::in_place_interface &table, Chris@101: size_type &length, ipcdetail::true_ is_intrusive, bool use_lock) Chris@16: { Chris@16: (void)is_intrusive; Chris@16: typedef IndexType > index_type; Chris@16: typedef typename index_type::iterator index_it; Chris@16: Chris@16: //------------------------------- Chris@16: scoped_lock guard(priv_get_lock(use_lock)); Chris@16: //------------------------------- Chris@16: //Find name in index Chris@16: ipcdetail::intrusive_compare_key key Chris@16: (name, std::char_traits::length(name)); Chris@16: index_it it = index.find(key); Chris@16: Chris@16: //Initialize return values Chris@16: void *ret_ptr = 0; Chris@16: length = 0; Chris@16: Chris@16: //If found, assign values Chris@16: if(it != index.end()){ Chris@16: //Get header Chris@16: block_header_t *ctrl_data = it->get_block_header(); Chris@16: Chris@16: //Sanity check Chris@16: BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0); Chris@16: BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT)); Chris@16: ret_ptr = ctrl_data->value(); Chris@16: length = ctrl_data->m_value_bytes/table.size; Chris@16: } Chris@16: return ret_ptr; Chris@16: } Chris@16: Chris@16: template Chris@16: void *priv_generic_find Chris@16: (const CharT* name, Chris@16: IndexType > &index, Chris@16: ipcdetail::in_place_interface &table, Chris@101: size_type &length, ipcdetail::false_ is_intrusive, bool use_lock) Chris@16: { Chris@16: (void)is_intrusive; Chris@16: typedef IndexType > index_type; Chris@16: typedef typename index_type::key_type key_type; Chris@16: typedef typename index_type::iterator index_it; Chris@16: Chris@16: //------------------------------- Chris@16: scoped_lock guard(priv_get_lock(use_lock)); Chris@16: //------------------------------- Chris@16: //Find name in index Chris@16: index_it it = index.find(key_type(name, std::char_traits::length(name))); Chris@16: Chris@16: //Initialize return values Chris@16: void *ret_ptr = 0; Chris@16: length = 0; Chris@16: Chris@16: //If found, assign values Chris@16: if(it != index.end()){ Chris@16: //Get header Chris@16: block_header_t *ctrl_data = reinterpret_cast Chris@16: (ipcdetail::to_raw_pointer(it->second.m_ptr)); Chris@16: Chris@16: //Sanity check Chris@16: BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0); Chris@16: BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT)); Chris@16: ret_ptr = ctrl_data->value(); Chris@16: length = ctrl_data->m_value_bytes/table.size; Chris@16: } Chris@16: return ret_ptr; Chris@16: } Chris@16: Chris@16: template Chris@16: bool priv_generic_named_destroy Chris@16: (block_header_t *block_header, Chris@16: IndexType > &index, Chris@101: ipcdetail::in_place_interface &table, ipcdetail::true_ is_node_index) Chris@16: { Chris@16: (void)is_node_index; Chris@16: typedef typename IndexType >::iterator index_it; Chris@16: Chris@16: index_it *ihdr = block_header_t::template to_first_header(block_header); Chris@16: return this->priv_generic_named_destroy_impl(*ihdr, index, table); Chris@16: } Chris@16: Chris@16: template Chris@16: bool priv_generic_named_destroy Chris@16: (block_header_t *block_header, Chris@16: IndexType > &index, Chris@16: ipcdetail::in_place_interface &table, Chris@16: ipcdetail::false_ is_node_index) Chris@16: { Chris@16: (void)is_node_index; Chris@16: CharT *name = static_cast(block_header->template name()); Chris@16: return this->priv_generic_named_destroy(name, index, table, is_intrusive_t()); Chris@16: } Chris@16: Chris@16: template Chris@16: bool priv_generic_named_destroy(const CharT *name, Chris@16: IndexType > &index, Chris@101: ipcdetail::in_place_interface &table, ipcdetail::true_ is_intrusive_index) Chris@16: { Chris@16: (void)is_intrusive_index; Chris@16: typedef IndexType > index_type; Chris@16: typedef typename index_type::iterator index_it; Chris@16: typedef typename index_type::value_type intrusive_value_type; Chris@16: Chris@16: //------------------------------- Chris@16: scoped_lock guard(m_header); Chris@16: //------------------------------- Chris@16: //Find name in index Chris@16: ipcdetail::intrusive_compare_key key Chris@16: (name, std::char_traits::length(name)); Chris@16: index_it it = index.find(key); Chris@16: Chris@16: //If not found, return false Chris@16: if(it == index.end()){ Chris@16: //This name is not present in the index, wrong pointer or name! Chris@16: //BOOST_ASSERT(0); Chris@16: return false; Chris@16: } Chris@16: Chris@16: block_header_t *ctrl_data = it->get_block_header(); Chris@16: intrusive_value_type *iv = intrusive_value_type::get_intrusive_value_type(ctrl_data); Chris@16: void *memory = iv; Chris@16: void *values = ctrl_data->value(); Chris@16: std::size_t num = ctrl_data->m_value_bytes/table.size; Chris@16: Chris@16: //Sanity check Chris@16: BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0); Chris@16: BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char()); Chris@16: Chris@16: //Erase node from index Chris@16: index.erase(it); Chris@16: Chris@16: //Destroy the headers Chris@16: ctrl_data->~block_header_t(); Chris@16: iv->~intrusive_value_type(); Chris@16: Chris@16: //Call destructors and free memory Chris@16: std::size_t destroyed; Chris@16: table.destroy_n(values, num, destroyed); Chris@16: this->deallocate(memory); Chris@16: return true; Chris@16: } Chris@16: Chris@16: template Chris@16: bool priv_generic_named_destroy(const CharT *name, Chris@16: IndexType > &index, Chris@16: ipcdetail::in_place_interface &table, Chris@16: ipcdetail::false_ is_intrusive_index) Chris@16: { Chris@16: (void)is_intrusive_index; Chris@16: typedef IndexType > index_type; Chris@16: typedef typename index_type::iterator index_it; Chris@16: typedef typename index_type::key_type key_type; Chris@16: Chris@16: //------------------------------- Chris@16: scoped_lock guard(m_header); Chris@16: //------------------------------- Chris@16: //Try to find the name in the index Chris@16: index_it it = index.find(key_type (name, Chris@16: std::char_traits::length(name))); Chris@16: Chris@16: //If not found, return false Chris@16: if(it == index.end()){ Chris@16: //This name is not present in the index, wrong pointer or name! Chris@16: //BOOST_ASSERT(0); Chris@16: return false; Chris@16: } Chris@16: return this->priv_generic_named_destroy_impl(it, index, table); Chris@16: } Chris@16: Chris@16: template Chris@16: bool priv_generic_named_destroy_impl Chris@16: (const typename IndexType >::iterator &it, Chris@16: IndexType > &index, Chris@16: ipcdetail::in_place_interface &table) Chris@16: { Chris@16: typedef IndexType > index_type; Chris@16: typedef typename index_type::iterator index_it; Chris@16: Chris@16: //Get allocation parameters Chris@16: block_header_t *ctrl_data = reinterpret_cast Chris@16: (ipcdetail::to_raw_pointer(it->second.m_ptr)); Chris@16: char *stored_name = static_cast(static_cast(const_cast(it->first.name()))); Chris@16: (void)stored_name; Chris@16: Chris@16: //Check if the distance between the name pointer and the memory pointer Chris@16: //is correct (this can detect incorrect type in destruction) Chris@101: std::size_t num = ctrl_data->m_value_bytes/table.size; Chris@16: void *values = ctrl_data->value(); Chris@16: Chris@16: //Sanity check Chris@16: BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0); Chris@16: BOOST_ASSERT(static_cast(stored_name) == static_cast(ctrl_data->template name())); Chris@16: BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char()); Chris@16: Chris@16: //Erase node from index Chris@16: index.erase(it); Chris@16: Chris@16: //Destroy the header Chris@16: ctrl_data->~block_header_t(); Chris@16: Chris@16: void *memory; Chris@16: if(is_node_index_t::value){ Chris@16: index_it *ihdr = block_header_t::template Chris@16: to_first_header(ctrl_data); Chris@16: ihdr->~index_it(); Chris@16: memory = ihdr; Chris@16: } Chris@16: else{ Chris@16: memory = ctrl_data; Chris@16: } Chris@16: Chris@16: //Call destructors and free memory Chris@101: std::size_t destroyed; Chris@16: table.destroy_n(values, num, destroyed); Chris@16: this->deallocate(memory); Chris@16: return true; Chris@16: } Chris@16: Chris@16: template Chris@101: void * priv_generic_named_construct Chris@101: (unsigned char type, const CharT *name, size_type num, bool try2find, Chris@101: bool dothrow, ipcdetail::in_place_interface &table, Chris@101: IndexType > &index, ipcdetail::true_ is_intrusive) Chris@16: { Chris@16: (void)is_intrusive; Chris@16: std::size_t namelen = std::char_traits::length(name); Chris@16: Chris@16: block_header_t block_info ( size_type(table.size*num) Chris@16: , size_type(table.alignment) Chris@16: , type Chris@16: , sizeof(CharT) Chris@16: , namelen); Chris@16: Chris@16: typedef IndexType > index_type; Chris@16: typedef typename index_type::iterator index_it; Chris@16: typedef std::pair index_ib; Chris@16: Chris@16: //------------------------------- Chris@16: scoped_lock guard(m_header); Chris@16: //------------------------------- Chris@16: //Insert the node. This can throw. Chris@16: //First, we want to know if the key is already present before Chris@16: //we allocate any memory, and if the key is not present, we Chris@16: //want to allocate all memory in a single buffer that will Chris@16: //contain the name and the user buffer. Chris@16: // Chris@16: //Since equal_range(key) + insert(hint, value) approach is Chris@16: //quite inefficient in container implementations Chris@16: //(they re-test if the position is correct), I've chosen Chris@16: //to insert the node, do an ugly un-const cast and modify Chris@16: //the key (which is a smart pointer) to an equivalent one Chris@16: index_ib insert_ret; Chris@16: Chris@16: typename index_type::insert_commit_data commit_data; Chris@16: typedef typename index_type::value_type intrusive_value_type; Chris@16: Chris@16: BOOST_TRY{ Chris@16: ipcdetail::intrusive_compare_key key(name, namelen); Chris@16: insert_ret = index.insert_check(key, commit_data); Chris@16: } Chris@16: //Ignore exceptions Chris@16: BOOST_CATCH(...){ Chris@16: if(dothrow) Chris@16: BOOST_RETHROW Chris@16: return 0; Chris@16: } Chris@16: BOOST_CATCH_END Chris@16: Chris@16: index_it it = insert_ret.first; Chris@16: Chris@16: //If found and this is find or construct, return data Chris@16: //else return null Chris@16: if(!insert_ret.second){ Chris@16: if(try2find){ Chris@16: return it->get_block_header()->value(); Chris@16: } Chris@16: if(dothrow){ Chris@16: throw interprocess_exception(already_exists_error); Chris@16: } Chris@16: else{ Chris@16: return 0; Chris@16: } Chris@16: } Chris@16: Chris@16: //Allocates buffer for name + data, this can throw (it hurts) Chris@16: void *buffer_ptr; Chris@16: Chris@16: //Check if there is enough memory Chris@16: if(dothrow){ Chris@16: buffer_ptr = this->allocate Chris@16: (block_info.template total_size_with_header()); Chris@16: } Chris@16: else{ Chris@16: buffer_ptr = this->allocate Chris@101: (block_info.template total_size_with_header(), nothrow<>::get()); Chris@16: if(!buffer_ptr) Chris@16: return 0; Chris@16: } Chris@16: Chris@16: //Now construct the intrusive hook plus the header Chris@101: intrusive_value_type * intrusive_hdr = ::new(buffer_ptr, boost_container_new_t()) intrusive_value_type(); Chris@101: block_header_t * hdr = ::new(intrusive_hdr->get_block_header(), boost_container_new_t())block_header_t(block_info); Chris@16: void *ptr = 0; //avoid gcc warning Chris@16: ptr = hdr->value(); Chris@16: Chris@16: //Copy name to memory segment and insert data Chris@16: CharT *name_ptr = static_cast(hdr->template name()); Chris@16: std::char_traits::copy(name_ptr, name, namelen+1); Chris@16: Chris@16: BOOST_TRY{ Chris@16: //Now commit the insertion using previous context data Chris@16: it = index.insert_commit(*intrusive_hdr, commit_data); Chris@16: } Chris@16: //Ignore exceptions Chris@16: BOOST_CATCH(...){ Chris@16: if(dothrow) Chris@16: BOOST_RETHROW Chris@16: return 0; Chris@16: } Chris@16: BOOST_CATCH_END Chris@16: Chris@16: //Avoid constructions if constructor is trivial Chris@16: //Build scoped ptr to avoid leaks with constructor exception Chris@16: ipcdetail::mem_algo_deallocator mem Chris@16: (buffer_ptr, *static_cast(this)); Chris@16: Chris@16: //Initialize the node value_eraser to erase inserted node Chris@16: //if something goes wrong. This will be executed *before* Chris@16: //the memory allocation as the intrusive value is built in that Chris@16: //memory Chris@16: value_eraser v_eraser(index, it); Chris@16: Chris@16: //Construct array, this can throw Chris@16: ipcdetail::array_construct(ptr, num, table); Chris@16: Chris@16: //Release rollbacks since construction was successful Chris@16: v_eraser.release(); Chris@16: mem.release(); Chris@16: return ptr; Chris@16: } Chris@16: Chris@16: //!Generic named new function for Chris@16: //!named functions Chris@16: template Chris@101: void * priv_generic_named_construct Chris@101: (unsigned char type, const CharT *name, size_type num, bool try2find, bool dothrow, Chris@101: ipcdetail::in_place_interface &table, Chris@101: IndexType > &index, ipcdetail::false_ is_intrusive) Chris@16: { Chris@16: (void)is_intrusive; Chris@16: std::size_t namelen = std::char_traits::length(name); Chris@16: Chris@16: block_header_t block_info ( size_type(table.size*num) Chris@16: , size_type(table.alignment) Chris@16: , type Chris@16: , sizeof(CharT) Chris@16: , namelen); Chris@16: Chris@16: typedef IndexType > index_type; Chris@16: typedef typename index_type::key_type key_type; Chris@16: typedef typename index_type::mapped_type mapped_type; Chris@16: typedef typename index_type::value_type value_type; Chris@16: typedef typename index_type::iterator index_it; Chris@16: typedef std::pair index_ib; Chris@16: Chris@16: //------------------------------- Chris@16: scoped_lock guard(m_header); Chris@16: //------------------------------- Chris@16: //Insert the node. This can throw. Chris@16: //First, we want to know if the key is already present before Chris@16: //we allocate any memory, and if the key is not present, we Chris@16: //want to allocate all memory in a single buffer that will Chris@16: //contain the name and the user buffer. Chris@16: // Chris@16: //Since equal_range(key) + insert(hint, value) approach is Chris@16: //quite inefficient in container implementations Chris@16: //(they re-test if the position is correct), I've chosen Chris@16: //to insert the node, do an ugly un-const cast and modify Chris@16: //the key (which is a smart pointer) to an equivalent one Chris@16: index_ib insert_ret; Chris@16: BOOST_TRY{ Chris@16: insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0))); Chris@16: } Chris@16: //Ignore exceptions Chris@16: BOOST_CATCH(...){ Chris@16: if(dothrow) Chris@16: BOOST_RETHROW; Chris@16: return 0; Chris@16: } Chris@16: BOOST_CATCH_END Chris@16: Chris@16: index_it it = insert_ret.first; Chris@16: Chris@16: //If found and this is find or construct, return data Chris@16: //else return null Chris@16: if(!insert_ret.second){ Chris@16: if(try2find){ Chris@16: block_header_t *hdr = static_cast Chris@16: (ipcdetail::to_raw_pointer(it->second.m_ptr)); Chris@16: return hdr->value(); Chris@16: } Chris@16: return 0; Chris@16: } Chris@16: //Initialize the node value_eraser to erase inserted node Chris@16: //if something goes wrong Chris@16: value_eraser v_eraser(index, it); Chris@16: Chris@16: //Allocates buffer for name + data, this can throw (it hurts) Chris@16: void *buffer_ptr; Chris@16: block_header_t * hdr; Chris@16: Chris@16: //Allocate and construct the headers Chris@16: if(is_node_index_t::value){ Chris@16: size_type total_size = block_info.template total_size_with_header(); Chris@16: if(dothrow){ Chris@16: buffer_ptr = this->allocate(total_size); Chris@16: } Chris@16: else{ Chris@101: buffer_ptr = this->allocate(total_size, nothrow<>::get()); Chris@16: if(!buffer_ptr) Chris@16: return 0; Chris@16: } Chris@101: index_it *idr = ::new(buffer_ptr, boost_container_new_t()) index_it(it); Chris@16: hdr = block_header_t::template from_first_header(idr); Chris@16: } Chris@16: else{ Chris@16: if(dothrow){ Chris@16: buffer_ptr = this->allocate(block_info.total_size()); Chris@16: } Chris@16: else{ Chris@101: buffer_ptr = this->allocate(block_info.total_size(), nothrow<>::get()); Chris@16: if(!buffer_ptr) Chris@16: return 0; Chris@16: } Chris@16: hdr = static_cast(buffer_ptr); Chris@16: } Chris@16: Chris@101: hdr = ::new(hdr, boost_container_new_t())block_header_t(block_info); Chris@16: void *ptr = 0; //avoid gcc warning Chris@16: ptr = hdr->value(); Chris@16: Chris@16: //Copy name to memory segment and insert data Chris@16: CharT *name_ptr = static_cast(hdr->template name()); Chris@16: std::char_traits::copy(name_ptr, name, namelen+1); Chris@16: Chris@16: //Do the ugly cast, please mama, forgive me! Chris@16: //This new key points to an identical string, so it must have the Chris@16: //same position than the overwritten key according to the predicate Chris@16: const_cast(it->first).name(name_ptr); Chris@16: it->second.m_ptr = hdr; Chris@16: Chris@16: //Build scoped ptr to avoid leaks with constructor exception Chris@16: ipcdetail::mem_algo_deallocator mem Chris@16: (buffer_ptr, *static_cast(this)); Chris@16: Chris@16: //Construct array, this can throw Chris@16: ipcdetail::array_construct(ptr, num, table); Chris@16: Chris@16: //All constructors successful, we don't want to release memory Chris@16: mem.release(); Chris@16: Chris@16: //Release node v_eraser since construction was successful Chris@16: v_eraser.release(); Chris@16: return ptr; Chris@16: } Chris@16: Chris@16: private: Chris@16: //!Returns the this pointer Chris@16: segment_manager *get_this_pointer() Chris@16: { return this; } Chris@16: Chris@16: typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex; Chris@16: Chris@16: scoped_lock priv_get_lock(bool use_lock) Chris@16: { Chris@16: scoped_lock local(m_header, defer_lock); Chris@16: if(use_lock){ Chris@16: local.lock(); Chris@16: } Chris@16: return scoped_lock(boost::move(local)); Chris@16: } Chris@16: Chris@16: //!This struct includes needed data and derives from Chris@16: //!rmutex to allow EBO when using null interprocess_mutex Chris@16: struct header_t Chris@16: : public rmutex Chris@16: { Chris@16: named_index_t m_named_index; Chris@16: unique_index_t m_unique_index; Chris@16: Chris@101: header_t(segment_manager_base_t *segment_mngr_base) Chris@101: : m_named_index (segment_mngr_base) Chris@101: , m_unique_index(segment_mngr_base) Chris@16: {} Chris@16: } m_header; Chris@16: Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@16: }; Chris@16: Chris@16: Chris@16: }} //namespace boost { namespace interprocess Chris@16: Chris@16: #include Chris@16: Chris@16: #endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP Chris@16: