]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/interprocess/include/boost/interprocess/detail/managed_multi_shared_memory.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / interprocess / include / boost / interprocess / detail / managed_multi_shared_memory.hpp
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_MANAGED_MULTI_SHARED_MEMORY_HPP
12 #define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_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/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
42
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>
48
49 //!\file
50 //!Describes a named shared memory object allocation user class.
51
52 namespace boost {
53
54 namespace interprocess {
55
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()?
60
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>
64 template
65 <
66 class CharType,
67 class MemoryAlgorithm,
68 template<class IndexConfig> class IndexType
69 >
70 class basic_managed_multi_shared_memory
71 : public ipcdetail::basic_managed_memory_impl
72 <CharType, MemoryAlgorithm, IndexType>
73 {
74
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;
79
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;
85
86 ////////////////////////////////////////////////////////////////////////
87 //
88 // Some internal helper structs/functors
89 //
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
96
97 // class segment_creator
98 // {
99 // public:
100 // segment_creator(shared_memory &shmem,
101 // const char *mem_name,
102 // const void *addr)
103 // : m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){}
104 //
105 // void *operator()(size_type size)
106 // {
107 // if(!m_shmem.create(m_mem_name, size, m_addr))
108 // return 0;
109 // return m_shmem.get_address();
110 // }
111 // private:
112 // shared_memory &m_shmem;
113 // const char *m_mem_name;
114 // const void *m_addr;
115 // };
116
117 class group_services
118 : public multi_segment_services
119 {
120 public:
121 typedef std::pair<void *, size_type> result_type;
122 typedef basic_managed_multi_shared_memory frontend_t;
123 typedef typename
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){}
128
129 virtual std::pair<void *, size_type> create_new_segment(size_type alloc_size)
130 { (void)alloc_size;
131 /*
132 //We should allocate an extra byte so that the
133 //[base_addr + alloc_size] byte belongs to this segment
134 alloc_size += 1;
135
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);
143 }*/
144 return result_type(static_cast<void *>(0), 0);
145 }
146
147 virtual bool update_segments ()
148 { return true; }
149
150 virtual ~group_services(){}
151
152 void set_group(segment_group_id group)
153 { m_group = group; }
154
155 segment_group_id get_group() const
156 { return m_group; }
157
158 void set_min_segment_size(size_type min_segment_size)
159 { m_min_segment_size = min_segment_size; }
160
161 size_type get_min_segment_size() const
162 { return m_min_segment_size; }
163
164 private:
165
166 frontend_t * const mp_frontend;
167 segment_group_id m_group;
168 size_type m_min_segment_size;
169 };
170
171 //!Functor to execute atomically when opening or creating a shared memory
172 //!segment.
173 struct create_open_func
174 {
175 enum type_t { DoCreate, DoOpen, DoOpenOrCreate };
176 typedef typename
177 basic_managed_multi_shared_memory::void_pointer void_pointer;
178
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){}
182
183 bool operator()(void *addr, size_type size, bool created) const
184 {
185 if(((m_type == DoOpen) && created) ||
186 ((m_type == DoCreate) && !created))
187 return false;
188 segment_group_id group = mp_frontend->m_group_services.get_group();
189 bool mapped = false;
190 bool impl_done = false;
191
192 //Associate this newly created segment as the
193 //segment id = 0 of this group
194 void_pointer::insert_mapping
195 ( group
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))){
203 return true;
204 }
205 }
206 else{
207 return true;
208 }
209
210 //This is the cleanup part
211 //---------------
212 if(impl_done){
213 mp_frontend->close_impl();
214 }
215 if(mapped){
216 bool ret = void_pointer::erase_last_mapping(group);
217 BOOST_ASSERT(ret);(void)ret;
218 }
219 return false;
220 }
221
222 static std::size_t get_min_size()
223 {
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
227 BOOST_ASSERT(false);
228 return std::size_t(-1);
229 }
230 else{
231 return static_cast<std::size_t>(sz);
232 }
233 }
234
235 self_t * const mp_frontend;
236 type_t m_type;
237 size_type m_segment_number;
238 };
239
240 //!Functor to execute atomically when closing a shared memory segment.
241 struct close_func
242 {
243 typedef typename
244 basic_managed_multi_shared_memory::void_pointer void_pointer;
245
246 close_func(self_t * const frontend)
247 : mp_frontend(frontend){}
248
249 void operator()(const mapped_region &region, bool last) const
250 {
251 if(last) mp_frontend->destroy_impl();
252 else mp_frontend->close_impl();
253 }
254 self_t * const mp_frontend;
255 };
256
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;
261
262 typedef list<managed_impl> shmem_list_t;
263
264 basic_managed_multi_shared_memory *get_this_pointer()
265 { return this; }
266
267 public:
268
269 basic_managed_multi_shared_memory(create_only_t,
270 const char *name,
271 size_type size,
272 const permissions &perm = permissions())
273 : m_group_services(get_this_pointer())
274 {
275 priv_open_or_create(create_open_func::DoCreate,name, size, perm);
276 }
277
278 basic_managed_multi_shared_memory(open_or_create_t,
279 const char *name,
280 size_type size,
281 const permissions &perm = permissions())
282 : m_group_services(get_this_pointer())
283 {
284 priv_open_or_create(create_open_func::DoOpenOrCreate, name, size, perm);
285 }
286
287 basic_managed_multi_shared_memory(open_only_t, const char *name)
288 : m_group_services(get_this_pointer())
289 {
290 priv_open_or_create(create_open_func::DoOpen, name, 0, permissions());
291 }
292
293 ~basic_managed_multi_shared_memory()
294 { this->priv_close(); }
295
296 private:
297 bool priv_open_or_create(typename create_open_func::type_t type,
298 const char *name,
299 size_type size,
300 const permissions &perm)
301 {
302 if(!m_shmem_list.empty())
303 return false;
304 typename void_pointer::segment_group_id group = 0;
305 BOOST_TRY{
306 m_root_name = name;
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);
312
313 if(group){
314 if(this->priv_new_segment(type, size, 0, perm)){
315 return true;
316 }
317 }
318 }
319 BOOST_CATCH(const std::bad_alloc&){
320 }
321 BOOST_CATCH_END
322 if(group){
323 void_pointer::delete_group(group);
324 }
325 return false;
326 }
327
328 bool priv_new_segment(typename create_open_func::type_t type,
329 size_type size,
330 const void *addr,
331 const permissions &perm)
332 {
333 BOOST_TRY{
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){
341 //This can throw.
342 formatter.reserve(str_size);
343 }
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();
350 //This can throw.
351 managed_impl mshm;
352
353 switch(type){
354 case create_open_func::DoCreate:
355 {
356 managed_impl shm(create_only, name, size, read_write, addr, func, perm);
357 mshm = boost::move(shm);
358 }
359 break;
360
361 case create_open_func::DoOpen:
362 {
363 managed_impl shm(open_only, name,read_write, addr, func);
364 mshm = boost::move(shm);
365 }
366 break;
367
368 case create_open_func::DoOpenOrCreate:
369 {
370 managed_impl shm(open_or_create, name, size, read_write, addr, func, perm);
371 mshm = boost::move(shm);
372 }
373 break;
374
375 default:
376 return false;
377 break;
378 }
379
380 //This can throw.
381 m_shmem_list.push_back(boost::move(mshm));
382 return true;
383 }
384 BOOST_CATCH(const std::bad_alloc&){
385 }
386 BOOST_CATCH_END
387 return false;
388 }
389
390 //!Frees resources. Never throws.
391 void priv_close()
392 {
393 if(!m_shmem_list.empty()){
394 bool ret;
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(),
400 // it = itbeg;
401 //(*itbeg)->close_with_func(close_func(this));
402 //Delete group. All mappings are erased too.
403 ret = void_pointer::delete_group(group);
404 (void)ret;
405 BOOST_ASSERT(ret);
406 m_shmem_list.clear();
407 }
408 }
409
410 private:
411 shmem_list_t m_shmem_list;
412 group_services m_group_services;
413 std::string m_root_name;
414 };
415
416 typedef basic_managed_multi_shared_memory
417 < char
418 , rbtree_best_fit<mutex_family, intersegment_ptr<void> >
419 , iset_index>
420 managed_multi_shared_memory;
421
422 } //namespace interprocess {
423
424 } //namespace boost {
425
426 #include <boost/interprocess/detail/config_end.hpp>
427
428 #endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
429