]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/interprocess/test/intermodule_singleton_test.cpp
add subtree-ish sources for 12.0.3
[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/config_begin.hpp>
11 #include <boost/interprocess/detail/intermodule_singleton.hpp>
12 #include <boost/interprocess/detail/portable_intermodule_singleton.hpp>
13 #include <iostream>
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 throw std::runtime_error(sstr.str().c_str());
188 }
189 }
190 };
191
192 //A class simulating a logger user.
193 //The destructor uses the logger so that
194 //the logger is resurrected if it was
195 //already destroyed
196 template<class LogSingleton>
197 class LogDeadReferenceUser
198 {
199 public:
200 LogDeadReferenceUser()
201 {
202 std::cout << "LogDeadReferenceUser(), LogSingleton: " << typeid(LogSingleton).name() << "\n" << std::endl;
203 }
204
205 void function_using_log()
206 { LogSingleton::get().log_it(); }
207
208 ~LogDeadReferenceUser()
209 {
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
213 try{
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());
218 }
219 catch(interprocess_exception &){
220 //Correct behaviour
221 }
222 }
223 };
224
225 template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType >
226 int phoenix_singleton_test()
227 {
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;
235
236 //Instantiate Phoenix tester singleton so that it will be destroyed the last
237 LogPhoenixTesterSingleton::get().dummy();
238
239 //Now instantitate a log user singleton
240 LogUserType &log_user = LogUserSingleton::get();
241
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();
248
249 //Next, LogUserSingleton destructor will resurrect
250 //LoggerSingleton.
251 //After that LoggerSingleton will be destroyed and
252 //lastly LogPhoenixTester will be destroyed checking
253 //LoggerSingleton was correctly destroyed.
254 return 0;
255 }
256
257 template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType >
258 int dead_reference_singleton_test()
259 {
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;
266
267 //Now instantitate a log user singleton
268 LogDeadReferenceUserType &log_user = LogDeadReferenceUserSingleton::get();
269
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();
276
277 //Next, LogDeadReferenceUserType destructor will try to use
278 //LoggerSingleton and an exception will be raised an catched.
279 return 0;
280 }
281
282 //reduce name length
283 template<typename C, bool LazyInit, bool Phoenix>
284 class port_singleton
285 : public ipcdetail::portable_intermodule_singleton<C, LazyInit, Phoenix>
286 {};
287
288 #ifdef BOOST_INTERPROCESS_WINDOWS
289 template<typename C, bool LazyInit, bool Phoenix>
290 class win_singleton
291 : public ipcdetail::windows_intermodule_singleton< C, LazyInit, Phoenix>
292 {};
293 #endif
294
295 int main ()
296 {
297 if(0 != intermodule_singleton_test<port_singleton>()){
298 return 1;
299 }
300
301 #ifdef BOOST_INTERPROCESS_WINDOWS
302 if(0 != intermodule_singleton_test<win_singleton>()){
303 return 1;
304 }
305 #endif
306
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>();
314 #endif
315 #endif
316
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>();
322 #endif
323
324 return 0;
325 }
326
327 #include <boost/interprocess/detail/config_end.hpp>