Imported Upstream version 1.57.0
[platform/upstream/boost.git] / libs / interprocess / test / robust_mutex_test.hpp
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
24 namespace boost{
25 namespace interprocess{
26 namespace test{
27
28 template<class RobustMutex>
29 int robust_mutex_test(int argc, char *argv[])
30 {
31    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             (::boost::interprocess::test::get_process_id_name()); }
46          ~shm_remove(){ shared_memory_object::remove
47             (::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> ("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(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          try{
105             instance[1].lock();
106          }
107          catch(interprocess_exception &){
108             exception_thrown = true;
109          }
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          try{
129             instance[2].lock();
130          }
131          catch(interprocess_exception &){
132             exception_thrown = true;
133          }
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>("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>("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(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>("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    }catch(...){
196       std::cout << "Exception thrown error!" << std::endl;
197       throw;
198    }
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