1 //////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Peter Dimov 2002-2005, 2007.
4 // (C) Copyright Ion Gaztanaga 2006-2012.
5 // Distributed under the Boost Software License, Version 1.0.
6 // (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
9 // See http://www.boost.org/libs/interprocess for documentation.
11 //////////////////////////////////////////////////////////////////////////////
13 #include <boost/interprocess/offset_ptr.hpp>
14 #include <boost/interprocess/smart_ptr/shared_ptr.hpp>
15 #include <boost/interprocess/smart_ptr/weak_ptr.hpp>
16 #include <boost/interprocess/smart_ptr/enable_shared_from_this.hpp>
17 #include <boost/interprocess/managed_shared_memory.hpp>
18 #include <boost/interprocess/allocators/allocator.hpp>
19 #include <boost/interprocess/containers/string.hpp>
20 #include <boost/interprocess/containers/vector.hpp>
21 #include <boost/interprocess/smart_ptr/deleter.hpp>
22 #include <boost/interprocess/smart_ptr/scoped_ptr.hpp>
23 #include <boost/core/lightweight_test.hpp>
25 #include "get_process_id_name.hpp"
28 #include <boost/interprocess/sync/upgradable_lock.hpp>
29 #include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
31 using namespace boost::interprocess
;
44 virtual ~derived_class()
50 typedef managed_shared_memory::segment_manager segment_mngr_t
;
51 typedef allocator
<base_class
, segment_mngr_t
> base_class_allocator
;
52 typedef deleter
<base_class
, segment_mngr_t
> base_deleter_t
;
53 typedef shared_ptr
<base_class
, base_class_allocator
, base_deleter_t
> base_shared_ptr
;
55 std::string process_name
;
56 test::get_process_id_name(process_name
);
58 shared_memory_object::remove(process_name
.c_str());
60 managed_shared_memory
shmem(create_only
, process_name
.c_str(), 10000);
63 base_shared_ptr
s_ptr(base_shared_ptr::pointer(0),
64 base_class_allocator(shmem
.get_segment_manager()),
65 base_deleter_t(shmem
.get_segment_manager()));
67 base_shared_ptr
s_ptr2(shmem
.construct
<base_class
>("base_class")(),
68 base_class_allocator(shmem
.get_segment_manager()),
69 base_deleter_t(shmem
.get_segment_manager()));
71 base_shared_ptr
s_ptr3(offset_ptr
<derived_class
>(shmem
.construct
<derived_class
>("derived_class")()),
72 base_class_allocator(shmem
.get_segment_manager()),
73 base_deleter_t(shmem
.get_segment_manager()));
75 if(s_ptr3
.get_deleter() == 0){
78 //if(s_ptr3.get_allocator() == 0){
82 base_shared_ptr s_ptr_empty
;
84 if(s_ptr_empty
.get_deleter() != 0){
87 //if(s_ptr_empty.get_allocator() != 0){
92 shared_memory_object::remove(process_name
.c_str());
96 int string_shared_ptr_vector_insertion_test()
98 typedef managed_shared_memory::segment_manager segment_mngr_t
;
101 typedef allocator
<char, segment_mngr_t
> char_allocator_t
;
103 //A shared memory string class
104 typedef basic_string
<char, std::char_traits
<char>, char_allocator_t
> string_t
;
106 //A shared memory string allocator
107 typedef allocator
<string_t
, segment_mngr_t
> string_allocator_t
;
109 //A deleter for shared_ptr<> that erases a shared memory string
110 typedef deleter
<string_t
, segment_mngr_t
> string_deleter_t
;
112 //A shared pointer that points to a shared memory string and its instantiation
113 typedef shared_ptr
<string_t
, string_allocator_t
, string_deleter_t
> string_shared_ptr_t
;
115 //An allocator for shared pointers to a string in shared memory
116 typedef allocator
<string_shared_ptr_t
, segment_mngr_t
> string_shared_ptr_allocator_t
;
118 //A weak pointer that points to a shared memory string and its instantiation
119 typedef weak_ptr
<string_t
, string_allocator_t
, string_deleter_t
> string_weak_ptr_t
;
121 //An allocator for weak pointers to a string in shared memory
122 typedef allocator
<string_weak_ptr_t
, segment_mngr_t
> string_weak_ptr_allocator_t
;
124 //A vector of shared pointers to strings (all in shared memory) and its instantiation
125 typedef vector
<string_shared_ptr_t
, string_shared_ptr_allocator_t
>
126 string_shared_ptr_vector_t
;
128 //A vector of weak pointers to strings (all in shared memory) and its instantiation
129 typedef vector
<string_weak_ptr_t
, string_weak_ptr_allocator_t
>
130 string_weak_ptr_vector_t
;
132 std::string process_name
;
133 test::get_process_id_name(process_name
);
135 //A shared memory managed memory classes
136 shared_memory_object::remove(process_name
.c_str());
138 managed_shared_memory
shmem(create_only
, process_name
.c_str(), 20000);
141 const int NumElements
= 100;
142 //Construct the allocator of strings
143 string_allocator_t
string_allocator(shmem
.get_segment_manager());
144 //Construct the allocator of a shared_ptr to string
145 string_shared_ptr_allocator_t
string_shared_ptr_allocator(shmem
.get_segment_manager());
146 //Construct the allocator of a shared_ptr to string
147 string_weak_ptr_allocator_t
string_weak_ptr_allocator(shmem
.get_segment_manager());
148 //This is a string deleter using destroy_ptr() function of the managed_shared_memory
149 string_deleter_t
deleter(shmem
.get_segment_manager());
150 //Create a string in shared memory, to avoid leaks with exceptions use
151 //scoped ptr until we store this pointer in the shared ptr
152 scoped_ptr
<string_t
, string_deleter_t
> scoped_string
153 (shmem
.construct
<string_t
>(anonymous_instance
)(string_allocator
), deleter
);
154 //Now construct a shared pointer to a string
155 string_shared_ptr_t
string_shared_ptr (scoped_string
.get(),
156 string_shared_ptr_allocator
,
158 //Check use count is just one
159 if(!string_shared_ptr
.unique()){
162 //We don't need the scoped_ptr anonymous since the raw pointer is in the shared ptr
163 scoped_string
.release();
164 //Now fill a shared memory vector of shared_ptrs to a string
165 string_shared_ptr_vector_t
my_sharedptr_vector(string_shared_ptr_allocator
);
166 my_sharedptr_vector
.insert(my_sharedptr_vector
.begin(), NumElements
, string_shared_ptr
);
167 //Insert in the middle to test movability
168 my_sharedptr_vector
.insert(my_sharedptr_vector
.begin() + my_sharedptr_vector
.size()/2, NumElements
, string_shared_ptr
);
169 //Now check the shared count is the objects contained in the
170 //vector plus string_shared_ptr
171 if(string_shared_ptr
.use_count() != static_cast<long>(my_sharedptr_vector
.size()+1)){
174 //Now create a weak ptr from the shared_ptr
175 string_weak_ptr_t
string_weak_ptr (string_shared_ptr
);
176 //Use count should remain the same
177 if(string_weak_ptr
.use_count() != static_cast<long>(my_sharedptr_vector
.size()+1)){
180 //Now reset the local shared_ptr and check use count
181 string_shared_ptr
.reset();
182 if(string_weak_ptr
.use_count() != static_cast<long>(my_sharedptr_vector
.size())){
185 //Now reset the local shared_ptr's use count should be zero
186 if(string_shared_ptr
.use_count() != 0){
189 //Now recreate the shared ptr from the weak ptr
190 //and recheck use count
191 string_shared_ptr
= string_shared_ptr_t(string_weak_ptr
);
192 if(string_shared_ptr
.use_count() != static_cast<long>(my_sharedptr_vector
.size()+1)){
195 //Now fill a vector of weak_ptr-s
196 string_weak_ptr_vector_t
my_weakptr_vector(string_weak_ptr_allocator
);
197 my_weakptr_vector
.insert(my_weakptr_vector
.begin(), NumElements
, string_weak_ptr
);
198 //The shared count should remain the same
199 if(string_shared_ptr
.use_count() != static_cast<long>(my_sharedptr_vector
.size()+1)){
202 //So weak pointers should be fine
203 string_weak_ptr_vector_t::iterator beg
= my_weakptr_vector
.begin(),
204 end
= my_weakptr_vector
.end();
205 for(;beg
!= end
; ++beg
){
209 //The shared pointer constructed from weak ptr should
210 //be the same as the original, since all weak pointer
211 //point the the same object
212 if(string_shared_ptr_t(*beg
) != string_shared_ptr
){
216 //Now destroy all the shared ptr-s of the shared ptr vector
217 my_sharedptr_vector
.clear();
218 //The only alive shared ptr should be the local one
219 if(string_shared_ptr
.use_count() != 1){
222 //Now we invalidate the last alive shared_ptr
223 string_shared_ptr
.reset();
224 //Now all weak pointers should have expired
225 beg
= my_weakptr_vector
.begin();
226 end
= my_weakptr_vector
.end();
227 for(;beg
!= end
; ++beg
){
231 bool success
= false;
232 //Now this should throw
234 string_shared_ptr_t
dummy(*beg
);
235 //We should never reach here
238 catch(const boost::interprocess::bad_weak_ptr
&){
245 //Clear weak ptr vector
246 my_weakptr_vector
.clear();
247 //Now lock returned shared ptr should return null
248 if(string_weak_ptr
.lock().get()){
252 string_weak_ptr
.reset();
255 shared_memory_object::remove(process_name
.c_str());
260 // This part is taken from shared_ptr_basic_test.cpp
262 // Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd.
263 // Copyright (c) 2006 Ion Gaztanaga
265 // Distributed under the Boost Software License, Version 1.0. (See
266 // accompanying file LICENSE_1_0.txt or copy at
267 // http://www.boost.org/LICENSE_1_0.txt)
275 // virtual destructor deliberately omitted
276 virtual ~X(){ --cnt
; }
278 virtual int id() const
283 X
& operator= (X
const &);
289 virtual ~Y(){ --cnt
; }
291 virtual int id() const
296 Y
& operator= (Y
const &);
300 { ++cnt
; return &cnt
; }
302 void release_object(int * p
)
303 { BOOST_TEST(p
== &cnt
); --cnt
; }
305 template<class T
, class A
, class D
>
306 void test_is_X(shared_ptr
<T
, A
, D
> const & p
)
308 BOOST_TEST(p
->id() == 1);
309 BOOST_TEST((*p
).id() == 1);
312 template<class T
, class A
, class D
>
313 void test_is_X(weak_ptr
<T
, A
, D
> const & p
)
315 BOOST_TEST(p
.get() != 0);
316 BOOST_TEST(p
.get()->id() == 1);
319 template<class T
, class A
, class D
>
320 void test_is_Y(shared_ptr
<T
, A
, D
> const & p
)
322 BOOST_TEST(p
->id() == 2);
323 BOOST_TEST((*p
).id() == 2);
326 template<class T
, class A
, class D
>
327 void test_is_Y(weak_ptr
<T
, A
, D
> const & p
)
329 shared_ptr
<T
, A
, D
> q
= p
.lock();
330 BOOST_TEST(q
.get() != 0);
331 BOOST_TEST(q
->id() == 2);
334 template<class T
, class T2
>
335 void test_eq(T
const & a
, T2
const & b
)
338 BOOST_TEST(!(a
!= b
));
339 BOOST_TEST(!(a
< b
));
340 BOOST_TEST(!(b
< a
));
343 template<class T
, class T2
>
344 void test_ne(T
const & a
, T2
const & b
)
346 BOOST_TEST(!(a
== b
));
348 BOOST_TEST(a
< b
|| b
< a
);
349 BOOST_TEST(!(a
< b
&& b
< a
));
352 template<class T
, class U
, class A
, class D
, class D2
>
353 void test_shared(weak_ptr
<T
, A
, D
> const & a
, weak_ptr
<U
, A
, D2
> const & b
)
355 BOOST_TEST(!(a
< b
));
356 BOOST_TEST(!(b
< a
));
359 template<class T
, class U
, class A
, class D
, class D2
>
360 void test_nonshared(weak_ptr
<T
, A
, D
> const & a
, weak_ptr
<U
, A
, D2
> const & b
)
362 BOOST_TEST(a
< b
|| b
< a
);
363 BOOST_TEST(!(a
< b
&& b
< a
));
366 template<class T
, class U
>
367 void test_eq2(T
const & a
, U
const & b
)
370 BOOST_TEST(!(a
!= b
));
373 template<class T
, class U
>
374 void test_ne2(T
const & a
, U
const & b
)
376 BOOST_TEST(!(a
== b
));
380 template<class T
, class A
, class D
>
381 void test_is_zero(shared_ptr
<T
, A
, D
> const & p
)
384 BOOST_TEST(p
.get() == 0);
387 template<class T
, class A
, class D
>
388 void test_is_nonzero(shared_ptr
<T
, A
, D
> const & p
)
390 // p? true: false is used to test p in a boolean context.
391 // BOOST_TEST(p) is not guaranteed to test the conversion,
392 // as the macro might test !!p instead.
393 BOOST_TEST(p
? true: false);
394 BOOST_TEST(p
.get() != 0);
397 int basic_shared_ptr_test()
399 typedef managed_shared_memory::segment_manager segment_mngr_t
;
400 typedef allocator
<void, segment_mngr_t
> v_allocator_t
;
401 typedef deleter
<X
, segment_mngr_t
> x_deleter_t
;
402 typedef deleter
<Y
, segment_mngr_t
> y_deleter_t
;
403 typedef shared_ptr
<X
, v_allocator_t
, x_deleter_t
> x_shared_ptr
;
404 typedef shared_ptr
<Y
, v_allocator_t
, y_deleter_t
> y_shared_ptr
;
405 typedef weak_ptr
<X
, v_allocator_t
, x_deleter_t
> x_weak_ptr
;
406 typedef weak_ptr
<Y
, v_allocator_t
, y_deleter_t
> y_weak_ptr
;
408 std::string process_name
;
409 test::get_process_id_name(process_name
);
411 shared_memory_object::remove(process_name
.c_str());
413 managed_shared_memory
shmem(create_only
, process_name
.c_str(), 10000);
415 v_allocator_t
v_allocator (shmem
.get_segment_manager());
416 x_deleter_t
x_deleter (shmem
.get_segment_manager());
417 y_deleter_t
y_deleter (shmem
.get_segment_manager());
419 y_shared_ptr
p (shmem
.construct
<Y
>(anonymous_instance
)(), v_allocator
, y_deleter
);
420 x_shared_ptr
p2(shmem
.construct
<X
>(anonymous_instance
)(), v_allocator
, x_deleter
);
429 shared_ptr
<X
, v_allocator_t
, y_deleter_t
> q(p
);
433 y_shared_ptr
p3 (dynamic_pointer_cast
<Y
>(p
));
434 shared_ptr
<Y
, v_allocator_t
, x_deleter_t
> p4 (dynamic_pointer_cast
<Y
>(p2
));
437 BOOST_TEST(p
.use_count() == 2);
438 BOOST_TEST(p2
.use_count() == 1);
439 BOOST_TEST(p3
.use_count() == 2);
444 shared_ptr
<void, v_allocator_t
, y_deleter_t
> p5(p
);
448 BOOST_TEST(p5
.use_count() == 3);
452 BOOST_TEST(!wp1
.expired());
453 BOOST_TEST(wp1
.use_count() != 0);
465 BOOST_TEST(p5
.use_count() == 1);
466 BOOST_TEST(wp1
.expired());
467 BOOST_TEST(wp1
.use_count() == 0);
470 x_shared_ptr
sp1(wp1
);
471 BOOST_ERROR("shared_ptr<X, A, D> sp1(wp1) failed to throw");
473 catch(boost::interprocess::bad_weak_ptr
const &)
476 test_is_zero(wp1
.lock());
478 weak_ptr
<X
, v_allocator_t
, y_deleter_t
> wp2
= static_pointer_cast
<X
>(p5
);
480 BOOST_TEST(wp2
.use_count() == 1);
482 test_nonshared(wp1
, wp2
);
484 // Scoped to not affect the subsequent use_count() tests.
486 shared_ptr
<X
, v_allocator_t
, y_deleter_t
> sp2(wp2
);
487 test_is_nonzero(wp2
.lock());
490 y_weak_ptr wp3
= dynamic_pointer_cast
<Y
>(wp2
.lock());
492 BOOST_TEST(wp3
.use_count() == 1);
493 test_shared(wp2
, wp3
);
495 weak_ptr
<X
, v_allocator_t
, y_deleter_t
> wp4(wp3
);
497 BOOST_TEST(wp4
.use_count() == 1);
498 test_shared(wp2
, wp4
);
501 test_is_zero(wp1
.lock());
510 y_shared_ptr p6
= static_pointer_cast
<Y
>(p5
);
514 BOOST_TEST(wp1
.use_count() == 0);
515 BOOST_TEST(wp2
.use_count() == 0);
516 BOOST_TEST(wp3
.use_count() == 0);
518 // Test operator< stability for std::set< weak_ptr<> >
519 // Thanks to Joe Gottman for pointing this out
520 BOOST_TEST(b1
== (wp1
< wp5
));
521 BOOST_TEST(b2
== (wp5
< wp1
));
524 BOOST_TEST(cnt
== 0);
526 shared_memory_object::remove(process_name
.c_str());
527 return boost::report_errors();
534 explicit alias_tester( int v
): v_( v
)
546 typedef managed_shared_memory::segment_manager segment_mngr_t
;
547 typedef allocator
<void, segment_mngr_t
> v_allocator_t
;
548 typedef deleter
<int, segment_mngr_t
> int_deleter_t
;
550 typedef shared_ptr
<int, v_allocator_t
, int_deleter_t
> int_shared_ptr
;
551 typedef shared_ptr
<const int, v_allocator_t
, int_deleter_t
> const_int_shared_ptr
;
553 std::string process_name
;
554 test::get_process_id_name(process_name
);
556 shared_memory_object::remove(process_name
.c_str());
558 managed_shared_memory
shmem(create_only
, process_name
.c_str(), 10000);
563 int_shared_ptr
p2( p
, &m
);
565 BOOST_TEST( ipcdetail::to_raw_pointer(p2
.get()) == &m
);
566 BOOST_TEST( p2
? true: false );
568 BOOST_TEST( p2
.use_count() == p
.use_count() );
569 BOOST_TEST( !( p
< p2
) && !( p2
< p
) );
571 p2
.reset( p
, static_cast<int*>(0) );
573 BOOST_TEST( p2
.get() == 0 );
575 BOOST_TEST( p2
? false: true );
577 BOOST_TEST( p2
.use_count() == p
.use_count() );
578 BOOST_TEST( !( p
< p2
) && !( p2
< p
) );
583 int_shared_ptr
p(make_managed_shared_ptr
584 (shmem
.construct
<int>(anonymous_instance
)(), shmem
));
585 const_int_shared_ptr
p2( p
, &m
);
587 BOOST_TEST( ipcdetail::to_raw_pointer(p2
.get()) == &m
);
588 BOOST_TEST( p2
? true: false );
590 BOOST_TEST( p2
.use_count() == p
.use_count() );
591 BOOST_TEST( !( p
< p2
) && !( p2
< p
) );
592 int_shared_ptr
p_nothrow(make_managed_shared_ptr
593 (shmem
.construct
<int>(anonymous_instance
)(), shmem
, std::nothrow
));
596 shared_memory_object::remove(process_name
.c_str());
601 if(0 != simple_test())
604 if(0 != string_shared_ptr_vector_insertion_test())
607 if(0 != basic_shared_ptr_test())