1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // (C) Copyright Ion Gaztanaga 2012-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_DETAIL_CONDITION_ANY_ALGORITHM_HPP |
12 | #define BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP |
13 | |
14 | #ifndef BOOST_CONFIG_HPP |
15 | # include <boost/config.hpp> |
16 | #endif |
17 | # |
18 | #if defined(BOOST_HAS_PRAGMA_ONCE) |
19 | # pragma once |
20 | #endif |
21 | |
22 | #include <boost/interprocess/detail/config_begin.hpp> |
23 | #include <boost/interprocess/detail/workaround.hpp> |
24 | #include <boost/interprocess/sync/scoped_lock.hpp> |
25 | #include <boost/interprocess/sync/detail/locks.hpp> |
26 | #include <limits> |
27 | |
28 | namespace boost { |
29 | namespace interprocess { |
30 | namespace ipcdetail { |
31 | |
32 | //////////////////////////////////////////////////////////////////////// |
33 | //////////////////////////////////////////////////////////////////////// |
34 | //////////////////////////////////////////////////////////////////////// |
35 | // |
36 | // Condition variable 'any' (able to use any type of external mutex) |
37 | // |
38 | // The code is based on Howard E. Hinnant's ISO C++ N2406 paper. |
39 | // Many thanks to Howard for his support and comments. |
40 | //////////////////////////////////////////////////////////////////////// |
41 | //////////////////////////////////////////////////////////////////////// |
42 | //////////////////////////////////////////////////////////////////////// |
43 | |
44 | // Required interface for ConditionAnyMembers |
45 | // class ConditionAnyMembers |
46 | // { |
47 | // typedef implementation_defined mutex_type; |
48 | // typedef implementation_defined condvar_type; |
49 | // |
50 | // condvar &get_condvar() |
51 | // mutex_type &get_mutex() |
52 | // }; |
53 | // |
54 | // Must be initialized as following |
55 | // |
56 | // get_condvar() [no threads blocked] |
57 | // get_mutex() [unlocked] |
58 | |
59 | template<class ConditionAnyMembers> |
60 | class condition_any_algorithm |
61 | { |
62 | private: |
63 | condition_any_algorithm(); |
64 | ~condition_any_algorithm(); |
65 | condition_any_algorithm(const condition_any_algorithm &); |
66 | condition_any_algorithm &operator=(const condition_any_algorithm &); |
67 | |
68 | typedef typename ConditionAnyMembers::mutex_type mutex_type; |
69 | typedef typename ConditionAnyMembers::condvar_type condvar_type; |
70 | |
71 | public: |
72 | template <class Lock> |
73 | static void wait(ConditionAnyMembers& data, Lock& lock) |
74 | { |
75 | //lock internal before unlocking external to avoid race with a notifier |
76 | scoped_lock<mutex_type> internal_lock(data.get_mutex()); |
77 | { |
78 | lock_inverter<Lock> inverted_lock(lock); |
79 | scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock); |
80 | { //unlock internal first to avoid deadlock with near simultaneous waits |
81 | scoped_lock<mutex_type> internal_unlock; |
82 | internal_lock.swap(internal_unlock); |
83 | data.get_condvar().wait(internal_unlock); |
84 | } |
85 | } |
86 | } |
87 | |
88 | template <class Lock, class TimePoint> |
89 | static bool timed_wait(ConditionAnyMembers &data, Lock& lock, const TimePoint &abs_time) |
90 | { |
91 | //lock internal before unlocking external to avoid race with a notifier |
92 | scoped_lock<mutex_type> internal_lock(data.get_mutex()); |
93 | { |
94 | //Unlock external lock and program for relock |
95 | lock_inverter<Lock> inverted_lock(lock); |
96 | scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock); |
97 | { //unlock internal first to avoid deadlock with near simultaneous waits |
98 | scoped_lock<mutex_type> internal_unlock; |
99 | internal_lock.swap(internal_unlock); |
100 | return data.get_condvar().timed_wait(internal_unlock, abs_time); |
101 | } |
102 | } |
103 | } |
104 | |
105 | static void signal(ConditionAnyMembers& data, bool broadcast) |
106 | { |
107 | scoped_lock<mutex_type> internal_lock(data.get_mutex()); |
108 | if(broadcast){ |
109 | data.get_condvar().notify_all(); |
110 | } |
111 | else{ |
112 | data.get_condvar().notify_one(); |
113 | } |
114 | } |
115 | }; |
116 | |
117 | |
118 | template<class ConditionAnyMembers> |
119 | class condition_any_wrapper |
120 | { |
121 | //Non-copyable |
122 | condition_any_wrapper(const condition_any_wrapper &); |
123 | condition_any_wrapper &operator=(const condition_any_wrapper &); |
124 | |
125 | ConditionAnyMembers m_data; |
126 | typedef ipcdetail::condition_any_algorithm<ConditionAnyMembers> algo_type; |
127 | |
128 | public: |
129 | |
130 | condition_any_wrapper(){} |
131 | |
132 | ~condition_any_wrapper(){} |
133 | |
134 | ConditionAnyMembers & get_members() |
135 | { return m_data; } |
136 | |
137 | const ConditionAnyMembers & get_members() const |
138 | { return m_data; } |
139 | |
140 | void notify_one() |
141 | { algo_type::signal(m_data, false); } |
142 | |
143 | void notify_all() |
144 | { algo_type::signal(m_data, true); } |
145 | |
146 | template <typename Lock> |
147 | void wait(Lock& lock) |
148 | { |
149 | if (!lock) |
150 | throw lock_exception(); |
151 | algo_type::wait(m_data, lock); |
152 | } |
153 | |
154 | template <typename L, typename Pr> |
155 | void wait(L& lock, Pr pred) |
156 | { |
157 | if (!lock) |
158 | throw lock_exception(); |
159 | |
160 | while (!pred()) |
161 | algo_type::wait(m_data, lock); |
162 | } |
163 | |
164 | template <typename L, typename TimePoint> |
165 | bool timed_wait(L& lock, const TimePoint &abs_time) |
166 | { |
167 | if (!lock) |
168 | throw lock_exception(); |
169 | return algo_type::timed_wait(m_data, lock, abs_time); |
170 | } |
171 | |
172 | template <typename L, typename TimePoint, typename Pr> |
173 | bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred) |
174 | { |
175 | if (!lock) |
176 | throw lock_exception(); |
177 | while (!pred()){ |
178 | if (!algo_type::timed_wait(m_data, lock, abs_time)) |
179 | return pred(); |
180 | } |
181 | return true; |
182 | } |
183 | }; |
184 | |
185 | } //namespace ipcdetail |
186 | } //namespace interprocess |
187 | } //namespace boost |
188 | |
189 | #include <boost/interprocess/detail/config_end.hpp> |
190 | |
191 | #endif //BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP |
192 | |