1 //////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Ion Gaztanaga 2006-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_OPEN_OR_CREATE_IMPL
12 #define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL
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/os_thread_functions.hpp>
24 #include <boost/interprocess/detail/os_file_functions.hpp>
25 #include <boost/interprocess/creation_tags.hpp>
26 #include <boost/interprocess/mapped_region.hpp>
27 #include <boost/interprocess/detail/utilities.hpp>
28 #include <boost/interprocess/detail/type_traits.hpp>
29 #include <boost/interprocess/detail/atomic.hpp>
30 #include <boost/interprocess/detail/interprocess_tester.hpp>
31 #include <boost/interprocess/creation_tags.hpp>
32 #include <boost/interprocess/detail/mpl.hpp>
33 #include <boost/interprocess/permissions.hpp>
34 #include <boost/container/detail/type_traits.hpp> //alignment_of, aligned_storage
35 #include <boost/interprocess/sync/spin/wait.hpp>
36 #include <boost/move/move.hpp>
37 #include <boost/cstdint.hpp>
40 namespace interprocess {
42 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
43 namespace ipcdetail{ class interprocess_tester; }
46 template<class DeviceAbstraction>
47 struct managed_open_or_create_impl_device_id_t
49 typedef const char *type;
52 #ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
54 class xsi_shared_memory_file_wrapper;
58 struct managed_open_or_create_impl_device_id_t<xsi_shared_memory_file_wrapper>
63 #endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
65 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
70 template <bool StoreDevice, class DeviceAbstraction>
71 class managed_open_or_create_impl_device_holder
74 DeviceAbstraction &get_device()
75 { static DeviceAbstraction dev; return dev; }
77 const DeviceAbstraction &get_device() const
78 { static DeviceAbstraction dev; return dev; }
81 template <class DeviceAbstraction>
82 class managed_open_or_create_impl_device_holder<true, DeviceAbstraction>
85 DeviceAbstraction &get_device()
88 const DeviceAbstraction &get_device() const
92 DeviceAbstraction dev;
95 template<class DeviceAbstraction, std::size_t MemAlignment, bool FileBased, bool StoreDevice>
96 class managed_open_or_create_impl
97 : public managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction>
100 BOOST_MOVABLE_BUT_NOT_COPYABLE(managed_open_or_create_impl)
102 typedef typename managed_open_or_create_impl_device_id_t<DeviceAbstraction>::type device_id_t;
103 typedef managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction> DevHolder;
106 UninitializedSegment,
113 static const std::size_t
114 ManagedOpenOrCreateUserOffset =
116 < sizeof(boost::uint32_t)
117 , MemAlignment ? (MemAlignment) :
118 (::boost::container::container_detail::alignment_of
119 < ::boost::container::container_detail::max_align_t >::value)
122 managed_open_or_create_impl()
125 managed_open_or_create_impl(create_only_t,
126 const device_id_t & id,
130 const permissions &perm)
139 , null_mapped_region_function());
142 managed_open_or_create_impl(open_only_t,
143 const device_id_t & id,
154 , null_mapped_region_function());
158 managed_open_or_create_impl(open_or_create_t,
159 const device_id_t & id,
163 const permissions &perm)
172 , null_mapped_region_function());
175 template <class ConstructFunc>
176 managed_open_or_create_impl(create_only_t,
177 const device_id_t & id,
181 const ConstructFunc &construct_func,
182 const permissions &perm)
194 template <class ConstructFunc>
195 managed_open_or_create_impl(open_only_t,
196 const device_id_t & id,
199 const ConstructFunc &construct_func)
211 template <class ConstructFunc>
212 managed_open_or_create_impl(open_or_create_t,
213 const device_id_t & id,
217 const ConstructFunc &construct_func,
218 const permissions &perm)
230 managed_open_or_create_impl(BOOST_RV_REF(managed_open_or_create_impl) moved)
231 { this->swap(moved); }
233 managed_open_or_create_impl &operator=(BOOST_RV_REF(managed_open_or_create_impl) moved)
235 managed_open_or_create_impl tmp(boost::move(moved));
240 ~managed_open_or_create_impl()
243 std::size_t get_user_size() const
244 { return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; }
246 void *get_user_address() const
247 { return static_cast<char*>(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset; }
249 std::size_t get_real_size() const
250 { return m_mapped_region.get_size(); }
252 void *get_real_address() const
253 { return m_mapped_region.get_address(); }
255 void swap(managed_open_or_create_impl &other)
257 this->m_mapped_region.swap(other.m_mapped_region);
261 { return m_mapped_region.flush(); }
263 const mapped_region &get_mapped_region() const
264 { return m_mapped_region; }
267 DeviceAbstraction &get_device()
268 { return this->DevHolder::get_device(); }
270 const DeviceAbstraction &get_device() const
271 { return this->DevHolder::get_device(); }
275 //These are templatized to allow explicit instantiations
277 static void truncate_device(DeviceAbstraction &, offset_t, false_)
281 static void truncate_device(DeviceAbstraction &dev, offset_t size, true_)
282 { dev.truncate(size); }
286 static bool check_offset_t_size(std::size_t , false_)
287 { return true; } //Empty
290 static bool check_offset_t_size(std::size_t size, true_)
291 { return size == std::size_t(offset_t(size)); }
293 //These are templatized to allow explicit instantiations
295 static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t size, const permissions &perm, false_ file_like)
298 DeviceAbstraction tmp(create_only, id, read_write, size, perm);
303 static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t, const permissions &perm, true_ file_like)
306 DeviceAbstraction tmp(create_only, id, read_write, perm);
310 template <class ConstructFunc> inline
311 void priv_open_or_create
313 const device_id_t & id,
315 mode_t mode, const void *addr,
316 const permissions &perm,
317 ConstructFunc construct_func)
319 typedef bool_<FileBased> file_like_t;
321 bool created = false;
324 DeviceAbstraction dev;
327 //Check if the requested size is enough to build the managed metadata
328 const std::size_t func_min_size = construct_func.get_min_size();
329 if( (std::size_t(-1) - ManagedOpenOrCreateUserOffset) < func_min_size ||
330 size < (func_min_size + ManagedOpenOrCreateUserOffset) ){
331 throw interprocess_exception(error_info(size_error));
334 //Check size can be represented by offset_t (used by truncate)
335 if(type != DoOpen && !check_offset_t_size<FileBased>(size, file_like_t())){
336 throw interprocess_exception(error_info(size_error));
338 if(type == DoOpen && mode == read_write){
339 DeviceAbstraction tmp(open_only, id, read_write);
343 else if(type == DoOpen && mode == read_only){
344 DeviceAbstraction tmp(open_only, id, read_only);
349 else if(type == DoOpen && mode == copy_on_write){
350 DeviceAbstraction tmp(open_only, id, read_only);
355 else if(type == DoCreate){
356 create_device<FileBased>(dev, id, size, perm, file_like_t());
359 else if(type == DoOpenOrCreate){
360 //This loop is very ugly, but brute force is sometimes better
361 //than diplomacy. If someone knows how to open or create a
362 //file and know if we have really created it or just open it
364 bool completed = false;
368 create_device<FileBased>(dev, id, size, perm, file_like_t());
372 catch(interprocess_exception &ex){
373 if(ex.get_error_code() != already_exists_error){
378 DeviceAbstraction tmp(open_only, id, read_write);
383 catch(interprocess_exception &e){
384 if(e.get_error_code() != not_found_error){
402 //If this throws, we are lost
403 truncate_device<FileBased>(dev, size, file_like_t());
405 //If the following throws, we will truncate the file to 1
406 mapped_region region(dev, read_write, 0, 0, addr);
407 boost::uint32_t *patomic_word = 0; //avoid gcc warning
408 patomic_word = static_cast<boost::uint32_t*>(region.get_address());
409 boost::uint32_t previous = atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment);
411 if(previous == UninitializedSegment){
413 construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
414 , size - ManagedOpenOrCreateUserOffset, true);
415 //All ok, just move resources to the external mapped region
416 m_mapped_region.swap(region);
419 atomic_write32(patomic_word, CorruptedSegment);
422 atomic_write32(patomic_word, InitializedSegment);
424 else if(previous == InitializingSegment || previous == InitializedSegment){
425 throw interprocess_exception(error_info(already_exists_error));
428 throw interprocess_exception(error_info(corrupted_error));
433 truncate_device<FileBased>(dev, 1u, file_like_t());
442 offset_t filesize = 0;
444 while(filesize == 0){
445 if(!get_file_size(file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){
446 error_info err = system_error_code();
447 throw interprocess_exception(err);
452 throw interprocess_exception(error_info(corrupted_error));
456 mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr);
458 boost::uint32_t *patomic_word = static_cast<boost::uint32_t*>(region.get_address());
459 boost::uint32_t value = atomic_read32(patomic_word);
462 while(value == InitializingSegment || value == UninitializedSegment){
464 value = atomic_read32(patomic_word);
467 if(value != InitializedSegment)
468 throw interprocess_exception(error_info(corrupted_error));
470 construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
471 , region.get_size() - ManagedOpenOrCreateUserOffset
473 //All ok, just move resources to the external mapped region
474 m_mapped_region.swap(region);
477 this->DevHolder::get_device() = boost::move(dev);
481 friend void swap(managed_open_or_create_impl &left, managed_open_or_create_impl &right)
487 friend class interprocess_tester;
488 void dont_close_on_destruction()
489 { interprocess_tester::dont_close_on_destruction(m_mapped_region); }
491 mapped_region m_mapped_region;
494 } //namespace ipcdetail {
496 } //namespace interprocess {
497 } //namespace boost {
499 #include <boost/interprocess/detail/config_end.hpp>
501 #endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL