| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // (C) Copyright Ion Gaztanaga 2010-2010. 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 "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; |
| |
| //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 |
| while(!*go_ahead){ |
| detail::thread_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 |
| while(!*go_ahead2){ |
| detail::thread_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 |