]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/interprocess/include/boost/interprocess/detail/managed_open_or_create_impl.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / interprocess / include / boost / interprocess / detail / managed_open_or_create_impl.hpp
1 //////////////////////////////////////////////////////////////////////////////
2 //
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)
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 #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/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>
38
39 namespace boost {
40 namespace interprocess {
41
42 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
43 namespace ipcdetail{ class interprocess_tester; }
44
45
46 template<class DeviceAbstraction>
47 struct managed_open_or_create_impl_device_id_t
48 {
49 typedef const char *type;
50 };
51
52 #ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
53
54 class xsi_shared_memory_file_wrapper;
55 class xsi_key;
56
57 template<>
58 struct managed_open_or_create_impl_device_id_t<xsi_shared_memory_file_wrapper>
59 {
60 typedef xsi_key type;
61 };
62
63 #endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
64
65 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
66
67 namespace ipcdetail {
68
69
70 template <bool StoreDevice, class DeviceAbstraction>
71 class managed_open_or_create_impl_device_holder
72 {
73 public:
74 DeviceAbstraction &get_device()
75 { static DeviceAbstraction dev; return dev; }
76
77 const DeviceAbstraction &get_device() const
78 { static DeviceAbstraction dev; return dev; }
79 };
80
81 template <class DeviceAbstraction>
82 class managed_open_or_create_impl_device_holder<true, DeviceAbstraction>
83 {
84 public:
85 DeviceAbstraction &get_device()
86 { return dev; }
87
88 const DeviceAbstraction &get_device() const
89 { return dev; }
90
91 private:
92 DeviceAbstraction dev;
93 };
94
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>
98 {
99 //Non-copyable
100 BOOST_MOVABLE_BUT_NOT_COPYABLE(managed_open_or_create_impl)
101
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;
104 enum
105 {
106 UninitializedSegment,
107 InitializingSegment,
108 InitializedSegment,
109 CorruptedSegment
110 };
111
112 public:
113 static const std::size_t
114 ManagedOpenOrCreateUserOffset =
115 ct_rounded_size
116 < sizeof(boost::uint32_t)
117 , MemAlignment ? (MemAlignment) :
118 (::boost::container::container_detail::alignment_of
119 < ::boost::container::container_detail::max_align_t >::value)
120 >::value;
121
122 managed_open_or_create_impl()
123 {}
124
125 managed_open_or_create_impl(create_only_t,
126 const device_id_t & id,
127 std::size_t size,
128 mode_t mode,
129 const void *addr,
130 const permissions &perm)
131 {
132 priv_open_or_create
133 ( DoCreate
134 , id
135 , size
136 , mode
137 , addr
138 , perm
139 , null_mapped_region_function());
140 }
141
142 managed_open_or_create_impl(open_only_t,
143 const device_id_t & id,
144 mode_t mode,
145 const void *addr)
146 {
147 priv_open_or_create
148 ( DoOpen
149 , id
150 , 0
151 , mode
152 , addr
153 , permissions()
154 , null_mapped_region_function());
155 }
156
157
158 managed_open_or_create_impl(open_or_create_t,
159 const device_id_t & id,
160 std::size_t size,
161 mode_t mode,
162 const void *addr,
163 const permissions &perm)
164 {
165 priv_open_or_create
166 ( DoOpenOrCreate
167 , id
168 , size
169 , mode
170 , addr
171 , perm
172 , null_mapped_region_function());
173 }
174
175 template <class ConstructFunc>
176 managed_open_or_create_impl(create_only_t,
177 const device_id_t & id,
178 std::size_t size,
179 mode_t mode,
180 const void *addr,
181 const ConstructFunc &construct_func,
182 const permissions &perm)
183 {
184 priv_open_or_create
185 (DoCreate
186 , id
187 , size
188 , mode
189 , addr
190 , perm
191 , construct_func);
192 }
193
194 template <class ConstructFunc>
195 managed_open_or_create_impl(open_only_t,
196 const device_id_t & id,
197 mode_t mode,
198 const void *addr,
199 const ConstructFunc &construct_func)
200 {
201 priv_open_or_create
202 ( DoOpen
203 , id
204 , 0
205 , mode
206 , addr
207 , permissions()
208 , construct_func);
209 }
210
211 template <class ConstructFunc>
212 managed_open_or_create_impl(open_or_create_t,
213 const device_id_t & id,
214 std::size_t size,
215 mode_t mode,
216 const void *addr,
217 const ConstructFunc &construct_func,
218 const permissions &perm)
219 {
220 priv_open_or_create
221 ( DoOpenOrCreate
222 , id
223 , size
224 , mode
225 , addr
226 , perm
227 , construct_func);
228 }
229
230 managed_open_or_create_impl(BOOST_RV_REF(managed_open_or_create_impl) moved)
231 { this->swap(moved); }
232
233 managed_open_or_create_impl &operator=(BOOST_RV_REF(managed_open_or_create_impl) moved)
234 {
235 managed_open_or_create_impl tmp(boost::move(moved));
236 this->swap(tmp);
237 return *this;
238 }
239
240 ~managed_open_or_create_impl()
241 {}
242
243 std::size_t get_user_size() const
244 { return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; }
245
246 void *get_user_address() const
247 { return static_cast<char*>(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset; }
248
249 std::size_t get_real_size() const
250 { return m_mapped_region.get_size(); }
251
252 void *get_real_address() const
253 { return m_mapped_region.get_address(); }
254
255 void swap(managed_open_or_create_impl &other)
256 {
257 this->m_mapped_region.swap(other.m_mapped_region);
258 }
259
260 bool flush()
261 { return m_mapped_region.flush(); }
262
263 const mapped_region &get_mapped_region() const
264 { return m_mapped_region; }
265
266
267 DeviceAbstraction &get_device()
268 { return this->DevHolder::get_device(); }
269
270 const DeviceAbstraction &get_device() const
271 { return this->DevHolder::get_device(); }
272
273 private:
274
275 //These are templatized to allow explicit instantiations
276 template<bool dummy>
277 static void truncate_device(DeviceAbstraction &, offset_t, false_)
278 {} //Empty
279
280 template<bool dummy>
281 static void truncate_device(DeviceAbstraction &dev, offset_t size, true_)
282 { dev.truncate(size); }
283
284
285 template<bool dummy>
286 static bool check_offset_t_size(std::size_t , false_)
287 { return true; } //Empty
288
289 template<bool dummy>
290 static bool check_offset_t_size(std::size_t size, true_)
291 { return size == std::size_t(offset_t(size)); }
292
293 //These are templatized to allow explicit instantiations
294 template<bool dummy>
295 static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t size, const permissions &perm, false_ file_like)
296 {
297 (void)file_like;
298 DeviceAbstraction tmp(create_only, id, read_write, size, perm);
299 tmp.swap(dev);
300 }
301
302 template<bool dummy>
303 static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t, const permissions &perm, true_ file_like)
304 {
305 (void)file_like;
306 DeviceAbstraction tmp(create_only, id, read_write, perm);
307 tmp.swap(dev);
308 }
309
310 template <class ConstructFunc> inline
311 void priv_open_or_create
312 (create_enum_t type,
313 const device_id_t & id,
314 std::size_t size,
315 mode_t mode, const void *addr,
316 const permissions &perm,
317 ConstructFunc construct_func)
318 {
319 typedef bool_<FileBased> file_like_t;
320 (void)mode;
321 bool created = false;
322 bool ronly = false;
323 bool cow = false;
324 DeviceAbstraction dev;
325
326 if(type != DoOpen){
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));
332 }
333 }
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));
337 }
338 if(type == DoOpen && mode == read_write){
339 DeviceAbstraction tmp(open_only, id, read_write);
340 tmp.swap(dev);
341 created = false;
342 }
343 else if(type == DoOpen && mode == read_only){
344 DeviceAbstraction tmp(open_only, id, read_only);
345 tmp.swap(dev);
346 created = false;
347 ronly = true;
348 }
349 else if(type == DoOpen && mode == copy_on_write){
350 DeviceAbstraction tmp(open_only, id, read_only);
351 tmp.swap(dev);
352 created = false;
353 cow = true;
354 }
355 else if(type == DoCreate){
356 create_device<FileBased>(dev, id, size, perm, file_like_t());
357 created = true;
358 }
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
363 //drop me a e-mail!
364 bool completed = false;
365 spin_wait swait;
366 while(!completed){
367 try{
368 create_device<FileBased>(dev, id, size, perm, file_like_t());
369 created = true;
370 completed = true;
371 }
372 catch(interprocess_exception &ex){
373 if(ex.get_error_code() != already_exists_error){
374 throw;
375 }
376 else{
377 try{
378 DeviceAbstraction tmp(open_only, id, read_write);
379 dev.swap(tmp);
380 created = false;
381 completed = true;
382 }
383 catch(interprocess_exception &e){
384 if(e.get_error_code() != not_found_error){
385 throw;
386 }
387 }
388 catch(...){
389 throw;
390 }
391 }
392 }
393 catch(...){
394 throw;
395 }
396 swait.yield();
397 }
398 }
399
400 if(created){
401 try{
402 //If this throws, we are lost
403 truncate_device<FileBased>(dev, size, file_like_t());
404
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);
410
411 if(previous == UninitializedSegment){
412 try{
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);
417 }
418 catch(...){
419 atomic_write32(patomic_word, CorruptedSegment);
420 throw;
421 }
422 atomic_write32(patomic_word, InitializedSegment);
423 }
424 else if(previous == InitializingSegment || previous == InitializedSegment){
425 throw interprocess_exception(error_info(already_exists_error));
426 }
427 else{
428 throw interprocess_exception(error_info(corrupted_error));
429 }
430 }
431 catch(...){
432 try{
433 truncate_device<FileBased>(dev, 1u, file_like_t());
434 }
435 catch(...){
436 }
437 throw;
438 }
439 }
440 else{
441 if(FileBased){
442 offset_t filesize = 0;
443 spin_wait swait;
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);
448 }
449 swait.yield();
450 }
451 if(filesize == 1){
452 throw interprocess_exception(error_info(corrupted_error));
453 }
454 }
455
456 mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr);
457
458 boost::uint32_t *patomic_word = static_cast<boost::uint32_t*>(region.get_address());
459 boost::uint32_t value = atomic_read32(patomic_word);
460
461 spin_wait swait;
462 while(value == InitializingSegment || value == UninitializedSegment){
463 swait.yield();
464 value = atomic_read32(patomic_word);
465 }
466
467 if(value != InitializedSegment)
468 throw interprocess_exception(error_info(corrupted_error));
469
470 construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
471 , region.get_size() - ManagedOpenOrCreateUserOffset
472 , false);
473 //All ok, just move resources to the external mapped region
474 m_mapped_region.swap(region);
475 }
476 if(StoreDevice){
477 this->DevHolder::get_device() = boost::move(dev);
478 }
479 }
480
481 friend void swap(managed_open_or_create_impl &left, managed_open_or_create_impl &right)
482 {
483 left.swap(right);
484 }
485
486 private:
487 friend class interprocess_tester;
488 void dont_close_on_destruction()
489 { interprocess_tester::dont_close_on_destruction(m_mapped_region); }
490
491 mapped_region m_mapped_region;
492 };
493
494 } //namespace ipcdetail {
495
496 } //namespace interprocess {
497 } //namespace boost {
498
499 #include <boost/interprocess/detail/config_end.hpp>
500
501 #endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL