Chris@16
|
1 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
2 // Code based on Howard Hinnant's shared_mutex class
|
Chris@16
|
3 //
|
Chris@16
|
4 // (C) Copyright Howard Hinnant 2007-2010. Distributed under the Boost
|
Chris@16
|
5 // Software License, Version 1.0. (see http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6 //
|
Chris@16
|
7 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
Chris@16
|
8 // Software License, Version 1.0. (See accompanying file
|
Chris@16
|
9 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
10 //
|
Chris@16
|
11 // See http://www.boost.org/libs/interprocess for documentation.
|
Chris@16
|
12 //
|
Chris@16
|
13 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
14
|
Chris@16
|
15 #ifndef BOOST_INTERPROCESS_SHARABLE_MUTEX_HPP
|
Chris@16
|
16 #define BOOST_INTERPROCESS_SHARABLE_MUTEX_HPP
|
Chris@16
|
17
|
Chris@101
|
18 #ifndef BOOST_CONFIG_HPP
|
Chris@101
|
19 # include <boost/config.hpp>
|
Chris@101
|
20 #endif
|
Chris@101
|
21 #
|
Chris@101
|
22 #if defined(BOOST_HAS_PRAGMA_ONCE)
|
Chris@16
|
23 # pragma once
|
Chris@16
|
24 #endif
|
Chris@16
|
25
|
Chris@16
|
26 #include <boost/interprocess/detail/config_begin.hpp>
|
Chris@16
|
27 #include <boost/interprocess/detail/workaround.hpp>
|
Chris@16
|
28 #include <boost/interprocess/sync/scoped_lock.hpp>
|
Chris@16
|
29 #include <boost/interprocess/detail/posix_time_types_wrk.hpp>
|
Chris@16
|
30 #include <boost/interprocess/sync/interprocess_mutex.hpp>
|
Chris@16
|
31 #include <boost/interprocess/sync/interprocess_condition.hpp>
|
Chris@16
|
32 #include <climits>
|
Chris@16
|
33
|
Chris@16
|
34
|
Chris@16
|
35 //!\file
|
Chris@16
|
36 //!Describes interprocess_sharable_mutex class
|
Chris@16
|
37
|
Chris@16
|
38 namespace boost {
|
Chris@16
|
39 namespace interprocess {
|
Chris@16
|
40
|
Chris@16
|
41 //!Wraps a interprocess_sharable_mutex that can be placed in shared memory and can be
|
Chris@16
|
42 //!shared between processes. Allows timed lock tries
|
Chris@16
|
43 class interprocess_sharable_mutex
|
Chris@16
|
44 {
|
Chris@16
|
45 //Non-copyable
|
Chris@16
|
46 interprocess_sharable_mutex(const interprocess_sharable_mutex &);
|
Chris@16
|
47 interprocess_sharable_mutex &operator=(const interprocess_sharable_mutex &);
|
Chris@16
|
48
|
Chris@16
|
49 friend class interprocess_condition;
|
Chris@16
|
50 public:
|
Chris@16
|
51
|
Chris@16
|
52 //!Constructs the sharable lock.
|
Chris@16
|
53 //!Throws interprocess_exception on error.
|
Chris@16
|
54 interprocess_sharable_mutex();
|
Chris@16
|
55
|
Chris@16
|
56 //!Destroys the sharable lock.
|
Chris@16
|
57 //!Does not throw.
|
Chris@16
|
58 ~interprocess_sharable_mutex();
|
Chris@16
|
59
|
Chris@16
|
60 //Exclusive locking
|
Chris@16
|
61
|
Chris@16
|
62 //!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
|
Chris@16
|
63 //! and if another thread has exclusive or sharable ownership of
|
Chris@16
|
64 //! the mutex, it waits until it can obtain the ownership.
|
Chris@16
|
65 //!Throws: interprocess_exception on error.
|
Chris@16
|
66 void lock();
|
Chris@16
|
67
|
Chris@16
|
68 //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
|
Chris@16
|
69 //! without waiting. If no other thread has exclusive or sharable
|
Chris@16
|
70 //! ownership of the mutex this succeeds.
|
Chris@16
|
71 //!Returns: If it can acquire exclusive ownership immediately returns true.
|
Chris@16
|
72 //! If it has to wait, returns false.
|
Chris@16
|
73 //!Throws: interprocess_exception on error.
|
Chris@16
|
74 bool try_lock();
|
Chris@16
|
75
|
Chris@16
|
76 //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
|
Chris@16
|
77 //! waiting if necessary until no other thread has exclusive or sharable
|
Chris@16
|
78 //! ownership of the mutex or abs_time is reached.
|
Chris@16
|
79 //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
|
Chris@16
|
80 //!Throws: interprocess_exception on error.
|
Chris@16
|
81 bool timed_lock(const boost::posix_time::ptime &abs_time);
|
Chris@16
|
82
|
Chris@16
|
83 //!Precondition: The thread must have exclusive ownership of the mutex.
|
Chris@16
|
84 //!Effects: The calling thread releases the exclusive ownership of the mutex.
|
Chris@16
|
85 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
86 void unlock();
|
Chris@16
|
87
|
Chris@16
|
88 //Sharable locking
|
Chris@16
|
89
|
Chris@16
|
90 //!Effects: The calling thread tries to obtain sharable ownership of the mutex,
|
Chris@16
|
91 //! and if another thread has exclusive ownership of the mutex,
|
Chris@16
|
92 //! waits until it can obtain the ownership.
|
Chris@16
|
93 //!Throws: interprocess_exception on error.
|
Chris@16
|
94 void lock_sharable();
|
Chris@16
|
95
|
Chris@16
|
96 //!Effects: The calling thread tries to acquire sharable ownership of the mutex
|
Chris@16
|
97 //! without waiting. If no other thread has exclusive ownership
|
Chris@16
|
98 //! of the mutex this succeeds.
|
Chris@16
|
99 //!Returns: If it can acquire sharable ownership immediately returns true. If it
|
Chris@16
|
100 //! has to wait, returns false.
|
Chris@16
|
101 //!Throws: interprocess_exception on error.
|
Chris@16
|
102 bool try_lock_sharable();
|
Chris@16
|
103
|
Chris@16
|
104 //!Effects: The calling thread tries to acquire sharable ownership of the mutex
|
Chris@16
|
105 //! waiting if necessary until no other thread has exclusive
|
Chris@16
|
106 //! ownership of the mutex or abs_time is reached.
|
Chris@16
|
107 //!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
|
Chris@16
|
108 //!Throws: interprocess_exception on error.
|
Chris@16
|
109 bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
|
Chris@16
|
110
|
Chris@16
|
111 //!Precondition: The thread must have sharable ownership of the mutex.
|
Chris@16
|
112 //!Effects: The calling thread releases the sharable ownership of the mutex.
|
Chris@16
|
113 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
114 void unlock_sharable();
|
Chris@16
|
115
|
Chris@101
|
116 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
Chris@16
|
117 private:
|
Chris@16
|
118 typedef scoped_lock<interprocess_mutex> scoped_lock_t;
|
Chris@16
|
119
|
Chris@16
|
120 //Pack all the control data in a word to be able
|
Chris@16
|
121 //to use atomic instructions in the future
|
Chris@16
|
122 struct control_word_t
|
Chris@16
|
123 {
|
Chris@16
|
124 unsigned exclusive_in : 1;
|
Chris@16
|
125 unsigned num_shared : sizeof(unsigned)*CHAR_BIT-1;
|
Chris@16
|
126 } m_ctrl;
|
Chris@16
|
127
|
Chris@16
|
128 interprocess_mutex m_mut;
|
Chris@16
|
129 interprocess_condition m_first_gate;
|
Chris@16
|
130 interprocess_condition m_second_gate;
|
Chris@16
|
131
|
Chris@16
|
132 private:
|
Chris@16
|
133 //Rollback structures for exceptions or failure return values
|
Chris@16
|
134 struct exclusive_rollback
|
Chris@16
|
135 {
|
Chris@16
|
136 exclusive_rollback(control_word_t &ctrl
|
Chris@16
|
137 ,interprocess_condition &first_gate)
|
Chris@16
|
138 : mp_ctrl(&ctrl), m_first_gate(first_gate)
|
Chris@16
|
139 {}
|
Chris@16
|
140
|
Chris@16
|
141 void release()
|
Chris@16
|
142 { mp_ctrl = 0; }
|
Chris@16
|
143
|
Chris@16
|
144 ~exclusive_rollback()
|
Chris@16
|
145 {
|
Chris@16
|
146 if(mp_ctrl){
|
Chris@16
|
147 mp_ctrl->exclusive_in = 0;
|
Chris@16
|
148 m_first_gate.notify_all();
|
Chris@16
|
149 }
|
Chris@16
|
150 }
|
Chris@16
|
151 control_word_t *mp_ctrl;
|
Chris@16
|
152 interprocess_condition &m_first_gate;
|
Chris@16
|
153 };
|
Chris@16
|
154
|
Chris@16
|
155 template<int Dummy>
|
Chris@16
|
156 struct base_constants_t
|
Chris@16
|
157 {
|
Chris@16
|
158 static const unsigned max_readers
|
Chris@16
|
159 = ~(unsigned(1) << (sizeof(unsigned)*CHAR_BIT-1));
|
Chris@16
|
160 };
|
Chris@16
|
161 typedef base_constants_t<0> constants;
|
Chris@101
|
162 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
Chris@16
|
163 };
|
Chris@16
|
164
|
Chris@101
|
165 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
Chris@16
|
166
|
Chris@16
|
167 template <int Dummy>
|
Chris@16
|
168 const unsigned interprocess_sharable_mutex::base_constants_t<Dummy>::max_readers;
|
Chris@16
|
169
|
Chris@16
|
170 inline interprocess_sharable_mutex::interprocess_sharable_mutex()
|
Chris@16
|
171 {
|
Chris@16
|
172 this->m_ctrl.exclusive_in = 0;
|
Chris@16
|
173 this->m_ctrl.num_shared = 0;
|
Chris@16
|
174 }
|
Chris@16
|
175
|
Chris@16
|
176 inline interprocess_sharable_mutex::~interprocess_sharable_mutex()
|
Chris@16
|
177 {}
|
Chris@16
|
178
|
Chris@16
|
179 inline void interprocess_sharable_mutex::lock()
|
Chris@16
|
180 {
|
Chris@16
|
181 scoped_lock_t lck(m_mut);
|
Chris@16
|
182
|
Chris@16
|
183 //The exclusive lock must block in the first gate
|
Chris@16
|
184 //if an exclusive lock has been acquired
|
Chris@16
|
185 while (this->m_ctrl.exclusive_in){
|
Chris@16
|
186 this->m_first_gate.wait(lck);
|
Chris@16
|
187 }
|
Chris@16
|
188
|
Chris@16
|
189 //Mark that exclusive lock has been acquired
|
Chris@16
|
190 this->m_ctrl.exclusive_in = 1;
|
Chris@16
|
191
|
Chris@16
|
192 //Prepare rollback
|
Chris@16
|
193 exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
|
Chris@16
|
194
|
Chris@16
|
195 //Now wait until all readers are gone
|
Chris@16
|
196 while (this->m_ctrl.num_shared){
|
Chris@16
|
197 this->m_second_gate.wait(lck);
|
Chris@16
|
198 }
|
Chris@16
|
199 rollback.release();
|
Chris@16
|
200 }
|
Chris@16
|
201
|
Chris@16
|
202 inline bool interprocess_sharable_mutex::try_lock()
|
Chris@16
|
203 {
|
Chris@16
|
204 scoped_lock_t lck(m_mut, try_to_lock);
|
Chris@16
|
205
|
Chris@16
|
206 //If we can't lock or any has there is any exclusive
|
Chris@16
|
207 //or sharable mark return false;
|
Chris@16
|
208 if(!lck.owns()
|
Chris@16
|
209 || this->m_ctrl.exclusive_in
|
Chris@16
|
210 || this->m_ctrl.num_shared){
|
Chris@16
|
211 return false;
|
Chris@16
|
212 }
|
Chris@16
|
213 this->m_ctrl.exclusive_in = 1;
|
Chris@16
|
214 return true;
|
Chris@16
|
215 }
|
Chris@16
|
216
|
Chris@16
|
217 inline bool interprocess_sharable_mutex::timed_lock
|
Chris@16
|
218 (const boost::posix_time::ptime &abs_time)
|
Chris@16
|
219 {
|
Chris@16
|
220 scoped_lock_t lck(m_mut, abs_time);
|
Chris@16
|
221 if(!lck.owns()) return false;
|
Chris@16
|
222
|
Chris@16
|
223 //The exclusive lock must block in the first gate
|
Chris@16
|
224 //if an exclusive lock has been acquired
|
Chris@16
|
225 while (this->m_ctrl.exclusive_in){
|
Chris@101
|
226 //Mutexes and condvars handle just fine infinite abs_times
|
Chris@101
|
227 //so avoid checking it here
|
Chris@16
|
228 if(!this->m_first_gate.timed_wait(lck, abs_time)){
|
Chris@16
|
229 if(this->m_ctrl.exclusive_in){
|
Chris@16
|
230 return false;
|
Chris@16
|
231 }
|
Chris@16
|
232 break;
|
Chris@16
|
233 }
|
Chris@16
|
234 }
|
Chris@16
|
235
|
Chris@16
|
236 //Mark that exclusive lock has been acquired
|
Chris@16
|
237 this->m_ctrl.exclusive_in = 1;
|
Chris@16
|
238
|
Chris@16
|
239 //Prepare rollback
|
Chris@16
|
240 exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
|
Chris@16
|
241
|
Chris@16
|
242 //Now wait until all readers are gone
|
Chris@16
|
243 while (this->m_ctrl.num_shared){
|
Chris@101
|
244 //Mutexes and condvars handle just fine infinite abs_times
|
Chris@101
|
245 //so avoid checking it here
|
Chris@16
|
246 if(!this->m_second_gate.timed_wait(lck, abs_time)){
|
Chris@16
|
247 if(this->m_ctrl.num_shared){
|
Chris@16
|
248 return false;
|
Chris@16
|
249 }
|
Chris@16
|
250 break;
|
Chris@16
|
251 }
|
Chris@16
|
252 }
|
Chris@16
|
253 rollback.release();
|
Chris@16
|
254 return true;
|
Chris@16
|
255 }
|
Chris@16
|
256
|
Chris@16
|
257 inline void interprocess_sharable_mutex::unlock()
|
Chris@16
|
258 {
|
Chris@16
|
259 scoped_lock_t lck(m_mut);
|
Chris@16
|
260 this->m_ctrl.exclusive_in = 0;
|
Chris@16
|
261 this->m_first_gate.notify_all();
|
Chris@16
|
262 }
|
Chris@16
|
263
|
Chris@16
|
264 //Sharable locking
|
Chris@16
|
265
|
Chris@16
|
266 inline void interprocess_sharable_mutex::lock_sharable()
|
Chris@16
|
267 {
|
Chris@16
|
268 scoped_lock_t lck(m_mut);
|
Chris@16
|
269
|
Chris@16
|
270 //The sharable lock must block in the first gate
|
Chris@16
|
271 //if an exclusive lock has been acquired
|
Chris@16
|
272 //or there are too many sharable locks
|
Chris@16
|
273 while(this->m_ctrl.exclusive_in
|
Chris@16
|
274 || this->m_ctrl.num_shared == constants::max_readers){
|
Chris@16
|
275 this->m_first_gate.wait(lck);
|
Chris@16
|
276 }
|
Chris@16
|
277
|
Chris@16
|
278 //Increment sharable count
|
Chris@16
|
279 ++this->m_ctrl.num_shared;
|
Chris@16
|
280 }
|
Chris@16
|
281
|
Chris@16
|
282 inline bool interprocess_sharable_mutex::try_lock_sharable()
|
Chris@16
|
283 {
|
Chris@16
|
284 scoped_lock_t lck(m_mut, try_to_lock);
|
Chris@16
|
285
|
Chris@16
|
286 //The sharable lock must fail
|
Chris@16
|
287 //if an exclusive lock has been acquired
|
Chris@16
|
288 //or there are too many sharable locks
|
Chris@16
|
289 if(!lck.owns()
|
Chris@16
|
290 || this->m_ctrl.exclusive_in
|
Chris@16
|
291 || this->m_ctrl.num_shared == constants::max_readers){
|
Chris@16
|
292 return false;
|
Chris@16
|
293 }
|
Chris@16
|
294
|
Chris@16
|
295 //Increment sharable count
|
Chris@16
|
296 ++this->m_ctrl.num_shared;
|
Chris@16
|
297 return true;
|
Chris@16
|
298 }
|
Chris@16
|
299
|
Chris@16
|
300 inline bool interprocess_sharable_mutex::timed_lock_sharable
|
Chris@16
|
301 (const boost::posix_time::ptime &abs_time)
|
Chris@16
|
302 {
|
Chris@16
|
303 scoped_lock_t lck(m_mut, abs_time);
|
Chris@16
|
304 if(!lck.owns()) return false;
|
Chris@16
|
305
|
Chris@16
|
306 //The sharable lock must block in the first gate
|
Chris@16
|
307 //if an exclusive lock has been acquired
|
Chris@16
|
308 //or there are too many sharable locks
|
Chris@16
|
309 while (this->m_ctrl.exclusive_in
|
Chris@16
|
310 || this->m_ctrl.num_shared == constants::max_readers){
|
Chris@101
|
311 //Mutexes and condvars handle just fine infinite abs_times
|
Chris@101
|
312 //so avoid checking it here
|
Chris@16
|
313 if(!this->m_first_gate.timed_wait(lck, abs_time)){
|
Chris@16
|
314 if(this->m_ctrl.exclusive_in
|
Chris@16
|
315 || this->m_ctrl.num_shared == constants::max_readers){
|
Chris@16
|
316 return false;
|
Chris@16
|
317 }
|
Chris@16
|
318 break;
|
Chris@16
|
319 }
|
Chris@16
|
320 }
|
Chris@16
|
321
|
Chris@16
|
322 //Increment sharable count
|
Chris@16
|
323 ++this->m_ctrl.num_shared;
|
Chris@16
|
324 return true;
|
Chris@16
|
325 }
|
Chris@16
|
326
|
Chris@16
|
327 inline void interprocess_sharable_mutex::unlock_sharable()
|
Chris@16
|
328 {
|
Chris@16
|
329 scoped_lock_t lck(m_mut);
|
Chris@16
|
330 //Decrement sharable count
|
Chris@16
|
331 --this->m_ctrl.num_shared;
|
Chris@16
|
332 if (this->m_ctrl.num_shared == 0){
|
Chris@16
|
333 this->m_second_gate.notify_one();
|
Chris@16
|
334 }
|
Chris@16
|
335 //Check if there are blocked sharables because of
|
Chris@16
|
336 //there were too many sharables
|
Chris@16
|
337 else if(this->m_ctrl.num_shared == (constants::max_readers-1)){
|
Chris@16
|
338 this->m_first_gate.notify_all();
|
Chris@16
|
339 }
|
Chris@16
|
340 }
|
Chris@16
|
341
|
Chris@101
|
342 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
Chris@16
|
343
|
Chris@16
|
344 } //namespace interprocess {
|
Chris@16
|
345 } //namespace boost {
|
Chris@16
|
346
|
Chris@16
|
347 #include <boost/interprocess/detail/config_end.hpp>
|
Chris@16
|
348
|
Chris@16
|
349 #endif //BOOST_INTERPROCESS_SHARABLE_MUTEX_HPP
|