1// Distributed under the Boost Software License, Version 1.0. (See
2// accompanying file LICENSE_1_0.txt or copy at
3// http://www.boost.org/LICENSE_1_0.txt)
4// (C) Copyright 2007 Anthony Williams
5// (C) Copyright 2011-2012 Vicente J. Botet Escriba
6
7#ifndef BOOST_THREAD_LOCK_TYPES_HPP
8#define BOOST_THREAD_LOCK_TYPES_HPP
9
10#include <boost/thread/detail/config.hpp>
11#include <boost/thread/detail/move.hpp>
12#include <boost/thread/exceptions.hpp>
13#include <boost/thread/lock_options.hpp>
14#include <boost/thread/lockable_traits.hpp>
15#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
16#include <boost/thread/is_locked_by_this_thread.hpp>
17#endif
18#include <boost/thread/thread_time.hpp>
19
20#include <boost/assert.hpp>
21#ifdef BOOST_THREAD_USES_CHRONO
22#include <boost/chrono/time_point.hpp>
23#include <boost/chrono/duration.hpp>
24#endif
25#include <boost/detail/workaround.hpp>
26
27#include <boost/config/abi_prefix.hpp>
28
29namespace boost
30{
31 struct xtime;
32
33 template <typename Mutex>
34 class shared_lock;
35
36 template <typename Mutex>
37 class upgrade_lock;
38
39 template <typename Mutex>
40 class unique_lock;
41
42 namespace detail
43 {
44 template <typename Mutex>
45 class try_lock_wrapper;
46 }
47
48#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
49 namespace sync
50 {
51 template<typename T>
52 struct is_basic_lockable<unique_lock<T> >
53 {
54 BOOST_STATIC_CONSTANT(bool, value = true);
55 };
56 template<typename T>
57 struct is_lockable<unique_lock<T> >
58 {
59 BOOST_STATIC_CONSTANT(bool, value = true);
60 };
61
62 template<typename T>
63 struct is_basic_lockable<shared_lock<T> >
64 {
65 BOOST_STATIC_CONSTANT(bool, value = true);
66 };
67 template<typename T>
68 struct is_lockable<shared_lock<T> >
69 {
70 BOOST_STATIC_CONSTANT(bool, value = true);
71 };
72
73 template<typename T>
74 struct is_basic_lockable<upgrade_lock<T> >
75 {
76 BOOST_STATIC_CONSTANT(bool, value = true);
77 };
78 template<typename T>
79 struct is_lockable<upgrade_lock<T> >
80 {
81 BOOST_STATIC_CONSTANT(bool, value = true);
82 };
83
84 template<typename T>
85 struct is_basic_lockable<detail::try_lock_wrapper<T> >
86 {
87 BOOST_STATIC_CONSTANT(bool, value = true);
88 };
89 template<typename T>
90 struct is_lockable<detail::try_lock_wrapper<T> >
91 {
92 BOOST_STATIC_CONSTANT(bool, value = true);
93 };
94 }
95#endif
96
97
98 template <typename Mutex>
99 class unique_lock
100 {
101 private:
102 Mutex* m;
103 bool is_locked;
104
105 private:
106 explicit unique_lock(upgrade_lock<Mutex>&);
107 unique_lock& operator=(upgrade_lock<Mutex>& other);
108 public:
109 typedef Mutex mutex_type;
110 BOOST_THREAD_MOVABLE_ONLY( unique_lock)
111
112#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF.
113#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
114 unique_lock(const volatile unique_lock&);
115#endif
116#endif
117 unique_lock()BOOST_NOEXCEPT :
118 m(0),is_locked(false)
119 {}
120
121 explicit unique_lock(Mutex& m_) :
122 m(&m_), is_locked(false)
123 {
124 lock();
125 }
126 unique_lock(Mutex& m_, adopt_lock_t) :
127 m(&m_), is_locked(true)
128 {
129#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
130 BOOST_ASSERT(is_locked_by_this_thread(m));
131#endif
132 }
133 unique_lock(Mutex& m_, defer_lock_t)BOOST_NOEXCEPT:
134 m(&m_),is_locked(false)
135 {}
136 unique_lock(Mutex& m_, try_to_lock_t) :
137 m(&m_), is_locked(false)
138 {
139 try_lock();
140 }
141#if defined BOOST_THREAD_USES_DATETIME
142 template<typename TimeDuration>
143 unique_lock(Mutex& m_,TimeDuration const& target_time):
144 m(&m_),is_locked(false)
145 {
146 timed_lock(target_time);
147 }
148 unique_lock(Mutex& m_,system_time const& target_time):
149 m(&m_),is_locked(false)
150 {
151 timed_lock(target_time);
152 }
153#endif
154#ifdef BOOST_THREAD_USES_CHRONO
155 template <class Clock, class Duration>
156 unique_lock(Mutex& mtx, const chrono::time_point<Clock, Duration>& t)
157 : m(&mtx), is_locked(mtx.try_lock_until(t))
158 {
159 }
160 template <class Rep, class Period>
161 unique_lock(Mutex& mtx, const chrono::duration<Rep, Period>& d)
162 : m(&mtx), is_locked(mtx.try_lock_for(d))
163 {
164 }
165#endif
166
167 unique_lock(BOOST_THREAD_RV_REF(unique_lock) other) BOOST_NOEXCEPT:
168 m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked)
169 {
170 BOOST_THREAD_RV(other).is_locked=false;
171 BOOST_THREAD_RV(other).m=0;
172 }
173
174 BOOST_THREAD_EXPLICIT_LOCK_CONVERSION unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other);
175
176#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
177 //std-2104 unique_lock move-assignment should not be noexcept
178 unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT
179 {
180 unique_lock temp(::boost::move(other));
181 swap(temp);
182 return *this;
183 }
184#endif
185
186 //std-2104 unique_lock move-assignment should not be noexcept
187 unique_lock& operator=(BOOST_THREAD_RV_REF(unique_lock) other) //BOOST_NOEXCEPT
188 {
189 unique_lock temp(::boost::move(other));
190 swap(temp);
191 return *this;
192 }
193#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF.
194#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
195 unique_lock& operator=(unique_lock<Mutex> other)
196 {
197 swap(other);
198 return *this;
199 }
200#endif // BOOST_WORKAROUND
201#endif
202
203 // Conversion from upgrade locking
204 unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<mutex_type> BOOST_THREAD_RV_REF_END ul, try_to_lock_t)
205 : m(0),is_locked(false)
206 {
207 if (BOOST_THREAD_RV(ul).owns_lock())
208 {
209 if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock())
210 {
211 m = BOOST_THREAD_RV(ul).release();
212 is_locked = true;
213 }
214 }
215 else
216 {
217 m = BOOST_THREAD_RV(ul).release();
218 }
219 }
220
221#ifdef BOOST_THREAD_USES_CHRONO
222 template <class Clock, class Duration>
223 unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<mutex_type> BOOST_THREAD_RV_REF_END ul,
224 const chrono::time_point<Clock, Duration>& abs_time)
225 : m(0),is_locked(false)
226 {
227 if (BOOST_THREAD_RV(ul).owns_lock())
228 {
229 if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock_until(abs_time))
230 {
231 m = BOOST_THREAD_RV(ul).release();
232 is_locked = true;
233 }
234 }
235 else
236 {
237 m = BOOST_THREAD_RV(ul).release();
238 }
239 }
240
241 template <class Rep, class Period>
242 unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<mutex_type> BOOST_THREAD_RV_REF_END ul,
243 const chrono::duration<Rep, Period>& rel_time)
244 : m(0),is_locked(false)
245 {
246 if (BOOST_THREAD_RV(ul).owns_lock())
247 {
248 if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock_for(rel_time))
249 {
250 m = BOOST_THREAD_RV(ul).release();
251 is_locked = true;
252 }
253 }
254 else
255 {
256 m = BOOST_THREAD_RV(ul).release();
257 }
258 }
259#endif
260
261#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
262 // Conversion from shared locking
263 unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, try_to_lock_t)
264 : m(0),is_locked(false)
265 {
266 if (BOOST_THREAD_RV(sl).owns_lock())
267 {
268 if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock())
269 {
270 m = BOOST_THREAD_RV(sl).release();
271 is_locked = true;
272 }
273 }
274 else
275 {
276 m = BOOST_THREAD_RV(sl).release();
277 }
278 }
279
280#ifdef BOOST_THREAD_USES_CHRONO
281 template <class Clock, class Duration>
282 unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl,
283 const chrono::time_point<Clock, Duration>& abs_time)
284 : m(0),is_locked(false)
285 {
286 if (BOOST_THREAD_RV(sl).owns_lock())
287 {
288 if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_until(abs_time))
289 {
290 m = BOOST_THREAD_RV(sl).release();
291 is_locked = true;
292 }
293 }
294 else
295 {
296 m = BOOST_THREAD_RV(sl).release();
297 }
298 }
299
300 template <class Rep, class Period>
301 unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl,
302 const chrono::duration<Rep, Period>& rel_time)
303 : m(0),is_locked(false)
304 {
305 if (BOOST_THREAD_RV(sl).owns_lock())
306 {
307 if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_for(rel_time))
308 {
309 m = BOOST_THREAD_RV(sl).release();
310 is_locked = true;
311 }
312 }
313 else
314 {
315 m = BOOST_THREAD_RV(sl).release();
316 }
317 }
318#endif // BOOST_THREAD_USES_CHRONO
319#endif // BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
320
321 void swap(unique_lock& other)BOOST_NOEXCEPT
322 {
323 std::swap(m,other.m);
324 std::swap(is_locked,other.is_locked);
325 }
326
327 ~unique_lock()
328 {
329 if (owns_lock())
330 {
331 m->unlock();
332 }
333 }
334 void lock()
335 {
336 if (m == 0)
337 {
338 boost::throw_exception(
339 boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
340 }
341 if (owns_lock())
342 {
343 boost::throw_exception(
344 boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
345 }
346 m->lock();
347 is_locked = true;
348 }
349 bool try_lock()
350 {
351 if (m == 0)
352 {
353 boost::throw_exception(
354 boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
355 }
356 if (owns_lock())
357 {
358 boost::throw_exception(
359 boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
360 }
361 is_locked = m->try_lock();
362 return is_locked;
363 }
364#if defined BOOST_THREAD_USES_DATETIME
365 template<typename TimeDuration>
366 bool timed_lock(TimeDuration const& relative_time)
367 {
368 if(m==0)
369 {
370 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
371 }
372 if(owns_lock())
373 {
374 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
375 }
376 is_locked=m->timed_lock(relative_time);
377 return is_locked;
378 }
379
380 bool timed_lock(::boost::system_time const& absolute_time)
381 {
382 if(m==0)
383 {
384 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
385 }
386 if(owns_lock())
387 {
388 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
389 }
390 is_locked=m->timed_lock(absolute_time);
391 return is_locked;
392 }
393 bool timed_lock(::boost::xtime const& absolute_time)
394 {
395 if(m==0)
396 {
397 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
398 }
399 if(owns_lock())
400 {
401 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
402 }
403 is_locked=m->timed_lock(absolute_time);
404 return is_locked;
405 }
406#endif
407#ifdef BOOST_THREAD_USES_CHRONO
408
409 template <class Rep, class Period>
410 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
411 {
412 if(m==0)
413 {
414 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
415 }
416 if(owns_lock())
417 {
418 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
419 }
420 is_locked=m->try_lock_for(rel_time);
421 return is_locked;
422 }
423 template <class Clock, class Duration>
424 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
425 {
426 if(m==0)
427 {
428 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
429 }
430 if(owns_lock())
431 {
432 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
433 }
434 is_locked=m->try_lock_until(abs_time);
435 return is_locked;
436 }
437#endif
438
439 void unlock()
440 {
441 if (m == 0)
442 {
443 boost::throw_exception(
444 boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
445 }
446 if (!owns_lock())
447 {
448 boost::throw_exception(
449 boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock doesn't own the mutex"));
450 }
451 m->unlock();
452 is_locked = false;
453 }
454
455#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
456 typedef void (unique_lock::*bool_type)();
457 operator bool_type() const BOOST_NOEXCEPT
458 {
459 return is_locked?&unique_lock::lock:0;
460 }
461 bool operator!() const BOOST_NOEXCEPT
462 {
463 return !owns_lock();
464 }
465#else
466 explicit operator bool() const BOOST_NOEXCEPT
467 {
468 return owns_lock();
469 }
470#endif
471 bool owns_lock() const BOOST_NOEXCEPT
472 {
473 return is_locked;
474 }
475
476 Mutex* mutex() const BOOST_NOEXCEPT
477 {
478 return m;
479 }
480
481 Mutex* release()BOOST_NOEXCEPT
482 {
483 Mutex* const res=m;
484 m=0;
485 is_locked=false;
486 return res;
487 }
488
489 friend class shared_lock<Mutex> ;
490 friend class upgrade_lock<Mutex> ;
491 };
492
493 template<typename Mutex>
494 void swap(unique_lock<Mutex>& lhs, unique_lock<Mutex>& rhs)
495 BOOST_NOEXCEPT
496 {
497 lhs.swap(rhs);
498 }
499
500 BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) unique_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END
501
502 template<typename Mutex>
503 class shared_lock
504 {
505 protected:
506 Mutex* m;
507 bool is_locked;
508
509 public:
510 typedef Mutex mutex_type;
511 BOOST_THREAD_MOVABLE_ONLY(shared_lock)
512
513 shared_lock() BOOST_NOEXCEPT:
514 m(0),is_locked(false)
515 {}
516
517 explicit shared_lock(Mutex& m_):
518 m(&m_),is_locked(false)
519 {
520 lock();
521 }
522 shared_lock(Mutex& m_,adopt_lock_t):
523 m(&m_),is_locked(true)
524 {
525#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
526 BOOST_ASSERT(is_locked_by_this_thread(m));
527#endif
528 }
529 shared_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT:
530 m(&m_),is_locked(false)
531 {}
532 shared_lock(Mutex& m_,try_to_lock_t):
533 m(&m_),is_locked(false)
534 {
535 try_lock();
536 }
537#if defined BOOST_THREAD_USES_DATETIME
538 shared_lock(Mutex& m_,system_time const& target_time):
539 m(&m_),is_locked(false)
540 {
541 timed_lock(target_time);
542 }
543#endif
544#ifdef BOOST_THREAD_USES_CHRONO
545 template <class Clock, class Duration>
546 shared_lock(Mutex& mtx, const chrono::time_point<Clock, Duration>& t)
547 : m(&mtx), is_locked(mtx.try_lock_shared_until(t))
548 {
549 }
550 template <class Rep, class Period>
551 shared_lock(Mutex& mtx, const chrono::duration<Rep, Period>& d)
552 : m(&mtx), is_locked(mtx.try_lock_shared_for(d))
553 {
554 }
555#endif
556
557 shared_lock(BOOST_THREAD_RV_REF_BEG shared_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT:
558 m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked)
559 {
560 BOOST_THREAD_RV(other).is_locked=false;
561 BOOST_THREAD_RV(other).m=0;
562 }
563
564 BOOST_THREAD_EXPLICIT_LOCK_CONVERSION shared_lock(BOOST_THREAD_RV_REF_BEG unique_lock<Mutex> BOOST_THREAD_RV_REF_END other):
565 m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked)
566 {
567 if(is_locked)
568 {
569 m->unlock_and_lock_shared();
570 }
571 BOOST_THREAD_RV(other).is_locked=false;
572 BOOST_THREAD_RV(other).m=0;
573 }
574
575 BOOST_THREAD_EXPLICIT_LOCK_CONVERSION shared_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other):
576 m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked)
577 {
578 if(is_locked)
579 {
580 m->unlock_upgrade_and_lock_shared();
581 }
582 BOOST_THREAD_RV(other).is_locked=false;
583 BOOST_THREAD_RV(other).m=0;
584 }
585
586 //std-2104 unique_lock move-assignment should not be noexcept
587 shared_lock& operator=(BOOST_THREAD_RV_REF_BEG shared_lock<Mutex> BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT
588 {
589 shared_lock temp(::boost::move(other));
590 swap(temp);
591 return *this;
592 }
593#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
594 shared_lock& operator=(BOOST_THREAD_RV_REF_BEG unique_lock<Mutex> BOOST_THREAD_RV_REF_END other)
595 {
596 shared_lock temp(::boost::move(other));
597 swap(temp);
598 return *this;
599 }
600
601 shared_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other)
602 {
603 shared_lock temp(::boost::move(other));
604 swap(temp);
605 return *this;
606 }
607#endif
608
609 void swap(shared_lock& other) BOOST_NOEXCEPT
610 {
611 std::swap(m,other.m);
612 std::swap(is_locked,other.is_locked);
613 }
614
615 Mutex* mutex() const BOOST_NOEXCEPT
616 {
617 return m;
618 }
619
620 Mutex* release() BOOST_NOEXCEPT
621 {
622 Mutex* const res=m;
623 m=0;
624 is_locked=false;
625 return res;
626 }
627
628 ~shared_lock()
629 {
630 if(owns_lock())
631 {
632 m->unlock_shared();
633 }
634 }
635 void lock()
636 {
637 if(m==0)
638 {
639 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
640 }
641 if(owns_lock())
642 {
643 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
644 }
645 m->lock_shared();
646 is_locked=true;
647 }
648 bool try_lock()
649 {
650 if(m==0)
651 {
652 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
653 }
654 if(owns_lock())
655 {
656 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
657 }
658 is_locked=m->try_lock_shared();
659 return is_locked;
660 }
661#if defined BOOST_THREAD_USES_DATETIME
662 bool timed_lock(boost::system_time const& target_time)
663 {
664 if(m==0)
665 {
666 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
667 }
668 if(owns_lock())
669 {
670 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
671 }
672 is_locked=m->timed_lock_shared(target_time);
673 return is_locked;
674 }
675 template<typename Duration>
676 bool timed_lock(Duration const& target_time)
677 {
678 if(m==0)
679 {
680 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
681 }
682 if(owns_lock())
683 {
684 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
685 }
686 is_locked=m->timed_lock_shared(target_time);
687 return is_locked;
688 }
689#endif
690#ifdef BOOST_THREAD_USES_CHRONO
691 template <class Rep, class Period>
692 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
693 {
694 if(m==0)
695 {
696 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
697 }
698 if(owns_lock())
699 {
700 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
701 }
702 is_locked=m->try_lock_shared_for(rel_time);
703 return is_locked;
704 }
705 template <class Clock, class Duration>
706 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
707 {
708 if(m==0)
709 {
710 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
711 }
712 if(owns_lock())
713 {
714 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
715 }
716 is_locked=m->try_lock_shared_until(abs_time);
717 return is_locked;
718 }
719#endif
720 void unlock()
721 {
722 if(m==0)
723 {
724 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
725 }
726 if(!owns_lock())
727 {
728 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock doesn't own the mutex"));
729 }
730 m->unlock_shared();
731 is_locked=false;
732 }
733
734#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
735 typedef void (shared_lock<Mutex>::*bool_type)();
736 operator bool_type() const BOOST_NOEXCEPT
737 {
738 return is_locked?&shared_lock::lock:0;
739 }
740 bool operator!() const BOOST_NOEXCEPT
741 {
742 return !owns_lock();
743 }
744#else
745 explicit operator bool() const BOOST_NOEXCEPT
746 {
747 return owns_lock();
748 }
749#endif
750 bool owns_lock() const BOOST_NOEXCEPT
751 {
752 return is_locked;
753 }
754
755 };
756
757 BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) shared_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END
758
759 template<typename Mutex>
760 void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs) BOOST_NOEXCEPT
761 {
762 lhs.swap(rhs);
763 }
764
765 template <typename Mutex>
766 class upgrade_lock
767 {
768 protected:
769 Mutex* m;
770 bool is_locked;
771
772 public:
773 typedef Mutex mutex_type;
774 BOOST_THREAD_MOVABLE_ONLY( upgrade_lock)
775
776 upgrade_lock()BOOST_NOEXCEPT:
777 m(0),is_locked(false)
778 {}
779
780 explicit upgrade_lock(Mutex& m_) :
781 m(&m_), is_locked(false)
782 {
783 lock();
784 }
785 upgrade_lock(Mutex& m_, adopt_lock_t) :
786 m(&m_), is_locked(true)
787 {
788#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
789 BOOST_ASSERT(is_locked_by_this_thread(m));
790#endif
791 }
792 upgrade_lock(Mutex& m_, defer_lock_t)BOOST_NOEXCEPT:
793 m(&m_),is_locked(false)
794 {}
795 upgrade_lock(Mutex& m_, try_to_lock_t) :
796 m(&m_), is_locked(false)
797 {
798 try_lock();
799 }
800
801#ifdef BOOST_THREAD_USES_CHRONO
802 template <class Clock, class Duration>
803 upgrade_lock(Mutex& mtx, const chrono::time_point<Clock, Duration>& t)
804 : m(&mtx), is_locked(mtx.try_lock_upgrade_until(t))
805 {
806 }
807 template <class Rep, class Period>
808 upgrade_lock(Mutex& mtx, const chrono::duration<Rep, Period>& d)
809 : m(&mtx), is_locked(mtx.try_lock_upgrade_for(d))
810 {
811 }
812#endif
813
814 upgrade_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT:
815 m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked)
816 {
817 BOOST_THREAD_RV(other).is_locked=false;
818 BOOST_THREAD_RV(other).m=0;
819 }
820
821 BOOST_THREAD_EXPLICIT_LOCK_CONVERSION upgrade_lock(BOOST_THREAD_RV_REF_BEG unique_lock<Mutex> BOOST_THREAD_RV_REF_END other):
822 m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked)
823 {
824 if(is_locked)
825 {
826 m->unlock_and_lock_upgrade();
827 }
828 BOOST_THREAD_RV(other).is_locked=false;
829 BOOST_THREAD_RV(other).m=0;
830 }
831
832 //std-2104 unique_lock move-assignment should not be noexcept
833 upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT
834 {
835 upgrade_lock temp(::boost::move(other));
836 swap(temp);
837 return *this;
838 }
839
840#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
841 upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG unique_lock<Mutex> BOOST_THREAD_RV_REF_END other)
842 {
843 upgrade_lock temp(::boost::move(other));
844 swap(temp);
845 return *this;
846 }
847#endif
848
849#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
850 // Conversion from shared locking
851 upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, try_to_lock_t)
852 : m(0),is_locked(false)
853 {
854 if (BOOST_THREAD_RV(sl).owns_lock())
855 {
856 if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade())
857 {
858 m = BOOST_THREAD_RV(sl).release();
859 is_locked = true;
860 }
861 }
862 else
863 {
864 m = BOOST_THREAD_RV(sl).release();
865 }
866 }
867
868#ifdef BOOST_THREAD_USES_CHRONO
869 template <class Clock, class Duration>
870 upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl,
871 const chrono::time_point<Clock, Duration>& abs_time)
872 : m(0),is_locked(false)
873 {
874 if (BOOST_THREAD_RV(sl).owns_lock())
875 {
876 if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade_until(abs_time))
877 {
878 m = BOOST_THREAD_RV(sl).release();
879 is_locked = true;
880 }
881 }
882 else
883 {
884 m = BOOST_THREAD_RV(sl).release();
885 }
886 }
887
888 template <class Rep, class Period>
889 upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl,
890 const chrono::duration<Rep, Period>& rel_time)
891 : m(0),is_locked(false)
892 {
893 if (BOOST_THREAD_RV(sl).owns_lock())
894 {
895 if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade_for(rel_time))
896 {
897 m = BOOST_THREAD_RV(sl).release();
898 is_locked = true;
899 }
900 }
901 else
902 {
903 m = BOOST_THREAD_RV(sl).release();
904 }
905 }
906#endif // BOOST_THREAD_USES_CHRONO
907#endif // BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
908 void swap(upgrade_lock& other)BOOST_NOEXCEPT
909 {
910 std::swap(m,other.m);
911 std::swap(is_locked,other.is_locked);
912 }
913 Mutex* mutex() const BOOST_NOEXCEPT
914 {
915 return m;
916 }
917
918 Mutex* release()BOOST_NOEXCEPT
919 {
920 Mutex* const res=m;
921 m=0;
922 is_locked=false;
923 return res;
924 }
925 ~upgrade_lock()
926 {
927 if (owns_lock())
928 {
929 m->unlock_upgrade();
930 }
931 }
932 void lock()
933 {
934 if (m == 0)
935 {
936 boost::throw_exception(
937 boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
938 }
939 if (owns_lock())
940 {
941 boost::throw_exception(
942 boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost upgrade_lock owns already the mutex"));
943 }
944 m->lock_upgrade();
945 is_locked = true;
946 }
947 bool try_lock()
948 {
949 if (m == 0)
950 {
951 boost::throw_exception(
952 boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
953 }
954 if (owns_lock())
955 {
956 boost::throw_exception(
957 boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost upgrade_lock owns already the mutex"));
958 }
959 is_locked = m->try_lock_upgrade();
960 return is_locked;
961 }
962 void unlock()
963 {
964 if (m == 0)
965 {
966 boost::throw_exception(
967 boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
968 }
969 if (!owns_lock())
970 {
971 boost::throw_exception(
972 boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost upgrade_lock doesn't own the mutex"));
973 }
974 m->unlock_upgrade();
975 is_locked = false;
976 }
977#ifdef BOOST_THREAD_USES_CHRONO
978 template <class Rep, class Period>
979 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
980 {
981 if(m==0)
982 {
983 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
984 }
985 if(owns_lock())
986 {
987 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
988 }
989 is_locked=m->try_lock_upgrade_for(rel_time);
990 return is_locked;
991 }
992 template <class Clock, class Duration>
993 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
994 {
995 if(m==0)
996 {
997 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
998 }
999 if(owns_lock())
1000 {
1001 boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
1002 }
1003 is_locked=m->try_lock_upgrade_until(abs_time);
1004 return is_locked;
1005 }
1006#endif
1007#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
1008 typedef void (upgrade_lock::*bool_type)();
1009 operator bool_type() const BOOST_NOEXCEPT
1010 {
1011 return is_locked?&upgrade_lock::lock:0;
1012 }
1013 bool operator!() const BOOST_NOEXCEPT
1014 {
1015 return !owns_lock();
1016 }
1017#else
1018 explicit operator bool() const BOOST_NOEXCEPT
1019 {
1020 return owns_lock();
1021 }
1022#endif
1023 bool owns_lock() const BOOST_NOEXCEPT
1024 {
1025 return is_locked;
1026 }
1027 friend class shared_lock<Mutex> ;
1028 friend class unique_lock<Mutex> ;
1029 };
1030
1031 template<typename Mutex>
1032 void swap(upgrade_lock<Mutex>& lhs, upgrade_lock<Mutex>& rhs)
1033 BOOST_NOEXCEPT
1034 {
1035 lhs.swap(rhs);
1036 }
1037
1038 BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END
1039
1040 template<typename Mutex>
1041 unique_lock<Mutex>::unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other):
1042 m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked)
1043 {
1044 if(is_locked)
1045 {
1046 m->unlock_upgrade_and_lock();
1047 }
1048 BOOST_THREAD_RV(other).release();
1049 }
1050
1051 template <class Mutex>
1052 class upgrade_to_unique_lock
1053 {
1054 private:
1055 upgrade_lock<Mutex>* source;
1056 unique_lock<Mutex> exclusive;
1057
1058 public:
1059 typedef Mutex mutex_type;
1060 BOOST_THREAD_MOVABLE_ONLY( upgrade_to_unique_lock)
1061
1062 explicit upgrade_to_unique_lock(upgrade_lock<Mutex>& m_) :
1063 source(&m_), exclusive(::boost::move(*source))
1064 {
1065 }
1066 ~upgrade_to_unique_lock()
1067 {
1068 if (source)
1069 {
1070 *source = BOOST_THREAD_MAKE_RV_REF(upgrade_lock<Mutex> (::boost::move(exclusive)));
1071 }
1072 }
1073
1074 upgrade_to_unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT:
1075 source(BOOST_THREAD_RV(other).source),exclusive(::boost::move(BOOST_THREAD_RV(other).exclusive))
1076 {
1077 BOOST_THREAD_RV(other).source=0;
1078 }
1079
1080 //std-2104 unique_lock move-assignment should not be noexcept
1081 upgrade_to_unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock<Mutex> BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT
1082 {
1083 upgrade_to_unique_lock temp(other);
1084 swap(temp);
1085 return *this;
1086 }
1087
1088 void swap(upgrade_to_unique_lock& other)BOOST_NOEXCEPT
1089 {
1090 std::swap(source,other.source);
1091 exclusive.swap(other.exclusive);
1092 }
1093
1094#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
1095 typedef void (upgrade_to_unique_lock::*bool_type)(upgrade_to_unique_lock&);
1096 operator bool_type() const BOOST_NOEXCEPT
1097 {
1098 return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0;
1099 }
1100 bool operator!() const BOOST_NOEXCEPT
1101 {
1102 return !owns_lock();
1103 }
1104#else
1105 explicit operator bool() const BOOST_NOEXCEPT
1106 {
1107 return owns_lock();
1108 }
1109#endif
1110
1111 bool owns_lock() const BOOST_NOEXCEPT
1112 {
1113 return exclusive.owns_lock();
1114 }
1115 Mutex* mutex() const BOOST_NOEXCEPT
1116 {
1117 return exclusive.mutex();
1118 }
1119 };
1120
1121BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_to_unique_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END
1122
1123namespace detail
1124{
1125 template<typename Mutex>
1126 class try_lock_wrapper:
1127private unique_lock<Mutex>
1128 {
1129 typedef unique_lock<Mutex> base;
1130 public:
1131 BOOST_THREAD_MOVABLE_ONLY(try_lock_wrapper)
1132
1133 try_lock_wrapper()
1134 {}
1135
1136 explicit try_lock_wrapper(Mutex& m):
1137 base(m,try_to_lock)
1138 {}
1139
1140 try_lock_wrapper(Mutex& m_,adopt_lock_t):
1141 base(m_,adopt_lock)
1142 {
1143#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
1144 BOOST_ASSERT(is_locked_by_this_thread(m_));
1145#endif
1146 }
1147 try_lock_wrapper(Mutex& m_,defer_lock_t):
1148 base(m_,defer_lock)
1149 {}
1150 try_lock_wrapper(Mutex& m_,try_to_lock_t):
1151 base(m_,try_to_lock)
1152 {}
1153#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
1154 try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other):
1155 base(::boost::move(other))
1156 {}
1157
1158#elif defined BOOST_THREAD_USES_MOVE
1159 try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other):
1160 base(::boost::move(static_cast<base&>(other)))
1161 {}
1162
1163#else
1164 try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other):
1165 base(BOOST_THREAD_RV_REF(base)(*other))
1166 {}
1167#endif
1168 try_lock_wrapper& operator=(BOOST_THREAD_RV_REF_BEG try_lock_wrapper<Mutex> BOOST_THREAD_RV_REF_END other)
1169 {
1170 try_lock_wrapper temp(other);
1171 swap(temp);
1172 return *this;
1173 }
1174 void swap(try_lock_wrapper& other)
1175 {
1176 base::swap(other);
1177 }
1178 void lock()
1179 {
1180 base::lock();
1181 }
1182 bool try_lock()
1183 {
1184 return base::try_lock();
1185 }
1186 void unlock()
1187 {
1188 base::unlock();
1189 }
1190 bool owns_lock() const
1191 {
1192 return base::owns_lock();
1193 }
1194 Mutex* mutex() const BOOST_NOEXCEPT
1195 {
1196 return base::mutex();
1197 }
1198 Mutex* release()
1199 {
1200 return base::release();
1201 }
1202
1203#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
1204 typedef typename base::bool_type bool_type;
1205 operator bool_type() const
1206 {
1207 return base::operator bool_type();
1208 }
1209 bool operator!() const
1210 {
1211 return !this->owns_lock();
1212 }
1213#else
1214 explicit operator bool() const
1215 {
1216 return owns_lock();
1217 }
1218#endif
1219 };
1220
1221 template<typename Mutex>
1222 void swap(try_lock_wrapper<Mutex>& lhs,try_lock_wrapper<Mutex>& rhs)
1223 {
1224 lhs.swap(rhs);
1225 }
1226}
1227}
1228#include <boost/config/abi_suffix.hpp>
1229
1230#endif
1231