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