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
18 #include <boost/interprocess/detail/config_begin.hpp>
19 #include <boost/interprocess/detail/os_thread_functions.hpp>
20 #include <boost/interprocess/detail/os_file_functions.hpp>
21 #include <boost/interprocess/creation_tags.hpp>
22 #include <boost/interprocess/mapped_region.hpp>
23 #include <boost/interprocess/detail/utilities.hpp>
24 #include <boost/interprocess/detail/type_traits.hpp>
25 #include <boost/interprocess/detail/atomic.hpp>
26 #include <boost/interprocess/detail/interprocess_tester.hpp>
27 #include <boost/interprocess/creation_tags.hpp>
28 #include <boost/interprocess/detail/mpl.hpp>
29 #include <boost/interprocess/permissions.hpp>
30 #include <boost/type_traits/alignment_of.hpp>
31 #include <boost/type_traits/type_with_alignment.hpp>
32 #include <boost/interprocess/sync/spin/wait.hpp>
33 #include <boost/move/move.hpp>
34 #include <boost/cstdint.hpp>
37 namespace interprocess {
39 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
40 namespace ipcdetail{ class interprocess_tester; }
43 template<class DeviceAbstraction>
44 struct managed_open_or_create_impl_device_id_t
46 typedef const char *type;
49 #ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
51 class xsi_shared_memory_file_wrapper;
55 struct managed_open_or_create_impl_device_id_t<xsi_shared_memory_file_wrapper>
60 #endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
62 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
67 template <bool StoreDevice, class DeviceAbstraction>
68 class managed_open_or_create_impl_device_holder
71 DeviceAbstraction &get_device()
72 { static DeviceAbstraction dev; return dev; }
74 const DeviceAbstraction &get_device() const
75 { static DeviceAbstraction dev; return dev; }
78 template <class DeviceAbstraction>
79 class managed_open_or_create_impl_device_holder<true, DeviceAbstraction>
82 DeviceAbstraction &get_device()
85 const DeviceAbstraction &get_device() const
89 DeviceAbstraction dev;
92 template<class DeviceAbstraction, std::size_t MemAlignment, bool FileBased, bool StoreDevice>
93 class managed_open_or_create_impl
94 : public managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction>
97 BOOST_MOVABLE_BUT_NOT_COPYABLE(managed_open_or_create_impl)
99 typedef typename managed_open_or_create_impl_device_id_t<DeviceAbstraction>::type device_id_t;
100 typedef managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction> DevHolder;
103 UninitializedSegment,
110 static const std::size_t
111 ManagedOpenOrCreateUserOffset =
113 < sizeof(boost::uint32_t)
114 , MemAlignment ? (MemAlignment) :
115 (::boost::alignment_of< ::boost::detail::max_align >::value)
118 managed_open_or_create_impl()
121 managed_open_or_create_impl(create_only_t,
122 const device_id_t & id,
126 const permissions &perm)
135 , null_mapped_region_function());
138 managed_open_or_create_impl(open_only_t,
139 const device_id_t & id,
150 , null_mapped_region_function());
154 managed_open_or_create_impl(open_or_create_t,
155 const device_id_t & id,
159 const permissions &perm)
168 , null_mapped_region_function());
171 template <class ConstructFunc>
172 managed_open_or_create_impl(create_only_t,
173 const device_id_t & id,
177 const ConstructFunc &construct_func,
178 const permissions &perm)
190 template <class ConstructFunc>
191 managed_open_or_create_impl(open_only_t,
192 const device_id_t & id,
195 const ConstructFunc &construct_func)
207 template <class ConstructFunc>
208 managed_open_or_create_impl(open_or_create_t,
209 const device_id_t & id,
213 const ConstructFunc &construct_func,
214 const permissions &perm)
226 managed_open_or_create_impl(BOOST_RV_REF(managed_open_or_create_impl) moved)
227 { this->swap(moved); }
229 managed_open_or_create_impl &operator=(BOOST_RV_REF(managed_open_or_create_impl) moved)
231 managed_open_or_create_impl tmp(boost::move(moved));
236 ~managed_open_or_create_impl()
239 std::size_t get_user_size() const
240 { return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; }
242 void *get_user_address() const
243 { return static_cast<char*>(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset; }
245 std::size_t get_real_size() const
246 { return m_mapped_region.get_size(); }
248 void *get_real_address() const
249 { return m_mapped_region.get_address(); }
251 void swap(managed_open_or_create_impl &other)
253 this->m_mapped_region.swap(other.m_mapped_region);
257 { return m_mapped_region.flush(); }
259 const mapped_region &get_mapped_region() const
260 { return m_mapped_region; }
263 DeviceAbstraction &get_device()
264 { return this->DevHolder::get_device(); }
266 const DeviceAbstraction &get_device() const
267 { return this->DevHolder::get_device(); }
271 //These are templatized to allow explicit instantiations
273 static void truncate_device(DeviceAbstraction &, offset_t, false_)
277 static void truncate_device(DeviceAbstraction &dev, offset_t size, true_)
278 { dev.truncate(size); }
282 static bool check_offset_t_size(std::size_t , false_)
283 { return true; } //Empty
286 static bool check_offset_t_size(std::size_t size, true_)
287 { return size == std::size_t(offset_t(size)); }
289 //These are templatized to allow explicit instantiations
291 static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t size, const permissions &perm, false_ file_like)
294 DeviceAbstraction tmp(create_only, id, read_write, size, perm);
299 static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t, const permissions &perm, true_ file_like)
302 DeviceAbstraction tmp(create_only, id, read_write, perm);
306 template <class ConstructFunc> inline
307 void priv_open_or_create
309 const device_id_t & id,
311 mode_t mode, const void *addr,
312 const permissions &perm,
313 ConstructFunc construct_func)
315 typedef bool_<FileBased> file_like_t;
317 bool created = false;
320 DeviceAbstraction dev;
323 //Check if the requested size is enough to build the managed metadata
324 const std::size_t func_min_size = construct_func.get_min_size();
325 if( (std::size_t(-1) - ManagedOpenOrCreateUserOffset) < func_min_size ||
326 size < (func_min_size + ManagedOpenOrCreateUserOffset) ){
327 throw interprocess_exception(error_info(size_error));
330 //Check size can be represented by offset_t (used by truncate)
331 if(type != DoOpen && !check_offset_t_size<FileBased>(size, file_like_t())){
332 throw interprocess_exception(error_info(size_error));
334 if(type == DoOpen && mode == read_write){
335 DeviceAbstraction tmp(open_only, id, read_write);
339 else if(type == DoOpen && mode == read_only){
340 DeviceAbstraction tmp(open_only, id, read_only);
345 else if(type == DoOpen && mode == copy_on_write){
346 DeviceAbstraction tmp(open_only, id, read_only);
351 else if(type == DoCreate){
352 create_device<FileBased>(dev, id, size, perm, file_like_t());
355 else if(type == DoOpenOrCreate){
356 //This loop is very ugly, but brute force is sometimes better
357 //than diplomacy. If someone knows how to open or create a
358 //file and know if we have really created it or just open it
360 bool completed = false;
364 create_device<FileBased>(dev, id, size, perm, file_like_t());
368 catch(interprocess_exception &ex){
369 if(ex.get_error_code() != already_exists_error){
374 DeviceAbstraction tmp(open_only, id, read_write);
379 catch(interprocess_exception &e){
380 if(e.get_error_code() != not_found_error){
398 //If this throws, we are lost
399 truncate_device<FileBased>(dev, size, file_like_t());
401 //If the following throws, we will truncate the file to 1
402 mapped_region region(dev, read_write, 0, 0, addr);
403 boost::uint32_t *patomic_word = 0; //avoid gcc warning
404 patomic_word = static_cast<boost::uint32_t*>(region.get_address());
405 boost::uint32_t previous = atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment);
407 if(previous == UninitializedSegment){
409 construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
410 , size - ManagedOpenOrCreateUserOffset, true);
411 //All ok, just move resources to the external mapped region
412 m_mapped_region.swap(region);
415 atomic_write32(patomic_word, CorruptedSegment);
418 atomic_write32(patomic_word, InitializedSegment);
420 else if(previous == InitializingSegment || previous == InitializedSegment){
421 throw interprocess_exception(error_info(already_exists_error));
424 throw interprocess_exception(error_info(corrupted_error));
429 truncate_device<FileBased>(dev, 1u, file_like_t());
438 offset_t filesize = 0;
440 while(filesize == 0){
441 if(!get_file_size(file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){
442 error_info err = system_error_code();
443 throw interprocess_exception(err);
448 throw interprocess_exception(error_info(corrupted_error));
452 mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr);
454 boost::uint32_t *patomic_word = static_cast<boost::uint32_t*>(region.get_address());
455 boost::uint32_t value = atomic_read32(patomic_word);
458 while(value == InitializingSegment || value == UninitializedSegment){
460 value = atomic_read32(patomic_word);
463 if(value != InitializedSegment)
464 throw interprocess_exception(error_info(corrupted_error));
466 construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
467 , region.get_size() - ManagedOpenOrCreateUserOffset
469 //All ok, just move resources to the external mapped region
470 m_mapped_region.swap(region);
473 this->DevHolder::get_device() = boost::move(dev);
477 friend void swap(managed_open_or_create_impl &left, managed_open_or_create_impl &right)
483 friend class interprocess_tester;
484 void dont_close_on_destruction()
485 { interprocess_tester::dont_close_on_destruction(m_mapped_region); }
487 mapped_region m_mapped_region;
490 } //namespace ipcdetail {
492 } //namespace interprocess {
493 } //namespace boost {
495 #include <boost/interprocess/detail/config_end.hpp>
497 #endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL