robust_mutex_test.hpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2010-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. #ifndef BOOST_INTERPROCESS_TEST_ROBUST_MUTEX_TEST_HEADER
  11. #define BOOST_INTERPROCESS_TEST_ROBUST_MUTEX_TEST_HEADER
  12. #include <boost/interprocess/detail/config_begin.hpp>
  13. #include <iostream>
  14. #include <cstdlib> //std::system
  15. #include <boost/interprocess/sync/scoped_lock.hpp>
  16. #include <boost/interprocess/managed_shared_memory.hpp>
  17. #include <boost/interprocess/sync/spin/wait.hpp>
  18. #include "get_process_id_name.hpp"
  19. #include "mutex_test_template.hpp"
  20. #include <iostream>
  21. namespace boost{
  22. namespace interprocess{
  23. namespace test{
  24. template<class RobustMutex>
  25. int robust_mutex_test(int argc, char *argv[])
  26. {
  27. try{
  28. if(argc == 1){ //Parent process
  29. //First usual mutex tests
  30. {
  31. // test_all_lock<RobustMutex>();
  32. // test_all_mutex<true, RobustMutex>();
  33. }
  34. std::cout << "robust mutex recovery test" << std::endl;
  35. //Remove shared memory on construction and destruction
  36. class shm_remove
  37. {
  38. public:
  39. shm_remove(){ shared_memory_object::remove
  40. (::boost::interprocess::test::get_process_id_name()); }
  41. ~shm_remove(){ shared_memory_object::remove
  42. (::boost::interprocess::test::get_process_id_name()); }
  43. } remover;
  44. (void)remover;
  45. //Construct managed shared memory
  46. managed_shared_memory segment(create_only, get_process_id_name(), 65536);
  47. //Create two robust mutexes
  48. RobustMutex *instance = segment.construct<RobustMutex>
  49. ("robust mutex")[2]();
  50. //Create a flag to notify that both mutexes are
  51. //locked and the owner is going to die soon.
  52. bool *go_ahead = segment.construct<bool> ("go ahead")(false);
  53. //Launch child process
  54. std::string s(argv[0]); s += " child ";
  55. s += get_process_id_name();
  56. std::cout << "... launching child" << std::endl;
  57. if(0 != std::system(s.c_str()))
  58. return 1;
  59. //Wait until child locks the mutexes and dies
  60. spin_wait swait;
  61. while(!*go_ahead){
  62. swait.yield();
  63. }
  64. std::cout << "... recovering mutex[0]" << std::endl;
  65. //First try to recover lock[0], put into consistent
  66. //state and relock it again
  67. {
  68. //Done, now try to lock it to see if robust
  69. //mutex recovery works
  70. instance[0].lock();
  71. if(!instance[0].previous_owner_dead())
  72. return 1;
  73. instance[0].consistent();
  74. instance[0].unlock();
  75. //Since it's consistent, locking is possible again
  76. instance[0].lock();
  77. instance[0].unlock();
  78. }
  79. //Now with lock[1], but dont' put it in consistent state
  80. //so the mutex is no longer usable
  81. std::cout << "... recovering mutex[1]" << std::endl;
  82. {
  83. //Done, now try to lock it to see if robust
  84. //mutex recovery works
  85. instance[1].lock();
  86. if(!instance[1].previous_owner_dead())
  87. return 1;
  88. //Unlock a recovered mutex without putting it into
  89. //into consistent state marks mutex as unusable.
  90. instance[1].unlock();
  91. //Since it's NOT consistent, locking is NOT possible again
  92. bool exception_thrown = false;
  93. try{
  94. instance[1].lock();
  95. }
  96. catch(interprocess_exception &){
  97. exception_thrown = true;
  98. }
  99. if(!exception_thrown){
  100. return 1;
  101. }
  102. }
  103. //Now with lock[2], this was locked by child but not
  104. //unlocked
  105. std::cout << "... recovering mutex[2]" << std::endl;
  106. {
  107. //Done, now try to lock it to see if robust
  108. //mutex recovery works
  109. instance[2].lock();
  110. if(!instance[2].previous_owner_dead())
  111. return 1;
  112. //Unlock a recovered mutex without putting it into
  113. //into consistent state marks mutex as unusable.
  114. instance[2].unlock();
  115. //Since it's NOT consistent, locking is NOT possible again
  116. bool exception_thrown = false;
  117. try{
  118. instance[2].lock();
  119. }
  120. catch(interprocess_exception &){
  121. exception_thrown = true;
  122. }
  123. if(!exception_thrown){
  124. return 1;
  125. }
  126. }
  127. }
  128. else{
  129. //Open managed shared memory
  130. managed_shared_memory segment(open_only, argv[2]);
  131. //Find mutexes
  132. RobustMutex *instance = segment.find<RobustMutex>("robust mutex").first;
  133. assert(instance);
  134. if(std::string(argv[1]) == std::string("child")){
  135. std::cout << "launched child" << std::endl;
  136. //Find flag
  137. bool *go_ahead = segment.find<bool>("go ahead").first;
  138. assert(go_ahead);
  139. //Lock, flag and die
  140. bool try_lock_res = instance[0].try_lock() && instance[1].try_lock();
  141. assert(try_lock_res);
  142. if(!try_lock_res)
  143. return 1;
  144. bool *go_ahead2 = segment.construct<bool>("go ahead2")(false);
  145. assert(go_ahead2);
  146. //Launch grandchild
  147. std::string s(argv[0]); s += " grandchild ";
  148. s += argv[2];
  149. std::cout << "... launching grandchild" << std::endl;
  150. if(0 != std::system(s.c_str())){
  151. std::cout << "launched terminated with error" << std::endl;
  152. return 1;
  153. }
  154. //Wait until child locks the 2nd mutex and dies
  155. spin_wait swait;
  156. while(!*go_ahead2){
  157. swait.yield();
  158. }
  159. //Done, now try to lock number 3 to see if robust
  160. //mutex recovery works
  161. instance[2].lock();
  162. if(!instance[2].previous_owner_dead()){
  163. return 1;
  164. }
  165. *go_ahead = true;
  166. }
  167. else{
  168. std::cout << "launched grandchild" << std::endl;
  169. //grandchild locks the lock and dies
  170. bool *go_ahead2 = segment.find<bool>("go ahead2").first;
  171. assert(go_ahead2);
  172. //Lock, flag and die
  173. bool try_lock_res = instance[2].try_lock();
  174. assert(try_lock_res);
  175. if(!try_lock_res){
  176. return 1;
  177. }
  178. *go_ahead2 = true;
  179. }
  180. }
  181. }catch(...){
  182. std::cout << "Exception thrown error!" << std::endl;
  183. throw;
  184. }
  185. return 0;
  186. }
  187. } //namespace test{
  188. } //namespace interprocess{
  189. } //namespace boost{
  190. #include <boost/interprocess/detail/config_end.hpp>
  191. #endif //BOOST_INTERPROCESS_TEST_ROBUST_EMULATION_TEST_HEADER