1 /*
2  * Distributed under the Boost Software License, Version 1.0.
3  *    (See accompanying file LICENSE_1_0.txt or copy at
4  *          http://www.boost.org/LICENSE_1_0.txt)
5  *
6  * (C) Copyright 2007-2008 Anthony Williams
7  * (C) Copyright 2011-2012 Vicente J. Botet Escriba
8  * (C) Copyright 2013 Andrey Semashev
9  */
10 /*!
11  * \file   detail/condition_variables/condition_variable_any_generic.hpp
12  *
13  * \brief  This header is the Boost.Sync library implementation, see the library documentation
14  *         at http://www.boost.org/doc/libs/release/libs/sync/doc/html/index.html.
15  */
16 
17 #ifndef BOOST_SYNC_DETAIL_CONDITION_VARIABLES_CONDITION_VARIABLE_ANY_GENERIC_HPP_INCLUDED_
18 #define BOOST_SYNC_DETAIL_CONDITION_VARIABLES_CONDITION_VARIABLE_ANY_GENERIC_HPP_INCLUDED_
19 
20 #include <cstddef>
21 #include <boost/utility/enable_if.hpp>
22 #include <boost/sync/detail/config.hpp>
23 #include <boost/sync/detail/time_traits.hpp>
24 #include <boost/sync/locks/lock_guard.hpp>
25 #include <boost/sync/locks/unique_lock.hpp>
26 #include <boost/sync/mutexes/mutex.hpp>
27 #include <boost/sync/condition_variables/condition_variable.hpp>
28 #include <boost/sync/condition_variables/cv_status.hpp>
29 #include <boost/sync/detail/header.hpp>
30 
31 #ifdef BOOST_HAS_PRAGMA_ONCE
32 #pragma once
33 #endif
34 
35 namespace boost {
36 
37 namespace sync {
38 
39 BOOST_SYNC_DETAIL_OPEN_ABI_NAMESPACE {
40 
41 class condition_variable_any
42 {
43 private:
44     template< typename Lock >
45     class relocker
46     {
47     private:
48         Lock* m_lock;
49 
50     public:
51         relocker() : m_lock(NULL) {}
52 
53         ~relocker() BOOST_NOEXCEPT_IF(false)
54         {
55             if (m_lock)
56                 m_lock->lock();
57         }
58 
59         void unlock(Lock& lock)
60         {
61             lock.unlock();
62             m_lock = &lock;
63         }
64     };
65 
66 private:
67     sync::mutex m_mutex;
68     sync::condition_variable m_cond;
69 
70 public:
71 #if defined(BOOST_SYNC_DEFINES_MUTEX_CONSTEXPR_CONSTRUCTOR) && defined(BOOST_SYNC_DEFINES_CONDITION_VARIABLE_CONSTEXPR_CONSTRUCTOR)
72 #define BOOST_SYNC_DEFINES_CONDITION_VARIABLE_ANY_CONSTEXPR_CONSTRUCTOR
73     BOOST_DEFAULTED_FUNCTION(BOOST_CONSTEXPR condition_variable_any() BOOST_NOEXCEPT, {})
74 #else
75     BOOST_DEFAULTED_FUNCTION(condition_variable_any(), {})
76 #endif
77 
78     void notify_one()
79     {
80         sync::lock_guard< sync::mutex > internal_lock(m_mutex);
81         m_cond.notify_one();
82     }
83 
84     void notify_all()
85     {
86         sync::lock_guard< sync::mutex > internal_lock(m_mutex);
87         m_cond.notify_all();
88     }
89 
90     template< typename Lock >
91     void wait(Lock& lock)
92     {
93         relocker< Lock > relock_guard;
94         sync::unique_lock< sync::mutex > internal_lock(m_mutex);
95         relock_guard.unlock(lock);
96         m_cond.wait(internal_lock);
97     }
98 
99     template< typename Lock, typename Predicate >
100     void wait(Lock& lock, Predicate pred)
101     {
102         while (!pred())
103             this->wait(lock);
104     }
105 
106     template< typename Lock, typename Time >
107     typename enable_if_c< sync::detail::time_traits< Time >::is_specialized, bool >::type
108     timed_wait(Lock& lock, Time const& t)
109     {
110         relocker< Lock > relock_guard;
111         sync::unique_lock< sync::mutex > internal_lock(m_mutex);
112         relock_guard.unlock(lock);
113         return m_cond.timed_wait(internal_lock, t);
114     }
115 
116     template< typename Lock, typename Time, typename Predicate >
117     typename enable_if_c< sync::detail::time_traits< Time >::is_specialized, bool >::type
118     timed_wait(Lock& lock, Time const& t, Predicate pred)
119     {
120         while (!pred())
121         {
122             if (!this->timed_wait(lock, t))
123                 return pred();
124         }
125         return true;
126     }
127 
128     template< typename Lock, typename TimePoint >
129     typename detail::enable_if_tag< TimePoint, detail::time_point_tag, sync::cv_status >::type
130     wait_until(Lock& lock, TimePoint const& abs_time)
131     {
132         relocker< Lock > relock_guard;
133         sync::unique_lock< sync::mutex > internal_lock(m_mutex);
134         relock_guard.unlock(lock);
135         return m_cond.wait_until(internal_lock, abs_time);
136     }
137 
138     template< typename Lock, typename TimePoint, typename Predicate >
139     typename detail::enable_if_tag< TimePoint, detail::time_point_tag, bool >::type
140     wait_until(Lock& lock, TimePoint const& abs_time, Predicate pred)
141     {
142         while (!pred())
143         {
144             if (this->wait_until(lock, abs_time) != sync::cv_status::no_timeout)
145                 return pred();
146         }
147         return true;
148     }
149 
150     template< typename Lock, typename Duration >
151     typename detail::enable_if_tag< Duration, detail::time_duration_tag, sync::cv_status >::type
152     wait_for(Lock& lock, Duration const& rel_time)
153     {
154         relocker< Lock > relock_guard;
155         sync::unique_lock< sync::mutex > internal_lock(m_mutex);
156         relock_guard.unlock(lock);
157         return m_cond.wait_for(internal_lock, rel_time);
158     }
159 
160     template< typename Lock, typename Duration, typename Predicate >
161     typename detail::enable_if_tag< Duration, detail::time_duration_tag, bool >::type
162     wait_for(Lock& lock, Duration const& rel_time, Predicate pred)
163     {
164         while (!pred())
165         {
166             if (this->wait_for(lock, rel_time) != sync::cv_status::no_timeout)
167                 return pred();
168         }
169         return true;
170     }
171 
172     BOOST_DELETED_FUNCTION(condition_variable_any(condition_variable_any const&))
173     BOOST_DELETED_FUNCTION(condition_variable_any& operator= (condition_variable_any const&))
174 };
175 
176 } // namespace abi
177 
178 } // namespace sync
179 
180 } // namespace boost
181 
182 #include <boost/sync/detail/footer.hpp>
183 
184 #endif // BOOST_SYNC_DETAIL_CONDITION_VARIABLES_CONDITION_VARIABLE_ANY_GENERIC_HPP_INCLUDED_
185