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
11#ifndef BOOST_INTERPROCESS_TEST_ROBUST_MUTEX_TEST_HEADER
12#define BOOST_INTERPROCESS_TEST_ROBUST_MUTEX_TEST_HEADER
13
14#include <boost/interprocess/detail/config_begin.hpp>
15#include <iostream>
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"
22#include <iostream>
23
24namespace boost{
25namespace interprocess{
26namespace test{
27
28template<class RobustMutex>
29int robust_mutex_test(int argc, char *argv[])
30{
31 BOOST_TRY{
32 if(argc == 1){ //Parent process
33 //First usual mutex tests
34 {
35 // test_all_lock<RobustMutex>();
36// test_all_mutex<true, RobustMutex>();
37 }
38 std::cout << "robust mutex recovery test" << std::endl;
39
40 //Remove shared memory on construction and destruction
41 class shm_remove
42 {
43 public:
44 shm_remove(){ shared_memory_object::remove
45 (filename: ::boost::interprocess::test::get_process_id_name()); }
46 ~shm_remove(){ shared_memory_object::remove
47 (filename: ::boost::interprocess::test::get_process_id_name()); }
48 } remover;
49 (void)remover;
50
51 //Construct managed shared memory
52 managed_shared_memory segment(create_only, get_process_id_name(), 65536);
53
54 //Create two robust mutexes
55 RobustMutex *instance = segment.construct<RobustMutex>
56 ("robust mutex")[2]();
57
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> (name: "go ahead")(false);
61
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(command: s.c_str()))
67 return 1;
68
69 //Wait until child locks the mutexes and dies
70 spin_wait swait;
71 while(!*go_ahead){
72 swait.yield();
73 }
74
75 std::cout << "... recovering mutex[0]" << std::endl;
76 //First try to recover lock[0], put into consistent
77 //state and relock it again
78 {
79 //Done, now try to lock it to see if robust
80 //mutex recovery works
81 instance[0].lock();
82 if(!instance[0].previous_owner_dead())
83 return 1;
84 instance[0].consistent();
85 instance[0].unlock();
86 //Since it's consistent, locking is possible again
87 instance[0].lock();
88 instance[0].unlock();
89 }
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;
93 {
94 //Done, now try to lock it to see if robust
95 //mutex recovery works
96 instance[1].lock();
97 if(!instance[1].previous_owner_dead())
98 return 1;
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;
104 BOOST_TRY{
105 instance[1].lock();
106 }
107 BOOST_CATCH(interprocess_exception &){
108 exception_thrown = true;
109 } BOOST_CATCH_END
110 if(!exception_thrown){
111 return 1;
112 }
113 }
114 //Now with lock[2], this was locked by child but not
115 //unlocked
116 std::cout << "... recovering mutex[2]" << std::endl;
117 {
118 //Done, now try to lock it to see if robust
119 //mutex recovery works
120 instance[2].lock();
121 if(!instance[2].previous_owner_dead())
122 return 1;
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;
128 BOOST_TRY{
129 instance[2].lock();
130 }
131 BOOST_CATCH(interprocess_exception &){
132 exception_thrown = true;
133 } BOOST_CATCH_END
134 if(!exception_thrown){
135 return 1;
136 }
137 }
138 }
139 else{
140 //Open managed shared memory
141 managed_shared_memory segment(open_only, argv[2]);
142 //Find mutexes
143 RobustMutex *instance = segment.find<RobustMutex>("robust mutex").first;
144 assert(instance);
145 if(std::string(argv[1]) == std::string("child")){
146 std::cout << "launched child" << std::endl;
147 //Find flag
148 bool *go_ahead = segment.find<bool>(name: "go ahead").first;
149 assert(go_ahead);
150 //Lock, flag and die
151 bool try_lock_res = instance[0].try_lock() && instance[1].try_lock();
152 assert(try_lock_res);
153 if(!try_lock_res)
154 return 1;
155
156 bool *go_ahead2 = segment.construct<bool>(name: "go ahead2")(false);
157 assert(go_ahead2);
158 //Launch grandchild
159 std::string s(argv[0]); s += " grandchild ";
160 s += argv[2];
161 std::cout << "... launching grandchild" << std::endl;
162 if(0 != std::system(command: s.c_str())){
163 std::cout << "launched terminated with error" << std::endl;
164 return 1;
165 }
166
167 //Wait until child locks the 2nd mutex and dies
168 spin_wait swait;
169 while(!*go_ahead2){
170 swait.yield();
171 }
172
173 //Done, now try to lock number 3 to see if robust
174 //mutex recovery works
175 instance[2].lock();
176 if(!instance[2].previous_owner_dead()){
177 return 1;
178 }
179 *go_ahead = true;
180 }
181 else{
182 std::cout << "launched grandchild" << std::endl;
183 //grandchild locks the lock and dies
184 bool *go_ahead2 = segment.find<bool>(name: "go ahead2").first;
185 assert(go_ahead2);
186 //Lock, flag and die
187 bool try_lock_res = instance[2].try_lock();
188 assert(try_lock_res);
189 if(!try_lock_res){
190 return 1;
191 }
192 *go_ahead2 = true;
193 }
194 }
195 }BOOST_CATCH(...){
196 std::cout << "Exception thrown error!" << std::endl;
197 BOOST_RETHROW
198 } BOOST_CATCH_END
199 return 0;
200}
201
202} //namespace test{
203} //namespace interprocess{
204} //namespace boost{
205
206#include <boost/interprocess/detail/config_end.hpp>
207
208#endif //BOOST_INTERPROCESS_TEST_ROBUST_EMULATION_TEST_HEADER
209

source code of boost/libs/interprocess/test/robust_mutex_test.hpp