1 //////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Ion Gaztanaga 2004-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 //////////////////////////////////////////////////////////////////////////////
10 #include <boost/interprocess/detail/config_begin.hpp>
11 #include <boost/interprocess/detail/intermodule_singleton.hpp>
12 #include <boost/interprocess/detail/portable_intermodule_singleton.hpp>
15 using namespace boost::interprocess
;
22 std::cout
<< "MyClass()\n" << std::endl
;
27 std::cout
<< "Shout\n" << std::endl
;
32 std::cout
<< "~MyClass()\n" << std::endl
;
50 template < template<class T
, bool LazyInit
, bool Phoenix
> class IntermoduleType
>
51 int intermodule_singleton_test()
53 bool exception_thrown
= false;
54 bool exception_2_thrown
= false;
57 IntermoduleType
<MyThrowingClass
, true, false>::get();
60 exception_thrown
= true;
63 IntermoduleType
<MyThrowingClass
, true, false>::get();
65 catch(interprocess_exception
&){
66 exception_2_thrown
= true;
70 if(!exception_thrown
|| !exception_2_thrown
){
74 MyClass
& mc
= IntermoduleType
<MyClass
, true, false>::get();
76 IntermoduleType
<MyClass
, true, false>::get().shout();
77 IntermoduleType
<MyDerivedClass
, true, false>::get().shout();
80 exception_2_thrown
= false;
82 IntermoduleType
<MyThrowingClass
, true, false>::get();
84 catch(interprocess_exception
&){
85 exception_2_thrown
= true;
87 if(!exception_2_thrown
){
94 //A class simulating a logger
95 //We'll register constructor/destructor counts
96 //to test the singleton was correctly resurrected
97 //by LogUser singleton.
105 std::cout
<< "Logger(),tag:" << typeid(Tag
).name() << "(construct #" << constructed_times
<< ")\n" << std::endl
;
114 std::cout
<< "~Logger(),tag:" << typeid(Tag
).name() << "(destroy #" << destroyed_times
<< ")\n" << std::endl
;
117 static unsigned int constructed_times
;
118 static unsigned int destroyed_times
;
122 unsigned int Logger
<Tag
>::constructed_times
;
125 unsigned int Logger
<Tag
>::destroyed_times
;
127 //A class simulating a logger user.
128 //The destructor uses the logger so that
129 //the logger is resurrected if it was
131 template<class LogSingleton
>
137 std::cout
<< "LogUser(),tag:" << typeid(LogSingleton
).name() << "\n" << std::endl
;
140 void function_using_log()
141 { LogSingleton::get().log_it(); }
145 std::cout
<< "~LogUser(),tag:" << typeid(LogSingleton
).name() << "\n" << std::endl
;
146 LogSingleton::get().log_it();
150 //A class that tests the correct
151 //phoenix singleton behaviour.
152 //Logger should be resurrected by LogUser
154 class LogPhoenixTester
159 std::cout
<< "LogPhoenixTester(), tag: " << typeid(Tag
).name() << "\n" << std::endl
;
167 //Test Phoenix singleton was correctly executed:
168 //created and destroyed two times
169 //This test will be executed after main ends
170 std::cout
<< "~LogPhoenixTester(), tag: " << typeid(Tag
).name() << "\n" << std::endl
;
171 if(Logger
<Tag
>::constructed_times
!= Logger
<Tag
>::destroyed_times
||
172 Logger
<Tag
>::constructed_times
!= 2)
174 std::stringstream sstr
;
175 sstr
<< "LogPhoenixTester failed for tag ";
176 sstr
<< typeid(Tag
).name();
178 if(Logger
<Tag
>::constructed_times
!= 2){
179 sstr
<< "Logger<Tag>::constructed_times != 2\n";
181 sstr
<< Logger
<Tag
>::constructed_times
<< ")\n";
184 sstr
<< "Logger<Tag>::constructed_times != Logger<Tag>::destroyed_times\n";
185 sstr
<< "(" << Logger
<Tag
>::constructed_times
<< " vs. " << Logger
<Tag
>::destroyed_times
<< ")\n";
187 throw std::runtime_error(sstr
.str().c_str());
192 //A class simulating a logger user.
193 //The destructor uses the logger so that
194 //the logger is resurrected if it was
196 template<class LogSingleton
>
197 class LogDeadReferenceUser
200 LogDeadReferenceUser()
202 std::cout
<< "LogDeadReferenceUser(), LogSingleton: " << typeid(LogSingleton
).name() << "\n" << std::endl
;
205 void function_using_log()
206 { LogSingleton::get().log_it(); }
208 ~LogDeadReferenceUser()
210 std::cout
<< "~LogDeadReferenceUser(), LogSingleton: " << typeid(LogSingleton
).name() << "\n" << std::endl
;
211 //Make sure the exception is thrown as we are
212 //trying to use a dead non-phoenix singleton
214 LogSingleton::get().log_it();
215 std::string
s("LogDeadReferenceUser failed for LogSingleton ");
216 s
+= typeid(LogSingleton
).name();
217 throw std::runtime_error(s
.c_str());
219 catch(interprocess_exception
&){
225 template < template<class T
, bool LazyInit
, bool Phoenix
> class IntermoduleType
>
226 int phoenix_singleton_test()
228 typedef int DummyType
;
229 typedef IntermoduleType
<DummyType
, true, true> Tag
;
230 typedef Logger
<Tag
> LoggerType
;
231 typedef IntermoduleType
<LoggerType
, true, true> LoggerSingleton
;
232 typedef LogUser
<LoggerSingleton
> LogUserType
;
233 typedef IntermoduleType
<LogUserType
, true, true> LogUserSingleton
;
234 typedef IntermoduleType
<LogPhoenixTester
<Tag
>, true, true> LogPhoenixTesterSingleton
;
236 //Instantiate Phoenix tester singleton so that it will be destroyed the last
237 LogPhoenixTesterSingleton::get().dummy();
239 //Now instantitate a log user singleton
240 LogUserType
&log_user
= LogUserSingleton::get();
242 //Then force LoggerSingleton instantiation
243 //calling a function that will use it.
244 //After main ends, LoggerSingleton will be destroyed
245 //before LogUserSingleton due to LIFO
246 //singleton semantics
247 log_user
.function_using_log();
249 //Next, LogUserSingleton destructor will resurrect
251 //After that LoggerSingleton will be destroyed and
252 //lastly LogPhoenixTester will be destroyed checking
253 //LoggerSingleton was correctly destroyed.
257 template < template<class T
, bool LazyInit
, bool Phoenix
> class IntermoduleType
>
258 int dead_reference_singleton_test()
260 typedef int DummyType
;
261 typedef IntermoduleType
<DummyType
, true, false> Tag
;
262 typedef Logger
<Tag
> LoggerType
;
263 typedef IntermoduleType
<LoggerType
, true, false> LoggerSingleton
;
264 typedef LogDeadReferenceUser
<LoggerSingleton
> LogDeadReferenceUserType
;
265 typedef IntermoduleType
<LogDeadReferenceUserType
, true, false> LogDeadReferenceUserSingleton
;
267 //Now instantitate a log user singleton
268 LogDeadReferenceUserType
&log_user
= LogDeadReferenceUserSingleton::get();
270 //Then force LoggerSingleton instantiation
271 //calling a function that will use it.
272 //After main ends, LoggerSingleton will be destroyed
273 //before LogDeadReferenceUserType due to LIFO
274 //singleton semantics
275 log_user
.function_using_log();
277 //Next, LogDeadReferenceUserType destructor will try to use
278 //LoggerSingleton and an exception will be raised an catched.
283 template<typename C
, bool LazyInit
, bool Phoenix
>
285 : public ipcdetail::portable_intermodule_singleton
<C
, LazyInit
, Phoenix
>
288 #ifdef BOOST_INTERPROCESS_WINDOWS
289 template<typename C
, bool LazyInit
, bool Phoenix
>
291 : public ipcdetail::windows_intermodule_singleton
< C
, LazyInit
, Phoenix
>
297 if(0 != intermodule_singleton_test
<port_singleton
>()){
301 #ifdef BOOST_INTERPROCESS_WINDOWS
302 if(0 != intermodule_singleton_test
<win_singleton
>()){
307 //Only few platforms support this
308 #ifdef BOOST_INTERPROCESS_ATEXIT_CALLABLE_FROM_ATEXIT
309 //Phoenix singletons are tested after main ends,
310 //LogPhoenixTester does the work
311 phoenix_singleton_test
<port_singleton
>();
312 #ifdef BOOST_INTERPROCESS_WINDOWS
313 phoenix_singleton_test
<win_singleton
>();
317 //Dead reference singletons are tested after main ends,
318 //LogDeadReferenceUser does the work
319 dead_reference_singleton_test
<port_singleton
>();
320 #ifdef BOOST_INTERPROCESS_WINDOWS
321 dead_reference_singleton_test
<win_singleton
>();
327 #include <boost/interprocess/detail/config_end.hpp>