////////////////////////////////////////////////////////////////////////////// | |
// | |
// (C) Copyright Ion Gaztanaga 2005-2009. 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> | |
//!\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 detail::basic_managed_memory_impl | |
<CharType, MemoryAlgorithm, IndexType> | |
{ | |
typedef basic_managed_multi_shared_memory | |
<CharType, MemoryAlgorithm, IndexType> self_t; | |
typedef typename MemoryAlgorithm::void_pointer void_pointer; | |
typedef typename detail:: | |
managed_open_or_create_impl<shared_memory_object> managed_impl; | |
typedef typename void_pointer::segment_group_id segment_group_id; | |
//////////////////////////////////////////////////////////////////////// | |
// | |
// 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()(std::size_t 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 *, std::size_t> 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 *, std::size_t> create_new_segment(std::size_t 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())){ | |
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(std::size_t min_segment_size) | |
{ m_min_segment_size = min_segment_size; } | |
std::size_t get_min_segment_size() const | |
{ return m_min_segment_size; } | |
private: | |
frontend_t * const mp_frontend; | |
segment_group_id m_group; | |
std::size_t 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, std::size_t segment_number) | |
: mp_frontend(frontend), m_type(type), m_segment_number(segment_number){} | |
bool operator()(void *addr, std::size_t 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; | |
std::size_t 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 ®ion, bool last) const | |
{ | |
if(last) mp_frontend->destroy_impl(); | |
else mp_frontend->close_impl(); | |
} | |
self_t * const mp_frontend; | |
}; | |
typedef detail::basic_managed_memory_impl | |
<CharType, MemoryAlgorithm, IndexType> base_t; | |
//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, | |
std::size_t 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, | |
std::size_t 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, | |
std::size_t 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, | |
std::size_t size, | |
const void *addr, | |
const permissions &perm) | |
{ | |
BOOST_TRY{ | |
//Get the number of groups of this multi_segment group | |
std::size_t 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 | |
std::size_t 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::interprocess::move(shm); | |
} | |
break; | |
case create_open_func::DoOpen: | |
{ | |
managed_impl shm(open_only, name,read_write, addr, func); | |
mshm = boost::interprocess::move(shm); | |
} | |
break; | |
case create_open_func::DoOpenOrCreate: | |
{ | |
managed_impl shm(open_or_create, name, size, read_write, addr, func, perm); | |
mshm = boost::interprocess::move(shm); | |
} | |
break; | |
default: | |
return false; | |
break; | |
} | |
//This can throw. | |
m_shmem_list.push_back(boost::interprocess::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 | |
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); | |
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 | |