1 //////////////////////////////////////////////////////////////////////////////
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)
7 // See http://www.boost.org/libs/interprocess for documentation.
9 //////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_INTERPROCESS_TEST_ROBUST_MUTEX_TEST_HEADER
12 #define BOOST_INTERPROCESS_TEST_ROBUST_MUTEX_TEST_HEADER
14 #include <boost/interprocess/detail/config_begin.hpp>
16 #include <cstdlib> //std::system
17 #include <boost/interprocess/sync/scoped_lock.hpp>
18 #include <boost/interprocess/managed_shared_memory.hpp>
19 #include <boost/interprocess/sync/spin/wait.hpp>
20 #include "get_process_id_name.hpp"
21 #include "mutex_test_template.hpp"
25 namespace interprocess{
28 template<class RobustMutex>
29 int robust_mutex_test(int argc, char *argv[])
32 if(argc == 1){ //Parent process
33 //First usual mutex tests
35 // test_all_lock<RobustMutex>();
36 // test_all_mutex<true, RobustMutex>();
38 std::cout << "robust mutex recovery test" << std::endl;
40 //Remove shared memory on construction and destruction
44 shm_remove(){ shared_memory_object::remove
45 (::boost::interprocess::test::get_process_id_name()); }
46 ~shm_remove(){ shared_memory_object::remove
47 (::boost::interprocess::test::get_process_id_name()); }
51 //Construct managed shared memory
52 managed_shared_memory segment(create_only, get_process_id_name(), 65536);
54 //Create two robust mutexes
55 RobustMutex *instance = segment.construct<RobustMutex>
56 ("robust mutex")[2]();
58 //Create a flag to notify that both mutexes are
59 //locked and the owner is going to die soon.
60 bool *go_ahead = segment.construct<bool> ("go ahead")(false);
62 //Launch child process
63 std::string s(argv[0]); s += " child ";
64 s += get_process_id_name();
65 std::cout << "... launching child" << std::endl;
66 if(0 != std::system(s.c_str()))
69 //Wait until child locks the mutexes and dies
75 std::cout << "... recovering mutex[0]" << std::endl;
76 //First try to recover lock[0], put into consistent
77 //state and relock it again
79 //Done, now try to lock it to see if robust
80 //mutex recovery works
82 if(!instance[0].previous_owner_dead())
84 instance[0].consistent();
86 //Since it's consistent, locking is possible again
90 //Now with lock[1], but dont' put it in consistent state
91 //so the mutex is no longer usable
92 std::cout << "... recovering mutex[1]" << std::endl;
94 //Done, now try to lock it to see if robust
95 //mutex recovery works
97 if(!instance[1].previous_owner_dead())
99 //Unlock a recovered mutex without putting it into
100 //into consistent state marks mutex as unusable.
101 instance[1].unlock();
102 //Since it's NOT consistent, locking is NOT possible again
103 bool exception_thrown = false;
107 catch(interprocess_exception &){
108 exception_thrown = true;
110 if(!exception_thrown){
114 //Now with lock[2], this was locked by child but not
116 std::cout << "... recovering mutex[2]" << std::endl;
118 //Done, now try to lock it to see if robust
119 //mutex recovery works
121 if(!instance[2].previous_owner_dead())
123 //Unlock a recovered mutex without putting it into
124 //into consistent state marks mutex as unusable.
125 instance[2].unlock();
126 //Since it's NOT consistent, locking is NOT possible again
127 bool exception_thrown = false;
131 catch(interprocess_exception &){
132 exception_thrown = true;
134 if(!exception_thrown){
140 //Open managed shared memory
141 managed_shared_memory segment(open_only, argv[2]);
143 RobustMutex *instance = segment.find<RobustMutex>("robust mutex").first;
145 if(std::string(argv[1]) == std::string("child")){
146 std::cout << "launched child" << std::endl;
148 bool *go_ahead = segment.find<bool>("go ahead").first;
151 bool try_lock_res = instance[0].try_lock() && instance[1].try_lock();
152 assert(try_lock_res);
156 bool *go_ahead2 = segment.construct<bool>("go ahead2")(false);
159 std::string s(argv[0]); s += " grandchild ";
161 std::cout << "... launching grandchild" << std::endl;
162 if(0 != std::system(s.c_str())){
163 std::cout << "launched terminated with error" << std::endl;
167 //Wait until child locks the 2nd mutex and dies
173 //Done, now try to lock number 3 to see if robust
174 //mutex recovery works
176 if(!instance[2].previous_owner_dead()){
182 std::cout << "launched grandchild" << std::endl;
183 //grandchild locks the lock and dies
184 bool *go_ahead2 = segment.find<bool>("go ahead2").first;
187 bool try_lock_res = instance[2].try_lock();
188 assert(try_lock_res);
196 std::cout << "Exception thrown error!" << std::endl;
203 } //namespace interprocess{
206 #include <boost/interprocess/detail/config_end.hpp>
208 #endif //BOOST_INTERPROCESS_TEST_ROBUST_EMULATION_TEST_HEADER