1 //////////////////////////////////////////////////////////////////////////////
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)
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 #include <boost/interprocess/detail/config_begin.hpp>
15 #include <boost/interprocess/detail/os_thread_functions.hpp>
16 #include <boost/interprocess/detail/os_file_functions.hpp>
17 #include <boost/interprocess/creation_tags.hpp>
18 #include <boost/interprocess/mapped_region.hpp>
19 #include <boost/interprocess/detail/utilities.hpp>
20 #include <boost/interprocess/detail/type_traits.hpp>
21 #include <boost/interprocess/detail/atomic.hpp>
22 #include <boost/interprocess/detail/interprocess_tester.hpp>
23 #include <boost/interprocess/creation_tags.hpp>
24 #include <boost/interprocess/detail/mpl.hpp>
25 #include <boost/interprocess/permissions.hpp>
26 #include <boost/type_traits/alignment_of.hpp>
27 #include <boost/type_traits/type_with_alignment.hpp>
28 #include <boost/move/move.hpp>
29 #include <boost/cstdint.hpp>
32 namespace interprocess {
35 namespace ipcdetail{ class interprocess_tester; }
38 template<class DeviceAbstraction>
39 struct managed_open_or_create_impl_device_id_t
41 typedef const char *type;
44 #ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
46 class xsi_shared_memory_file_wrapper;
50 struct managed_open_or_create_impl_device_id_t<xsi_shared_memory_file_wrapper>
55 #endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
62 template <bool StoreDevice, class DeviceAbstraction>
63 class managed_open_or_create_impl_device_holder
66 DeviceAbstraction &get_device()
67 { static DeviceAbstraction dev; return dev; }
69 const DeviceAbstraction &get_device() const
70 { static DeviceAbstraction dev; return dev; }
73 template <class DeviceAbstraction>
74 class managed_open_or_create_impl_device_holder<true, DeviceAbstraction>
77 DeviceAbstraction &get_device()
80 const DeviceAbstraction &get_device() const
84 DeviceAbstraction dev;
87 template<class DeviceAbstraction, std::size_t MemAlignment = 0, bool FileBased = true, bool StoreDevice = true>
88 class managed_open_or_create_impl
89 : public managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction>
92 BOOST_MOVABLE_BUT_NOT_COPYABLE(managed_open_or_create_impl)
94 typedef typename managed_open_or_create_impl_device_id_t<DeviceAbstraction>::type device_id_t;
95 typedef managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction> DevHolder;
105 static const std::size_t
106 ManagedOpenOrCreateUserOffset =
108 < sizeof(boost::uint32_t)
109 , MemAlignment ? (MemAlignment) :
110 (::boost::alignment_of< ::boost::detail::max_align >::value)
113 managed_open_or_create_impl()
116 managed_open_or_create_impl(create_only_t,
117 const device_id_t & id,
121 const permissions &perm)
130 , null_mapped_region_function());
133 managed_open_or_create_impl(open_only_t,
134 const device_id_t & id,
145 , null_mapped_region_function());
149 managed_open_or_create_impl(open_or_create_t,
150 const device_id_t & id,
154 const permissions &perm)
163 , null_mapped_region_function());
166 template <class ConstructFunc>
167 managed_open_or_create_impl(create_only_t,
168 const device_id_t & id,
172 const ConstructFunc &construct_func,
173 const permissions &perm)
185 template <class ConstructFunc>
186 managed_open_or_create_impl(open_only_t,
187 const device_id_t & id,
190 const ConstructFunc &construct_func)
202 template <class ConstructFunc>
203 managed_open_or_create_impl(open_or_create_t,
204 const device_id_t & id,
208 const ConstructFunc &construct_func,
209 const permissions &perm)
221 managed_open_or_create_impl(BOOST_RV_REF(managed_open_or_create_impl) moved)
222 { this->swap(moved); }
224 managed_open_or_create_impl &operator=(BOOST_RV_REF(managed_open_or_create_impl) moved)
226 managed_open_or_create_impl tmp(boost::move(moved));
231 ~managed_open_or_create_impl()
234 std::size_t get_user_size() const
235 { return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; }
237 void *get_user_address() const
238 { return static_cast<char*>(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset; }
240 std::size_t get_real_size() const
241 { return m_mapped_region.get_size(); }
243 void *get_real_address() const
244 { return m_mapped_region.get_address(); }
246 void swap(managed_open_or_create_impl &other)
248 this->m_mapped_region.swap(other.m_mapped_region);
252 { return m_mapped_region.flush(); }
254 const mapped_region &get_mapped_region() const
255 { return m_mapped_region; }
258 DeviceAbstraction &get_device()
259 { return this->DevHolder::get_device(); }
261 const DeviceAbstraction &get_device() const
262 { return this->DevHolder::get_device(); }
266 //These are templatized to allow explicit instantiations
268 static void truncate_device(DeviceAbstraction &, offset_t, false_)
272 static void truncate_device(DeviceAbstraction &dev, offset_t size, true_)
273 { dev.truncate(size); }
277 static bool check_offset_t_size(std::size_t , false_)
278 { return true; } //Empty
281 static bool check_offset_t_size(std::size_t size, true_)
282 { return size == std::size_t(offset_t(size)); }
284 //These are templatized to allow explicit instantiations
286 static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t size, const permissions &perm, false_ file_like)
289 DeviceAbstraction tmp(create_only, id, read_write, size, perm);
294 static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t, const permissions &perm, true_ file_like)
297 DeviceAbstraction tmp(create_only, id, read_write, perm);
301 template <class ConstructFunc> inline
302 void priv_open_or_create
304 const device_id_t & id,
306 mode_t mode, const void *addr,
307 const permissions &perm,
308 ConstructFunc construct_func)
310 typedef bool_<FileBased> file_like_t;
313 bool created = false;
316 DeviceAbstraction dev;
318 if(type != DoOpen && size < ManagedOpenOrCreateUserOffset){
319 throw interprocess_exception(error_info(size_error));
321 //Check size can be represented by offset_t (used by truncate)
322 if(type != DoOpen && !check_offset_t_size<FileBased>(size, file_like_t())){
323 throw interprocess_exception(error_info(size_error));
325 if(type == DoOpen && mode == read_write){
326 DeviceAbstraction tmp(open_only, id, read_write);
330 else if(type == DoOpen && mode == read_only){
331 DeviceAbstraction tmp(open_only, id, read_only);
336 else if(type == DoOpen && mode == copy_on_write){
337 DeviceAbstraction tmp(open_only, id, read_only);
342 else if(type == DoCreate){
343 create_device<FileBased>(dev, id, size, perm, file_like_t());
346 else if(type == DoOpenOrCreate){
347 //This loop is very ugly, but brute force is sometimes better
348 //than diplomacy. If someone knows how to open or create a
349 //file and know if we have really created it or just open it
351 bool completed = false;
354 create_device<FileBased>(dev, id, size, perm, file_like_t());
358 catch(interprocess_exception &ex){
359 if(ex.get_error_code() != already_exists_error){
364 DeviceAbstraction tmp(open_only, id, read_write);
369 catch(interprocess_exception &ex){
370 if(ex.get_error_code() != not_found_error){
388 //If this throws, we are lost
389 truncate_device<FileBased>(dev, size, file_like_t());
391 //If the following throws, we will truncate the file to 1
392 mapped_region region(dev, read_write, 0, 0, addr);
393 boost::uint32_t *patomic_word = 0; //avoid gcc warning
394 patomic_word = static_cast<boost::uint32_t*>(region.get_address());
395 boost::uint32_t previous = atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment);
397 if(previous == UninitializedSegment){
399 construct_func(static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset, size - ManagedOpenOrCreateUserOffset, true);
400 //All ok, just move resources to the external mapped region
401 m_mapped_region.swap(region);
404 atomic_write32(patomic_word, CorruptedSegment);
407 atomic_write32(patomic_word, InitializedSegment);
409 else if(previous == InitializingSegment || previous == InitializedSegment){
410 throw interprocess_exception(error_info(already_exists_error));
413 throw interprocess_exception(error_info(corrupted_error));
418 truncate_device<FileBased>(dev, 1u, file_like_t());
427 offset_t filesize = 0;
428 while(filesize == 0){
429 if(!get_file_size(file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){
430 throw interprocess_exception(error_info(system_error_code()));
435 throw interprocess_exception(error_info(corrupted_error));
439 mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr);
441 boost::uint32_t *patomic_word = static_cast<boost::uint32_t*>(region.get_address());
442 boost::uint32_t value = atomic_read32(patomic_word);
444 while(value == InitializingSegment || value == UninitializedSegment){
446 value = atomic_read32(patomic_word);
449 if(value != InitializedSegment)
450 throw interprocess_exception(error_info(corrupted_error));
452 construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
453 , region.get_size() - ManagedOpenOrCreateUserOffset
455 //All ok, just move resources to the external mapped region
456 m_mapped_region.swap(region);
459 this->DevHolder::get_device() = boost::move(dev);
464 friend class interprocess_tester;
465 void dont_close_on_destruction()
466 { interprocess_tester::dont_close_on_destruction(m_mapped_region); }
468 mapped_region m_mapped_region;
471 template<class DeviceAbstraction>
472 inline void swap(managed_open_or_create_impl<DeviceAbstraction> &x
473 ,managed_open_or_create_impl<DeviceAbstraction> &y)
476 } //namespace ipcdetail {
478 } //namespace interprocess {
479 } //namespace boost {
481 #include <boost/interprocess/detail/config_end.hpp>
483 #endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL