Chris@16
|
1 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
2 //
|
Chris@16
|
3 // Code based on Howard Hinnant's upgrade_mutex class
|
Chris@16
|
4 //
|
Chris@16
|
5 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
Chris@16
|
6 // Software License, Version 1.0. (See accompanying file
|
Chris@16
|
7 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
8 //
|
Chris@16
|
9 // See http://www.boost.org/libs/interprocess for documentation.
|
Chris@16
|
10 //
|
Chris@16
|
11 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
12
|
Chris@16
|
13 #ifndef BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
|
Chris@16
|
14 #define BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
|
Chris@16
|
15
|
Chris@101
|
16 #ifndef BOOST_CONFIG_HPP
|
Chris@101
|
17 # include <boost/config.hpp>
|
Chris@101
|
18 #endif
|
Chris@101
|
19 #
|
Chris@101
|
20 #if defined(BOOST_HAS_PRAGMA_ONCE)
|
Chris@16
|
21 # pragma once
|
Chris@16
|
22 #endif
|
Chris@16
|
23
|
Chris@16
|
24 #include <boost/interprocess/detail/config_begin.hpp>
|
Chris@16
|
25 #include <boost/interprocess/detail/workaround.hpp>
|
Chris@16
|
26 #include <boost/interprocess/sync/scoped_lock.hpp>
|
Chris@16
|
27 #include <boost/interprocess/detail/posix_time_types_wrk.hpp>
|
Chris@16
|
28 #include <boost/interprocess/sync/interprocess_mutex.hpp>
|
Chris@16
|
29 #include <boost/interprocess/sync/interprocess_condition.hpp>
|
Chris@16
|
30 #include <climits>
|
Chris@16
|
31
|
Chris@16
|
32
|
Chris@16
|
33 //!\file
|
Chris@16
|
34 //!Describes interprocess_upgradable_mutex class
|
Chris@16
|
35
|
Chris@16
|
36 namespace boost {
|
Chris@16
|
37 namespace interprocess {
|
Chris@16
|
38
|
Chris@16
|
39 //!Wraps a interprocess_upgradable_mutex that can be placed in shared memory and can be
|
Chris@16
|
40 //!shared between processes. Allows timed lock tries
|
Chris@16
|
41 class interprocess_upgradable_mutex
|
Chris@16
|
42 {
|
Chris@16
|
43 //Non-copyable
|
Chris@16
|
44 interprocess_upgradable_mutex(const interprocess_upgradable_mutex &);
|
Chris@16
|
45 interprocess_upgradable_mutex &operator=(const interprocess_upgradable_mutex &);
|
Chris@16
|
46
|
Chris@16
|
47 friend class interprocess_condition;
|
Chris@16
|
48 public:
|
Chris@16
|
49
|
Chris@16
|
50 //!Constructs the upgradable lock.
|
Chris@16
|
51 //!Throws interprocess_exception on error.
|
Chris@16
|
52 interprocess_upgradable_mutex();
|
Chris@16
|
53
|
Chris@16
|
54 //!Destroys the upgradable lock.
|
Chris@16
|
55 //!Does not throw.
|
Chris@16
|
56 ~interprocess_upgradable_mutex();
|
Chris@16
|
57
|
Chris@16
|
58 //Exclusive locking
|
Chris@16
|
59
|
Chris@16
|
60 //!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
|
Chris@16
|
61 //! and if another thread has exclusive, sharable or upgradable ownership of
|
Chris@16
|
62 //! the mutex, it waits until it can obtain the ownership.
|
Chris@16
|
63 //!Throws: interprocess_exception on error.
|
Chris@16
|
64 void lock();
|
Chris@16
|
65
|
Chris@16
|
66 //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
|
Chris@16
|
67 //! without waiting. If no other thread has exclusive, sharable or upgradable
|
Chris@16
|
68 //! ownership of the mutex this succeeds.
|
Chris@16
|
69 //!Returns: If it can acquire exclusive ownership immediately returns true.
|
Chris@16
|
70 //! If it has to wait, returns false.
|
Chris@16
|
71 //!Throws: interprocess_exception on error.
|
Chris@16
|
72 bool try_lock();
|
Chris@16
|
73
|
Chris@16
|
74 //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
|
Chris@16
|
75 //! waiting if necessary until no other thread has exclusive, sharable or
|
Chris@16
|
76 //! upgradable ownership of the mutex or abs_time is reached.
|
Chris@16
|
77 //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
|
Chris@16
|
78 //!Throws: interprocess_exception on error.
|
Chris@16
|
79 bool timed_lock(const boost::posix_time::ptime &abs_time);
|
Chris@16
|
80
|
Chris@16
|
81 //!Precondition: The thread must have exclusive ownership of the mutex.
|
Chris@16
|
82 //!Effects: The calling thread releases the exclusive ownership of the mutex.
|
Chris@16
|
83 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
84 void unlock();
|
Chris@16
|
85
|
Chris@16
|
86 //Sharable locking
|
Chris@16
|
87
|
Chris@16
|
88 //!Effects: The calling thread tries to obtain sharable ownership of the mutex,
|
Chris@16
|
89 //! and if another thread has exclusive ownership of the mutex,
|
Chris@16
|
90 //! waits until it can obtain the ownership.
|
Chris@16
|
91 //!Throws: interprocess_exception on error.
|
Chris@16
|
92 void lock_sharable();
|
Chris@16
|
93
|
Chris@16
|
94 //!Effects: The calling thread tries to acquire sharable ownership of the mutex
|
Chris@16
|
95 //! without waiting. If no other thread has exclusive ownership
|
Chris@16
|
96 //! of the mutex this succeeds.
|
Chris@16
|
97 //!Returns: If it can acquire sharable ownership immediately returns true. If it
|
Chris@16
|
98 //! has to wait, returns false.
|
Chris@16
|
99 //!Throws: interprocess_exception on error.
|
Chris@16
|
100 bool try_lock_sharable();
|
Chris@16
|
101
|
Chris@16
|
102 //!Effects: The calling thread tries to acquire sharable ownership of the mutex
|
Chris@16
|
103 //! waiting if necessary until no other thread has exclusive
|
Chris@16
|
104 //! ownership of the mutex or abs_time is reached.
|
Chris@16
|
105 //!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
|
Chris@16
|
106 //!Throws: interprocess_exception on error.
|
Chris@16
|
107 bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
|
Chris@16
|
108
|
Chris@16
|
109 //!Precondition: The thread must have sharable ownership of the mutex.
|
Chris@16
|
110 //!Effects: The calling thread releases the sharable ownership of the mutex.
|
Chris@16
|
111 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
112 void unlock_sharable();
|
Chris@16
|
113
|
Chris@16
|
114 //Upgradable locking
|
Chris@16
|
115
|
Chris@16
|
116 //!Effects: The calling thread tries to obtain upgradable ownership of the mutex,
|
Chris@16
|
117 //! and if another thread has exclusive or upgradable ownership of the mutex,
|
Chris@16
|
118 //! waits until it can obtain the ownership.
|
Chris@16
|
119 //!Throws: interprocess_exception on error.
|
Chris@16
|
120 void lock_upgradable();
|
Chris@16
|
121
|
Chris@16
|
122 //!Effects: The calling thread tries to acquire upgradable ownership of the mutex
|
Chris@16
|
123 //! without waiting. If no other thread has exclusive or upgradable ownership
|
Chris@16
|
124 //! of the mutex this succeeds.
|
Chris@16
|
125 //!Returns: If it can acquire upgradable ownership immediately returns true.
|
Chris@16
|
126 //! If it has to wait, returns false.
|
Chris@16
|
127 //!Throws: interprocess_exception on error.
|
Chris@16
|
128 bool try_lock_upgradable();
|
Chris@16
|
129
|
Chris@16
|
130 //!Effects: The calling thread tries to acquire upgradable ownership of the mutex
|
Chris@16
|
131 //! waiting if necessary until no other thread has exclusive or upgradable
|
Chris@16
|
132 //! ownership of the mutex or abs_time is reached.
|
Chris@16
|
133 //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
|
Chris@16
|
134 //!Throws: interprocess_exception on error.
|
Chris@16
|
135 bool timed_lock_upgradable(const boost::posix_time::ptime &abs_time);
|
Chris@16
|
136
|
Chris@16
|
137 //!Precondition: The thread must have upgradable ownership of the mutex.
|
Chris@16
|
138 //!Effects: The calling thread releases the upgradable ownership of the mutex.
|
Chris@16
|
139 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
140 void unlock_upgradable();
|
Chris@16
|
141
|
Chris@16
|
142 //Demotions
|
Chris@16
|
143
|
Chris@16
|
144 //!Precondition: The thread must have exclusive ownership of the mutex.
|
Chris@16
|
145 //!Effects: The thread atomically releases exclusive ownership and acquires
|
Chris@16
|
146 //! upgradable ownership. This operation is non-blocking.
|
Chris@16
|
147 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
148 void unlock_and_lock_upgradable();
|
Chris@16
|
149
|
Chris@16
|
150 //!Precondition: The thread must have exclusive ownership of the mutex.
|
Chris@16
|
151 //!Effects: The thread atomically releases exclusive ownership and acquires
|
Chris@16
|
152 //! sharable ownership. This operation is non-blocking.
|
Chris@16
|
153 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
154 void unlock_and_lock_sharable();
|
Chris@16
|
155
|
Chris@16
|
156 //!Precondition: The thread must have upgradable ownership of the mutex.
|
Chris@16
|
157 //!Effects: The thread atomically releases upgradable ownership and acquires
|
Chris@16
|
158 //! sharable ownership. This operation is non-blocking.
|
Chris@16
|
159 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
160 void unlock_upgradable_and_lock_sharable();
|
Chris@16
|
161
|
Chris@16
|
162 //Promotions
|
Chris@16
|
163
|
Chris@16
|
164 //!Precondition: The thread must have upgradable ownership of the mutex.
|
Chris@16
|
165 //!Effects: The thread atomically releases upgradable ownership and acquires
|
Chris@16
|
166 //! exclusive ownership. This operation will block until all threads with
|
Chris@16
|
167 //! sharable ownership release their sharable lock.
|
Chris@16
|
168 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
169 void unlock_upgradable_and_lock();
|
Chris@16
|
170
|
Chris@16
|
171 //!Precondition: The thread must have upgradable ownership of the mutex.
|
Chris@16
|
172 //!Effects: The thread atomically releases upgradable ownership and tries to
|
Chris@16
|
173 //! acquire exclusive ownership. This operation will fail if there are threads
|
Chris@16
|
174 //! with sharable ownership, but it will maintain upgradable ownership.
|
Chris@16
|
175 //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
|
Chris@16
|
176 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
177 bool try_unlock_upgradable_and_lock();
|
Chris@16
|
178
|
Chris@16
|
179 //!Precondition: The thread must have upgradable ownership of the mutex.
|
Chris@16
|
180 //!Effects: The thread atomically releases upgradable ownership and tries to acquire
|
Chris@16
|
181 //! exclusive ownership, waiting if necessary until abs_time. This operation will
|
Chris@16
|
182 //! fail if there are threads with sharable ownership or timeout reaches, but it
|
Chris@16
|
183 //! will maintain upgradable ownership.
|
Chris@16
|
184 //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
|
Chris@16
|
185 //!Throws: An exception derived from interprocess_exception on error. */
|
Chris@16
|
186 bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &abs_time);
|
Chris@16
|
187
|
Chris@16
|
188 //!Precondition: The thread must have sharable ownership of the mutex.
|
Chris@16
|
189 //!Effects: The thread atomically releases sharable ownership and tries to acquire
|
Chris@16
|
190 //! exclusive ownership. This operation will fail if there are threads with sharable
|
Chris@16
|
191 //! or upgradable ownership, but it will maintain sharable ownership.
|
Chris@16
|
192 //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
|
Chris@16
|
193 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
194 bool try_unlock_sharable_and_lock();
|
Chris@16
|
195
|
Chris@16
|
196 //!Precondition: The thread must have sharable ownership of the mutex.
|
Chris@16
|
197 //!Effects: The thread atomically releases sharable ownership and tries to acquire
|
Chris@16
|
198 //! upgradable ownership. This operation will fail if there are threads with sharable
|
Chris@16
|
199 //! or upgradable ownership, but it will maintain sharable ownership.
|
Chris@16
|
200 //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
|
Chris@16
|
201 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
202 bool try_unlock_sharable_and_lock_upgradable();
|
Chris@16
|
203
|
Chris@101
|
204 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
Chris@16
|
205 private:
|
Chris@16
|
206 typedef scoped_lock<interprocess_mutex> scoped_lock_t;
|
Chris@16
|
207
|
Chris@16
|
208 //Pack all the control data in a word to be able
|
Chris@16
|
209 //to use atomic instructions in the future
|
Chris@16
|
210 struct control_word_t
|
Chris@16
|
211 {
|
Chris@16
|
212 unsigned exclusive_in : 1;
|
Chris@16
|
213 unsigned upgradable_in : 1;
|
Chris@16
|
214 unsigned num_upr_shar : sizeof(unsigned)*CHAR_BIT-2;
|
Chris@16
|
215 } m_ctrl;
|
Chris@16
|
216
|
Chris@16
|
217 interprocess_mutex m_mut;
|
Chris@16
|
218 interprocess_condition m_first_gate;
|
Chris@16
|
219 interprocess_condition m_second_gate;
|
Chris@16
|
220
|
Chris@16
|
221 private:
|
Chris@16
|
222 //Rollback structures for exceptions or failure return values
|
Chris@16
|
223 struct exclusive_rollback
|
Chris@16
|
224 {
|
Chris@16
|
225 exclusive_rollback(control_word_t &ctrl
|
Chris@16
|
226 ,interprocess_condition &first_gate)
|
Chris@16
|
227 : mp_ctrl(&ctrl), m_first_gate(first_gate)
|
Chris@16
|
228 {}
|
Chris@16
|
229
|
Chris@16
|
230 void release()
|
Chris@16
|
231 { mp_ctrl = 0; }
|
Chris@16
|
232
|
Chris@16
|
233 ~exclusive_rollback()
|
Chris@16
|
234 {
|
Chris@16
|
235 if(mp_ctrl){
|
Chris@16
|
236 mp_ctrl->exclusive_in = 0;
|
Chris@16
|
237 m_first_gate.notify_all();
|
Chris@16
|
238 }
|
Chris@16
|
239 }
|
Chris@16
|
240 control_word_t *mp_ctrl;
|
Chris@16
|
241 interprocess_condition &m_first_gate;
|
Chris@16
|
242 };
|
Chris@16
|
243
|
Chris@16
|
244 struct upgradable_to_exclusive_rollback
|
Chris@16
|
245 {
|
Chris@16
|
246 upgradable_to_exclusive_rollback(control_word_t &ctrl)
|
Chris@16
|
247 : mp_ctrl(&ctrl)
|
Chris@16
|
248 {}
|
Chris@16
|
249
|
Chris@16
|
250 void release()
|
Chris@16
|
251 { mp_ctrl = 0; }
|
Chris@16
|
252
|
Chris@16
|
253 ~upgradable_to_exclusive_rollback()
|
Chris@16
|
254 {
|
Chris@16
|
255 if(mp_ctrl){
|
Chris@16
|
256 //Recover upgradable lock
|
Chris@16
|
257 mp_ctrl->upgradable_in = 1;
|
Chris@16
|
258 ++mp_ctrl->num_upr_shar;
|
Chris@16
|
259 //Execute the second half of exclusive locking
|
Chris@16
|
260 mp_ctrl->exclusive_in = 0;
|
Chris@16
|
261 }
|
Chris@16
|
262 }
|
Chris@16
|
263 control_word_t *mp_ctrl;
|
Chris@16
|
264 };
|
Chris@16
|
265
|
Chris@16
|
266 template<int Dummy>
|
Chris@16
|
267 struct base_constants_t
|
Chris@16
|
268 {
|
Chris@16
|
269 static const unsigned max_readers
|
Chris@16
|
270 = ~(unsigned(3) << (sizeof(unsigned)*CHAR_BIT-2));
|
Chris@16
|
271 };
|
Chris@16
|
272 typedef base_constants_t<0> constants;
|
Chris@101
|
273 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
Chris@16
|
274 };
|
Chris@16
|
275
|
Chris@101
|
276 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
Chris@16
|
277
|
Chris@16
|
278 template <int Dummy>
|
Chris@16
|
279 const unsigned interprocess_upgradable_mutex::base_constants_t<Dummy>::max_readers;
|
Chris@16
|
280
|
Chris@16
|
281 inline interprocess_upgradable_mutex::interprocess_upgradable_mutex()
|
Chris@16
|
282 {
|
Chris@16
|
283 this->m_ctrl.exclusive_in = 0;
|
Chris@16
|
284 this->m_ctrl.upgradable_in = 0;
|
Chris@16
|
285 this->m_ctrl.num_upr_shar = 0;
|
Chris@16
|
286 }
|
Chris@16
|
287
|
Chris@16
|
288 inline interprocess_upgradable_mutex::~interprocess_upgradable_mutex()
|
Chris@16
|
289 {}
|
Chris@16
|
290
|
Chris@16
|
291 inline void interprocess_upgradable_mutex::lock()
|
Chris@16
|
292 {
|
Chris@16
|
293 scoped_lock_t lck(m_mut);
|
Chris@16
|
294
|
Chris@16
|
295 //The exclusive lock must block in the first gate
|
Chris@16
|
296 //if an exclusive or upgradable lock has been acquired
|
Chris@16
|
297 while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
|
Chris@16
|
298 this->m_first_gate.wait(lck);
|
Chris@16
|
299 }
|
Chris@16
|
300
|
Chris@16
|
301 //Mark that exclusive lock has been acquired
|
Chris@16
|
302 this->m_ctrl.exclusive_in = 1;
|
Chris@16
|
303
|
Chris@16
|
304 //Prepare rollback
|
Chris@16
|
305 exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
|
Chris@16
|
306
|
Chris@16
|
307 //Now wait until all readers are gone
|
Chris@16
|
308 while (this->m_ctrl.num_upr_shar){
|
Chris@16
|
309 this->m_second_gate.wait(lck);
|
Chris@16
|
310 }
|
Chris@16
|
311 rollback.release();
|
Chris@16
|
312 }
|
Chris@16
|
313
|
Chris@16
|
314 inline bool interprocess_upgradable_mutex::try_lock()
|
Chris@16
|
315 {
|
Chris@16
|
316 scoped_lock_t lck(m_mut, try_to_lock);
|
Chris@16
|
317
|
Chris@16
|
318 //If we can't lock or any has there is any exclusive, upgradable
|
Chris@16
|
319 //or sharable mark return false;
|
Chris@16
|
320 if(!lck.owns()
|
Chris@16
|
321 || this->m_ctrl.exclusive_in
|
Chris@16
|
322 || this->m_ctrl.num_upr_shar){
|
Chris@16
|
323 return false;
|
Chris@16
|
324 }
|
Chris@16
|
325 this->m_ctrl.exclusive_in = 1;
|
Chris@16
|
326 return true;
|
Chris@16
|
327 }
|
Chris@16
|
328
|
Chris@16
|
329 inline bool interprocess_upgradable_mutex::timed_lock
|
Chris@16
|
330 (const boost::posix_time::ptime &abs_time)
|
Chris@16
|
331 {
|
Chris@101
|
332 //Mutexes and condvars handle just fine infinite abs_times
|
Chris@101
|
333 //so avoid checking it here
|
Chris@16
|
334 scoped_lock_t lck(m_mut, abs_time);
|
Chris@16
|
335 if(!lck.owns()) return false;
|
Chris@16
|
336
|
Chris@16
|
337 //The exclusive lock must block in the first gate
|
Chris@16
|
338 //if an exclusive or upgradable lock has been acquired
|
Chris@16
|
339 while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
|
Chris@16
|
340 if(!this->m_first_gate.timed_wait(lck, abs_time)){
|
Chris@16
|
341 if(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
|
Chris@16
|
342 return false;
|
Chris@16
|
343 }
|
Chris@16
|
344 break;
|
Chris@16
|
345 }
|
Chris@16
|
346 }
|
Chris@16
|
347
|
Chris@16
|
348 //Mark that exclusive lock has been acquired
|
Chris@16
|
349 this->m_ctrl.exclusive_in = 1;
|
Chris@16
|
350
|
Chris@16
|
351 //Prepare rollback
|
Chris@16
|
352 exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
|
Chris@16
|
353
|
Chris@16
|
354 //Now wait until all readers are gone
|
Chris@16
|
355 while (this->m_ctrl.num_upr_shar){
|
Chris@16
|
356 if(!this->m_second_gate.timed_wait(lck, abs_time)){
|
Chris@16
|
357 if(this->m_ctrl.num_upr_shar){
|
Chris@16
|
358 return false;
|
Chris@16
|
359 }
|
Chris@16
|
360 break;
|
Chris@16
|
361 }
|
Chris@16
|
362 }
|
Chris@16
|
363 rollback.release();
|
Chris@16
|
364 return true;
|
Chris@16
|
365 }
|
Chris@16
|
366
|
Chris@16
|
367 inline void interprocess_upgradable_mutex::unlock()
|
Chris@16
|
368 {
|
Chris@16
|
369 scoped_lock_t lck(m_mut);
|
Chris@16
|
370 this->m_ctrl.exclusive_in = 0;
|
Chris@16
|
371 this->m_first_gate.notify_all();
|
Chris@16
|
372 }
|
Chris@16
|
373
|
Chris@16
|
374 //Upgradable locking
|
Chris@16
|
375
|
Chris@16
|
376 inline void interprocess_upgradable_mutex::lock_upgradable()
|
Chris@16
|
377 {
|
Chris@16
|
378 scoped_lock_t lck(m_mut);
|
Chris@16
|
379
|
Chris@16
|
380 //The upgradable lock must block in the first gate
|
Chris@16
|
381 //if an exclusive or upgradable lock has been acquired
|
Chris@16
|
382 //or there are too many sharable locks
|
Chris@16
|
383 while(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in
|
Chris@16
|
384 || this->m_ctrl.num_upr_shar == constants::max_readers){
|
Chris@16
|
385 this->m_first_gate.wait(lck);
|
Chris@16
|
386 }
|
Chris@16
|
387
|
Chris@16
|
388 //Mark that upgradable lock has been acquired
|
Chris@16
|
389 //And add upgradable to the sharable count
|
Chris@16
|
390 this->m_ctrl.upgradable_in = 1;
|
Chris@16
|
391 ++this->m_ctrl.num_upr_shar;
|
Chris@16
|
392 }
|
Chris@16
|
393
|
Chris@16
|
394 inline bool interprocess_upgradable_mutex::try_lock_upgradable()
|
Chris@16
|
395 {
|
Chris@16
|
396 scoped_lock_t lck(m_mut, try_to_lock);
|
Chris@16
|
397
|
Chris@16
|
398 //The upgradable lock must fail
|
Chris@16
|
399 //if an exclusive or upgradable lock has been acquired
|
Chris@16
|
400 //or there are too many sharable locks
|
Chris@16
|
401 if(!lck.owns()
|
Chris@16
|
402 || this->m_ctrl.exclusive_in
|
Chris@16
|
403 || this->m_ctrl.upgradable_in
|
Chris@16
|
404 || this->m_ctrl.num_upr_shar == constants::max_readers){
|
Chris@16
|
405 return false;
|
Chris@16
|
406 }
|
Chris@16
|
407
|
Chris@16
|
408 //Mark that upgradable lock has been acquired
|
Chris@16
|
409 //And add upgradable to the sharable count
|
Chris@16
|
410 this->m_ctrl.upgradable_in = 1;
|
Chris@16
|
411 ++this->m_ctrl.num_upr_shar;
|
Chris@16
|
412 return true;
|
Chris@16
|
413 }
|
Chris@16
|
414
|
Chris@16
|
415 inline bool interprocess_upgradable_mutex::timed_lock_upgradable
|
Chris@16
|
416 (const boost::posix_time::ptime &abs_time)
|
Chris@16
|
417 {
|
Chris@101
|
418 //Mutexes and condvars handle just fine infinite abs_times
|
Chris@101
|
419 //so avoid checking it here
|
Chris@16
|
420 scoped_lock_t lck(m_mut, abs_time);
|
Chris@16
|
421 if(!lck.owns()) return false;
|
Chris@16
|
422
|
Chris@16
|
423 //The upgradable lock must block in the first gate
|
Chris@16
|
424 //if an exclusive or upgradable lock has been acquired
|
Chris@16
|
425 //or there are too many sharable locks
|
Chris@16
|
426 while(this->m_ctrl.exclusive_in
|
Chris@16
|
427 || this->m_ctrl.upgradable_in
|
Chris@16
|
428 || this->m_ctrl.num_upr_shar == constants::max_readers){
|
Chris@16
|
429 if(!this->m_first_gate.timed_wait(lck, abs_time)){
|
Chris@16
|
430 if((this->m_ctrl.exclusive_in
|
Chris@16
|
431 || this->m_ctrl.upgradable_in
|
Chris@16
|
432 || this->m_ctrl.num_upr_shar == constants::max_readers)){
|
Chris@16
|
433 return false;
|
Chris@16
|
434 }
|
Chris@16
|
435 break;
|
Chris@16
|
436 }
|
Chris@16
|
437 }
|
Chris@16
|
438
|
Chris@16
|
439 //Mark that upgradable lock has been acquired
|
Chris@16
|
440 //And add upgradable to the sharable count
|
Chris@16
|
441 this->m_ctrl.upgradable_in = 1;
|
Chris@16
|
442 ++this->m_ctrl.num_upr_shar;
|
Chris@16
|
443 return true;
|
Chris@16
|
444 }
|
Chris@16
|
445
|
Chris@16
|
446 inline void interprocess_upgradable_mutex::unlock_upgradable()
|
Chris@16
|
447 {
|
Chris@16
|
448 scoped_lock_t lck(m_mut);
|
Chris@16
|
449 //Mark that upgradable lock has been acquired
|
Chris@16
|
450 //And add upgradable to the sharable count
|
Chris@16
|
451 this->m_ctrl.upgradable_in = 0;
|
Chris@16
|
452 --this->m_ctrl.num_upr_shar;
|
Chris@16
|
453 this->m_first_gate.notify_all();
|
Chris@16
|
454 }
|
Chris@16
|
455
|
Chris@16
|
456 //Sharable locking
|
Chris@16
|
457
|
Chris@16
|
458 inline void interprocess_upgradable_mutex::lock_sharable()
|
Chris@16
|
459 {
|
Chris@16
|
460 scoped_lock_t lck(m_mut);
|
Chris@16
|
461
|
Chris@16
|
462 //The sharable lock must block in the first gate
|
Chris@16
|
463 //if an exclusive lock has been acquired
|
Chris@16
|
464 //or there are too many sharable locks
|
Chris@16
|
465 while(this->m_ctrl.exclusive_in
|
Chris@16
|
466 || this->m_ctrl.num_upr_shar == constants::max_readers){
|
Chris@16
|
467 this->m_first_gate.wait(lck);
|
Chris@16
|
468 }
|
Chris@16
|
469
|
Chris@16
|
470 //Increment sharable count
|
Chris@16
|
471 ++this->m_ctrl.num_upr_shar;
|
Chris@16
|
472 }
|
Chris@16
|
473
|
Chris@16
|
474 inline bool interprocess_upgradable_mutex::try_lock_sharable()
|
Chris@16
|
475 {
|
Chris@16
|
476 scoped_lock_t lck(m_mut, try_to_lock);
|
Chris@16
|
477
|
Chris@16
|
478 //The sharable lock must fail
|
Chris@16
|
479 //if an exclusive lock has been acquired
|
Chris@16
|
480 //or there are too many sharable locks
|
Chris@16
|
481 if(!lck.owns()
|
Chris@16
|
482 || this->m_ctrl.exclusive_in
|
Chris@16
|
483 || this->m_ctrl.num_upr_shar == constants::max_readers){
|
Chris@16
|
484 return false;
|
Chris@16
|
485 }
|
Chris@16
|
486
|
Chris@16
|
487 //Increment sharable count
|
Chris@16
|
488 ++this->m_ctrl.num_upr_shar;
|
Chris@16
|
489 return true;
|
Chris@16
|
490 }
|
Chris@16
|
491
|
Chris@16
|
492 inline bool interprocess_upgradable_mutex::timed_lock_sharable
|
Chris@16
|
493 (const boost::posix_time::ptime &abs_time)
|
Chris@16
|
494 {
|
Chris@101
|
495 //Mutexes and condvars handle just fine infinite abs_times
|
Chris@101
|
496 //so avoid checking it here
|
Chris@16
|
497 scoped_lock_t lck(m_mut, abs_time);
|
Chris@16
|
498 if(!lck.owns()) return false;
|
Chris@16
|
499
|
Chris@16
|
500 //The sharable lock must block in the first gate
|
Chris@16
|
501 //if an exclusive lock has been acquired
|
Chris@16
|
502 //or there are too many sharable locks
|
Chris@16
|
503 while (this->m_ctrl.exclusive_in
|
Chris@16
|
504 || this->m_ctrl.num_upr_shar == constants::max_readers){
|
Chris@101
|
505 if(!this->m_first_gate.timed_wait(lck, abs_time)){
|
Chris@16
|
506 if(this->m_ctrl.exclusive_in
|
Chris@16
|
507 || this->m_ctrl.num_upr_shar == constants::max_readers){
|
Chris@16
|
508 return false;
|
Chris@16
|
509 }
|
Chris@16
|
510 break;
|
Chris@16
|
511 }
|
Chris@16
|
512 }
|
Chris@16
|
513
|
Chris@16
|
514 //Increment sharable count
|
Chris@16
|
515 ++this->m_ctrl.num_upr_shar;
|
Chris@16
|
516 return true;
|
Chris@16
|
517 }
|
Chris@16
|
518
|
Chris@16
|
519 inline void interprocess_upgradable_mutex::unlock_sharable()
|
Chris@16
|
520 {
|
Chris@16
|
521 scoped_lock_t lck(m_mut);
|
Chris@16
|
522 //Decrement sharable count
|
Chris@16
|
523 --this->m_ctrl.num_upr_shar;
|
Chris@16
|
524 if (this->m_ctrl.num_upr_shar == 0){
|
Chris@16
|
525 this->m_second_gate.notify_one();
|
Chris@16
|
526 }
|
Chris@16
|
527 //Check if there are blocked sharables because of
|
Chris@16
|
528 //there were too many sharables
|
Chris@16
|
529 else if(this->m_ctrl.num_upr_shar == (constants::max_readers-1)){
|
Chris@16
|
530 this->m_first_gate.notify_all();
|
Chris@16
|
531 }
|
Chris@16
|
532 }
|
Chris@16
|
533
|
Chris@16
|
534 //Downgrading
|
Chris@16
|
535
|
Chris@16
|
536 inline void interprocess_upgradable_mutex::unlock_and_lock_upgradable()
|
Chris@16
|
537 {
|
Chris@16
|
538 scoped_lock_t lck(m_mut);
|
Chris@16
|
539 //Unmark it as exclusive
|
Chris@16
|
540 this->m_ctrl.exclusive_in = 0;
|
Chris@16
|
541 //Mark it as upgradable
|
Chris@16
|
542 this->m_ctrl.upgradable_in = 1;
|
Chris@16
|
543 //The sharable count should be 0 so increment it
|
Chris@16
|
544 this->m_ctrl.num_upr_shar = 1;
|
Chris@16
|
545 //Notify readers that they can enter
|
Chris@16
|
546 m_first_gate.notify_all();
|
Chris@16
|
547 }
|
Chris@16
|
548
|
Chris@16
|
549 inline void interprocess_upgradable_mutex::unlock_and_lock_sharable()
|
Chris@16
|
550 {
|
Chris@16
|
551 scoped_lock_t lck(m_mut);
|
Chris@16
|
552 //Unmark it as exclusive
|
Chris@16
|
553 this->m_ctrl.exclusive_in = 0;
|
Chris@16
|
554 //The sharable count should be 0 so increment it
|
Chris@16
|
555 this->m_ctrl.num_upr_shar = 1;
|
Chris@16
|
556 //Notify readers that they can enter
|
Chris@16
|
557 m_first_gate.notify_all();
|
Chris@16
|
558 }
|
Chris@16
|
559
|
Chris@16
|
560 inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock_sharable()
|
Chris@16
|
561 {
|
Chris@16
|
562 scoped_lock_t lck(m_mut);
|
Chris@16
|
563 //Unmark it as upgradable (we don't have to decrement count)
|
Chris@16
|
564 this->m_ctrl.upgradable_in = 0;
|
Chris@16
|
565 //Notify readers/upgradable that they can enter
|
Chris@16
|
566 m_first_gate.notify_all();
|
Chris@16
|
567 }
|
Chris@16
|
568
|
Chris@16
|
569 //Upgrading
|
Chris@16
|
570
|
Chris@16
|
571 inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock()
|
Chris@16
|
572 {
|
Chris@16
|
573 scoped_lock_t lck(m_mut);
|
Chris@16
|
574 //Simulate unlock_upgradable() without
|
Chris@16
|
575 //notifying sharables.
|
Chris@16
|
576 this->m_ctrl.upgradable_in = 0;
|
Chris@16
|
577 --this->m_ctrl.num_upr_shar;
|
Chris@16
|
578 //Execute the second half of exclusive locking
|
Chris@16
|
579 this->m_ctrl.exclusive_in = 1;
|
Chris@16
|
580
|
Chris@16
|
581 //Prepare rollback
|
Chris@16
|
582 upgradable_to_exclusive_rollback rollback(m_ctrl);
|
Chris@16
|
583
|
Chris@16
|
584 while (this->m_ctrl.num_upr_shar){
|
Chris@16
|
585 this->m_second_gate.wait(lck);
|
Chris@16
|
586 }
|
Chris@16
|
587 rollback.release();
|
Chris@16
|
588 }
|
Chris@16
|
589
|
Chris@16
|
590 inline bool interprocess_upgradable_mutex::try_unlock_upgradable_and_lock()
|
Chris@16
|
591 {
|
Chris@16
|
592 scoped_lock_t lck(m_mut, try_to_lock);
|
Chris@16
|
593 //Check if there are no readers
|
Chris@16
|
594 if(!lck.owns()
|
Chris@16
|
595 || this->m_ctrl.num_upr_shar != 1){
|
Chris@16
|
596 return false;
|
Chris@16
|
597 }
|
Chris@16
|
598 //Now unlock upgradable and mark exclusive
|
Chris@16
|
599 this->m_ctrl.upgradable_in = 0;
|
Chris@16
|
600 --this->m_ctrl.num_upr_shar;
|
Chris@16
|
601 this->m_ctrl.exclusive_in = 1;
|
Chris@16
|
602 return true;
|
Chris@16
|
603 }
|
Chris@16
|
604
|
Chris@16
|
605 inline bool interprocess_upgradable_mutex::timed_unlock_upgradable_and_lock
|
Chris@16
|
606 (const boost::posix_time::ptime &abs_time)
|
Chris@16
|
607 {
|
Chris@101
|
608 //Mutexes and condvars handle just fine infinite abs_times
|
Chris@101
|
609 //so avoid checking it here
|
Chris@16
|
610 scoped_lock_t lck(m_mut, abs_time);
|
Chris@16
|
611 if(!lck.owns()) return false;
|
Chris@16
|
612
|
Chris@16
|
613 //Simulate unlock_upgradable() without
|
Chris@16
|
614 //notifying sharables.
|
Chris@16
|
615 this->m_ctrl.upgradable_in = 0;
|
Chris@16
|
616 --this->m_ctrl.num_upr_shar;
|
Chris@16
|
617 //Execute the second half of exclusive locking
|
Chris@16
|
618 this->m_ctrl.exclusive_in = 1;
|
Chris@16
|
619
|
Chris@16
|
620 //Prepare rollback
|
Chris@16
|
621 upgradable_to_exclusive_rollback rollback(m_ctrl);
|
Chris@16
|
622
|
Chris@16
|
623 while (this->m_ctrl.num_upr_shar){
|
Chris@16
|
624 if(!this->m_second_gate.timed_wait(lck, abs_time)){
|
Chris@16
|
625 if(this->m_ctrl.num_upr_shar){
|
Chris@16
|
626 return false;
|
Chris@16
|
627 }
|
Chris@16
|
628 break;
|
Chris@16
|
629 }
|
Chris@16
|
630 }
|
Chris@16
|
631 rollback.release();
|
Chris@16
|
632 return true;
|
Chris@16
|
633 }
|
Chris@16
|
634
|
Chris@16
|
635 inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock()
|
Chris@16
|
636 {
|
Chris@16
|
637 scoped_lock_t lck(m_mut, try_to_lock);
|
Chris@16
|
638
|
Chris@16
|
639 //If we can't lock or any has there is any exclusive, upgradable
|
Chris@16
|
640 //or sharable mark return false;
|
Chris@16
|
641 if(!lck.owns()
|
Chris@16
|
642 || this->m_ctrl.exclusive_in
|
Chris@16
|
643 || this->m_ctrl.upgradable_in
|
Chris@16
|
644 || this->m_ctrl.num_upr_shar != 1){
|
Chris@16
|
645 return false;
|
Chris@16
|
646 }
|
Chris@16
|
647 this->m_ctrl.exclusive_in = 1;
|
Chris@16
|
648 this->m_ctrl.num_upr_shar = 0;
|
Chris@16
|
649 return true;
|
Chris@16
|
650 }
|
Chris@16
|
651
|
Chris@16
|
652 inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock_upgradable()
|
Chris@16
|
653 {
|
Chris@16
|
654 scoped_lock_t lck(m_mut, try_to_lock);
|
Chris@16
|
655
|
Chris@16
|
656 //The upgradable lock must fail
|
Chris@16
|
657 //if an exclusive or upgradable lock has been acquired
|
Chris@16
|
658 if(!lck.owns()
|
Chris@16
|
659 || this->m_ctrl.exclusive_in
|
Chris@16
|
660 || this->m_ctrl.upgradable_in){
|
Chris@16
|
661 return false;
|
Chris@16
|
662 }
|
Chris@16
|
663
|
Chris@16
|
664 //Mark that upgradable lock has been acquired
|
Chris@16
|
665 this->m_ctrl.upgradable_in = 1;
|
Chris@16
|
666 return true;
|
Chris@16
|
667 }
|
Chris@16
|
668
|
Chris@101
|
669 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
Chris@16
|
670
|
Chris@16
|
671 } //namespace interprocess {
|
Chris@16
|
672 } //namespace boost {
|
Chris@16
|
673
|
Chris@16
|
674
|
Chris@16
|
675 #include <boost/interprocess/detail/config_end.hpp>
|
Chris@16
|
676
|
Chris@16
|
677 #endif //BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
|