1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2005-2009. 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 #if (defined _MSC_VER) && (_MSC_VER >= 1200)
15 #  pragma once
16 #endif
17 
18 #include <boost/interprocess/detail/config_begin.hpp>
19 #include <boost/interprocess/detail/workaround.hpp>
20 
21 #include <boost/interprocess/detail/managed_memory_impl.hpp>
22 #include <boost/interprocess/creation_tags.hpp>
23 #include <boost/detail/no_exceptions_support.hpp>
24 #include <boost/interprocess/detail/multi_segment_services.hpp>
25 #include <boost/interprocess/detail/utilities.hpp>
26 #include <boost/interprocess/shared_memory_object.hpp>
27 #include <boost/interprocess/containers/list.hpp>//list
28 #include <boost/interprocess/mapped_region.hpp> //mapped_region
29 #include <boost/interprocess/shared_memory_object.hpp>
30 #include <boost/interprocess/permissions.hpp>
31 #include <boost/interprocess/detail/managed_open_or_create_impl.hpp> //managed_open_or_create_impl
32 #include <new>
33 #include <boost/interprocess/containers/string.hpp>
34 #include <boost/interprocess/streams/vectorstream.hpp>
35 #include <memory>
36 #include <boost/assert.hpp>
37 
38 //!\file
39 //!Describes a named shared memory object allocation user class.
40 
41 namespace boost {
42 
43 namespace interprocess {
44 
45 //TODO: We must somehow obtain the permissions of the first segment
46 //to apply them to subsequent segments
47 //-Use GetSecurityInfo?
48 //-Change everything to use only a shared memory object expanded via truncate()?
49 
50 //!A basic shared memory named object creation class. Initializes the
51 //!shared memory segment. Inherits all basic functionality from
52 //!basic_managed_memory_impl<CharType, MemoryAlgorithm, IndexType>
53 template
54       <
55          class CharType,
56          class MemoryAlgorithm,
57          template<class IndexConfig> class IndexType
58       >
59 class basic_managed_multi_shared_memory
60    :  public detail::basic_managed_memory_impl
61          <CharType, MemoryAlgorithm, IndexType>
62 {
63 
64    typedef basic_managed_multi_shared_memory
65                <CharType, MemoryAlgorithm, IndexType>    self_t;
66    typedef typename MemoryAlgorithm::void_pointer        void_pointer;
67    typedef typename detail::
68       managed_open_or_create_impl<shared_memory_object>  managed_impl;
69    typedef typename void_pointer::segment_group_id       segment_group_id;
70    ////////////////////////////////////////////////////////////////////////
71    //
72    //               Some internal helper structs/functors
73    //
74    ////////////////////////////////////////////////////////////////////////
75    //!This class defines an operator() that creates a shared memory
76    //!of the requested size. The rest of the parameters are
77    //!passed in the constructor. The class a template parameter
78    //!to be used with create_from_file/create_from_istream functions
79    //!of basic_named_object classes
80 
81 //   class segment_creator
82 //   {
83 //      public:
84 //      segment_creator(shared_memory &shmem,
85 //                      const char *mem_name,
86 //                      const void *addr)
87 //      : m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){}
88 //
89 //      void *operator()(std::size_t size)
90 //      {
91 //         if(!m_shmem.create(m_mem_name, size, m_addr))
92 //            return 0;
93 //         return m_shmem.get_address();
94 //      }
95 //      private:
96 //      shared_memory &m_shmem;
97 //      const char *m_mem_name;
98 //      const void *m_addr;
99 //   };
100 
101    class group_services
102       :  public multi_segment_services
103    {
104       public:
105       typedef std::pair<void *, std::size_t>                result_type;
106       typedef basic_managed_multi_shared_memory             frontend_t;
107       typedef typename
108          basic_managed_multi_shared_memory::void_pointer    void_pointer;
109       typedef typename void_pointer::segment_group_id       segment_group_id;
group_services(frontend_t * const frontend)110       group_services(frontend_t *const frontend)
111          :  mp_frontend(frontend), m_group(0), m_min_segment_size(0){}
112 
create_new_segment(std::size_t alloc_size)113       virtual std::pair<void *, std::size_t> create_new_segment(std::size_t alloc_size)
114       {
115          //We should allocate an extra byte so that the
116          //[base_addr + alloc_size] byte belongs to this segment
117          alloc_size += 1;
118 
119          //If requested size is less than minimum, update that
120          alloc_size = (m_min_segment_size > alloc_size) ?
121                        m_min_segment_size : alloc_size;
122          if(mp_frontend->priv_new_segment(create_open_func::DoCreate,
123                                           alloc_size, 0, permissions())){
124             shmem_list_t::value_type &m_impl = *mp_frontend->m_shmem_list.rbegin();
125             return result_type(m_impl.get_real_address(), m_impl.get_real_size()-1);
126          }
127          return result_type(static_cast<void *>(0), 0);
128       }
129 
update_segments()130       virtual bool update_segments ()
131       {  return true;   }
132 
~group_services()133       virtual ~group_services(){}
134 
set_group(segment_group_id group)135       void set_group(segment_group_id group)
136          {  m_group = group;  }
137 
get_group() const138       segment_group_id get_group() const
139          {  return m_group;  }
140 
set_min_segment_size(std::size_t min_segment_size)141       void set_min_segment_size(std::size_t min_segment_size)
142          {  m_min_segment_size = min_segment_size;  }
143 
get_min_segment_size() const144       std::size_t get_min_segment_size() const
145          {  return m_min_segment_size;  }
146 
147       private:
148 
149       frontend_t * const   mp_frontend;
150       segment_group_id     m_group;
151       std::size_t          m_min_segment_size;
152    };
153 
154    //!Functor to execute atomically when opening or creating a shared memory
155    //!segment.
156    struct create_open_func
157    {
158       enum type_t {  DoCreate, DoOpen, DoOpenOrCreate  };
159       typedef typename
160          basic_managed_multi_shared_memory::void_pointer   void_pointer;
161 
create_open_funcboost::interprocess::basic_managed_multi_shared_memory::create_open_func162       create_open_func(self_t * const    frontend,
163                        type_t type, std::size_t segment_number)
164          : mp_frontend(frontend), m_type(type), m_segment_number(segment_number){}
165 
operator ()boost::interprocess::basic_managed_multi_shared_memory::create_open_func166       bool operator()(void *addr, std::size_t size, bool created) const
167       {
168          if(((m_type == DoOpen)   &&  created) ||
169             ((m_type == DoCreate) && !created))
170             return false;
171          segment_group_id group = mp_frontend->m_group_services.get_group();
172          bool mapped       = false;
173          bool impl_done    = false;
174 
175          //Associate this newly created segment as the
176          //segment id = 0 of this group
177          void_pointer::insert_mapping
178             ( group
179             , static_cast<char*>(addr) - managed_impl::ManagedOpenOrCreateUserOffset
180             , size + managed_impl::ManagedOpenOrCreateUserOffset);
181          //Check if this is the master segment
182          if(!m_segment_number){
183             //Create or open the Interprocess machinery
184             if((impl_done = created ?
185                mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size))){
186                return true;
187             }
188          }
189          else{
190             return true;
191          }
192 
193          //This is the cleanup part
194          //---------------
195          if(impl_done){
196             mp_frontend->close_impl();
197          }
198          if(mapped){
199             bool ret = void_pointer::erase_last_mapping(group);
200             BOOST_ASSERT(ret);(void)ret;
201          }
202          return false;
203       }
204       self_t * const    mp_frontend;
205       type_t            m_type;
206       std::size_t       m_segment_number;
207    };
208 
209    //!Functor to execute atomically when closing a shared memory segment.
210    struct close_func
211    {
212       typedef typename
213          basic_managed_multi_shared_memory::void_pointer   void_pointer;
214 
close_funcboost::interprocess::basic_managed_multi_shared_memory::close_func215       close_func(self_t * const frontend)
216          : mp_frontend(frontend){}
217 
operator ()boost::interprocess::basic_managed_multi_shared_memory::close_func218       void operator()(const mapped_region &region, bool last) const
219       {
220          if(last) mp_frontend->destroy_impl();
221          else     mp_frontend->close_impl();
222       }
223       self_t * const    mp_frontend;
224    };
225 
226    typedef detail::basic_managed_memory_impl
227       <CharType, MemoryAlgorithm, IndexType>                   base_t;
228 
229    //Friend declarations
230    friend struct basic_managed_multi_shared_memory::create_open_func;
231    friend struct basic_managed_multi_shared_memory::close_func;
232    friend class basic_managed_multi_shared_memory::group_services;
233 
234    typedef list<managed_impl> shmem_list_t;
235 
get_this_pointer()236    basic_managed_multi_shared_memory *get_this_pointer()
237       {  return this;   }
238 
239  public:
240 
basic_managed_multi_shared_memory(create_only_t,const char * name,std::size_t size,const permissions & perm=permissions ())241    basic_managed_multi_shared_memory(create_only_t,
242                                      const char *name,
243                                      std::size_t size,
244                                      const permissions &perm = permissions())
245       :  m_group_services(get_this_pointer())
246    {
247       priv_open_or_create(create_open_func::DoCreate,name, size, perm);
248    }
249 
basic_managed_multi_shared_memory(open_or_create_t,const char * name,std::size_t size,const permissions & perm=permissions ())250    basic_managed_multi_shared_memory(open_or_create_t,
251                                      const char *name,
252                                      std::size_t size,
253                                      const permissions &perm = permissions())
254       :  m_group_services(get_this_pointer())
255    {
256       priv_open_or_create(create_open_func::DoOpenOrCreate, name, size, perm);
257    }
258 
basic_managed_multi_shared_memory(open_only_t,const char * name)259    basic_managed_multi_shared_memory(open_only_t, const char *name)
260       :  m_group_services(get_this_pointer())
261    {
262       priv_open_or_create(create_open_func::DoOpen, name, 0, permissions());
263    }
264 
~basic_managed_multi_shared_memory()265    ~basic_managed_multi_shared_memory()
266       {  this->priv_close(); }
267 
268    private:
priv_open_or_create(typename create_open_func::type_t type,const char * name,std::size_t size,const permissions & perm)269    bool  priv_open_or_create(typename create_open_func::type_t type,
270                              const char *name,
271                              std::size_t size,
272                              const permissions &perm)
273    {
274       if(!m_shmem_list.empty())
275          return false;
276       typename void_pointer::segment_group_id group = 0;
277       BOOST_TRY{
278          m_root_name = name;
279          //Insert multi segment services and get a group identifier
280          group = void_pointer::new_segment_group(&m_group_services);
281          size = void_pointer::round_size(size);
282          m_group_services.set_group(group);
283          m_group_services.set_min_segment_size(size);
284 
285          if(group){
286             if(this->priv_new_segment(type, size, 0, perm)){
287                return true;
288             }
289          }
290       }
291       BOOST_CATCH(const std::bad_alloc&){
292       }
293       BOOST_CATCH_END
294       if(group){
295          void_pointer::delete_group(group);
296       }
297       return false;
298    }
299 
priv_new_segment(typename create_open_func::type_t type,std::size_t size,const void * addr,const permissions & perm)300    bool  priv_new_segment(typename create_open_func::type_t type,
301                           std::size_t size,
302                           const void *addr,
303                           const permissions &perm)
304    {
305       BOOST_TRY{
306          //Get the number of groups of this multi_segment group
307          std::size_t segment_id  = m_shmem_list.size();
308          //Format the name of the shared memory: append segment number.
309          boost::interprocess::basic_ovectorstream<boost::interprocess::string> formatter;
310          //Pre-reserve string size
311          std::size_t str_size = m_root_name.length()+10;
312          if(formatter.vector().size() < str_size){
313             //This can throw.
314             formatter.reserve(str_size);
315          }
316          //Format segment's name
317          formatter << m_root_name
318                    << static_cast<unsigned int>(segment_id) << std::ends;
319          //This functor will be executed when constructing
320          create_open_func func(this, type, segment_id);
321          const char *name = formatter.vector().c_str();
322          //This can throw.
323          managed_impl mshm;
324 
325          switch(type){
326             case create_open_func::DoCreate:
327             {
328                managed_impl shm(create_only, name, size, read_write, addr, func, perm);
329                mshm = boost::interprocess::move(shm);
330             }
331             break;
332 
333             case create_open_func::DoOpen:
334             {
335                managed_impl shm(open_only, name,read_write, addr, func);
336                mshm = boost::interprocess::move(shm);
337             }
338             break;
339 
340             case create_open_func::DoOpenOrCreate:
341             {
342                managed_impl shm(open_or_create, name, size, read_write, addr, func, perm);
343                mshm = boost::interprocess::move(shm);
344             }
345             break;
346 
347             default:
348                return false;
349             break;
350          }
351 
352          //This can throw.
353          m_shmem_list.push_back(boost::interprocess::move(mshm));
354          return true;
355       }
356       BOOST_CATCH(const std::bad_alloc&){
357       }
358       BOOST_CATCH_END
359       return false;
360    }
361 
362    //!Frees resources. Never throws.
priv_close()363    void priv_close()
364    {
365       if(!m_shmem_list.empty()){
366          bool ret;
367          //Obtain group identifier
368          segment_group_id group = m_group_services.get_group();
369          //Erase main segment and its resources
370          shmem_list_t::iterator  itbeg = m_shmem_list.begin(),
371                                  itend = m_shmem_list.end(),
372                                  it    = itbeg;
373          //(*itbeg)->close_with_func(close_func(this));
374          //Delete group. All mappings are erased too.
375          ret = void_pointer::delete_group(group);
376          BOOST_ASSERT(ret);
377          m_shmem_list.clear();
378       }
379    }
380 
381    private:
382    shmem_list_t   m_shmem_list;
383    group_services m_group_services;
384    std::string    m_root_name;
385 };
386 
387 typedef basic_managed_multi_shared_memory
388    < char
389    , rbtree_best_fit<mutex_family, intersegment_ptr<void> >
390    , iset_index>
391    managed_multi_shared_memory;
392 
393 }  //namespace interprocess {
394 
395 }  //namespace boost {
396 
397 #include <boost/interprocess/detail/config_end.hpp>
398 
399 #endif   //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
400 
401