1 //////////////////////////////////////////////////////////////////////////////
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)
7 // See http://www.boost.org/libs/interprocess for documentation.
9 //////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
12 #define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
14 #ifndef BOOST_CONFIG_HPP
15 # include <boost/config.hpp>
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
22 #include <boost/interprocess/detail/config_begin.hpp>
23 #include <boost/interprocess/detail/workaround.hpp>
25 #include <boost/interprocess/detail/managed_memory_impl.hpp>
26 #include <boost/interprocess/creation_tags.hpp>
27 #include <boost/core/no_exceptions_support.hpp>
28 #include <boost/interprocess/detail/multi_segment_services.hpp>
29 #include <boost/interprocess/detail/utilities.hpp>
30 #include <boost/interprocess/shared_memory_object.hpp>
31 #include <boost/interprocess/containers/list.hpp>//list
32 #include <boost/interprocess/mapped_region.hpp> //mapped_region
33 #include <boost/interprocess/shared_memory_object.hpp>
34 #include <boost/interprocess/permissions.hpp>
35 #include <boost/interprocess/detail/managed_open_or_create_impl.hpp> //managed_open_or_create_impl
36 #include <boost/interprocess/containers/string.hpp>
37 #include <boost/interprocess/streams/vectorstream.hpp>
38 #include <boost/intrusive/detail/minimal_pair_header.hpp>
39 #include <string> //string
40 #include <new> //bad_alloc
41 #include <ostream>//std::ends
43 #include <boost/assert.hpp>
44 //These includes needed to fulfill default template parameters of
45 //predeclarations in interprocess_fwd.hpp
46 #include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
47 #include <boost/interprocess/sync/mutex_family.hpp>
50 //!Describes a named shared memory object allocation user class.
54 namespace interprocess
{
56 //TODO: We must somehow obtain the permissions of the first segment
57 //to apply them to subsequent segments
58 //-Use GetSecurityInfo?
59 //-Change everything to use only a shared memory object expanded via truncate()?
61 //!A basic shared memory named object creation class. Initializes the
62 //!shared memory segment. Inherits all basic functionality from
63 //!basic_managed_memory_impl<CharType, MemoryAlgorithm, IndexType>
67 class MemoryAlgorithm
,
68 template<class IndexConfig
> class IndexType
70 class basic_managed_multi_shared_memory
71 : public ipcdetail::basic_managed_memory_impl
72 <CharType
, MemoryAlgorithm
, IndexType
>
75 typedef basic_managed_multi_shared_memory
76 <CharType
, MemoryAlgorithm
, IndexType
> self_t
;
77 typedef ipcdetail::basic_managed_memory_impl
78 <CharType
, MemoryAlgorithm
, IndexType
> base_t
;
80 typedef typename
MemoryAlgorithm::void_pointer void_pointer
;
81 typedef typename
ipcdetail::
82 managed_open_or_create_impl
<shared_memory_object
, MemoryAlgorithm::Alignment
, true, false> managed_impl
;
83 typedef typename
void_pointer::segment_group_id segment_group_id
;
84 typedef typename
base_t::size_type size_type
;
86 ////////////////////////////////////////////////////////////////////////
88 // Some internal helper structs/functors
90 ////////////////////////////////////////////////////////////////////////
91 //!This class defines an operator() that creates a shared memory
92 //!of the requested size. The rest of the parameters are
93 //!passed in the constructor. The class a template parameter
94 //!to be used with create_from_file/create_from_istream functions
95 //!of basic_named_object classes
97 // class segment_creator
100 // segment_creator(shared_memory &shmem,
101 // const char *mem_name,
103 // : m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){}
105 // void *operator()(size_type size)
107 // if(!m_shmem.create(m_mem_name, size, m_addr))
109 // return m_shmem.get_address();
112 // shared_memory &m_shmem;
113 // const char *m_mem_name;
114 // const void *m_addr;
118 : public multi_segment_services
121 typedef std::pair
<void *, size_type
> result_type
;
122 typedef basic_managed_multi_shared_memory frontend_t
;
124 basic_managed_multi_shared_memory::void_pointer void_pointer
;
125 typedef typename
void_pointer::segment_group_id segment_group_id
;
126 group_services(frontend_t
*const frontend
)
127 : mp_frontend(frontend
), m_group(0), m_min_segment_size(0){}
129 virtual std::pair
<void *, size_type
> create_new_segment(size_type alloc_size
)
132 //We should allocate an extra byte so that the
133 //[base_addr + alloc_size] byte belongs to this segment
136 //If requested size is less than minimum, update that
137 alloc_size = (m_min_segment_size > alloc_size) ?
138 m_min_segment_size : alloc_size;
139 if(mp_frontend->priv_new_segment(create_open_func::DoCreate,
140 alloc_size, 0, permissions())){
141 typename shmem_list_t::value_type &m_impl = *mp_frontend->m_shmem_list.rbegin();
142 return result_type(m_impl.get_real_address(), m_impl.get_real_size()-1);
144 return result_type(static_cast<void *>(0), 0);
147 virtual bool update_segments ()
150 virtual ~group_services(){}
152 void set_group(segment_group_id group
)
155 segment_group_id
get_group() const
158 void set_min_segment_size(size_type min_segment_size
)
159 { m_min_segment_size
= min_segment_size
; }
161 size_type
get_min_segment_size() const
162 { return m_min_segment_size
; }
166 frontend_t
* const mp_frontend
;
167 segment_group_id m_group
;
168 size_type m_min_segment_size
;
171 //!Functor to execute atomically when opening or creating a shared memory
173 struct create_open_func
175 enum type_t
{ DoCreate
, DoOpen
, DoOpenOrCreate
};
177 basic_managed_multi_shared_memory::void_pointer void_pointer
;
179 create_open_func(self_t
* const frontend
,
180 type_t type
, size_type segment_number
)
181 : mp_frontend(frontend
), m_type(type
), m_segment_number(segment_number
){}
183 bool operator()(void *addr
, size_type size
, bool created
) const
185 if(((m_type
== DoOpen
) && created
) ||
186 ((m_type
== DoCreate
) && !created
))
188 segment_group_id group
= mp_frontend
->m_group_services
.get_group();
190 bool impl_done
= false;
192 //Associate this newly created segment as the
193 //segment id = 0 of this group
194 void_pointer::insert_mapping
196 , static_cast<char*>(addr
) - managed_impl::ManagedOpenOrCreateUserOffset
197 , size
+ managed_impl::ManagedOpenOrCreateUserOffset
);
198 //Check if this is the master segment
199 if(!m_segment_number
){
200 //Create or open the Interprocess machinery
201 if((impl_done
= created
?
202 mp_frontend
->create_impl(addr
, size
) : mp_frontend
->open_impl(addr
, size
))){
210 //This is the cleanup part
213 mp_frontend
->close_impl();
216 bool ret
= void_pointer::erase_last_mapping(group
);
217 BOOST_ASSERT(ret
);(void)ret
;
222 static std::size_t get_min_size()
224 const size_type sz
= self_t::segment_manager::get_min_size();
225 if(sz
> std::size_t(-1)){
226 //The minimum size is not representable by std::size_t
228 return std::size_t(-1);
231 return static_cast<std::size_t>(sz
);
235 self_t
* const mp_frontend
;
237 size_type m_segment_number
;
240 //!Functor to execute atomically when closing a shared memory segment.
244 basic_managed_multi_shared_memory::void_pointer void_pointer
;
246 close_func(self_t
* const frontend
)
247 : mp_frontend(frontend
){}
249 void operator()(const mapped_region
®ion
, bool last
) const
251 if(last
) mp_frontend
->destroy_impl();
252 else mp_frontend
->close_impl();
254 self_t
* const mp_frontend
;
257 //Friend declarations
258 friend struct basic_managed_multi_shared_memory::create_open_func
;
259 friend struct basic_managed_multi_shared_memory::close_func
;
260 friend class basic_managed_multi_shared_memory::group_services
;
262 typedef list
<managed_impl
> shmem_list_t
;
264 basic_managed_multi_shared_memory
*get_this_pointer()
269 basic_managed_multi_shared_memory(create_only_t
,
272 const permissions
&perm
= permissions())
273 : m_group_services(get_this_pointer())
275 priv_open_or_create(create_open_func::DoCreate
,name
, size
, perm
);
278 basic_managed_multi_shared_memory(open_or_create_t
,
281 const permissions
&perm
= permissions())
282 : m_group_services(get_this_pointer())
284 priv_open_or_create(create_open_func::DoOpenOrCreate
, name
, size
, perm
);
287 basic_managed_multi_shared_memory(open_only_t
, const char *name
)
288 : m_group_services(get_this_pointer())
290 priv_open_or_create(create_open_func::DoOpen
, name
, 0, permissions());
293 ~basic_managed_multi_shared_memory()
294 { this->priv_close(); }
297 bool priv_open_or_create(typename
create_open_func::type_t type
,
300 const permissions
&perm
)
302 if(!m_shmem_list
.empty())
304 typename
void_pointer::segment_group_id group
= 0;
307 //Insert multi segment services and get a group identifier
308 group
= void_pointer::new_segment_group(&m_group_services
);
309 size
= void_pointer::round_size(size
);
310 m_group_services
.set_group(group
);
311 m_group_services
.set_min_segment_size(size
);
314 if(this->priv_new_segment(type
, size
, 0, perm
)){
319 BOOST_CATCH(const std::bad_alloc
&){
323 void_pointer::delete_group(group
);
328 bool priv_new_segment(typename
create_open_func::type_t type
,
331 const permissions
&perm
)
334 //Get the number of groups of this multi_segment group
335 size_type segment_id
= m_shmem_list
.size();
336 //Format the name of the shared memory: append segment number.
337 boost::interprocess::basic_ovectorstream
<boost::interprocess::string
> formatter
;
338 //Pre-reserve string size
339 size_type str_size
= m_root_name
.length()+10;
340 if(formatter
.vector().size() < str_size
){
342 formatter
.reserve(str_size
);
344 //Format segment's name
345 formatter
<< m_root_name
346 << static_cast<unsigned int>(segment_id
) << std::ends
;
347 //This functor will be executed when constructing
348 create_open_func
func(this, type
, segment_id
);
349 const char *name
= formatter
.vector().c_str();
354 case create_open_func::DoCreate
:
356 managed_impl
shm(create_only
, name
, size
, read_write
, addr
, func
, perm
);
357 mshm
= boost::move(shm
);
361 case create_open_func::DoOpen
:
363 managed_impl
shm(open_only
, name
,read_write
, addr
, func
);
364 mshm
= boost::move(shm
);
368 case create_open_func::DoOpenOrCreate
:
370 managed_impl
shm(open_or_create
, name
, size
, read_write
, addr
, func
, perm
);
371 mshm
= boost::move(shm
);
381 m_shmem_list
.push_back(boost::move(mshm
));
384 BOOST_CATCH(const std::bad_alloc
&){
390 //!Frees resources. Never throws.
393 if(!m_shmem_list
.empty()){
395 //Obtain group identifier
396 segment_group_id group
= m_group_services
.get_group();
397 //Erase main segment and its resources
398 //typename shmem_list_t::iterator itbeg = m_shmem_list.begin(),
399 // itend = m_shmem_list.end(),
401 //(*itbeg)->close_with_func(close_func(this));
402 //Delete group. All mappings are erased too.
403 ret
= void_pointer::delete_group(group
);
406 m_shmem_list
.clear();
411 shmem_list_t m_shmem_list
;
412 group_services m_group_services
;
413 std::string m_root_name
;
416 typedef basic_managed_multi_shared_memory
418 , rbtree_best_fit
<mutex_family
, intersegment_ptr
<void> >
420 managed_multi_shared_memory
;
422 } //namespace interprocess {
424 } //namespace boost {
426 #include <boost/interprocess/detail/config_end.hpp>
428 #endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP