PageRenderTime 71ms CodeModel.GetById 10ms app.highlight 57ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/interprocess/detail/managed_open_or_create_impl.hpp

http://hadesmem.googlecode.com/
C++ Header | 456 lines | 370 code | 64 blank | 22 comment | 46 complexity | 2699ace7a9fa65bfdc674b5843cd0ece MD5 | raw file
  1//////////////////////////////////////////////////////////////////////////////
  2//
  3// (C) Copyright Ion Gaztanaga 2006. 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_OPEN_OR_CREATE_IMPL
 12#define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL
 13
 14#include <boost/interprocess/detail/os_thread_functions.hpp>
 15#include <boost/interprocess/detail/os_file_functions.hpp>
 16#include <boost/interprocess/creation_tags.hpp>
 17#include <boost/interprocess/mapped_region.hpp>
 18#include <boost/interprocess/detail/utilities.hpp>
 19#include <boost/interprocess/detail/type_traits.hpp>
 20#include <boost/interprocess/detail/atomic.hpp>
 21#include <boost/interprocess/detail/interprocess_tester.hpp>
 22#include <boost/interprocess/creation_tags.hpp>
 23#include <boost/interprocess/detail/mpl.hpp>
 24#include <boost/interprocess/detail/move.hpp>
 25#include <boost/interprocess/permissions.hpp>
 26#include <boost/cstdint.hpp>
 27
 28namespace boost {
 29namespace interprocess {
 30
 31/// @cond
 32namespace detail{ class interprocess_tester; }
 33
 34
 35template<class DeviceAbstraction>
 36struct managed_open_or_create_impl_device_id_t
 37{
 38   typedef const char *type;
 39};
 40
 41#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
 42
 43class xsi_shared_memory_file_wrapper;
 44class xsi_key;
 45
 46template<>
 47struct managed_open_or_create_impl_device_id_t<xsi_shared_memory_file_wrapper>
 48{  
 49   typedef xsi_key type;
 50};
 51
 52#endif   //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
 53   
 54/// @endcond
 55
 56namespace detail {
 57
 58
 59template <bool StoreDevice, class DeviceAbstraction>
 60class managed_open_or_create_impl_device_holder
 61{
 62   public:
 63   DeviceAbstraction &get_device()
 64   {  static DeviceAbstraction dev; return dev; }
 65
 66   const DeviceAbstraction &get_device() const
 67   {  static DeviceAbstraction dev; return dev; }
 68};
 69
 70template <class DeviceAbstraction>
 71class managed_open_or_create_impl_device_holder<true, DeviceAbstraction>
 72{
 73   public:
 74   DeviceAbstraction &get_device()
 75   {  return dev; }
 76
 77   const DeviceAbstraction &get_device() const
 78   {  return dev; }
 79   
 80   private:
 81   DeviceAbstraction dev;
 82};
 83
 84template<class DeviceAbstraction, bool FileBased = true, bool StoreDevice = true>
 85class managed_open_or_create_impl
 86   : public managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction>
 87{
 88   //Non-copyable
 89   BOOST_INTERPROCESS_MOVABLE_BUT_NOT_COPYABLE(managed_open_or_create_impl)
 90
 91   typedef typename managed_open_or_create_impl_device_id_t<DeviceAbstraction>::type device_id_t;
 92   typedef managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction> DevHolder;
 93   enum
 94   {  
 95      UninitializedSegment,  
 96      InitializingSegment,  
 97      InitializedSegment,
 98      CorruptedSegment
 99   };
100
101   public:
102   static const std::size_t
103      ManagedOpenOrCreateUserOffset = 
104         detail::ct_rounded_size
105            < sizeof(boost::uint32_t)
106            , detail::alignment_of<detail::max_align>::value>::value;
107
108   managed_open_or_create_impl()
109   {}
110
111   managed_open_or_create_impl(create_only_t, 
112                 const device_id_t & id,
113                 std::size_t size,
114                 mode_t mode,
115                 const void *addr,
116                 const permissions &perm)
117   {
118      priv_open_or_create
119         ( detail::DoCreate
120         , id
121         , size
122         , mode
123         , addr
124         , perm
125         , null_mapped_region_function());
126   }
127
128   managed_open_or_create_impl(open_only_t, 
129                 const device_id_t & id,
130                 mode_t mode,
131                 const void *addr)
132   {
133      priv_open_or_create
134         ( detail::DoOpen
135         , id
136         , 0
137         , mode
138         , addr
139         , permissions()
140         , null_mapped_region_function());
141   }
142
143
144   managed_open_or_create_impl(open_or_create_t, 
145                 const device_id_t & id,
146                 std::size_t size,
147                 mode_t mode,
148                 const void *addr,
149                 const permissions &perm)
150   {
151      priv_open_or_create
152         ( detail::DoOpenOrCreate
153         , id
154         , size
155         , mode
156         , addr
157         , perm
158         , null_mapped_region_function());
159   }
160
161   template <class ConstructFunc>
162   managed_open_or_create_impl(create_only_t, 
163                 const device_id_t & id,
164                 std::size_t size,
165                 mode_t mode,
166                 const void *addr,
167                 const ConstructFunc &construct_func,
168                 const permissions &perm)
169   {
170      priv_open_or_create
171         (detail::DoCreate
172         , id
173         , size
174         , mode
175         , addr
176         , perm
177         , construct_func);
178   }
179
180   template <class ConstructFunc>
181   managed_open_or_create_impl(open_only_t, 
182                 const device_id_t & id,
183                 mode_t mode,
184                 const void *addr,
185                 const ConstructFunc &construct_func)
186   {
187      priv_open_or_create
188         ( detail::DoOpen
189         , id
190         , 0
191         , mode
192         , addr
193         , permissions()
194         , construct_func);
195   }
196
197   template <class ConstructFunc>
198   managed_open_or_create_impl(open_or_create_t, 
199                 const device_id_t & id,
200                 std::size_t size,
201                 mode_t mode,
202                 const void *addr,
203                 const ConstructFunc &construct_func,
204                 const permissions &perm)
205   {
206      priv_open_or_create
207         ( detail::DoOpenOrCreate
208         , id
209         , size
210         , mode
211         , addr
212         , perm
213         , construct_func);
214   }
215
216   managed_open_or_create_impl(BOOST_INTERPROCESS_RV_REF(managed_open_or_create_impl) moved)
217   {  this->swap(moved);   }
218
219   managed_open_or_create_impl &operator=(BOOST_INTERPROCESS_RV_REF(managed_open_or_create_impl) moved)
220   {  
221      managed_open_or_create_impl tmp(boost::interprocess::move(moved));
222      this->swap(tmp);
223      return *this;  
224   }
225
226   ~managed_open_or_create_impl()
227   {}
228
229   std::size_t get_user_size()  const
230   {  return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; }
231
232   void *get_user_address()  const
233   {  return static_cast<char*>(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset;  }
234
235   std::size_t get_real_size()  const
236   {  return m_mapped_region.get_size(); }
237
238   void *get_real_address()  const
239   {  return m_mapped_region.get_address();  }
240
241   void swap(managed_open_or_create_impl &other)
242   {
243      this->m_mapped_region.swap(other.m_mapped_region);
244   }
245
246   bool flush()
247   {  return m_mapped_region.flush();  }
248
249   const mapped_region &get_mapped_region() const
250   {  return m_mapped_region;  }
251
252
253   DeviceAbstraction &get_device()
254   {  return this->DevHolder::get_device(); }
255
256   const DeviceAbstraction &get_device() const
257   {  return this->DevHolder::get_device(); }
258
259   private:
260
261   //These are templatized to allow explicit instantiations
262   template<bool dummy>
263   static void truncate_device(DeviceAbstraction &, std::size_t, detail::false_)
264   {} //Empty
265
266   template<bool dummy>
267   static void truncate_device(DeviceAbstraction &dev, std::size_t size, detail::true_)
268   {  dev.truncate(size);  }
269
270   //These are templatized to allow explicit instantiations
271   template<bool dummy>
272   static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t size, const permissions &perm, detail::false_)
273   {
274      DeviceAbstraction tmp(create_only, id, read_write, size, perm);
275      tmp.swap(dev);
276   }
277
278   template<bool dummy>
279   static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t, const permissions &perm, detail::true_)
280   {
281      DeviceAbstraction tmp(create_only, id, read_write, perm);
282      tmp.swap(dev);
283   }
284
285   template <class ConstructFunc> inline 
286   void priv_open_or_create
287      (detail::create_enum_t type, 
288       const device_id_t & id, 
289       std::size_t size,
290       mode_t mode, const void *addr,
291       const permissions &perm,
292       ConstructFunc construct_func)
293   {
294      typedef detail::bool_<FileBased> file_like_t;
295      (void)mode;
296      error_info err;
297      bool created = false;
298      bool ronly   = false;
299      bool cow     = false;
300      DeviceAbstraction dev;
301
302      if(type != detail::DoOpen && size < ManagedOpenOrCreateUserOffset){
303         throw interprocess_exception(error_info(size_error));
304      }
305
306      if(type == detail::DoOpen && mode == read_write){
307         DeviceAbstraction tmp(open_only, id, read_write);
308         tmp.swap(dev);
309         created = false;
310      }
311      else if(type == detail::DoOpen && mode == read_only){
312         DeviceAbstraction tmp(open_only, id, read_only);
313         tmp.swap(dev);
314         created = false;
315         ronly   = true;
316      }
317      else if(type == detail::DoOpen && mode == copy_on_write){
318         DeviceAbstraction tmp(open_only, id, read_only);
319         tmp.swap(dev);
320         created = false;
321         cow     = true;
322      }
323      else if(type == detail::DoCreate){
324         create_device<FileBased>(dev, id, size, perm, file_like_t());
325         created = true;
326      }
327      else if(type == detail::DoOpenOrCreate){
328         //This loop is very ugly, but brute force is sometimes better
329         //than diplomacy. If someone knows how to open or create a
330         //file and know if we have really created it or just open it
331         //drop me a e-mail!
332         bool completed = false;
333         while(!completed){
334            try{
335               create_device<FileBased>(dev, id, size, perm, file_like_t());
336               created     = true;
337               completed   = true;
338            }
339            catch(interprocess_exception &ex){
340               if(ex.get_error_code() != already_exists_error){
341                  throw;
342               }
343               else{
344                  try{
345                     DeviceAbstraction tmp(open_only, id, read_write);
346                     dev.swap(tmp);
347                     created     = false;
348                     completed   = true;
349                  }
350                  catch(interprocess_exception &ex){
351                     if(ex.get_error_code() != not_found_error){
352                        throw;
353                     }
354                  }
355               }
356            }
357            detail::thread_yield();
358         }
359      }
360
361      if(created){
362         try{
363            //If this throws, we are lost
364            truncate_device<FileBased>(dev, size, file_like_t());
365
366            //If the following throws, we will truncate the file to 1
367            mapped_region        region(dev, read_write, 0, 0, addr);
368            boost::uint32_t *patomic_word = 0;  //avoid gcc warning
369            patomic_word = static_cast<boost::uint32_t*>(region.get_address());
370            boost::uint32_t previous = detail::atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment);
371
372            if(previous == UninitializedSegment){
373               try{
374                  construct_func(static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset, size - ManagedOpenOrCreateUserOffset, true);
375                  //All ok, just move resources to the external mapped region
376                  m_mapped_region.swap(region);
377               }
378               catch(...){
379                  detail::atomic_write32(patomic_word, CorruptedSegment);
380                  throw;
381               }
382               detail::atomic_write32(patomic_word, InitializedSegment);
383            }
384            else if(previous == InitializingSegment || previous == InitializedSegment){
385               throw interprocess_exception(error_info(already_exists_error));
386            }
387            else{
388               throw interprocess_exception(error_info(corrupted_error));
389            }
390         }
391         catch(...){
392            try{
393               truncate_device<FileBased>(dev, 1u, file_like_t());
394            }
395            catch(...){
396            }
397            throw;
398         }
399      }
400      else{
401         if(FileBased){
402            offset_t filesize = 0;
403            while(filesize == 0){
404               if(!detail::get_file_size(detail::file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){
405                  throw interprocess_exception(error_info(system_error_code()));
406               }
407               detail::thread_yield();
408            }
409            if(filesize == 1){
410               throw interprocess_exception(error_info(corrupted_error));
411            }
412         }
413
414         mapped_region  region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr);
415
416         boost::uint32_t *patomic_word = static_cast<boost::uint32_t*>(region.get_address());
417         boost::uint32_t value = detail::atomic_read32(patomic_word);
418
419         while(value == InitializingSegment || value == UninitializedSegment){
420            detail::thread_yield();
421            value = detail::atomic_read32(patomic_word);
422         }
423
424         if(value != InitializedSegment)
425            throw interprocess_exception(error_info(corrupted_error));
426
427         construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
428                        , region.get_size() - ManagedOpenOrCreateUserOffset
429                        , false);
430         //All ok, just move resources to the external mapped region
431         m_mapped_region.swap(region);
432      }
433      if(StoreDevice){
434         this->DevHolder::get_device() = boost::interprocess::move(dev);
435      }
436   }
437
438   private:
439   friend class detail::interprocess_tester;
440   void dont_close_on_destruction()
441   {  detail::interprocess_tester::dont_close_on_destruction(m_mapped_region);  }
442
443   mapped_region     m_mapped_region;
444};
445
446template<class DeviceAbstraction>
447inline void swap(managed_open_or_create_impl<DeviceAbstraction> &x
448                ,managed_open_or_create_impl<DeviceAbstraction> &y)
449{  x.swap(y);  }
450
451}  //namespace detail {
452
453}  //namespace interprocess {
454}  //namespace boost {
455
456#endif   //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL