inline const char *add_to_process_id_name(const char *name) { static std::string str; get_process_id_name(str); str += name; return str.c_str(); }
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; }
inline const char *get_process_id_name() { static std::string str; get_process_id_name(str); return str.c_str(); }