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[])
{
BOOST_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;
BOOST_TRY{
instance[1].lock();
}
BOOST_CATCH(interprocess_exception &){
exception_thrown = true;
} BOOST_CATCH_END
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;
BOOST_TRY{
instance[2].lock();
}
BOOST_CATCH(interprocess_exception &){
exception_thrown = true;
} BOOST_CATCH_END
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;
}
}
}BOOST_CATCH(...){
std::cout << "Exception thrown error!" << std::endl;
BOOST_RETHROW
} BOOST_CATCH_END
return 0;
}
} //namespace test{
} //namespace interprocess{
} //namespace boost{
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_TEST_ROBUST_EMULATION_TEST_HEADER
|