]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/interprocess/test/intermodule_singleton_test.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / interprocess / test / intermodule_singleton_test.cpp
1 //////////////////////////////////////////////////////////////////////////////
2 //
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)
6 //
7 // See http://www.boost.org/libs/interprocess for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10 #include <boost/interprocess/detail/intermodule_singleton.hpp>
11 #include <boost/interprocess/detail/portable_intermodule_singleton.hpp>
12 #include <iostream>
13 #include <cstdlib> //for std::abort
14
15 using namespace boost::interprocess;
16
17 class MyClass
18 {
19 public:
20 MyClass()
21 {
22 std::cout << "MyClass()\n" << std::endl;
23 }
24
25 void shout() const
26 {
27 std::cout << "Shout\n" << std::endl;
28 }
29
30 ~MyClass()
31 {
32 std::cout << "~MyClass()\n" << std::endl;
33 }
34 };
35
36 class MyDerivedClass
37 : public MyClass
38 {};
39
40 class MyThrowingClass
41 {
42 public:
43 MyThrowingClass()
44 {
45 throw int(0);
46 }
47 };
48
49
50 template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType >
51 int intermodule_singleton_test()
52 {
53 bool exception_thrown = false;
54 bool exception_2_thrown = false;
55
56 try{
57 IntermoduleType<MyThrowingClass, true, false>::get();
58 }
59 catch(int &){
60 exception_thrown = true;
61 //Second try
62 try{
63 IntermoduleType<MyThrowingClass, true, false>::get();
64 }
65 catch(interprocess_exception &){
66 exception_2_thrown = true;
67 }
68 }
69
70 if(!exception_thrown || !exception_2_thrown){
71 return 1;
72 }
73
74 MyClass & mc = IntermoduleType<MyClass, true, false>::get();
75 mc.shout();
76 IntermoduleType<MyClass, true, false>::get().shout();
77 IntermoduleType<MyDerivedClass, true, false>::get().shout();
78
79 //Second try
80 exception_2_thrown = false;
81 try{
82 IntermoduleType<MyThrowingClass, true, false>::get();
83 }
84 catch(interprocess_exception &){
85 exception_2_thrown = true;
86 }
87 if(!exception_2_thrown){
88 return 1;
89 }
90
91 return 0;
92 }
93
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.
98 template<class Tag>
99 class Logger
100 {
101 public:
102 Logger()
103 {
104 ++constructed_times;
105 std::cout << "Logger(),tag:" << typeid(Tag).name() << "(construct #" << constructed_times << ")\n" << std::endl;
106 }
107
108 void log_it()
109 {}
110
111 ~Logger()
112 {
113 ++destroyed_times;
114 std::cout << "~Logger(),tag:" << typeid(Tag).name() << "(destroy #" << destroyed_times << ")\n" << std::endl;
115 }
116
117 static unsigned int constructed_times;
118 static unsigned int destroyed_times;
119 };
120
121 template<class Tag>
122 unsigned int Logger<Tag>::constructed_times;
123
124 template<class Tag>
125 unsigned int Logger<Tag>::destroyed_times;
126
127 //A class simulating a logger user.
128 //The destructor uses the logger so that
129 //the logger is resurrected if it was
130 //already destroyed
131 template<class LogSingleton>
132 class LogUser
133 {
134 public:
135 LogUser()
136 {
137 std::cout << "LogUser(),tag:" << typeid(LogSingleton).name() << "\n" << std::endl;
138 }
139
140 void function_using_log()
141 { LogSingleton::get().log_it(); }
142
143 ~LogUser()
144 {
145 std::cout << "~LogUser(),tag:" << typeid(LogSingleton).name() << "\n" << std::endl;
146 LogSingleton::get().log_it();
147 }
148 };
149
150 //A class that tests the correct
151 //phoenix singleton behaviour.
152 //Logger should be resurrected by LogUser
153 template<class Tag>
154 class LogPhoenixTester
155 {
156 public:
157 LogPhoenixTester()
158 {
159 std::cout << "LogPhoenixTester(), tag: " << typeid(Tag).name() << "\n" << std::endl;
160 }
161
162 void dummy()
163 {}
164
165 ~LogPhoenixTester()
166 {
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)
173 {
174 std::stringstream sstr;
175 sstr << "LogPhoenixTester failed for tag ";
176 sstr << typeid(Tag).name();
177 sstr << "\n";
178 if(Logger<Tag>::constructed_times != 2){
179 sstr << "Logger<Tag>::constructed_times != 2\n";
180 sstr << "(";
181 sstr << Logger<Tag>::constructed_times << ")\n";
182 }
183 else{
184 sstr << "Logger<Tag>::constructed_times != Logger<Tag>::destroyed_times\n";
185 sstr << "(" << Logger<Tag>::constructed_times << " vs. " << Logger<Tag>::destroyed_times << ")\n";
186 }
187 std::cout << "~LogPhoenixTester(), error: " << sstr.str() << std::endl;
188 std::abort();
189 }
190 }
191 };
192
193 //A class simulating a logger user.
194 //The destructor uses the logger so that
195 //the logger is resurrected if it was
196 //already destroyed
197 template<class LogSingleton>
198 class LogDeadReferenceUser
199 {
200 public:
201 LogDeadReferenceUser()
202 {
203 std::cout << "LogDeadReferenceUser(), LogSingleton: " << typeid(LogSingleton).name() << "\n" << std::endl;
204 }
205
206 void function_using_log()
207 { LogSingleton::get().log_it(); }
208
209 ~LogDeadReferenceUser()
210 {
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
214 try{
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;
219 std::abort();
220 }
221 catch(interprocess_exception &){
222 //Correct behaviour
223 }
224 }
225 };
226
227 template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType >
228 int phoenix_singleton_test()
229 {
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;
237
238 //Instantiate Phoenix tester singleton so that it will be destroyed the last
239 LogPhoenixTesterSingleton::get().dummy();
240
241 //Now instantitate a log user singleton
242 LogUserType &log_user = LogUserSingleton::get();
243
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();
250
251 //Next, LogUserSingleton destructor will resurrect
252 //LoggerSingleton.
253 //After that LoggerSingleton will be destroyed and
254 //lastly LogPhoenixTester will be destroyed checking
255 //LoggerSingleton was correctly destroyed.
256 return 0;
257 }
258
259 template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType >
260 int dead_reference_singleton_test()
261 {
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;
268
269 //Now instantitate a log user singleton
270 LogDeadReferenceUserType &log_user = LogDeadReferenceUserSingleton::get();
271
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();
278
279 //Next, LogDeadReferenceUserType destructor will try to use
280 //LoggerSingleton and an exception will be raised an catched.
281 return 0;
282 }
283
284 //reduce name length
285 template<typename C, bool LazyInit, bool Phoenix>
286 class port_singleton
287 : public ipcdetail::portable_intermodule_singleton<C, LazyInit, Phoenix>
288 {};
289
290 #ifdef BOOST_INTERPROCESS_WINDOWS
291 template<typename C, bool LazyInit, bool Phoenix>
292 class win_singleton
293 : public ipcdetail::windows_intermodule_singleton< C, LazyInit, Phoenix>
294 {};
295 #endif
296
297 int main ()
298 {
299 if(0 != intermodule_singleton_test<port_singleton>()){
300 return 1;
301 }
302
303 #ifdef BOOST_INTERPROCESS_WINDOWS
304 if(0 != intermodule_singleton_test<win_singleton>()){
305 return 1;
306 }
307 #endif
308
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>();
316 #endif
317 #endif
318
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>();
324 #endif
325
326 return 0;
327 }