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/intermodule_singleton.hpp>
11 #include <boost/interprocess/detail/portable_intermodule_singleton.hpp>
13 #include <cstdlib> //for std::abort
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 std::cout
<< "~LogPhoenixTester(), error: " << sstr
.str() << std::endl
;
193 //A class simulating a logger user.
194 //The destructor uses the logger so that
195 //the logger is resurrected if it was
197 template<class LogSingleton
>
198 class LogDeadReferenceUser
201 LogDeadReferenceUser()
203 std::cout
<< "LogDeadReferenceUser(), LogSingleton: " << typeid(LogSingleton
).name() << "\n" << std::endl
;
206 void function_using_log()
207 { LogSingleton::get().log_it(); }
209 ~LogDeadReferenceUser()
211 std::cout
<< "~LogDeadReferenceUser(), LogSingleton: " << typeid(LogSingleton
).name() << "\n" << std::endl
;
212 //Make sure the exception is thrown as we are
213 //trying to use a dead non-phoenix singleton
215 LogSingleton::get().log_it();
216 std::string
s("LogDeadReferenceUser failed for LogSingleton ");
217 s
+= typeid(LogSingleton
).name();
218 std::cout
<< "~LogDeadReferenceUser(), error: " << s
<< std::endl
;
221 catch(interprocess_exception
&){
227 template < template<class T
, bool LazyInit
, bool Phoenix
> class IntermoduleType
>
228 int phoenix_singleton_test()
230 typedef int DummyType
;
231 typedef IntermoduleType
<DummyType
, true, true> Tag
;
232 typedef Logger
<Tag
> LoggerType
;
233 typedef IntermoduleType
<LoggerType
, true, true> LoggerSingleton
;
234 typedef LogUser
<LoggerSingleton
> LogUserType
;
235 typedef IntermoduleType
<LogUserType
, true, true> LogUserSingleton
;
236 typedef IntermoduleType
<LogPhoenixTester
<Tag
>, true, true> LogPhoenixTesterSingleton
;
238 //Instantiate Phoenix tester singleton so that it will be destroyed the last
239 LogPhoenixTesterSingleton::get().dummy();
241 //Now instantitate a log user singleton
242 LogUserType
&log_user
= LogUserSingleton::get();
244 //Then force LoggerSingleton instantiation
245 //calling a function that will use it.
246 //After main ends, LoggerSingleton will be destroyed
247 //before LogUserSingleton due to LIFO
248 //singleton semantics
249 log_user
.function_using_log();
251 //Next, LogUserSingleton destructor will resurrect
253 //After that LoggerSingleton will be destroyed and
254 //lastly LogPhoenixTester will be destroyed checking
255 //LoggerSingleton was correctly destroyed.
259 template < template<class T
, bool LazyInit
, bool Phoenix
> class IntermoduleType
>
260 int dead_reference_singleton_test()
262 typedef int DummyType
;
263 typedef IntermoduleType
<DummyType
, true, false> Tag
;
264 typedef Logger
<Tag
> LoggerType
;
265 typedef IntermoduleType
<LoggerType
, true, false> LoggerSingleton
;
266 typedef LogDeadReferenceUser
<LoggerSingleton
> LogDeadReferenceUserType
;
267 typedef IntermoduleType
<LogDeadReferenceUserType
, true, false> LogDeadReferenceUserSingleton
;
269 //Now instantitate a log user singleton
270 LogDeadReferenceUserType
&log_user
= LogDeadReferenceUserSingleton::get();
272 //Then force LoggerSingleton instantiation
273 //calling a function that will use it.
274 //After main ends, LoggerSingleton will be destroyed
275 //before LogDeadReferenceUserType due to LIFO
276 //singleton semantics
277 log_user
.function_using_log();
279 //Next, LogDeadReferenceUserType destructor will try to use
280 //LoggerSingleton and an exception will be raised an catched.
285 template<typename C
, bool LazyInit
, bool Phoenix
>
287 : public ipcdetail::portable_intermodule_singleton
<C
, LazyInit
, Phoenix
>
290 #ifdef BOOST_INTERPROCESS_WINDOWS
291 template<typename C
, bool LazyInit
, bool Phoenix
>
293 : public ipcdetail::windows_intermodule_singleton
< C
, LazyInit
, Phoenix
>
299 if(0 != intermodule_singleton_test
<port_singleton
>()){
303 #ifdef BOOST_INTERPROCESS_WINDOWS
304 if(0 != intermodule_singleton_test
<win_singleton
>()){
309 //Only few platforms support this
310 #ifdef BOOST_INTERPROCESS_ATEXIT_CALLABLE_FROM_ATEXIT
311 //Phoenix singletons are tested after main ends,
312 //LogPhoenixTester does the work
313 phoenix_singleton_test
<port_singleton
>();
314 #ifdef BOOST_INTERPROCESS_WINDOWS
315 phoenix_singleton_test
<win_singleton
>();
319 //Dead reference singletons are tested after main ends,
320 //LogDeadReferenceUser does the work
321 dead_reference_singleton_test
<port_singleton
>();
322 #ifdef BOOST_INTERPROCESS_WINDOWS
323 dead_reference_singleton_test
<win_singleton
>();