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;
group_services(frontend_t * const frontend)126       group_services(frontend_t *const frontend)
127          :  mp_frontend(frontend), m_group(0), m_min_segment_size(0){}
128 
create_new_segment(size_type alloc_size)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 
update_segments()147       virtual bool update_segments ()
148       {  return true;   }
149 
~group_services()150       virtual ~group_services(){}
151 
set_group(segment_group_id group)152       void set_group(segment_group_id group)
153          {  m_group = group;  }
154 
get_group() const155       segment_group_id get_group() const
156          {  return m_group;  }
157 
set_min_segment_size(size_type min_segment_size)158       void set_min_segment_size(size_type min_segment_size)
159          {  m_min_segment_size = min_segment_size;  }
160 
get_min_segment_size() const161       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 
create_open_funcboost::interprocess::basic_managed_multi_shared_memory::create_open_func179       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 
operator ()boost::interprocess::basic_managed_multi_shared_memory::create_open_func183       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 
get_min_sizeboost::interprocess::basic_managed_multi_shared_memory::create_open_func222       std::size_t get_min_size() const
223       {
224          const size_type sz = mp_frontend->get_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 
close_funcboost::interprocess::basic_managed_multi_shared_memory::close_func246       close_func(self_t * const frontend)
247          : mp_frontend(frontend){}
248 
operator ()boost::interprocess::basic_managed_multi_shared_memory::close_func249       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 
get_this_pointer()264    basic_managed_multi_shared_memory *get_this_pointer()
265       {  return this;   }
266 
267  public:
268 
basic_managed_multi_shared_memory(create_only_t,const char * name,size_type size,const permissions & perm=permissions ())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 
basic_managed_multi_shared_memory(open_or_create_t,const char * name,size_type size,const permissions & perm=permissions ())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 
basic_managed_multi_shared_memory(open_only_t,const char * name)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 
~basic_managed_multi_shared_memory()293    ~basic_managed_multi_shared_memory()
294       {  this->priv_close(); }
295 
296    private:
priv_open_or_create(typename create_open_func::type_t type,const char * name,size_type size,const permissions & perm)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 
priv_new_segment(typename create_open_func::type_t type,size_type size,const void * addr,const permissions & perm)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.
priv_close()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 
430