summaryrefslogtreecommitdiff
path: root/boost/interprocess/detail/managed_multi_shared_memory.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/interprocess/detail/managed_multi_shared_memory.hpp')
-rw-r--r--boost/interprocess/detail/managed_multi_shared_memory.hpp408
1 files changed, 408 insertions, 0 deletions
diff --git a/boost/interprocess/detail/managed_multi_shared_memory.hpp b/boost/interprocess/detail/managed_multi_shared_memory.hpp
new file mode 100644
index 0000000000..579d1ad6ff
--- /dev/null
+++ b/boost/interprocess/detail/managed_multi_shared_memory.hpp
@@ -0,0 +1,408 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// See http://www.boost.org/libs/interprocess for documentation.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
+#define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/detail/managed_memory_impl.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/interprocess/detail/multi_segment_services.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/shared_memory_object.hpp>
+#include <boost/interprocess/containers/list.hpp>//list
+#include <boost/interprocess/mapped_region.hpp> //mapped_region
+#include <boost/interprocess/shared_memory_object.hpp>
+#include <boost/interprocess/permissions.hpp>
+#include <boost/interprocess/detail/managed_open_or_create_impl.hpp> //managed_open_or_create_impl
+#include <new>
+#include <boost/interprocess/containers/string.hpp>
+#include <boost/interprocess/streams/vectorstream.hpp>
+#include <memory>
+#include <boost/assert.hpp>
+//These includes needed to fulfill default template parameters of
+//predeclarations in interprocess_fwd.hpp
+#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
+#include <boost/interprocess/sync/mutex_family.hpp>
+
+//!\file
+//!Describes a named shared memory object allocation user class.
+
+namespace boost {
+
+namespace interprocess {
+
+//TODO: We must somehow obtain the permissions of the first segment
+//to apply them to subsequent segments
+//-Use GetSecurityInfo?
+//-Change everything to use only a shared memory object expanded via truncate()?
+
+//!A basic shared memory named object creation class. Initializes the
+//!shared memory segment. Inherits all basic functionality from
+//!basic_managed_memory_impl<CharType, MemoryAlgorithm, IndexType>
+template
+ <
+ class CharType,
+ class MemoryAlgorithm,
+ template<class IndexConfig> class IndexType
+ >
+class basic_managed_multi_shared_memory
+ : public ipcdetail::basic_managed_memory_impl
+ <CharType, MemoryAlgorithm, IndexType>
+{
+
+ typedef basic_managed_multi_shared_memory
+ <CharType, MemoryAlgorithm, IndexType> self_t;
+ typedef ipcdetail::basic_managed_memory_impl
+ <CharType, MemoryAlgorithm, IndexType> base_t;
+
+ typedef typename MemoryAlgorithm::void_pointer void_pointer;
+ typedef typename ipcdetail::
+ managed_open_or_create_impl<shared_memory_object, MemoryAlgorithm::Alignment> managed_impl;
+ typedef typename void_pointer::segment_group_id segment_group_id;
+ typedef typename base_t::size_type size_type;
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Some internal helper structs/functors
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //!This class defines an operator() that creates a shared memory
+ //!of the requested size. The rest of the parameters are
+ //!passed in the constructor. The class a template parameter
+ //!to be used with create_from_file/create_from_istream functions
+ //!of basic_named_object classes
+
+// class segment_creator
+// {
+// public:
+// segment_creator(shared_memory &shmem,
+// const char *mem_name,
+// const void *addr)
+// : m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){}
+//
+// void *operator()(size_type size)
+// {
+// if(!m_shmem.create(m_mem_name, size, m_addr))
+// return 0;
+// return m_shmem.get_address();
+// }
+// private:
+// shared_memory &m_shmem;
+// const char *m_mem_name;
+// const void *m_addr;
+// };
+
+ class group_services
+ : public multi_segment_services
+ {
+ public:
+ typedef std::pair<void *, size_type> result_type;
+ typedef basic_managed_multi_shared_memory frontend_t;
+ typedef typename
+ basic_managed_multi_shared_memory::void_pointer void_pointer;
+ typedef typename void_pointer::segment_group_id segment_group_id;
+ group_services(frontend_t *const frontend)
+ : mp_frontend(frontend), m_group(0), m_min_segment_size(0){}
+
+ virtual std::pair<void *, size_type> create_new_segment(size_type alloc_size)
+ { (void)alloc_size;
+ /*
+ //We should allocate an extra byte so that the
+ //[base_addr + alloc_size] byte belongs to this segment
+ alloc_size += 1;
+
+ //If requested size is less than minimum, update that
+ alloc_size = (m_min_segment_size > alloc_size) ?
+ m_min_segment_size : alloc_size;
+ if(mp_frontend->priv_new_segment(create_open_func::DoCreate,
+ alloc_size, 0, permissions())){
+ typename shmem_list_t::value_type &m_impl = *mp_frontend->m_shmem_list.rbegin();
+ return result_type(m_impl.get_real_address(), m_impl.get_real_size()-1);
+ }*/
+ return result_type(static_cast<void *>(0), 0);
+ }
+
+ virtual bool update_segments ()
+ { return true; }
+
+ virtual ~group_services(){}
+
+ void set_group(segment_group_id group)
+ { m_group = group; }
+
+ segment_group_id get_group() const
+ { return m_group; }
+
+ void set_min_segment_size(size_type min_segment_size)
+ { m_min_segment_size = min_segment_size; }
+
+ size_type get_min_segment_size() const
+ { return m_min_segment_size; }
+
+ private:
+
+ frontend_t * const mp_frontend;
+ segment_group_id m_group;
+ size_type m_min_segment_size;
+ };
+
+ //!Functor to execute atomically when opening or creating a shared memory
+ //!segment.
+ struct create_open_func
+ {
+ enum type_t { DoCreate, DoOpen, DoOpenOrCreate };
+ typedef typename
+ basic_managed_multi_shared_memory::void_pointer void_pointer;
+
+ create_open_func(self_t * const frontend,
+ type_t type, size_type segment_number)
+ : mp_frontend(frontend), m_type(type), m_segment_number(segment_number){}
+
+ bool operator()(void *addr, size_type size, bool created) const
+ {
+ if(((m_type == DoOpen) && created) ||
+ ((m_type == DoCreate) && !created))
+ return false;
+ segment_group_id group = mp_frontend->m_group_services.get_group();
+ bool mapped = false;
+ bool impl_done = false;
+
+ //Associate this newly created segment as the
+ //segment id = 0 of this group
+ void_pointer::insert_mapping
+ ( group
+ , static_cast<char*>(addr) - managed_impl::ManagedOpenOrCreateUserOffset
+ , size + managed_impl::ManagedOpenOrCreateUserOffset);
+ //Check if this is the master segment
+ if(!m_segment_number){
+ //Create or open the Interprocess machinery
+ if((impl_done = created ?
+ mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size))){
+ return true;
+ }
+ }
+ else{
+ return true;
+ }
+
+ //This is the cleanup part
+ //---------------
+ if(impl_done){
+ mp_frontend->close_impl();
+ }
+ if(mapped){
+ bool ret = void_pointer::erase_last_mapping(group);
+ BOOST_ASSERT(ret);(void)ret;
+ }
+ return false;
+ }
+ self_t * const mp_frontend;
+ type_t m_type;
+ size_type m_segment_number;
+ };
+
+ //!Functor to execute atomically when closing a shared memory segment.
+ struct close_func
+ {
+ typedef typename
+ basic_managed_multi_shared_memory::void_pointer void_pointer;
+
+ close_func(self_t * const frontend)
+ : mp_frontend(frontend){}
+
+ void operator()(const mapped_region &region, bool last) const
+ {
+ if(last) mp_frontend->destroy_impl();
+ else mp_frontend->close_impl();
+ }
+ self_t * const mp_frontend;
+ };
+
+ //Friend declarations
+ friend struct basic_managed_multi_shared_memory::create_open_func;
+ friend struct basic_managed_multi_shared_memory::close_func;
+ friend class basic_managed_multi_shared_memory::group_services;
+
+ typedef list<managed_impl> shmem_list_t;
+
+ basic_managed_multi_shared_memory *get_this_pointer()
+ { return this; }
+
+ public:
+
+ basic_managed_multi_shared_memory(create_only_t,
+ const char *name,
+ size_type size,
+ const permissions &perm = permissions())
+ : m_group_services(get_this_pointer())
+ {
+ priv_open_or_create(create_open_func::DoCreate,name, size, perm);
+ }
+
+ basic_managed_multi_shared_memory(open_or_create_t,
+ const char *name,
+ size_type size,
+ const permissions &perm = permissions())
+ : m_group_services(get_this_pointer())
+ {
+ priv_open_or_create(create_open_func::DoOpenOrCreate, name, size, perm);
+ }
+
+ basic_managed_multi_shared_memory(open_only_t, const char *name)
+ : m_group_services(get_this_pointer())
+ {
+ priv_open_or_create(create_open_func::DoOpen, name, 0, permissions());
+ }
+
+ ~basic_managed_multi_shared_memory()
+ { this->priv_close(); }
+
+ private:
+ bool priv_open_or_create(typename create_open_func::type_t type,
+ const char *name,
+ size_type size,
+ const permissions &perm)
+ {
+ if(!m_shmem_list.empty())
+ return false;
+ typename void_pointer::segment_group_id group = 0;
+ BOOST_TRY{
+ m_root_name = name;
+ //Insert multi segment services and get a group identifier
+ group = void_pointer::new_segment_group(&m_group_services);
+ size = void_pointer::round_size(size);
+ m_group_services.set_group(group);
+ m_group_services.set_min_segment_size(size);
+
+ if(group){
+ if(this->priv_new_segment(type, size, 0, perm)){
+ return true;
+ }
+ }
+ }
+ BOOST_CATCH(const std::bad_alloc&){
+ }
+ BOOST_CATCH_END
+ if(group){
+ void_pointer::delete_group(group);
+ }
+ return false;
+ }
+
+ bool priv_new_segment(typename create_open_func::type_t type,
+ size_type size,
+ const void *addr,
+ const permissions &perm)
+ {
+ BOOST_TRY{
+ //Get the number of groups of this multi_segment group
+ size_type segment_id = m_shmem_list.size();
+ //Format the name of the shared memory: append segment number.
+ boost::interprocess::basic_ovectorstream<boost::interprocess::string> formatter;
+ //Pre-reserve string size
+ size_type str_size = m_root_name.length()+10;
+ if(formatter.vector().size() < str_size){
+ //This can throw.
+ formatter.reserve(str_size);
+ }
+ //Format segment's name
+ formatter << m_root_name
+ << static_cast<unsigned int>(segment_id) << std::ends;
+ //This functor will be executed when constructing
+ create_open_func func(this, type, segment_id);
+ const char *name = formatter.vector().c_str();
+ //This can throw.
+ managed_impl mshm;
+
+ switch(type){
+ case create_open_func::DoCreate:
+ {
+ managed_impl shm(create_only, name, size, read_write, addr, func, perm);
+ mshm = boost::move(shm);
+ }
+ break;
+
+ case create_open_func::DoOpen:
+ {
+ managed_impl shm(open_only, name,read_write, addr, func);
+ mshm = boost::move(shm);
+ }
+ break;
+
+ case create_open_func::DoOpenOrCreate:
+ {
+ managed_impl shm(open_or_create, name, size, read_write, addr, func, perm);
+ mshm = boost::move(shm);
+ }
+ break;
+
+ default:
+ return false;
+ break;
+ }
+
+ //This can throw.
+ m_shmem_list.push_back(boost::move(mshm));
+ return true;
+ }
+ BOOST_CATCH(const std::bad_alloc&){
+ }
+ BOOST_CATCH_END
+ return false;
+ }
+
+ //!Frees resources. Never throws.
+ void priv_close()
+ {
+ if(!m_shmem_list.empty()){
+ bool ret;
+ //Obtain group identifier
+ segment_group_id group = m_group_services.get_group();
+ //Erase main segment and its resources
+ //typename shmem_list_t::iterator itbeg = m_shmem_list.begin(),
+ // itend = m_shmem_list.end(),
+ // it = itbeg;
+ //(*itbeg)->close_with_func(close_func(this));
+ //Delete group. All mappings are erased too.
+ ret = void_pointer::delete_group(group);
+ (void)ret;
+ BOOST_ASSERT(ret);
+ m_shmem_list.clear();
+ }
+ }
+
+ private:
+ shmem_list_t m_shmem_list;
+ group_services m_group_services;
+ std::string m_root_name;
+};
+
+typedef basic_managed_multi_shared_memory
+ < char
+ , rbtree_best_fit<mutex_family, intersegment_ptr<void> >
+ , iset_index>
+ managed_multi_shared_memory;
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
+