]> git.proxmox.com Git - ceph.git/blame - 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
CommitLineData
7c673cae
FG
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//////////////////////////////////////////////////////////////////////////////
7c673cae
FG
10#include <boost/interprocess/detail/intermodule_singleton.hpp>
11#include <boost/interprocess/detail/portable_intermodule_singleton.hpp>
12#include <iostream>
92f5a8d4 13#include <cstdlib> //for std::abort
7c673cae
FG
14
15using namespace boost::interprocess;
16
17class 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
36class MyDerivedClass
37 : public MyClass
38{};
39
40class MyThrowingClass
41{
42 public:
43 MyThrowingClass()
44 {
45 throw int(0);
46 }
47};
48
49
50template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType >
51int 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.
98template<class Tag>
99class 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
121template<class Tag>
122unsigned int Logger<Tag>::constructed_times;
123
124template<class Tag>
125unsigned 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
131template<class LogSingleton>
132class 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
153template<class Tag>
154class 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 }
92f5a8d4
TL
187 std::cout << "~LogPhoenixTester(), error: " << sstr.str() << std::endl;
188 std::abort();
7c673cae
FG
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
197template<class LogSingleton>
198class 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();
92f5a8d4
TL
218 std::cout << "~LogDeadReferenceUser(), error: " << s << std::endl;
219 std::abort();
7c673cae
FG
220 }
221 catch(interprocess_exception &){
222 //Correct behaviour
223 }
224 }
225};
226
227template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType >
228int 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
259template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType >
260int 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
285template<typename C, bool LazyInit, bool Phoenix>
286class port_singleton
287 : public ipcdetail::portable_intermodule_singleton<C, LazyInit, Phoenix>
288{};
289
290#ifdef BOOST_INTERPROCESS_WINDOWS
291template<typename C, bool LazyInit, bool Phoenix>
292class win_singleton
293 : public ipcdetail::windows_intermodule_singleton< C, LazyInit, Phoenix>
294{};
295#endif
296
297int 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}