intermodule_singleton_test.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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. #include <cstdlib> //for std::abort
  15. using namespace boost::interprocess;
  16. class MyClass
  17. {
  18. public:
  19. MyClass()
  20. {
  21. std::cout << "MyClass()\n" << std::endl;
  22. }
  23. void shout() const
  24. {
  25. std::cout << "Shout\n" << std::endl;
  26. }
  27. ~MyClass()
  28. {
  29. std::cout << "~MyClass()\n" << std::endl;
  30. }
  31. };
  32. class MyDerivedClass
  33. : public MyClass
  34. {};
  35. class MyThrowingClass
  36. {
  37. public:
  38. MyThrowingClass()
  39. {
  40. throw int(0);
  41. }
  42. };
  43. template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType >
  44. int intermodule_singleton_test()
  45. {
  46. bool exception_thrown = false;
  47. bool exception_2_thrown = false;
  48. try{
  49. IntermoduleType<MyThrowingClass, true, false>::get();
  50. }
  51. catch(int &){
  52. exception_thrown = true;
  53. //Second try
  54. try{
  55. IntermoduleType<MyThrowingClass, true, false>::get();
  56. }
  57. catch(interprocess_exception &){
  58. exception_2_thrown = true;
  59. }
  60. }
  61. if(!exception_thrown || !exception_2_thrown){
  62. return 1;
  63. }
  64. MyClass & mc = IntermoduleType<MyClass, true, false>::get();
  65. mc.shout();
  66. IntermoduleType<MyClass, true, false>::get().shout();
  67. IntermoduleType<MyDerivedClass, true, false>::get().shout();
  68. //Second try
  69. exception_2_thrown = false;
  70. try{
  71. IntermoduleType<MyThrowingClass, true, false>::get();
  72. }
  73. catch(interprocess_exception &){
  74. exception_2_thrown = true;
  75. }
  76. if(!exception_2_thrown){
  77. return 1;
  78. }
  79. return 0;
  80. }
  81. //A class simulating a logger
  82. //We'll register constructor/destructor counts
  83. //to test the singleton was correctly resurrected
  84. //by LogUser singleton.
  85. template<class Tag>
  86. class Logger
  87. {
  88. public:
  89. Logger()
  90. {
  91. ++constructed_times;
  92. std::cout << "Logger(),tag:" << typeid(Tag).name() << "(construct #" << constructed_times << ")\n" << std::endl;
  93. }
  94. void log_it()
  95. {}
  96. ~Logger()
  97. {
  98. ++destroyed_times;
  99. std::cout << "~Logger(),tag:" << typeid(Tag).name() << "(destroy #" << destroyed_times << ")\n" << std::endl;
  100. }
  101. static unsigned int constructed_times;
  102. static unsigned int destroyed_times;
  103. };
  104. template<class Tag>
  105. unsigned int Logger<Tag>::constructed_times;
  106. template<class Tag>
  107. unsigned int Logger<Tag>::destroyed_times;
  108. //A class simulating a logger user.
  109. //The destructor uses the logger so that
  110. //the logger is resurrected if it was
  111. //already destroyed
  112. template<class LogSingleton>
  113. class LogUser
  114. {
  115. public:
  116. LogUser()
  117. {
  118. std::cout << "LogUser(),tag:" << typeid(LogSingleton).name() << "\n" << std::endl;
  119. }
  120. void function_using_log()
  121. { LogSingleton::get().log_it(); }
  122. ~LogUser()
  123. {
  124. std::cout << "~LogUser(),tag:" << typeid(LogSingleton).name() << "\n" << std::endl;
  125. LogSingleton::get().log_it();
  126. }
  127. };
  128. //A class that tests the correct
  129. //phoenix singleton behaviour.
  130. //Logger should be resurrected by LogUser
  131. template<class Tag>
  132. class LogPhoenixTester
  133. {
  134. public:
  135. LogPhoenixTester()
  136. {
  137. std::cout << "LogPhoenixTester(), tag: " << typeid(Tag).name() << "\n" << std::endl;
  138. }
  139. void dummy()
  140. {}
  141. ~LogPhoenixTester()
  142. {
  143. //Test Phoenix singleton was correctly executed:
  144. //created and destroyed two times
  145. //This test will be executed after main ends
  146. std::cout << "~LogPhoenixTester(), tag: " << typeid(Tag).name() << "\n" << std::endl;
  147. if(Logger<Tag>::constructed_times != Logger<Tag>::destroyed_times ||
  148. Logger<Tag>::constructed_times != 2)
  149. {
  150. std::stringstream sstr;
  151. sstr << "LogPhoenixTester failed for tag ";
  152. sstr << typeid(Tag).name();
  153. sstr << "\n";
  154. if(Logger<Tag>::constructed_times != 2){
  155. sstr << "Logger<Tag>::constructed_times != 2\n";
  156. sstr << "(";
  157. sstr << Logger<Tag>::constructed_times << ")\n";
  158. }
  159. else{
  160. sstr << "Logger<Tag>::constructed_times != Logger<Tag>::destroyed_times\n";
  161. sstr << "(" << Logger<Tag>::constructed_times << " vs. " << Logger<Tag>::destroyed_times << ")\n";
  162. }
  163. std::cout << "~LogPhoenixTester(), error: " << sstr.str() << std::endl;
  164. std::abort();
  165. }
  166. }
  167. };
  168. //A class simulating a logger user.
  169. //The destructor uses the logger so that
  170. //the logger is resurrected if it was
  171. //already destroyed
  172. template<class LogSingleton>
  173. class LogDeadReferenceUser
  174. {
  175. public:
  176. LogDeadReferenceUser()
  177. {
  178. std::cout << "LogDeadReferenceUser(), LogSingleton: " << typeid(LogSingleton).name() << "\n" << std::endl;
  179. }
  180. void function_using_log()
  181. { LogSingleton::get().log_it(); }
  182. ~LogDeadReferenceUser()
  183. {
  184. std::cout << "~LogDeadReferenceUser(), LogSingleton: " << typeid(LogSingleton).name() << "\n" << std::endl;
  185. //Make sure the exception is thrown as we are
  186. //trying to use a dead non-phoenix singleton
  187. try{
  188. LogSingleton::get().log_it();
  189. std::string s("LogDeadReferenceUser failed for LogSingleton ");
  190. s += typeid(LogSingleton).name();
  191. std::cout << "~LogDeadReferenceUser(), error: " << s << std::endl;
  192. std::abort();
  193. }
  194. catch(interprocess_exception &){
  195. //Correct behaviour
  196. }
  197. }
  198. };
  199. template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType >
  200. int phoenix_singleton_test()
  201. {
  202. typedef int DummyType;
  203. typedef IntermoduleType<DummyType, true, true> Tag;
  204. typedef Logger<Tag> LoggerType;
  205. typedef IntermoduleType<LoggerType, true, true> LoggerSingleton;
  206. typedef LogUser<LoggerSingleton> LogUserType;
  207. typedef IntermoduleType<LogUserType, true, true> LogUserSingleton;
  208. typedef IntermoduleType<LogPhoenixTester<Tag>, true, true> LogPhoenixTesterSingleton;
  209. //Instantiate Phoenix tester singleton so that it will be destroyed the last
  210. LogPhoenixTesterSingleton::get().dummy();
  211. //Now instantitate a log user singleton
  212. LogUserType &log_user = LogUserSingleton::get();
  213. //Then force LoggerSingleton instantiation
  214. //calling a function that will use it.
  215. //After main ends, LoggerSingleton will be destroyed
  216. //before LogUserSingleton due to LIFO
  217. //singleton semantics
  218. log_user.function_using_log();
  219. //Next, LogUserSingleton destructor will resurrect
  220. //LoggerSingleton.
  221. //After that LoggerSingleton will be destroyed and
  222. //lastly LogPhoenixTester will be destroyed checking
  223. //LoggerSingleton was correctly destroyed.
  224. return 0;
  225. }
  226. template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType >
  227. int dead_reference_singleton_test()
  228. {
  229. typedef int DummyType;
  230. typedef IntermoduleType<DummyType, true, false> Tag;
  231. typedef Logger<Tag> LoggerType;
  232. typedef IntermoduleType<LoggerType, true, false> LoggerSingleton;
  233. typedef LogDeadReferenceUser<LoggerSingleton> LogDeadReferenceUserType;
  234. typedef IntermoduleType<LogDeadReferenceUserType, true, false> LogDeadReferenceUserSingleton;
  235. //Now instantitate a log user singleton
  236. LogDeadReferenceUserType &log_user = LogDeadReferenceUserSingleton::get();
  237. //Then force LoggerSingleton instantiation
  238. //calling a function that will use it.
  239. //After main ends, LoggerSingleton will be destroyed
  240. //before LogDeadReferenceUserType due to LIFO
  241. //singleton semantics
  242. log_user.function_using_log();
  243. //Next, LogDeadReferenceUserType destructor will try to use
  244. //LoggerSingleton and an exception will be raised an catched.
  245. return 0;
  246. }
  247. //reduce name length
  248. template<typename C, bool LazyInit, bool Phoenix>
  249. class port_singleton
  250. : public ipcdetail::portable_intermodule_singleton<C, LazyInit, Phoenix>
  251. {};
  252. #ifdef BOOST_INTERPROCESS_WINDOWS
  253. template<typename C, bool LazyInit, bool Phoenix>
  254. class win_singleton
  255. : public ipcdetail::windows_intermodule_singleton< C, LazyInit, Phoenix>
  256. {};
  257. #endif
  258. int main ()
  259. {
  260. if(0 != intermodule_singleton_test<port_singleton>()){
  261. return 1;
  262. }
  263. #ifdef BOOST_INTERPROCESS_WINDOWS
  264. if(0 != intermodule_singleton_test<win_singleton>()){
  265. return 1;
  266. }
  267. #endif
  268. //Only few platforms support this
  269. #ifdef BOOST_INTERPROCESS_ATEXIT_CALLABLE_FROM_ATEXIT
  270. //Phoenix singletons are tested after main ends,
  271. //LogPhoenixTester does the work
  272. phoenix_singleton_test<port_singleton>();
  273. #ifdef BOOST_INTERPROCESS_WINDOWS
  274. phoenix_singleton_test<win_singleton>();
  275. #endif
  276. #endif
  277. //Dead reference singletons are tested after main ends,
  278. //LogDeadReferenceUser does the work
  279. dead_reference_singleton_test<port_singleton>();
  280. #ifdef BOOST_INTERPROCESS_WINDOWS
  281. dead_reference_singleton_test<win_singleton>();
  282. #endif
  283. return 0;
  284. }
  285. #include <boost/interprocess/detail/config_end.hpp>